Project

General

Profile

Download (23.7 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2017 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.cdm.io.common.utils;
10

    
11
import java.util.Arrays;
12
import java.util.HashMap;
13
import java.util.HashSet;
14
import java.util.List;
15
import java.util.Map;
16
import java.util.Optional;
17
import java.util.Set;
18
import java.util.UUID;
19
import java.util.function.Predicate;
20

    
21
import org.apache.log4j.Logger;
22

    
23
import eu.etaxonomy.cdm.api.application.ICdmRepository;
24
import eu.etaxonomy.cdm.api.service.IService;
25
import eu.etaxonomy.cdm.common.CdmUtils;
26
import eu.etaxonomy.cdm.io.common.ImportResult;
27
import eu.etaxonomy.cdm.io.common.ImportStateBase;
28
import eu.etaxonomy.cdm.model.agent.AgentBase;
29
import eu.etaxonomy.cdm.model.agent.Institution;
30
import eu.etaxonomy.cdm.model.agent.Person;
31
import eu.etaxonomy.cdm.model.agent.Team;
32
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
33
import eu.etaxonomy.cdm.model.common.CdmBase;
34
import eu.etaxonomy.cdm.model.common.ICdmBase;
35
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
36
import eu.etaxonomy.cdm.model.media.Rights;
37
import eu.etaxonomy.cdm.model.media.RightsType;
38
import eu.etaxonomy.cdm.model.name.HybridRelationship;
39
import eu.etaxonomy.cdm.model.name.INonViralName;
40
import eu.etaxonomy.cdm.model.name.TaxonName;
41
import eu.etaxonomy.cdm.model.occurrence.Collection;
42
import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;
43
import eu.etaxonomy.cdm.model.reference.Reference;
44
import eu.etaxonomy.cdm.strategy.match.DefaultMatchStrategy;
45
import eu.etaxonomy.cdm.strategy.match.IMatchStrategyEqual;
46
import eu.etaxonomy.cdm.strategy.match.IMatchable;
47
import eu.etaxonomy.cdm.strategy.match.MatchException;
48
import eu.etaxonomy.cdm.strategy.match.MatchMode;
49

    
50
/**
51
 * Helper class for deduplicating authors, references, names, etc.
52
 * during import.
53
 *
54
 * Note 2021: Was originally used as fast deduplication tool for commandline imports
55
 * into empty databases. Currently it is transformed into a deduplication tool that
56
 * can be used during application based imports.
57
 *
58
 * @author a.mueller
59
 * @since 11.02.2017
60
 */
61
public class ImportDeduplicationHelper {
62

    
63
    private static final Logger logger = Logger.getLogger(ImportDeduplicationHelper.class);
64

    
65
    private ICdmRepository repository;
66

    
67
    //for possible future use
68
    @SuppressWarnings("unused")
69
    private ImportStateBase<?,?> state;
70

    
71
    public static final int NEVER_USE_MAP = 0;
72
    public static final int ALWAYS_USE_MAP = -1;
73
    //should deduplication use maps indexing the full database content? If yes, what is the maximum number of records for this.
74
    //If more records exist deduplication is done on the fly.
75
    //0 = never use map
76
    //-1 = always use map
77
    private int maxCountFullLoad = ALWAYS_USE_MAP;
78
    public int getMaxCountFullLoad() {
79
        return maxCountFullLoad;
80
    }
81
    public void setMaxCountFullLoad(int maxCountFullLoad) {
82
        this.maxCountFullLoad = maxCountFullLoad;
83
    }
84

    
85
    private enum Status{
86
        NOT_INIT,
87
        USE_MAP,
88
        USE_REPO;
89
    }
90

    
91
    private class DedupInfo<S extends IdentifiableEntity>{
92
        Class<S> clazz;
93
        IMatchStrategyEqual matcher;
94
        Map<String, Set<S>> map = new HashMap<>();
95
        Status status = Status.NOT_INIT;
96

    
97
        @SuppressWarnings("unchecked")
98
        private DedupInfo(Class<S> clazz, DedupMap dedupMap){
99
            this.clazz = clazz;
100
            if (IMatchable.class.isAssignableFrom(clazz)) {
101
                matcher = DefaultMatchStrategy.NewInstance((Class<IMatchable>)clazz);
102
            }
103
            dedupMap.put(clazz, this);
104
        }
105
        @Override
106
        public String toString() {
107
            return clazz.getSimpleName() + ":" + status.name()+":mapsize=" + map.size()+":"+ (matcher == null?"without":"with") + " matcher";
108
        }
109
    }
110

    
111
    private class DedupMap<T extends IdentifiableEntity> extends HashMap<Class<T>, DedupInfo<T>>{
112
        private static final long serialVersionUID = 3757206594833330646L;
113
    }
114
    private DedupMap<? extends IdentifiableEntity> dedupMap = new DedupMap<>();
115

    
116
    private DedupInfo<Reference> referenceDedupInfo = new DedupInfo<>(Reference.class, dedupMap);
117
    private DedupInfo<Person> personDedupInfo = new DedupInfo<>(Person.class, dedupMap);
118
    private DedupInfo<Team> teamDedupInfo = new DedupInfo<>(Team.class, dedupMap);
119
    private DedupInfo<TaxonName> nameDedupInfo = new DedupInfo<>(TaxonName.class, dedupMap);
120

    
121

    
122
    private Status institutionStatus = Status.NOT_INIT;
123
    private Status copyrightStatus = Status.NOT_INIT;
124
    private Status collectionStatus = Status.NOT_INIT;
125

    
126
    private Map<String, Set<Institution>> institutionMap = new HashMap<>();
127
    //using titleCache
128
    private Map<String, Set<Rights>> copyrightMap = new HashMap<>();
129
    private Map<String, Set<Collection>> collectionMap = new HashMap<>();
130

    
131
    /**
132
     * Clears all internal maps.
133
     */
134
    public void reset() {
135
        dedupMap.values().forEach(di->di.map.clear());
136
        institutionMap.clear();
137
        copyrightMap.clear();
138
        collectionMap.clear();
139
    }
140

    
141
//    private IMatchStrategy collectionMatcher = DefaultMatchStrategy.NewInstance(Collection.class);
142

    
143
 // ************************** FACTORY *******************************/
144

    
145
     public static <STATE extends ImportStateBase<?,?>> ImportDeduplicationHelper NewInstance(ICdmRepository repository, STATE state){
146
         return new ImportDeduplicationHelper(repository, state);
147
     }
148

    
149
 // ************************ CONSTRUCTOR *****************************/
150

    
151
    private ImportDeduplicationHelper(ICdmRepository repository, ImportStateBase<?,?> state) {
152
         this.repository = repository;
153
         if (repository == null){
154
             logger.warn("Repository is null. Deduplication does not work against database.");
155
         }
156
         if (state == null){
157
             logger.warn("State is null. Deduplication works without state.");
158
         }
159
         this.state = state;
160
         try {
161
             dedupMap.get(Reference.class).matcher.setMatchMode("title", MatchMode.EQUAL);
162
             dedupMap.get(Team.class).matcher.setMatchMode("nomenclaturalTitleCache", MatchMode.EQUAL_OR_SECOND_NULL);
163
         } catch (MatchException e) {
164
             throw new RuntimeException(e);  //should not happen
165
         }
166
    }
167

    
168
    public void restartSession(){
169
        restartSession(repository, null);
170
    }
171

    
172
    /**
173
     * Clears all internal maps and loads them with same data as before but in current session.
174
     */
175
    public void restartSession(ICdmRepository repository, ImportResult importResult){
176
        if (repository == null){
177
            return;
178
        }
179
        referenceDedupInfo.map = refreshSetMap(referenceDedupInfo.map, (IService)repository.getReferenceService(), importResult);
180
        personDedupInfo.map = refreshSetMap(personDedupInfo.map, (IService)repository.getAgentService(), importResult);
181
        teamDedupInfo.map = refreshSetMap(teamDedupInfo.map, (IService)repository.getAgentService(), importResult);
182
        institutionMap = refreshSetMap(institutionMap, (IService)repository.getAgentService(), importResult);
183

    
184
        nameDedupInfo.map = refreshSetMap(nameDedupInfo.map, (IService)repository.getNameService(), importResult);
185
        collectionMap = refreshSetMap(collectionMap, (IService)repository.getCollectionService(), importResult);
186
        //TODO copyright ?
187
    }
188

    
189
    //maybe this was used for Institution before
190
    private <T extends ICdmBase> Map<String, T> refreshMap(Map<String, T> oldMap,
191
            IService<T> service, ImportResult importResult) {
192

    
193
        Map<String, T> newMap = new HashMap<>();
194
        for (String key : oldMap.keySet()){
195
            T old = oldMap.get(key);
196
            if (old!= null){
197
                T cdmBase = service.find(old.getUuid());
198
                if (cdmBase == null){
199
                    String message = "No cdm object was found for uuid " + old.getUuid() + " of class " + old.getClass().getSimpleName();
200
                    importResult.addWarning(message);
201
                }else{
202
                    newMap.put(key, CdmBase.deproxy(cdmBase));
203
                }
204
            }else{
205
                String message = "Value for key " +  key + " was null in deduplication map";
206
                importResult.addWarning(message);
207
            }
208
        }
209
        return newMap;
210
    }
211

    
212
    private <T extends ICdmBase> Map<String, Set<T>> refreshSetMap(Map<String, Set<T>> oldMap,
213
            IService<T> service, ImportResult importResult) {
214

    
215
        Map<String, Set<T>> newMap = new HashMap<>();
216
        logger.debug("Start loading map");  //TODO debug only
217
        //create UUID set
218
        Set<UUID> uuidSet = new HashSet<>();
219
        for (String key : oldMap.keySet()){
220
            Set<T> oldSet = oldMap.get(key);
221
            for (T item : oldSet){
222
                UUID uuid = item.getUuid();
223
                uuidSet.add(uuid);
224
            }
225
        }
226
        //create uuid-item map
227
        Map<UUID, T> itemMap = new HashMap<>();
228
        List<T> list = service.find(uuidSet);
229
        for (T item : list){
230
            itemMap.put(item.getUuid(), item);
231
        }
232
        //refresh
233
        for (String key : oldMap.keySet()){
234
            Set<T> oldSet = oldMap.get(key);
235
            Set<T> newSet = new HashSet<>();
236
            if (oldSet != null){
237
                newMap.put(key, newSet);
238
                for (T item : oldSet){
239
                    T cdmBase = CdmBase.deproxy(itemMap.get(item.getUuid()));
240
                    if (cdmBase == null){
241
                        String message = "No cdm object was found for uuid " + item.getUuid() + " of class " + item.getClass().getSimpleName();
242
                        importResult.addWarning(message);
243
                    }else{
244
                        newSet.add(cdmBase);
245
                    }
246
                }
247
            }else{
248
                String message = "Value for key " +  key + " was null in deduplication map";
249
                importResult.addWarning(message);
250
            }
251
        }
252
        return newMap;
253
    }
254

    
255
//************************ PUTTER / GETTER *****************************/
256

    
257
    //ENTITY
258
    private <S extends IdentifiableEntity<?>> void putEntity(String title, S entity, Map<String,Set<S>> map){
259
        Set<S> entitySet = map.get(title);
260
        if (entitySet == null){
261
            entitySet = new HashSet<>();
262
            map.put(title, entitySet);
263
        }
264
        entitySet.add(CdmBase.deproxy(entity));
265
    }
266

    
267
    private <S extends IdentifiableEntity> Set<S> getEntityByTitle(String title, DedupInfo<S> dedupInfo){
268
        return dedupInfo.map.get(title);
269
    }
270

    
271
    private <S extends IdentifiableEntity> Optional<S> getMatchingEntity(S entityOrig, DedupInfo<S> dedupInfo){
272
        S entity = CdmBase.deproxy(entityOrig);
273
        Predicate<S> matchFilter = reference ->{
274
            try {
275
                return dedupInfo.matcher.invoke((IMatchable)reference, (IMatchable)entity).isSuccessful();
276
            } catch (MatchException e) {
277
                throw new RuntimeException(e);
278
            }
279
        };
280
        Optional<S> result = Optional.ofNullable(getEntityByTitle(entity.getTitleCache(), dedupInfo))
281
                .orElse(new HashSet<>())
282
                .stream()
283
                .filter(matchFilter)
284
                .findAny();
285
        if (result.isPresent() || dedupInfo.status == Status.USE_MAP  || repository == null){
286
            return result;
287
        }else {
288
            try {
289
                return (Optional<S>)repository.getCommonService().findMatching((IMatchable)entity, dedupInfo.matcher).stream().findFirst();
290
            } catch (MatchException e) {
291
                throw new RuntimeException(e);
292
            }
293
        }
294
    }
295

    
296
    // AGENTS
297
    private void putAgentBase(String title, AgentBase<?> agent){
298
        if (agent.isInstanceOf(Person.class) ){
299
            putEntity(title, CdmBase.deproxy(agent, Person.class), personDedupInfo.map);
300
        }else if (agent.isInstanceOf(Team.class)){
301
            putEntity(title, CdmBase.deproxy(agent, Team.class), teamDedupInfo.map);
302
        }else{
303
            putEntity(title, CdmBase.deproxy(agent, Institution.class), institutionMap);
304
        }
305
    }
306

    
307
    private <T extends TeamOrPersonBase<?>> T getTeamOrPerson(T agent){
308
        T result = agent;
309
        if (agent.isInstanceOf(Person.class)){
310
            result = (T)getMatchingEntity(CdmBase.deproxy(agent, Person.class), personDedupInfo).orElse(null) ; // personMap.get(title);
311
        }else if (agent.isInstanceOf(Team.class)) {
312
            result = (T)getMatchingEntity(CdmBase.deproxy(agent, Team.class), teamDedupInfo).orElse(null); // teamMap.get(title);
313
        }
314
        return result;
315
    }
316

    
317
    //COLLECTIONS
318
    private Set<Collection> getCollections(String title){
319
        return collectionMap.get(title);
320
    }
321

    
322
    private Optional<Collection> getMatchingCollections(Collection existing){
323
        Predicate<Collection> matchFilter = collection ->{
324
//            try {
325
                //TODO right Collection matching
326
                if (CdmUtils.nullSafeEqual(collection.getName(), existing.getName())
327
                        && CdmUtils.nullSafeEqual(collection.getCode(), existing.getCode())){
328
                    return true;
329
                }else{
330
                    return false;
331
                }
332
//                return collectionMatcher.invoke(collection, existing);
333
//            } catch (MatchException e) {
334
//                throw new RuntimeException(e);
335
//            }
336
        };
337
        return Optional.ofNullable(getCollections(existing.getTitleCache()))
338
                .orElse(new HashSet<>())
339
                .stream()
340
                .filter(matchFilter)
341
                .findAny();
342
    }
343

    
344
// **************************** METHODS *****************************/
345

    
346
    /**
347
     * This method replaces name authors, nomenclatural reference and
348
     * nomenclatural reference author by existing authors and references
349
     * if matching authors or references exist. If not, the given authors
350
     * and references are added to the map of existing entities.
351
     *
352
     * @param state the import state
353
     * @param name the name with authors and references to replace
354
     */
355
    public void replaceAuthorNamesAndNomRef(INonViralName name) {
356

    
357
        TeamOrPersonBase<?> combAuthor = name.getCombinationAuthorship();
358
        name.setCombinationAuthorship(getExistingAuthor(combAuthor));
359

    
360
        TeamOrPersonBase<?> exAuthor = name.getExCombinationAuthorship();
361
        name.setExCombinationAuthorship(getExistingAuthor(exAuthor));
362

    
363
        TeamOrPersonBase<?> basioAuthor = name.getBasionymAuthorship();
364
        name.setBasionymAuthorship(getExistingAuthor(basioAuthor));
365

    
366
        TeamOrPersonBase<?> exBasioAuthor = name.getExBasionymAuthorship();
367
        name.setExBasionymAuthorship(getExistingAuthor(exBasioAuthor));
368

    
369
        INomenclaturalReference nomRef = name.getNomenclaturalReference();
370
        if (nomRef != null){
371
            TeamOrPersonBase<?> refAuthor = nomRef.getAuthorship();
372
            nomRef.setAuthorship(getExistingAuthor(refAuthor));
373

    
374
            Reference existingRef = getExistingReference((Reference)nomRef);
375
            //TODO AM: why do we need to check null here (we don't do this for authors, maybe because it is an original source?)
376
            if (existingRef != null){
377
                name.setNomenclaturalReference(existingRef);
378
            }
379
        }
380
    }
381

    
382
    public void replaceReferenceRelatedData(Reference ref) {
383

    
384
        TeamOrPersonBase<?> author = ref.getAuthorship();
385
        ref.setAuthorship(getExistingAuthor(author));
386

    
387
        ref.setInReference(getExistingReference(ref.getInReference()));
388
    }
389

    
390
    public <T extends TeamOrPersonBase<?>> T getExistingAuthor(T author) {
391
        if (author == null){
392
            return null;
393
        }else{
394
            //TODO
395
            init(personDedupInfo);
396
            init(teamDedupInfo);
397
            initAuthorTitleCaches(author);
398
            T result = getTeamOrPerson(author);
399
            if (result == null){
400
                putAgentBase(author.getTitleCache(), author);
401
                if (author.isInstanceOf(Team.class)){
402
                    handleTeam(CdmBase.deproxy(author, Team.class));
403
                }
404
                result = author;
405
            }
406
            return result;
407
        }
408
    }
409

    
410
    private <T extends TeamOrPersonBase<?>> void initAuthorTitleCaches(T teamOrPerson) {
411
        //NOTE: this is more or less redundant copy from CdmPreDataChangeListener
412
        if (teamOrPerson.isInstanceOf(Team.class)){
413
            Team team = CdmBase.deproxy(teamOrPerson, Team.class);
414
            if (!team.isProtectedNomenclaturalTitleCache()){
415
                team.setNomenclaturalTitleCache(null, false);
416
            }
417
            if (!team.isProtectedCollectorTitleCache()){
418
                team.setCollectorTitleCache(null, false);
419
            }
420
        }
421
        teamOrPerson.getNomenclaturalTitleCache();
422
        teamOrPerson.getCollectorTitleCache();
423
        if (! teamOrPerson.isProtectedTitleCache()){
424
            teamOrPerson.setTitleCache(teamOrPerson.generateTitle(), false);
425
        }
426
    }
427

    
428
    private void initReferenceCaches(Reference ref) {
429
        ////TODO better do via matching strategy  (newReference might have caches == null)
430
        //more or less copy from CdmPreDataChangeListener
431
        ref.getAbbrevTitleCache();
432
        ref.getTitleCache();
433
   }
434

    
435
    public AgentBase<?> getExistingAgent(AgentBase<?> agent) {
436
        if (agent == null){
437
            return null;
438
        } else if (agent.isInstanceOf(TeamOrPersonBase.class)){
439
            return getExistingAuthor(CdmBase.deproxy(agent, TeamOrPersonBase.class));
440
        }else{
441
            throw new RuntimeException("Institution matching not yet implemented");
442
//            initInstitutionMap();
443
//            Set<Institution> result = institutionMap.get(agent.getTitleCache());
444
//            if (result == null){
445
//                result = putEntity(agent.getTitleCache(), CdmBase.deproxy(agent, Institution.class), institutionMap);
446
//            }
447
//            return result;
448
        }
449
    }
450

    
451
    private <S extends IdentifiableEntity<?>> void init(DedupInfo<S> dedupInfo) {
452
        dedupInfo.status = init(dedupInfo.clazz, dedupInfo.status, dedupInfo.map);
453
    }
454

    
455
    private <S extends IdentifiableEntity<?>> Status init(Class<S> clazz, Status status, Map<String,Set<S>> map) {
456

    
457
        if (status == Status.NOT_INIT && repository != null){
458
            if (maxCountFullLoad != NEVER_USE_MAP){
459
                long nExisting = -2;
460
                if (maxCountFullLoad != ALWAYS_USE_MAP){
461
                    nExisting = repository.getCommonService().count(clazz);
462
                }
463
                if (nExisting <= maxCountFullLoad ){
464
                    List<String> propertyPaths = Arrays.asList("");
465
                    List<S> existingEntities = repository.getCommonService().list(clazz, null, null, null, propertyPaths);
466
                    for (S ref : existingEntities){
467
                        putEntity(ref.getTitleCache(), ref, map);
468
                    }
469
                    return Status.USE_MAP;
470
                }else{
471
                    return Status.USE_REPO;
472
                }
473
            }else{
474
                return Status.USE_REPO;
475
            }
476
        }
477
        return status;
478
    }
479

    
480
    private void handleTeam(Team team) {
481
        List<Person> members = team.getTeamMembers();
482
        for (int i =0; i< members.size(); i++){
483
            Person person = CdmBase.deproxy(members.get(i));
484
            Person existingPerson = getMatchingEntity(person, personDedupInfo).orElse(null);
485
            if (existingPerson != null){
486
                members.set(i, existingPerson);
487
            }else{
488
                putAgentBase(person.getTitleCache(), person);
489
            }
490
        }
491
    }
492

    
493
    public Collection getExistingCollection(Collection collection) {
494
        if (collection == null){
495
            return null;
496
        }else{
497
            initCollectionMap();
498
            Collection result = getMatchingCollections(collection).orElse(null);
499
            if (result == null){
500
                result = collection;
501
                putEntity(result.getTitleCache(), result, collectionMap);
502
            }else{
503
                if(logger.isDebugEnabled()) {
504
                    logger.debug("Matches");
505
                 }
506
            }
507
            return result;
508
        }
509
    }
510

    
511
    private void initCollectionMap() {
512
        collectionStatus = init(Collection.class, collectionStatus, collectionMap);
513
    }
514

    
515
   public Reference getExistingReference(Reference ref) {
516
       if (ref == null){
517
           return null;
518
       }else{
519
           init(referenceDedupInfo);
520
           initReferenceCaches(ref);
521
           Reference result = getMatchingEntity(ref, referenceDedupInfo).orElse(null);
522
           if (result == null){
523
               result = ref;
524
               Reference inRef = result.getInReference();
525
               if (inRef != null){
526
                   result.setInReference(getExistingReference(result.getInReference()));
527
               }
528
               putEntity(result.getTitleCache(), result, referenceDedupInfo.map);
529
           }else{
530
               if(logger.isDebugEnabled()) {logger.debug("Matches");}
531
           }
532
           return result;
533
       }
534
   }
535

    
536
   public TaxonName getExistingName(TaxonName name) {
537
       if (name == null){
538
           return null;
539
       }else{
540
           init(nameDedupInfo);
541
           TaxonName result = getMatchingEntity(name, nameDedupInfo).orElse(null);
542
           if (result == null){
543
               result = name;
544
               Set<HybridRelationship> parentRelations = result.getHybridChildRelations();
545
               for (HybridRelationship rel : parentRelations){
546
                   TaxonName parent = rel.getParentName();
547
                   if (parent != null){
548
                       rel.setParentName(getExistingName(parent));
549
                   }
550
               }
551
               putEntity(result.getTitleCache(), result, nameDedupInfo.map);
552
           }else{
553
               if(logger.isDebugEnabled()) {
554
                   logger.debug("Matches");
555
                }
556
           }
557
           return result;
558
       }
559
   }
560

    
561
   public Rights getExistingCopyright(Rights right) {
562
       if (right == null || !RightsType.COPYRIGHT().equals(right.getType())){
563
           return null;
564
       }else{
565
           initCopyrightMap();
566
           String key = makeCopyrightKey(right);
567
           Set<Rights> set = copyrightMap.get(key);
568
           if (set == null || set.isEmpty()){
569
               putCopyright(key, right);
570
               return right;
571
           }else if (set.size()>1){
572
               //TODO
573
               logger.warn("More than 1 matching copyright not yet handled for key: " + key);
574
           }
575
           return set.iterator().next();
576
       }
577
   }
578

    
579
    private void initCopyrightMap() {
580
        if (copyrightStatus == Status.NOT_INIT && repository != null){
581
            List<String> propertyPaths = Arrays.asList("");
582
            List<Rights> existingRights = repository.getRightsService().list(null, null, null, null, propertyPaths);
583
            for (Rights right : existingRights){
584
                if (RightsType.COPYRIGHT().equals(right.getType())){
585
                    putCopyright(makeCopyrightKey(right), right);
586
                }
587
            }
588
            copyrightStatus = Status.USE_MAP;
589
        }
590
    }
591

    
592
    private void putCopyright(String key, Rights right) {
593
        Set<Rights> rights = copyrightMap.get(key);
594
        if (rights == null){
595
            rights = new HashSet<>();
596
            copyrightMap.put(key, rights);
597
        }
598
        rights.add(CdmBase.deproxy(right));
599
    }
600

    
601
    private String makeCopyrightKey(Rights right) {
602
        if (right.getAgent() != null){
603
            return right.getAgent().getTitleCache();
604
        }else if (right.getText() != null){
605
            return right.getText();
606
        }else {
607
            logger.warn("Key for copyright could not be created: " + right);
608
            return right.getUuid().toString();
609
        }
610
    }
611

    
612
}
    (1-1/1)