Bug 7947: Move subscribers to a separate cache
[lispflowmapping.git] / mappingservice / implementation / src / main / java / org / opendaylight / lispflowmapping / implementation / MappingService.java
1 /*
2  * Copyright (c) 2015, 2017 Cisco Systems, Inc.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.lispflowmapping.implementation;
9
10 import com.google.common.base.Preconditions;
11 import com.google.common.util.concurrent.Futures;
12 import java.util.ArrayList;
13 import java.util.List;
14 import java.util.Set;
15 import java.util.concurrent.Future;
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
18 import org.opendaylight.lispflowmapping.config.ConfigIni;
19 import org.opendaylight.lispflowmapping.dsbackend.DataStoreBackEnd;
20 import org.opendaylight.lispflowmapping.implementation.mdsal.AuthenticationKeyDataListener;
21 import org.opendaylight.lispflowmapping.implementation.mdsal.MappingDataListener;
22 import org.opendaylight.lispflowmapping.implementation.util.DSBEInputUtil;
23 import org.opendaylight.lispflowmapping.implementation.util.RPCInputConvertorUtil;
24 import org.opendaylight.lispflowmapping.interfaces.dao.ILispDAO;
25 import org.opendaylight.lispflowmapping.interfaces.dao.Subscriber;
26 import org.opendaylight.lispflowmapping.interfaces.mappingservice.IMappingService;
27 import org.opendaylight.lispflowmapping.lisp.type.MappingData;
28 import org.opendaylight.lispflowmapping.lisp.util.LispAddressUtil;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.SiteId;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.XtrId;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.container.Eid;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.locatorrecords.LocatorRecord;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.locatorrecords.LocatorRecordBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.authkey.container.MappingAuthkey;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecord;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecordBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.AddKeyInput;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.AddKeysInput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.AddMappingInput;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.AddMappingsInput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetAllKeysOutput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetAllMappingsOutput;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetKeyInput;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetKeyOutput;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetKeyOutputBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetKeysInput;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetKeysOutput;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetMappingInput;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetMappingOutput;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetMappingOutputBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetMappingWithXtrIdInput;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetMappingWithXtrIdOutput;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetMappingWithXtrIdOutputBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetMappingsInput;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetMappingsOutput;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.MappingOrigin;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.OdlMappingserviceService;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.RemoveKeyInput;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.RemoveKeysInput;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.RemoveMappingInput;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.RemoveMappingsInput;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.UpdateKeyInput;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.UpdateKeysInput;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.UpdateMappingInput;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.UpdateMappingsInput;
66 import org.opendaylight.yangtools.yang.common.RpcError;
67 import org.opendaylight.yangtools.yang.common.RpcResult;
68 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
71
72 /**
73  * Dispatcher of API calls that implements the RPC and Java APIs in mappingservice.yang and IMappingService
74  * respectively. It also coordinates and acts as container for all objects in charge of
75  *  - saving and updating md-sal datastore stored mappings
76  *  - monitoring md-sal datastore mapping updates and pushing them to the in memory mapping-system
77  *  - in memory mapping-system
78  *
79  * @author Lorand Jakab
80  * @author Florin Coras
81  *
82  */
83 public class MappingService implements OdlMappingserviceService, IMappingService, AutoCloseable {
84     protected static final Logger LOG = LoggerFactory.getLogger(MappingService.class);
85     private static final String NOT_FOUND_TAG = "data-missing";
86     private static final String DATA_EXISTS_TAG = "data-exists";
87
88     private MappingSystem mappingSystem;
89     private DataStoreBackEnd dsbe;
90     private AuthenticationKeyDataListener keyListener;
91     private MappingDataListener mappingListener;
92     private final ILispDAO dao;
93
94     private final DataBroker dataBroker;
95     private final NotificationPublishService notificationPublishService;
96
97     private boolean mappingMergePolicy = ConfigIni.getInstance().mappingMergeIsSet();
98     private boolean notificationPolicy = ConfigIni.getInstance().smrIsSet();
99     private boolean iterateMask = true;
100     private boolean isMaster = false;
101
102     public MappingService(final DataBroker broker,
103             final NotificationPublishService notificationPublishService,
104             final ILispDAO lispDAO) {
105         this.dataBroker = broker;
106         this.notificationPublishService = notificationPublishService;
107         this.dao = lispDAO;
108
109         LOG.debug("MappingService created!");
110     }
111
112
113     @Override
114     public void setMappingMerge(boolean mergeMapping) {
115         this.mappingMergePolicy = mergeMapping;
116         if (mappingSystem != null) {
117             mappingSystem.setMappingMerge(mergeMapping);
118             ConfigIni.getInstance().setMappingMerge(mappingMergePolicy);
119         }
120     }
121
122     @Override
123     public void setLookupPolicy(IMappingService.LookupPolicy policy) {
124         ConfigIni.getInstance().setLookupPolicy(policy);
125     }
126
127     public void initialize() {
128         LOG.info("Mapping Service initializing...");
129         dsbe = new DataStoreBackEnd(dataBroker);
130
131         mappingSystem = new MappingSystem(dao, iterateMask, notificationPublishService, mappingMergePolicy);
132         mappingSystem.setDataStoreBackEnd(dsbe);
133         mappingSystem.initialize();
134
135         keyListener = new AuthenticationKeyDataListener(dataBroker, mappingSystem);
136         mappingListener = new MappingDataListener(dataBroker, mappingSystem, notificationPublishService);
137         LOG.info("Mapping Service loaded.");
138     }
139
140     @Override
141     public Future<RpcResult<Void>> addKey(AddKeyInput input) {
142         Preconditions.checkNotNull(input, "add-key RPC input must be not null!");
143         LOG.trace("RPC received to add the following key: " + input.toString());
144
145         RpcResultBuilder<Void> rpcResultBuilder;
146
147         MappingAuthkey key = mappingSystem.getAuthenticationKey(convertToBinaryIfNecessary(input.getEid()));
148
149         if (key != null) {
150             String message = "Key already exists! Please use update-key if you want to change it.";
151             rpcResultBuilder = RpcResultBuilder.<Void>failed()
152                     .withError(RpcError.ErrorType.PROTOCOL, DATA_EXISTS_TAG, message);
153             return Futures.immediateFuture(rpcResultBuilder.build());
154         }
155
156         dsbe.addAuthenticationKey(RPCInputConvertorUtil.toAuthenticationKey(input));
157         rpcResultBuilder = RpcResultBuilder.success();
158
159         return Futures.immediateFuture(rpcResultBuilder.build());
160     }
161
162     @Override
163     public Future<RpcResult<Void>> addMapping(AddMappingInput input) {
164         Preconditions.checkNotNull(input, "add-mapping RPC input must be not null!");
165         LOG.trace("RPC received to add the following mapping: " + input.toString());
166
167         dsbe.addMapping(RPCInputConvertorUtil.toMapping(input));
168
169         RpcResultBuilder<Void> rpcResultBuilder;
170
171         rpcResultBuilder = RpcResultBuilder.success();
172
173         return Futures.immediateFuture(rpcResultBuilder.build());
174     }
175
176     @Override
177     public void addMapping(MappingOrigin origin, Eid key, SiteId siteId, MappingData mappingData) {
178         // SB registrations are first written to the MappingSystem and only afterwards are persisted to the datastore
179         if (origin.equals(MappingOrigin.Southbound)) {
180             // Store data first in MapCache and only afterwards persist to datastore. This should be used only for SB
181             // registrations
182             mappingSystem.addMapping(origin, key, mappingData);
183             dsbe.addMapping(DSBEInputUtil.toMapping(origin, key, siteId, mappingData));
184             if (mappingData.getXtrId() != null) {
185                 dsbe.addXtrIdMapping(DSBEInputUtil.toXtrIdMapping(mappingData));
186             }
187         } else {
188             dsbe.addMapping(DSBEInputUtil.toMapping(origin, key, siteId, mappingData));
189         }
190     }
191
192     @Override
193     public MappingData addNegativeMapping(Eid key) {
194         return mappingSystem.addNegativeMapping(key);
195     }
196
197     @Override
198     public void refreshMappingRegistration(Eid key, XtrId xtrId, Long timestamp) {
199         mappingSystem.refreshMappingRegistration(key, xtrId, timestamp);
200     }
201
202     @Override
203     public Future<RpcResult<GetKeyOutput>> getKey(GetKeyInput input) {
204         Preconditions.checkNotNull(input, "get-key RPC input must be not null!");
205         LOG.trace("RPC received to get the following key: " + input.toString());
206
207         RpcResultBuilder<GetKeyOutput> rpcResultBuilder;
208
209         MappingAuthkey key = mappingSystem.getAuthenticationKey(convertToBinaryIfNecessary(input.getEid()));
210
211         if (key == null) {
212             String message = "Key was not found in the mapping database";
213             rpcResultBuilder = RpcResultBuilder.<GetKeyOutput>failed()
214                     .withError(RpcError.ErrorType.APPLICATION, NOT_FOUND_TAG, message);
215         } else {
216             rpcResultBuilder = RpcResultBuilder.success(new GetKeyOutputBuilder().setMappingAuthkey(key));
217         }
218
219         return Futures.immediateFuture(rpcResultBuilder.build());
220     }
221
222     @Override
223     public Future<RpcResult<GetMappingOutput>> getMapping(GetMappingInput input) {
224         Preconditions.checkNotNull(input, "get-mapping RPC input must be not null!");
225         LOG.trace("RPC received to get the following mapping: " + input.toString());
226
227         RpcResultBuilder<GetMappingOutput> rpcResultBuilder;
228
229         MappingData reply = mappingSystem.getMapping(convertToBinaryIfNecessary(input.getEid()));
230
231         if (reply == null) {
232             String message = "No mapping was found in the mapping database";
233             rpcResultBuilder = RpcResultBuilder.<GetMappingOutput>failed()
234                     .withError(RpcError.ErrorType.APPLICATION, NOT_FOUND_TAG, message);
235         } else {
236             final MappingRecord convertedReply = convertFromBinaryIfNecessary(reply.getRecord());
237             rpcResultBuilder = RpcResultBuilder.success(new GetMappingOutputBuilder().setMappingRecord(convertedReply));
238         }
239
240         return Futures.immediateFuture(rpcResultBuilder.build());
241     }
242
243     @Override
244     public MappingData getMapping(MappingOrigin origin, Eid key) {
245         return mappingSystem.getMapping(origin, key);
246     }
247
248     @Override
249     public MappingData getMapping(Eid key) {
250         return mappingSystem.getMapping(key);
251     }
252
253     @Override
254     public MappingData getMapping(Eid srcKey, Eid dstKey) {
255         return mappingSystem.getMapping(srcKey, dstKey);
256     }
257
258     @Override
259     public void subscribe(Subscriber subscriber, Eid subscribedEid) {
260         mappingSystem.subscribe(subscriber, subscribedEid);
261     }
262
263     @Override
264     public Set<Subscriber> getSubscribers(Eid eid) {
265         return mappingSystem.getSubscribers(eid);
266     }
267
268     @Override
269     public Future<RpcResult<GetMappingWithXtrIdOutput>> getMappingWithXtrId(GetMappingWithXtrIdInput input) {
270         Preconditions.checkNotNull(input, "get-mapping RPC input must be not null!");
271         LOG.trace("RPC received to get the following mapping: " + input.toString());
272
273         RpcResultBuilder<GetMappingWithXtrIdOutput> rpcResultBuilder;
274
275         MappingData reply = mappingSystem.getMapping(null, convertToBinaryIfNecessary(input.getEid()),
276                 input.getXtrId());
277
278         if (reply == null) {
279             String message = "No mapping was found in the mapping database";
280             rpcResultBuilder = RpcResultBuilder.<GetMappingWithXtrIdOutput>failed()
281                     .withError(RpcError.ErrorType.APPLICATION, NOT_FOUND_TAG, message);
282         } else {
283             final MappingRecord convertedReply = convertFromBinaryIfNecessary(reply.getRecord());
284             rpcResultBuilder = RpcResultBuilder.success(new GetMappingWithXtrIdOutputBuilder()
285                     .setMappingRecord(convertedReply));
286         }
287
288         return Futures.immediateFuture(rpcResultBuilder.build());
289     }
290
291     @Override
292     public Future<RpcResult<Void>> removeKey(RemoveKeyInput input) {
293         Preconditions.checkNotNull(input, "remove-key RPC input must be not null!");
294         LOG.trace("RPC received to remove the following key: " + input.toString());
295
296         RpcResultBuilder<Void> rpcResultBuilder;
297
298         dsbe.removeAuthenticationKey(RPCInputConvertorUtil.toAuthenticationKey(input));
299
300         rpcResultBuilder = RpcResultBuilder.success();
301
302         return Futures.immediateFuture(rpcResultBuilder.build());
303     }
304
305     @Override
306     public Future<RpcResult<Void>> removeMapping(RemoveMappingInput input) {
307         Preconditions.checkNotNull(input, "remove-mapping RPC input must be not null!");
308         LOG.trace("RPC received to remove the following mapping: " + input.toString());
309
310         RpcResultBuilder<Void> rpcResultBuilder;
311
312         dsbe.removeMapping(RPCInputConvertorUtil.toMapping(input));
313
314         rpcResultBuilder = RpcResultBuilder.success();
315
316         return Futures.immediateFuture(rpcResultBuilder.build());
317     }
318
319     @Override
320     public void removeMapping(MappingOrigin origin, Eid key) {
321         if (origin.equals(MappingOrigin.Southbound)) {
322             mappingSystem.removeMapping(origin, key);
323         }
324         dsbe.removeMapping(DSBEInputUtil.toMapping(origin, key));
325     }
326
327     @Override
328     public Future<RpcResult<Void>> updateKey(UpdateKeyInput input) {
329         Preconditions.checkNotNull(input, "update-key RPC input must be not null!");
330         LOG.trace("RPC received to update the following key: " + input.toString());
331
332         RpcResultBuilder<Void> rpcResultBuilder;
333
334         MappingAuthkey key = mappingSystem.getAuthenticationKey(convertToBinaryIfNecessary(input.getEid()));
335
336         if (key == null) {
337             String message = "Key doesn't exist! Please use add-key if you want to create a new authentication key.";
338             rpcResultBuilder = RpcResultBuilder.<Void>failed()
339                     .withError(RpcError.ErrorType.PROTOCOL, NOT_FOUND_TAG, message);
340             return Futures.immediateFuture(rpcResultBuilder.build());
341         }
342
343         dsbe.updateAuthenticationKey(RPCInputConvertorUtil.toAuthenticationKey(input));
344         rpcResultBuilder = RpcResultBuilder.success();
345
346         return Futures.immediateFuture(rpcResultBuilder.build());
347     }
348
349     @Override
350     public Future<RpcResult<Void>> updateMapping(UpdateMappingInput input) {
351         LOG.trace("RPC received to update the following mapping: " + input.toString());
352         Preconditions.checkNotNull(input, "update-mapping RPC input must be not null!");
353
354         RpcResultBuilder<Void> rpcResultBuilder;
355
356         dsbe.updateMapping(RPCInputConvertorUtil.toMapping(input));
357
358         rpcResultBuilder = RpcResultBuilder.success();
359
360         return Futures.immediateFuture(rpcResultBuilder.build());
361     }
362
363     @Override
364     public Future<RpcResult<Void>> removeKeys(RemoveKeysInput input) {
365         // TODO Auto-generated method stub
366         return null;
367     }
368
369     @Override
370     public Future<RpcResult<Void>> removeMappings(RemoveMappingsInput input) {
371         // TODO Auto-generated method stub
372         return null;
373     }
374
375     @Override
376     public Future<RpcResult<GetKeysOutput>> getKeys(GetKeysInput input) {
377         // TODO Auto-generated method stub
378         return null;
379     }
380
381     @Override
382     public Future<RpcResult<Void>> addMappings(AddMappingsInput input) {
383         // TODO Auto-generated method stub
384         return null;
385     }
386
387     @Override
388     public Future<RpcResult<Void>> updateKeys(UpdateKeysInput input) {
389         // TODO Auto-generated method stub
390         return null;
391     }
392
393     @Override
394     public Future<RpcResult<Void>> removeAllMappings() {
395         // TODO Auto-generated method stub
396         return null;
397     }
398
399     @Override
400     public Future<RpcResult<Void>> removeAllKeys() {
401         // TODO Auto-generated method stub
402         return null;
403     }
404
405     @Override
406     public Future<RpcResult<GetAllKeysOutput>> getAllKeys() {
407         // TODO Auto-generated method stub
408         return null;
409     }
410
411     @Override
412     public Future<RpcResult<Void>> updateMappings(UpdateMappingsInput input) {
413         // TODO Auto-generated method stub
414         return null;
415     }
416
417     @Override
418     public Future<RpcResult<Void>> addKeys(AddKeysInput input) {
419         // TODO Auto-generated method stub
420         return null;
421     }
422
423     @Override
424     public Future<RpcResult<GetAllMappingsOutput>> getAllMappings() {
425         // TODO Auto-generated method stub
426         return null;
427     }
428
429     @Override
430     public Future<RpcResult<GetMappingsOutput>> getMappings(
431             GetMappingsInput input) {
432         // TODO Auto-generated method stub
433         return null;
434     }
435
436     @Override
437     public Future<RpcResult<Void>> removeAllOperationalContent() {
438         RpcResultBuilder<Void> rpcResultBuilder;
439
440         /*
441          * Since master nodes ignore datastore changes for southbound originated mappings, they need to be removed
442          * explicitly.
443          */
444         if (isMaster) {
445             mappingSystem.cleanSBMappings();
446         }
447         dsbe.removeAllOperationalDatastoreContent();
448
449         rpcResultBuilder = RpcResultBuilder.success();
450
451         return Futures.immediateFuture(rpcResultBuilder.build());
452     }
453
454     @Override
455     public Eid getWidestNegativePrefix(Eid key) {
456         return mappingSystem.getWidestNegativePrefix(key);
457     }
458
459     @Override
460     public void addAuthenticationKey(Eid key, MappingAuthkey authKey) {
461         dsbe.addAuthenticationKey(DSBEInputUtil.toAuthenticationKey(key, authKey));
462     }
463
464     @Override
465     public MappingAuthkey getAuthenticationKey(Eid key) {
466         return mappingSystem.getAuthenticationKey(key);
467     }
468
469     @Override
470     public void removeAuthenticationKey(Eid key) {
471         dsbe.removeAuthenticationKey(DSBEInputUtil.toAuthenticationKey(key, null));
472     }
473
474     @Override
475     public void addData(MappingOrigin origin, Eid key, String subKey, Object data) {
476         mappingSystem.addData(origin, key, subKey, data);
477     }
478
479     @Override
480     public Object getData(MappingOrigin origin, Eid key, String subKey) {
481         return mappingSystem.getData(origin, key, subKey);
482     }
483
484     @Override
485     public void removeData(MappingOrigin origin, Eid key, String subKey) {
486         mappingSystem.removeData(origin, key, subKey);
487     }
488
489     @Override
490     public Eid getParentPrefix(Eid key) {
491         return mappingSystem.getParentPrefix(key);
492     }
493
494     @Override
495     public String printMappings() {
496         return mappingSystem.printMappings();
497     }
498
499     @Override
500     public String prettyPrintMappings() {
501         return mappingSystem.prettyPrintMappings();
502     }
503
504     @Override
505     public String printKeys() {
506         return mappingSystem.printKeys();
507     }
508
509     @Override
510     public String prettyPrintKeys() {
511         return mappingSystem.prettyPrintKeys();
512     }
513
514     @Override
515     public void close() throws Exception {
516         LOG.info("Mapping Service is being destroyed!");
517         keyListener.closeDataChangeListener();
518         mappingListener.closeDataChangeListener();
519         mappingSystem.destroy();
520     }
521
522     @Override
523     public void cleanCachedMappings() {
524         mappingSystem.cleanCaches();
525         dsbe.removeAllDatastoreContent();
526     }
527
528     private static Eid convertToBinaryIfNecessary(Eid eid) {
529         if (LispAddressUtil.addressNeedsConversionToBinary(eid.getAddress())) {
530             return LispAddressUtil.convertToBinary(eid);
531         }
532         return eid;
533     }
534
535     private static MappingRecord convertFromBinaryIfNecessary(MappingRecord originalRecord) {
536         List<LocatorRecord> originalLocators = originalRecord.getLocatorRecord();
537
538         List<LocatorRecord> convertedLocators = null;
539         if (originalLocators != null) {
540             // If convertedLocators is non-null, while originalLocators is also non-null, conversion has been made
541             convertedLocators = convertFromBinaryIfNecessary(originalLocators);
542         }
543
544         if (LispAddressUtil.addressNeedsConversionFromBinary(originalRecord.getEid().getAddress())
545                 || (originalLocators != null && convertedLocators != null)) {
546             MappingRecordBuilder mrb = new MappingRecordBuilder(originalRecord);
547             mrb.setEid(LispAddressUtil.convertFromBinary(originalRecord.getEid()));
548             if (convertedLocators != null) {
549                 mrb.setLocatorRecord(convertedLocators);
550             }
551             return mrb.build();
552         }
553         return originalRecord;
554     }
555
556     private static List<LocatorRecord> convertFromBinaryIfNecessary(List<LocatorRecord> originalLocators) {
557         List<LocatorRecord> convertedLocators = null;
558         for (LocatorRecord record : originalLocators) {
559             if (LispAddressUtil.addressNeedsConversionFromBinary(record.getRloc().getAddress())) {
560                 LocatorRecordBuilder lrb = new LocatorRecordBuilder(record);
561                 lrb.setRloc(LispAddressUtil.convertFromBinary(record.getRloc()));
562                 if (convertedLocators == null) {
563                     convertedLocators = new ArrayList<LocatorRecord>();
564                 }
565                 convertedLocators.add(lrb.build());
566             }
567         }
568         if (convertedLocators != null) {
569             return convertedLocators;
570         }
571         return originalLocators;
572     }
573
574     @Override
575     public void setIsMaster(boolean isMaster) {
576         this.isMaster = isMaster;
577         mappingSystem.setIsMaster(isMaster);
578     }
579
580     @Override
581     public boolean isMaster() {
582         return isMaster;
583     }
584 }