Project

General

Profile

Download (32 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2016 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.strategy.cache.reference;
10

    
11
import java.util.List;
12
import java.util.UUID;
13

    
14
import org.apache.commons.lang3.StringUtils;
15
import org.apache.log4j.Logger;
16
import org.joda.time.DateTime;
17
import org.joda.time.format.DateTimeFormat;
18
import org.joda.time.format.DateTimeFormatter;
19

    
20
import eu.etaxonomy.cdm.common.CdmUtils;
21
import eu.etaxonomy.cdm.model.agent.Person;
22
import eu.etaxonomy.cdm.model.agent.Team;
23
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
24
import eu.etaxonomy.cdm.model.common.CdmBase;
25
import eu.etaxonomy.cdm.model.common.VerbatimTimePeriod;
26
import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;
27
import eu.etaxonomy.cdm.model.reference.Reference;
28
import eu.etaxonomy.cdm.model.reference.ReferenceType;
29
import eu.etaxonomy.cdm.strategy.StrategyBase;
30
import eu.etaxonomy.cdm.strategy.cache.agent.TeamDefaultCacheStrategy;
31

    
32
/**
33
 * #5833
34
 * The new single default cache strategy for {@link Reference references}.
35
 * As we do have only one {@link Reference} class left which implements multiple interfaces,
36
 * we may also only need 1 single cache strategy. However, care must be taken as the formatting
37
 * differs dependent on the type an the in-reference structure.
38
 *
39
 * Generally the cache strategy allows to compute 3 formats:<BR>
40
 *
41
 *  1.) for bibliographic references (stored in {@link Reference#getTitleCache() titleCache}).<BR>
42
 *
43
 *  2.) for nomenclatural references (stored in {@link Reference#getAbbrevTitleCache() abbrevTitleCache}),
44
 *      but without micro reference (detail).<BR>
45
 *
46
 *  3.) for nomenclatural references with micro reference, but not stored anywhere as the micro reference
47
 *      is part of the name, not of the reference<BR>
48
 *
49
 *  4.) for short citation (e.g. Author 2009) as defined in {@link IReferenceCacheStrategy#getCitation(Reference, String)}
50
 *  and {@link IReferenceCacheStrategy#createShortCitation(Reference, String, Boolean)}
51
 *
52
 * @author a.mueller
53
 * @since 25.05.2016
54
 */
55
public class DefaultReferenceCacheStrategy
56
        extends StrategyBase
57
        implements INomenclaturalReferenceCacheStrategy{
58

    
59
    private static final long serialVersionUID = 6773742298840407263L;
60
    private static final Logger logger = Logger.getLogger(DefaultReferenceCacheStrategy.class);
61

    
62
    private final static UUID uuid = UUID.fromString("63e669ca-c6be-4a8a-b157-e391c22580f9");
63

    
64
    //article
65
    public static final String UNDEFINED_JOURNAL = "- undefined journal -";
66
    private static final String afterAuthor = ", ";
67

    
68
    //book
69

    
70

    
71
    //(book?) section
72
    private String afterSectionAuthor = " - ";
73

    
74
    //in reference
75
    private String inSeparator = "in ";
76
    private static final String afterInRefAuthor = ", ";
77

    
78
    //common
79
    private static final String blank = " ";
80
    private static final String beforeYear = ". ";
81
    private static final String beforeMicroReference = ": ";
82
    private static final String afterYear = "";
83

    
84
    private static final boolean trim = true;
85

    
86
// ************************ FACTORY ****************************/
87

    
88
    public static DefaultReferenceCacheStrategy NewInstance(){
89
        return new DefaultReferenceCacheStrategy();
90
    }
91

    
92
// ******************************* Main methods ******************************/
93

    
94
    @Override
95
    protected UUID getUuid() {
96
        return uuid;
97
    }
98

    
99
    @Override
100
    public String getTitleCache(Reference reference) {
101
        if (reference == null){
102
            return null;
103
        }
104
        if (reference.isProtectedTitleCache()){
105
            return reference.getTitleCache();
106
        }
107
        boolean isNotAbbrev = false;
108

    
109
        String result;
110
        ReferenceType type = reference.getType();
111

    
112
        if (isRealInRef(reference)){
113
            result = titleCacheRealInRef(reference, isNotAbbrev);
114
        }else if(isNomRef(type)){
115
            //all Non-InRef NomRefs
116
            result =  getTitleWithoutYearAndAuthor(reference, isNotAbbrev);
117
            result = addPages(result, reference);
118
            result = addYear(result, reference, false);
119
            TeamOrPersonBase<?> team = reference.getAuthorship();
120

    
121
            if (type == ReferenceType.Article){
122
                result = CdmUtils.concat(" ", reference.getTitle(), result);
123
                if (team != null &&  isNotBlank(team.getTitleCache())){
124
                    String authorSeparator = isNotBlank(reference.getTitle())? afterAuthor : " ";
125
                    result = team.getTitleCache() + authorSeparator + result;
126
                }
127
            }else{  //if Book, CdDvd, flat Generic, Thesis, WebPage
128
                if (team != null){
129
                    String teamTitle = CdmUtils.getPreferredNonEmptyString(team.getTitleCache(),
130
                            team.getNomenclaturalTitle(), isNotAbbrev, trim);
131
                    if (teamTitle.length() > 0 ){
132
                        String concat = isNotBlank(result) ? afterAuthor : "";
133
                        result = teamTitle + concat + result;
134
                    }
135
                }
136
            }
137
        }else if (type == ReferenceType.Journal){
138
            result = titleCacheJournal(reference, isNotAbbrev);
139
        }else{
140
            result = titleCacheDefaultReference(reference, isNotAbbrev);
141
        }
142
        if (reference.getType() == ReferenceType.WebPage && reference.getUri() != null && !result.contains(reference.getUri().toString())){
143
            //might become UTF8.EN_DASH in future
144
            result = CdmUtils.concat(" - ", result, reference.getUri().toString());
145
        }
146
        if(reference.getAccessed() != null){
147
            //TODO still a bit preliminary, also brackets may change in future
148
            result = result + " [accessed " + getAccessedString(reference.getAccessed()) +"]";
149
        }
150
        return result;
151
    }
152

    
153
    private String getAccessedString(DateTime accessed) {
154
        DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm");
155
        String result = formatter.print(accessed);
156
        if (result.endsWith(" 00:00")){
157
            result = result.replace(" 00:00", "");
158
        }
159
        return result;
160
    }
161

    
162
    private String addPages(String result, Reference reference) {
163
        //pages
164
        if (isNotBlank(reference.getPages())){
165
            //Removing trailing added just in case, maybe not necessary
166
            result = RemoveTrailingDot(Nz(result)).trim() + ": " + reference.getPages();
167
        }
168
        return result;
169
    }
170

    
171
    private static String RemoveTrailingDot(String str) {
172
        if (str != null && str.endsWith(".")){
173
            str = str.substring(0, str.length()-1);
174
        }
175
        return str;
176
    }
177

    
178
    @Override
179
    public String getFullAbbrevTitleString(Reference reference) {
180
        if (reference == null){
181
            return null;
182
        }
183
        String result;
184
        ReferenceType type = reference.getType();
185
        boolean isAbbrev = true;
186

    
187
        if (reference.isProtectedAbbrevTitleCache()){
188
            return reference.getAbbrevTitleCache();
189
        }
190

    
191
        if (type == ReferenceType.Article){
192
            result =  getTitleWithoutYearAndAuthor(reference, isAbbrev);
193
            boolean useFullDatePublished = false;
194
            result = addYear(result, reference, useFullDatePublished);
195
            TeamOrPersonBase<?> team = reference.getAuthorship();
196
            String articleTitle = CdmUtils.getPreferredNonEmptyString(reference.getTitle(),
197
                    reference.getAbbrevTitle(), isAbbrev, trim);
198
            result = CdmUtils.concat(" ", articleTitle, result);  //Article should maybe left out for nomenclatural references (?)
199
            if (team != null &&  isNotBlank(team.getNomenclaturalTitle())){
200
                String authorSeparator = isNotBlank(articleTitle) ? afterAuthor : " ";
201
                result = team.getNomenclaturalTitle() + authorSeparator + result;
202
            }
203
        }else if (isRealInRef(reference)){
204
            result = titleCacheRealInRef(reference, isAbbrev);
205
        }else if (isNomRef(type)){
206
            //FIXME same as titleCache => try to merge, but note article case
207
            result =  getTitleWithoutYearAndAuthor(reference, isAbbrev);
208
            boolean useFullDatePublished = false;
209
            result = addYear(result, reference, useFullDatePublished);
210
            TeamOrPersonBase<?> team = reference.getAuthorship();
211

    
212
            if (team != null){
213
                String teamTitle = CdmUtils.getPreferredNonEmptyString(team.getTitleCache(),
214
                        team.getNomenclaturalTitle(), isAbbrev, trim);
215
                if (teamTitle.length() > 0 ){
216
                    String concat = isNotBlank(result) ? afterAuthor : "";
217
                    result = teamTitle + concat + result;
218
                }
219
            }
220
        }else if(type == ReferenceType.Journal){
221
            result = titleCacheJournal(reference, isAbbrev);
222
        }else{
223
            result = titleCacheDefaultReference(reference, isAbbrev);
224
        }
225

    
226
        return result;
227
    }
228

    
229
    //TODO see comment on createShortCitation(...)
230
    @Override
231
    public String getCitation(Reference reference, String microReference) {
232
        // mostly copied from nomRefCacheStrat, refCache, journalCache
233

    
234
        if (reference == null){
235
            return null;
236
        }
237
        StringBuilder result = new StringBuilder();
238
        TeamOrPersonBase<?> team = reference.getAuthorship();
239

    
240
        String nextConcat = "";
241

    
242
        if (team != null &&  isNotBlank(team.getTitleCache())){
243
            result.append(team.getTitleCache() );
244
            //here is the difference between nomRef and others
245
            if (isNomRef(reference.getType())) {
246
                nextConcat = afterAuthor;
247
            }else{
248
                //FIXME check if this really makes sense
249
                result.append(afterAuthor);
250
                nextConcat = beforeYear;
251
            }
252
        }
253

    
254
        String year = reference.getYear();
255
        if (isNotBlank(year)){
256
            result.append(nextConcat + year);
257
        }
258
        if (isNotBlank(microReference)){
259
            result.append(": " + microReference);
260
        }
261

    
262
        return result.toString();
263
    }
264

    
265
    @Override
266
    public String createShortCitation(Reference reference, String citationDetail, Boolean withYearBrackets) {
267
        if (withYearBrackets == null){
268
            withYearBrackets = false;
269
        }
270
        if(reference.isProtectedTitleCache()){
271
            return handleCitationDetailInTitleCache(reference.getTitleCache(), citationDetail);
272
        }
273
        TeamOrPersonBase<?> authorship = reference.getAuthorship();
274
        String shortCitation = "";
275
        if (authorship == null) {
276
            return handleCitationDetailInTitleCache(reference.getTitleCache(), citationDetail);
277
        }
278
        authorship = CdmBase.deproxy(authorship);
279
        if (authorship instanceof Person){
280
            shortCitation = getPersonString((Person)authorship);
281
        }
282
        else if (authorship instanceof Team){
283

    
284
            Team team = CdmBase.deproxy(authorship, Team.class);
285
            if (team.isProtectedTitleCache()){
286
                shortCitation = team.getTitleCache();
287
            }else{
288
                List<Person> teamMembers = team.getTeamMembers();
289
                int etAlPosition = 2;
290
                for (int i = 1; i <= teamMembers.size() &&
291
                        (i < etAlPosition || teamMembers.size() == etAlPosition && !team.isHasMoreMembers()) ; i++){
292
                    Person teamMember = teamMembers.get(i-1);
293
                    if(teamMember == null){
294
                        // this can happen in UIs in the process of adding new members
295
                        continue;
296
                    }
297
                    String concat = TeamDefaultCacheStrategy.concatString(team, teamMembers, i);
298
                    shortCitation += concat + getPersonString(teamMember);
299
                }
300
                if (teamMembers.size() == 0){
301
                    shortCitation = TeamDefaultCacheStrategy.EMPTY_TEAM;
302
                } else if (team.isHasMoreMembers() || teamMembers.size() > etAlPosition){
303
                    shortCitation += TeamDefaultCacheStrategy.ET_AL_TEAM_CONCATINATION_FULL + "al.";
304
                }
305
            }
306
        }
307
        shortCitation = CdmUtils.concat(" ", shortCitation, getShortCitationDate(reference, withYearBrackets, citationDetail));
308

    
309
        return shortCitation;
310
    }
311

    
312
    /**
313
     * Adds the citationDetail to the titleCache string that is returned from a method as data is not
314
     * accurately parsed.
315
     * @return
316
     */
317
    private String handleCitationDetailInTitleCache(String titleCache, String citationDetail) {
318
        if (StringUtils.isBlank(citationDetail)){
319
            return titleCache;
320
        }else if (StringUtils.isBlank(titleCache)){
321
            return ": " + citationDetail;
322
        }else if (citationDetail.length() <= 3){
323
            if (titleCache.contains(": " + citationDetail)){
324
                return titleCache;
325
            }
326
        }else{
327
            if (titleCache.contains(citationDetail)){
328
                return titleCache;
329
            }
330
        }
331
        return titleCache + ": " + citationDetail;
332
    }
333

    
334
    private String getShortCitationDate(Reference reference, boolean withBrackets, String citationDetail) {
335
        String result = null;
336
        if (reference.getDatePublished() != null && !reference.getDatePublished().isEmpty()) {
337
            if (isNotBlank(reference.getDatePublished().getFreeText())){
338
                result = reference.getDatePublished().getFreeText();
339
            }else if (isNotBlank(reference.getYear()) ){
340
                result = reference.getYear();
341
            }
342
            if (StringUtils.isNotEmpty(citationDetail)){
343
                result = CdmUtils.Nz(result) + ": " + citationDetail;
344
            }
345
            if (StringUtils.isNotBlank(result) && withBrackets){
346
                result = "(" + result + ")";
347
            }
348
        }else if (reference.getInReference() != null){
349
            result = getShortCitationDate(reference.getInReference(), withBrackets, citationDetail);
350
        }
351
        return result;
352
    }
353

    
354
    private String getPersonString(Person person) {
355
        String shortCitation;
356
        shortCitation = person.getFamilyName();
357
        if (isBlank(shortCitation) ){
358
            shortCitation = person.getTitleCache();
359
        }
360
        return shortCitation;
361
    }
362

    
363
    @Override
364
    public String getNomenclaturalCache(Reference reference) {
365
        return this.getNomenclaturalCitation(reference, null);
366
    }
367

    
368
// ************************ TITLE CACHE SUBS ********************************************/
369

    
370
    private String titleCacheRealInRef(Reference reference, boolean isAbbrev) {
371
        ReferenceType type = reference.getType();
372
        Reference inRef = reference.getInReference();
373
        boolean hasInRef = (inRef != null);
374

    
375
        String result;
376
        //copy from InRefDefaultCacheStrategyBase
377
        if (inRef != null){
378
            result = CdmUtils.getPreferredNonEmptyString(inRef.getTitleCache(),
379
                    inRef.getAbbrevTitleCache(), isAbbrev, trim)  ;
380
        }else{
381
            result = String.format("- undefined %s -", getUndefinedLabel(type));
382
        }
383

    
384
        //in
385
        result = inSeparator +  result;
386

    
387
        //section title
388
        String title = CdmUtils.getPreferredNonEmptyString(
389
                reference.getTitle(), reference.getAbbrevTitle(), isAbbrev, trim);
390
        if (title.length() > 0){
391
            result = title + blank + result;
392
        }
393

    
394
        //section author
395
        TeamOrPersonBase<?> thisRefTeam = reference.getAuthorship();
396
        String thisRefAuthor = "";
397
        if (thisRefTeam != null){
398
            thisRefAuthor = CdmUtils.getPreferredNonEmptyString(thisRefTeam.getTitleCache(),
399
                    thisRefTeam.getNomenclaturalTitle(), isAbbrev, trim);
400
        }
401
        result = CdmUtils.concat(afterSectionAuthor, thisRefAuthor, result);
402

    
403
        //date
404
        if (reference.getDatePublished() != null && ! reference.getDatePublished().isEmpty()){
405
            String thisRefDate = reference.getDatePublished().toString();
406
            if (hasInRef && reference.getInBook().getDatePublished() != null){
407
                VerbatimTimePeriod inRefDate = reference.getInReference().getDatePublished();
408
                String inRefDateString = inRefDate.getYear();
409
                if (isNotBlank(inRefDateString)){
410
                    int pos = StringUtils.lastIndexOf(result, inRefDateString);
411
                    if (pos > -1 ){
412
                        result = result.substring(0, pos) + thisRefDate + result.substring(pos + inRefDateString.length());
413
                    }else{
414
                        logger.warn("InRefDateString (" + inRefDateString + ") could not be found in result (" + result +")");
415
                    }
416
                }else{
417
                    //avoid duplicate dots ('..')
418
                    String bYearSeparator = result.substring(result.length() -1).equals(beforeYear.substring(0, 1)) ? beforeYear.substring(1) : beforeYear;
419
                    result = result + bYearSeparator + thisRefDate + afterYear;
420
                }
421
            }else{
422
                result = result + beforeYear + thisRefDate + afterYear;
423
            }
424
        }
425
        return result;
426
    }
427

    
428
    private String titleCacheJournal(Reference reference, boolean isAbbrev) {
429
        String result;
430
        //copied from Journal
431

    
432
        //title
433
        result = CdmUtils.getPreferredNonEmptyString(reference.getTitle(),
434
                reference.getAbbrevTitle(), isAbbrev, trim);
435

    
436
//          //delete .
437
//          while (result.endsWith(".")){
438
//              result = result.substring(0, result.length()-1);
439
//          }
440
//          result = addYear(result, journal);
441

    
442
        TeamOrPersonBase<?> team = reference.getAuthorship();
443
        if (team != null){
444
            String author = CdmUtils.getPreferredNonEmptyString(team.getTitleCache(),
445
                    team.getNomenclaturalTitle(), isAbbrev, trim);
446
            if (isNotBlank(author)){
447
                result = author + afterAuthor + result;
448
            }
449
        }
450
        return result;
451
    }
452

    
453
    private String titleCacheDefaultReference(Reference reference, boolean isAbbrev) {
454
        String result;
455
        //copied from ReferenceDefaultCacheStrategy
456
        result = "";
457
        String titel = CdmUtils.getPreferredNonEmptyString(reference.getTitle(),
458
                reference.getAbbrevTitle(), isAbbrev, trim);
459
        if (isNotBlank(titel)){
460
            result = titel + blank;
461
        }
462
        //delete .
463
        while (result.endsWith(".")){
464
            result = result.substring(0, result.length()-1);
465
        }
466

    
467
        result = addYearReferenceDefault(result, reference);
468
        TeamOrPersonBase<?> team = reference.getAuthorship();
469
        if (team != null){
470
            String author = CdmUtils.getPreferredNonEmptyString(team.getTitleCache(),
471
                    team.getNomenclaturalTitle(), isAbbrev, trim);
472
            if (isNotBlank(author)){
473
                result = author + afterAuthor + result;
474
            }
475
        }
476
        return result;
477
    }
478

    
479
// ******************************* HELPER *****************************************/
480

    
481
    @Override
482
    public String getBeforeMicroReference(){
483
        return beforeMicroReference;
484
    }
485

    
486
    private String addYear(String string, Reference nomRef, boolean useFullDatePublished){
487
        String result;
488
        if (string == null){
489
            return null;
490
        }
491
        String year = useFullDatePublished ? nomRef.getDatePublishedString() : nomRef.getYear();
492
        if (isBlank(year)){
493
            result = string + afterYear;
494
        }else{
495
            String concat = isBlank(string)  ? "" : string.endsWith(".")  ? " " : beforeYear;
496
            result = string + concat + year + afterYear;
497
        }
498
        return result;
499
    }
500

    
501
    private String getTitleWithoutYearAndAuthor(Reference ref, boolean isAbbrev){
502
        return TitleWithoutYearAndAuthorHelper.getTitleWithoutYearAndAuthor(ref, isAbbrev);
503
    }
504
    private String getTitleWithoutYearAndAuthorGeneric(Reference ref, boolean isAbbrev){
505
        return TitleWithoutYearAndAuthorHelper.getTitleWithoutYearAndAuthorGeneric(ref, isAbbrev);
506
    }
507

    
508
    private Object getUndefinedLabel(ReferenceType type) {
509
        if (type == ReferenceType.BookSection){
510
            return "book";
511
        }else if (type == ReferenceType.Generic){
512
            return "generic reference";
513
        }else if (type == ReferenceType.Section){
514
            return "in reference";
515
        } else {
516
            return type.getLabel();
517
        }
518
    }
519

    
520
    /**
521
     * Returns <code>true</code> if the type of the reference originally corresponded to a cache strategy
522
     * which inherited from {@link InRefDefaultCacheStrategyBase} and in case of type {@link ReferenceType#Generic}
523
     * if it really has an inreference (reference.getInreference() != null).
524
     * @param reference
525
     */
526
    private boolean isRealInRef(Reference reference) {
527
        ReferenceType type = (reference.getType());
528
        if (type == null){
529
            return false;
530
        }else if (type == ReferenceType.BookSection || type == ReferenceType.Section){
531
            return true;
532
        }else if (type == ReferenceType.Generic){
533
            return reference.getInReference() != null;
534
        }else{
535
            return false;
536
        }
537
    }
538

    
539
    /**
540
     * Returns <code>true</code> if the type of the reference originally corresponded to a cache strategy
541
     * which inherited from {@link NomRefDefaultCacheStrategyBase}.
542
     * @param type
543
     */
544
    protected static boolean isNomRef(ReferenceType type){
545
        switch (type){
546
            case Article:
547
            case Book:
548
            case BookSection:
549
            case CdDvd:
550
            case Generic:
551
            case Section:
552
            case Thesis:
553
            case WebPage:
554
                return true;
555

    
556
            case Journal:
557
            default:
558
                return false;
559
        }
560
    }
561

    
562
    /**
563
     * Returns year information as originally computed by {@link ReferenceDefaultCacheStrategy}.
564
     */
565
    private String addYearReferenceDefault(String string, Reference ref){
566
        String result;
567
        if (string == null){
568
            return null;
569
        }
570
        String year = CdmUtils.Nz(ref.getYear());
571
        if ("".equals(year)){
572
            result = string + afterYear;
573
        }else{
574
            result = string.trim() + beforeYear + year + afterYear;
575
        }
576
        return result;
577
    }
578

    
579
// ********************* Nomenclatural title ***************************************/
580

    
581
    @Override
582
    public String getNomenclaturalCitation(Reference reference, String microReference) {
583
        if (reference.isProtectedAbbrevTitleCache()){
584
            String cache = reference.getAbbrevTitleCache();
585
            return handleDetailAndYearForProtected(reference, cache, microReference);
586
        }
587

    
588
        String result = getTokenizedNomenclaturalTitel(reference);
589
        //if no data is available and only titleCache is protected take the protected title
590
        //this is to avoid empty cache if someone forgets to set also the abbrevTitleCache
591
        //we need to think about handling protected not separate for abbrevTitleCache  and titleCache
592
        if (result.equals(INomenclaturalReference.MICRO_REFERENCE_TOKEN) && reference.isProtectedTitleCache() ){
593
            String cache = reference.getTitleCache();
594
            return handleDetailAndYearForProtected(reference, cache, microReference);
595
        }
596

    
597
        microReference = Nz(microReference);
598
        if (isNotBlank(microReference)){
599
            microReference = getBeforeMicroReference() + microReference;
600
            if (microReference.endsWith(".")  && result.contains(INomenclaturalReference.MICRO_REFERENCE_TOKEN + ".") ){
601
                microReference = microReference.substring(0, microReference.length() - 1);
602
            }
603
        }
604
        result = replaceMicroRefToken(microReference, result);
605
        if (result.startsWith(". ")){  //only year available, remove '. '
606
            result = result.substring(2);
607
        }
608
        return result;
609
    }
610

    
611
    private String handleDetailAndYearForProtected(Reference nomenclaturalReference, String cache, String microReference) {
612
        String microRef = isNotBlank(microReference) ? getBeforeMicroReference() + microReference : "";
613
        if (cache == null){
614
            logger.warn("Cache is null. This should never be the case.");
615
            cache = "";
616
        }
617
        String  result = cache + (cache.contains(microRef) ? "" : microRef);
618

    
619
        String date = nomenclaturalReference.getDatePublishedString();
620
        if (isNotBlank(date) && ! result.contains(date)){
621
            result = result + beforeYear + date;
622
        }
623
        return result;
624
    }
625

    
626
    /**
627
     * Returns the nomenclatural title with micro reference represented as token
628
     * which can later be replaced by the real data.
629
     *
630
     * @see INomenclaturalReference#MICRO_REFERENCE_TOKEN
631
     */
632
    private String getTokenizedNomenclaturalTitel(Reference ref) {
633
        if (isRealInRef(ref)){
634
            return getTokenizedNomenclaturalTitelInRef(ref);
635
        }else{
636
            String result = getTitleWithoutYearAndAuthor(ref, true);
637
            result += INomenclaturalReference.MICRO_REFERENCE_TOKEN;
638
            result = addYear(result, ref, true);
639
            return result;
640
        }
641
    }
642

    
643
    private String getTokenizedNomenclaturalTitelInRef(Reference thisRef) {
644
        if (thisRef == null){
645
            return null;
646
        }
647

    
648
        Reference inRef = CdmBase.deproxy(thisRef.getInReference(), Reference.class);
649
        if (inRef != null && inRef.getInReference() != null && thisRef.getType() == ReferenceType.Section){
650
            //this is a reference of type Section which has a in-in-Ref
651
            //TODO maybe we do not need to restrict to type=Section only
652
            return this.getTokenizedNomenclaturalTitelInInRef(thisRef);
653
        }
654

    
655
        String result;
656
        //use generics's publication date if it exists
657
        if (inRef == null ||  (thisRef.hasDatePublished() ) ){
658
            result =  inRef == null ? "" : getTitleWithoutYearAndAuthorGeneric(inRef, true);
659
            //added //TODO unify with non-inRef references formatting
660

    
661
            if (isNotBlank(thisRef.getVolume())){
662
                result = result + " " + thisRef.getVolume();
663
            }
664
            //TODO series / edition
665

    
666
            //end added
667
            result += INomenclaturalReference.MICRO_REFERENCE_TOKEN;
668
            result = addYear(result, thisRef, true);
669
        }else{
670
            //else use inRefs's publication date
671
            result = inRef.getNomenclaturalCitation(INomenclaturalReference.MICRO_REFERENCE_TOKEN);
672
            if (result != null){
673
                result = result.replace(beforeMicroReference +  INomenclaturalReference.MICRO_REFERENCE_TOKEN, INomenclaturalReference.MICRO_REFERENCE_TOKEN);
674
            }
675
        }
676
        //FIXME: vol. etc., https://dev.e-taxonomy.eu/redmine/issues/2862
677

    
678
        result = getInRefAuthorPart(thisRef.getInReference(), afterInRefAuthor) + result;
679
        result = "in " +  result;
680
        return result;
681
    }
682

    
683
    /**
684
     * For handling in-in-Ref case.
685
     * Must only be called if a reference has inRef and inInRef
686
     * @param section
687
     * @return
688
     */
689
    private String getTokenizedNomenclaturalTitelInInRef(Reference ref) {
690
        String result;
691

    
692
        Reference inRef = CdmBase.deproxy(ref.getInReference(), Reference.class);
693
        Reference inInRef = CdmBase.deproxy(inRef.getInReference(), Reference.class);
694

    
695
        if (! isNomRef(inInRef.getType())){
696
            if (! isNomRef(inRef.getType())){
697
                logger.warn("Neither inReference nor inInReference is a "
698
                        + " nomenclatural reference. This is not correct or not handled yet."
699
                        + " Generic titleWithoutYearAndAuthor used instead");
700
                result = getTitleWithoutYearAndAuthorGeneric(inInRef, true);
701
                //FIXME: vol. etc., https://dev.e-taxonomy.eu/redmine/issues/2862  (comment taken from super.getTokenizedNomenclaturalTitel())
702
            }else{
703
                result = getTitleWithoutYearAndAuthor(inRef, true);
704
            }
705
        }else{
706
            result = getTitleWithoutYearAndAuthor(inInRef, true);
707
        }
708
        result += INomenclaturalReference.MICRO_REFERENCE_TOKEN;
709

    
710
        Reference dataReference = (ref.hasDatePublished() ? ref : inRef.hasDatePublished() ? inRef : inInRef);
711

    
712
        result = addYear(result, dataReference, true);
713

    
714
        result = getInRefAuthorPart(inInRef, afterInRefAuthor) + result;
715
        if (! result.startsWith("in ")){
716
            result = "in " +  result;
717
        }
718
        return result;
719
    }
720

    
721
    /**
722
     * See https://dev.e-taxonomy.eu/redmine/issues/8881
723
     */
724
    private String getInRefAuthorPart(Reference book, String seperator){
725
        if (book == null){
726
            return "";
727
        }
728

    
729
        TeamOrPersonBase<?> author = book.getAuthorship();
730
        String result;
731
        if (author == null){
732
            result = "";
733
        }else if(author.isInstanceOf(Person.class)){
734
            Person person = CdmBase.deproxy(author, Person.class);
735
            result = getInRefPerson(person);
736
        }else{
737
            Team team = CdmBase.deproxy(author, Team.class);
738
            if (team.isProtectedNomenclaturalTitleCache()){
739
                //not yet finally discussed may change in future
740
                result = team.getNomenclaturalTitle();
741
            }else if (team.isProtectedTitleCache()){
742
                //not yet finally discussed may change in future
743
                result = team.getTitleCache();
744
            }else if (team.getTeamMembers().isEmpty()){
745
                //not yet finally discussed may change in future
746
                result = team.getTitleCache();
747
            }else{
748
                result = "";
749
                int size = team.getTeamMembers().size();
750
                for (Person person : team.getTeamMembers()){
751
                    int index = team.getTeamMembers().lastIndexOf(person);
752
                    String sep = (team.isHasMoreMembers() || index != size - 1) ?
753
                            TeamDefaultCacheStrategy.STD_TEAM_CONCATINATION : TeamDefaultCacheStrategy.FINAL_TEAM_CONCATINATION;
754
                    result = CdmUtils.concat(sep, result, getInRefPerson(person));
755
                }
756
                if (team.isHasMoreMembers()){
757
                    result += TeamDefaultCacheStrategy.ET_AL_TEAM_CONCATINATION_FULL + "al.";
758
                }
759
            }
760
        }
761

    
762
        result = Nz(result);
763
        if (! result.trim().equals("")){
764
            result = result + seperator;
765
        }
766
        return result;
767
    }
768

    
769
    private String getInRefPerson(Person person) {
770
        String result;
771
        if (isNotBlank(person.getFamilyName())){
772
            result = person.getFamilyName();
773
        }else if (isNotBlank(person.getNomenclaturalTitle())){
774
            result = person.getNomenclaturalTitle();  //TODO discuss if nomTitle is really better here then titleCache
775
        }else{
776
            result = person.getTitleCache();  //maybe remove everything behind a ","
777
        }
778
        return result;
779
    }
780

    
781
    private String replaceMicroRefToken(String microReference, String string) {
782
        int index = string.indexOf(INomenclaturalReference.MICRO_REFERENCE_TOKEN);
783

    
784
        if (index > -1){
785
            String before = string.substring(0, index);
786
            String after = string.substring(index + INomenclaturalReference.MICRO_REFERENCE_TOKEN.length() );
787
            String localMicroReference = microReference.trim();   //needed ?
788
            if (after.length() > 0){
789
                if (  ("".equals(localMicroReference) && before.endsWith(after.substring(0,1)) || localMicroReference.endsWith(after.substring(0,1)))){
790
                    after = after.substring(1);
791
                }
792
            }
793
            String result = before + localMicroReference + after;
794
            return result;
795
        }else{
796
            return string;
797
        }
798
    }
799

    
800
// *************************** EXTERNAL USE *******************************************/
801

    
802
   public static String putAuthorToEndOfString(String referenceTitleCache, String authorTitleCache) {
803
       if(authorTitleCache != null){
804
           referenceTitleCache = referenceTitleCache.replace(authorTitleCache + ", ", "");
805
           referenceTitleCache += " - " + authorTitleCache;
806
       }
807
       return referenceTitleCache;
808
   }
809
}
(1-1/4)