• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pkiraly / metadata-qa-marc / #1430

12 Mar 2025 12:23PM UTC coverage: 90.395% (-0.06%) from 90.457%
#1430

push

pkiraly
Merge branch 'main' of github.com:pkiraly/qa-catalogue

36517 of 40397 relevant lines covered (90.4%)

0.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.26
/src/main/java/de/gwdg/metadataqa/marc/dao/DataField.java
1
package de.gwdg.metadataqa.marc.dao;
2

3
import de.gwdg.metadataqa.marc.EncodedValue;
4
import de.gwdg.metadataqa.marc.Extractable;
5
import de.gwdg.metadataqa.marc.MarcSubfield;
6
import de.gwdg.metadataqa.marc.Utils;
7
import de.gwdg.metadataqa.marc.dao.record.BibliographicRecord;
8
import de.gwdg.metadataqa.marc.definition.MarcVersion;
9
import de.gwdg.metadataqa.marc.definition.SourceSpecificationType;
10
import de.gwdg.metadataqa.marc.definition.TagDefinitionLoader;
11
import de.gwdg.metadataqa.marc.definition.bibliographic.SchemaType;
12
import de.gwdg.metadataqa.marc.definition.general.indexer.FieldIndexer;
13
import de.gwdg.metadataqa.marc.definition.general.indexer.subject.SchemaFromInd1OrIf7FromSubfield2;
14
import de.gwdg.metadataqa.marc.definition.general.indexer.subject.SchemaFromInd1OrIfEmptyFromSubfield2;
15
import de.gwdg.metadataqa.marc.definition.general.indexer.subject.SchemaFromInd2;
16
import de.gwdg.metadataqa.marc.definition.general.indexer.subject.SchemaFromInd2AndSubfield2;
17
import de.gwdg.metadataqa.marc.definition.general.indexer.subject.SchemaFromInd2For055OrIf7FromSubfield2;
18
import de.gwdg.metadataqa.marc.definition.general.indexer.subject.SchemaFromSubfield2;
19
import de.gwdg.metadataqa.marc.definition.structure.DataFieldDefinition;
20
import de.gwdg.metadataqa.marc.definition.structure.Indicator;
21
import de.gwdg.metadataqa.marc.definition.structure.SubfieldDefinition;
22
import de.gwdg.metadataqa.marc.model.SolrFieldType;
23
import de.gwdg.metadataqa.marc.utils.keygenerator.DataFieldKeyGenerator;
24
import de.gwdg.metadataqa.marc.utils.keygenerator.DataFieldKeyGeneratorFactory;
25
import de.gwdg.metadataqa.marc.utils.pica.PicaFieldDefinition;
26
import org.apache.commons.lang3.StringUtils;
27

28
import java.io.Serializable;
29
import java.util.ArrayList;
30
import java.util.Collections;
31
import java.util.HashMap;
32
import java.util.LinkedHashMap;
33
import java.util.LinkedList;
34
import java.util.List;
35
import java.util.Map;
36
import java.util.logging.Level;
37
import java.util.logging.Logger;
38

39
public class DataField implements Extractable, Serializable {
1✔
40

41
  private static final Logger logger = Logger.getLogger(DataField.class.getCanonicalName());
1✔
42
  private static final long serialVersionUID = -2283988601945108192L;
43

44
  private final DataFieldDefinition definition;
45
  private String tag;
46
  private final String ind1;
47
  private final String ind2;
48
  private List<MarcSubfield> subfields;
49
  private final Map<String, List<MarcSubfield>> subfieldIndex = new LinkedHashMap<>();
1✔
50
  /**
51
   * Occurrence is only used in PICA records
52
   */
53
  private String occurrence;
54
  private List<String> unhandledSubfields = null;
1✔
55
  private BibliographicRecord bibliographicRecord;
56
  private List<FieldIndexer> fieldIndexers;
57
  private boolean fieldIndexerInitialized = false;
1✔
58

59
  public <T extends DataFieldDefinition> DataField(T definition, String ind1, String ind2) {
1✔
60
    this.definition = definition;
1✔
61
    this.ind1 = ind1;
1✔
62
    this.ind2 = ind2;
1✔
63
    this.subfields = new ArrayList<>();
1✔
64
  }
1✔
65

66
  public <T extends DataFieldDefinition> DataField(T definition,
67
                                                   String ind1,
68
                                                   String ind2,
69
                                                   List<Map<String, String>> subfields) {
70
    this(definition, ind1, ind2);
1✔
71
    if (subfields == null) {
1✔
72
      return;
×
73
    }
74

75
    for (Map<String, String> subfield : subfields) {
1✔
76
      String code = subfield.get("code");
1✔
77
      String value = subfield.get("content");
1✔
78
      SubfieldDefinition subfieldDefinition = definition.getSubfield(code);
1✔
79

80
      if (subfieldDefinition != null) {
1✔
81
        MarcSubfield marcSubfield = new MarcSubfield(subfieldDefinition, code, value);
1✔
82
        marcSubfield.setField(this);
1✔
83
        this.subfields.add(marcSubfield);
1✔
84
        indexSubfield(code, marcSubfield);
1✔
85
        continue;
1✔
86
      }
87

88
      if (!(definition.getTag().equals("886") && code.equals("k")) && !definition.getTag().equals("936")) {
1✔
89
        String errorMessage = String.format("no definition for %s$%s (value: '%s') %s %s%n",
1✔
90
          definition.getTag(), code, value, definition.getTag().equals("886"),
1✔
91
          code.equals("k"));
1✔
92
        logger.severe(errorMessage);
1✔
93
      }
94
    }
1✔
95
  }
1✔
96

97
  public <T extends DataFieldDefinition> DataField(T definition,
98
                                                   String ind1,
99
                                                   String ind2,
100
                                                   String... subfields) {
101
    this(definition, ind1, ind2);
1✔
102
    if (subfields != null) {
1✔
103
      parseSubfieldArray(subfields);
1✔
104
    }
105
  }
1✔
106

107
  public DataField(String tag, String input) {
108
    this(tag, input, MarcVersion.MARC21);
1✔
109
  }
1✔
110

111
  public DataField(String tag, String input, MarcVersion version) {
1✔
112
    definition = TagDefinitionLoader.load(tag, version);
1✔
113
    if (definition == null) {
1✔
114
      this.tag = tag;
1✔
115
    }
116
    this.subfields = new ArrayList<>();
1✔
117

118
    ind1 = input.substring(0, 1);
1✔
119
    ind2 = input.substring(1, 2);
1✔
120
    parseAndAddSubfields(input.substring(2));
1✔
121
  }
1✔
122

123
  public DataField(String tag, String ind1, String ind2, MarcVersion marcVersion) {
1✔
124
    definition = TagDefinitionLoader.load(tag, marcVersion);
1✔
125
    if (definition == null) {
1✔
126
      this.tag = tag;
1✔
127
    }
128
    this.ind1 = ind1;
1✔
129
    this.ind2 = ind2;
1✔
130
    this.subfields = new ArrayList<>();
1✔
131
  }
1✔
132

133
  public DataField(String tag, String ind1, String ind2, String content, MarcVersion marcVersion) {
1✔
134
    definition = TagDefinitionLoader.load(tag, marcVersion);
1✔
135
    if (definition == null) {
1✔
136
      this.tag = tag;
1✔
137
    }
138
    this.ind1 = ind1;
1✔
139
    this.ind2 = ind2;
1✔
140
    this.subfields = new ArrayList<>();
1✔
141

142
    parseAndAddSubfields(content);
1✔
143
  }
1✔
144

145
  public static List<String[]> parseSubfields(String content) {
146
    List<String[]> subfields = new ArrayList<>();
1✔
147

148
    boolean codeFlag = false;
1✔
149
    String code = null;
1✔
150
    StringBuilder value = new StringBuilder();
1✔
151
    for (int i = 0; i < content.length(); i++) {
1✔
152
      String c = Character.toString(content.charAt(i));
1✔
153
      if (c.equals("$")) {
1✔
154
        codeFlag = true;
1✔
155
        if (code != null)
1✔
156
          subfields.add(new String[]{code, value.toString()});
1✔
157
        code = null;
1✔
158
        value = new StringBuilder();
1✔
159
      } else {
160
        if (codeFlag) {
1✔
161
          code = c;
1✔
162
          codeFlag = false;
1✔
163
        } else {
164
          value.append(c);
1✔
165
        }
166
      }
167
    }
168
    subfields.add(new String[]{code, value.toString()});
1✔
169

170
    return subfields;
1✔
171
  }
172

173
  private void parseAndAddSubfields(String content) {
174
    for (String[] sf : parseSubfields(content))
1✔
175
      addSubfield(sf[0], sf[1]);
1✔
176
  }
1✔
177

178
  public BibliographicRecord getBibliographicRecord() {
179
    return bibliographicRecord;
1✔
180
  }
181

182
  public void setBibliographicRecord(BibliographicRecord bibliographicRecord) {
183
    this.bibliographicRecord = bibliographicRecord;
1✔
184
    for (MarcSubfield marcSubfield : subfields)
1✔
185
      marcSubfield.setMarcRecord(bibliographicRecord);
1✔
186
  }
1✔
187

188
  public void indexSubfields() {
189
    for (MarcSubfield marcSubfield : subfields)
1✔
190
      indexSubfield(marcSubfield.getCode(), marcSubfield);
1✔
191
  }
1✔
192

193
  private void indexSubfield(String code, MarcSubfield marcSubfield) {
194
    subfieldIndex.computeIfAbsent(code, s -> new LinkedList<>());
1✔
195
    subfieldIndex.get(code).add(marcSubfield);
1✔
196
  }
1✔
197

198
  private void parseSubfieldArray(String[] subfields) {
199
    for (int i = 0; i < subfields.length; i += 2) {
1✔
200
      String code = subfields[i];
1✔
201
      String value = subfields[i + 1];
1✔
202
      addSubfield(code, value);
1✔
203
    }
204
  }
1✔
205

206
  private void addSubfield(String code, String value) {
207
    SubfieldDefinition subfieldDefinition = definition != null
1✔
208
                                          ? definition.getSubfield(code)
1✔
209
                                          : null;
1✔
210
    MarcSubfield marcSubfield = new MarcSubfield(subfieldDefinition, code, value);
1✔
211
    marcSubfield.setField(this);
1✔
212
    this.subfields.add(marcSubfield);
1✔
213
    indexSubfield(code, marcSubfield);
1✔
214
  }
1✔
215

216
  public Map<String, List<String>> getHumanReadableMap() {
217
    Map<String, List<String>> map = new LinkedHashMap<>();
1✔
218
    if (definition.getInd1().exists())
1✔
219
      map.put(definition.getInd1().getLabel(), Collections.singletonList(resolveInd1()));
1✔
220
    if (definition.getInd2().exists())
1✔
221
      map.put(definition.getInd2().getLabel(), Collections.singletonList(resolveInd2()));
1✔
222
    for (MarcSubfield subfield : subfields) {
1✔
223
      map.computeIfAbsent(subfield.getLabel(), s -> new ArrayList<>());
1✔
224
      map.get(subfield.getLabel()).add(subfield.resolve());
1✔
225
    }
1✔
226
    return map;
1✔
227
  }
228

229
  public String simpleFormat() {
230
    StringBuilder output = new StringBuilder();
1✔
231

232
    output.append(ind1);
1✔
233
    output.append(ind2);
1✔
234
    output.append(" ");
1✔
235

236
    for (MarcSubfield subfield : subfields) {
1✔
237
      output.append(String.format(
1✔
238
        "$%s%s",
239
        subfield.getDefinition().getCode(), subfield.getValue()
1✔
240
      ));
241
    }
1✔
242

243
    return output.toString();
1✔
244
  }
245

246
  public String format() {
247
    StringBuilder output = new StringBuilder();
1✔
248
    if (definition != null)
1✔
249
      output.append(String.format("[%s: %s]%n", definition.getTag(), definition.getLabel()));
1✔
250
    else
251
      output.append(String.format("[%s]%n", getTag()));
1✔
252

253
    if (definition != null && definition.getInd1() != null && definition.getInd1().exists())
1✔
254
      output.append(String.format("%s: %s%n", definition.getInd1().getLabel(), resolveInd1()));
1✔
255
    else if (StringUtils.isNotBlank(getInd1()))
1✔
256
      output.append(String.format("ind1: %s%n", getInd1()));
1✔
257

258
    if (definition != null && definition.getInd2() != null && definition.getInd2().exists())
1✔
259
      output.append(String.format("%s: %s%n", definition.getInd2().getLabel(), resolveInd2()));
1✔
260
    else if (StringUtils.isNotBlank(getInd2()))
1✔
261
      output.append(String.format("ind2: %s%n", getInd2()));
1✔
262

263
    for (MarcSubfield subfield : subfields) {
1✔
264
      output.append(String.format("%s: %s%n", subfield.getLabel(), subfield.resolve()));
1✔
265
    }
1✔
266

267
    return output.toString();
1✔
268
  }
269

270
  public String formatAsText() {
271
    StringBuilder output = new StringBuilder();
1✔
272
    output.append(getTag());
1✔
273
    output.append(" ").append(ind1).append(ind2).append(" ");
1✔
274

275
    boolean first = true;
1✔
276
    for (MarcSubfield subfield : subfields) {
1✔
277
      if (!first)
1✔
278
        output.append("       ");
1✔
279
      output.append("$").append(subfield.getCode()).append(" ").append(subfield.getValue()).append("\n");
1✔
280
      first = false;
1✔
281
    }
1✔
282

283
    return output.toString();
1✔
284
  }
285

286
  public String formatAsMarc() {
287
    StringBuilder output = new StringBuilder();
1✔
288

289
    if (definition != null && definition.getInd1().exists())
1✔
290
      output.append(String.format("%s_ind1: %s%n", getTag(), resolveInd1()));
1✔
291

292
    if (definition != null && definition.getInd2().exists())
1✔
293
      output.append(String.format("%s_ind2: %s%n", getTag(), resolveInd2()));
1✔
294

295
    for (MarcSubfield subfield : subfields) {
1✔
296
      output.append(String.format("%s_%s: %s%n", getTag(), subfield.getCode(), subfield.resolve()));
1✔
297
    }
1✔
298

299
    return output.toString();
1✔
300
  }
301

302
  public String formatForIndex() {
303
    StringBuilder output = new StringBuilder();
1✔
304

305
    if (definition.getInd1().exists())
1✔
306
      output.append(String.format("%s_ind1: %s%n", definition.getIndexTag(), resolveInd1()));
1✔
307

308
    if (definition.getInd2().exists())
1✔
309
      output.append(String.format("%s_ind2: %s%n", definition.getIndexTag(), resolveInd2()));
1✔
310

311
    for (MarcSubfield subfield : subfields) {
1✔
312
      String subfieldOutput = formatSubfieldForIndex(subfield);
1✔
313
      output.append(subfieldOutput);
1✔
314
    }
1✔
315

316
    return output.toString();
1✔
317
  }
318

319
  private String formatSubfieldForIndex(MarcSubfield subfield) {
320
    StringBuilder output = new StringBuilder();
1✔
321

322
    String code = subfield.getCodeForIndex();
1✔
323

324
    // If PICA, then code = code, otherwise code = '_' + code
325
    if (!bibliographicRecord.getSchemaType().equals(SchemaType.PICA) && !code.isEmpty()) {
1✔
326
      code = "_" + code;
1✔
327
    }
328

329
    output.append(String.format("%s%s: %s%n", definition.getIndexTag(), code, subfield.resolve()));
1✔
330
    if (subfield.getDefinition() == null || !subfield.getDefinition().hasContentParser()) {
1✔
331
      return output.toString();
1✔
332
    }
333
    Map<String, String> extra = subfield.parseContent();
1✔
334
    if (extra == null) {
1✔
335
      return output.toString();
×
336
    }
337

338
    for (Map.Entry<String, String> entry : extra.entrySet()) {
1✔
339
      output.append(String.format(
1✔
340
        "%s%s_%s: %s%n",
341
        definition.getIndexTag(), code, entry.getKey(), entry.getValue()
1✔
342
      ));
343
    }
1✔
344

345
    return output.toString();
1✔
346
  }
347

348
  @Override
349
  public Map<String, List<String>> getKeyValuePairs() {
350
    return getKeyValuePairs(SolrFieldType.MARC);
1✔
351
  }
352

353
  @Override
354
  public Map<String, List<String>> getKeyValuePairs(SolrFieldType type) {
355
    return getKeyValuePairs(type, MarcVersion.MARC21);
1✔
356
  }
357

358
  @Override
359
  public Map<String, List<String>> getKeyValuePairs(SolrFieldType type,
360
                                                    MarcVersion marcVersion) {
361
    Map<String, List<String>> pairs = new HashMap<>();
1✔
362

363
    // If the field is PICA and has a definition, use the definition's tag
364
    // Otherwise, use the tag found in the field
365
    determineTag();
1✔
366

367
    SchemaType schemaType = bibliographicRecord != null ? bibliographicRecord.getSchemaType() : SchemaType.MARC21;
1✔
368
    DataFieldKeyGenerator keyGenerator = DataFieldKeyGeneratorFactory.create(type, definition, tag, schemaType);
1✔
369
    keyGenerator.setMarcVersion(marcVersion);
1✔
370

371
    // Indicator 1
372
    boolean hasInd1def = (definition != null && definition.getInd1() != null && definition.getInd1().exists());
1✔
373
    if (hasInd1def || !getInd1().equals(" ")) {
1✔
374
      String value = resolveInd1();
1✔
375
      pairs.put(keyGenerator.forInd1(), Collections.singletonList(value));
1✔
376
    }
377

378
    // ind2
379
    boolean hasInd2def = (definition != null && definition.getInd2() != null && definition.getInd2().exists());
1✔
380
    if (hasInd2def || !getInd2().equals(" ")) {
1✔
381
      String value = resolveInd2();
1✔
382
      pairs.put(keyGenerator.forInd2(), Collections.singletonList(value));
1✔
383
    }
384

385
    // subfields
386
    for (MarcSubfield subfield : subfields) {
1✔
387
      Utils.mergeMap(pairs, subfield.getKeyValuePairs(keyGenerator));
1✔
388
    }
1✔
389

390
    // Index fields that have SourceSpecificationType defined (which also means a FieldIndexer)
391
    indexFieldsWithSchemas(pairs, keyGenerator);
1✔
392

393
    // Full field indexing for authority fields
394
    indexAllAuthoritySubfields(pairs, keyGenerator);
1✔
395

396
    // Full field indexing for subject fields
397
    indexClassifications(schemaType, pairs, keyGenerator);
1✔
398

399
    return pairs;
1✔
400
  }
401

402
  /**
403
   * Sets the value of the tag field based on the definition, schema type, and occurrence. That tag will later be
404
   * used to generate keys for the index.
405
   */
406
  private void determineTag() {
407
    if (bibliographicRecord == null || !bibliographicRecord.getSchemaType().equals(SchemaType.PICA) || definition == null) {
1✔
408
      tag = getTag();
1✔
409
      if (getOccurrence() != null) {
1✔
410
        tag += "/" + getOccurrence();
1✔
411
      }
412
      return;
1✔
413
    }
414

415
    PicaFieldDefinition picaDefinition = (PicaFieldDefinition) definition;
1✔
416
    tag = picaDefinition.getTag();
1✔
417
    if (picaDefinition.getCounter() != null) {
1✔
418
      tag += "_" + picaDefinition.getCounter();
1✔
419
    } else if (picaDefinition.getOccurrence() != null) {
1✔
420
      tag += "_" + picaDefinition.getOccurrence();
1✔
421
    }
422
  }
1✔
423

424
  private void indexClassifications(SchemaType schemaType,
425
                                    Map<String, List<String>> pairs,
426
                                    DataFieldKeyGenerator keyGenerator) {
427
    String fieldTag = schemaType.equals(SchemaType.PICA) ? this.getTagWithOccurrence() : this.getTag();
1✔
428

429
    if (bibliographicRecord == null || !bibliographicRecord.isSubjectTag(fieldTag)) {
1✔
430
      return;
1✔
431
    }
432

433
    List<String> subfieldValues = new ArrayList<>();
1✔
434
    for (MarcSubfield subfield : subfields) {
1✔
435
      if (bibliographicRecord.isSkippableSubjectSubfield(fieldTag, subfield.getCode())) {
1✔
436
        continue;
1✔
437
      }
438
      String value = subfield.getValue();
1✔
439
      subfieldValues.add(value);
1✔
440
    }
1✔
441
    String key = keyGenerator.forFullField();
1✔
442
    String value = StringUtils.join(subfieldValues, ", ");
1✔
443

444
    pairs.putIfAbsent(key, new ArrayList<>());
1✔
445
    pairs.get(key).add(value);
1✔
446
  }
1✔
447

448
  private void indexAllAuthoritySubfields(Map<String, List<String>> pairs, DataFieldKeyGenerator keyGenerator) {
449
    String fieldTag = getTag();
1✔
450
    if (bibliographicRecord == null || !bibliographicRecord.isAuthorityTag(fieldTag)) {
1✔
451
      return;
1✔
452
    }
453

454
    List<String> subfieldValues = new ArrayList<>();
1✔
455
    // This gets all subfield values in the field and concatenates them
456
    // If the field is PICA, then the value of subfield E is concatenated with the value of subfield M
457
    for (MarcSubfield subfield : subfields) {
1✔
458
      String value = indexAuthorityNameFullSomethingWhatever(fieldTag, subfield);
1✔
459
      if (value != null) {
1✔
460
        subfieldValues.add(value);
1✔
461
      }
462
    }
1✔
463

464
    String key = keyGenerator.forFullField();
1✔
465
    String value = StringUtils.join(subfieldValues, ", ");
1✔
466

467
    pairs.putIfAbsent(key, new ArrayList<>());
1✔
468
    pairs.get(key).add(value);
1✔
469
  }
1✔
470

471
  private String indexAuthorityNameFullSomethingWhatever(String fieldTag, MarcSubfield subfield) {
472

473
    if (bibliographicRecord.isSkippableAuthoritySubfield(fieldTag, subfield.getCode())) {
1✔
474
      return null;
1✔
475
    }
476

477
    String value = subfield.getValue();
1✔
478
    if (!bibliographicRecord.getSchemaType().equals(SchemaType.PICA)) {
1✔
479
      return value;
1✔
480
    }
481

482
    if (!subfield.getCode().equals("E") && subfield.getCode().equals("M") && subfieldIndex.containsKey("E")) {
1✔
483
        return null;
1✔
484
    }
485

486
    value += "-";
1✔
487
    if (subfieldIndex.containsKey("M")) {
1✔
488
      value += subfieldIndex.get("M").get(0).getValue();
1✔
489
    }
490
    return value;
1✔
491
  }
492

493
  private void indexFieldsWithSchemas(Map<String, List<String>> pairs, DataFieldKeyGenerator keyGenerator) {
494
    List<FieldIndexer> fieldWithSchemaIndexers = getFieldIndexers();
1✔
495

496
    if (fieldWithSchemaIndexers == null || fieldWithSchemaIndexers.isEmpty()) {
1✔
497
      return;
1✔
498
    }
499

500
    try {
501
      for (FieldIndexer indexer : getFieldIndexers()) {
1✔
502
        Map<String, List<String>> extra = indexer.index(this, keyGenerator);
1✔
503
        Utils.mergeMap(pairs, extra);
1✔
504
      }
1✔
505
    } catch (IllegalArgumentException e) {
×
506
      logger.log(Level.SEVERE, "{0} in record {1} {2}", new Object[]{e.getLocalizedMessage(), bibliographicRecord.getId(), this});
×
507
    }
1✔
508
  }
1✔
509

510
  private FieldIndexer getFieldIndexer() {
511
    FieldIndexer fieldIndexer = null;
1✔
512

513
    // If the Schema is UNIMARC and the field is either a classification (subject) or an authority field,
514
    // then use the subfield 2 to determine the schema
515
    boolean isUnimarc = bibliographicRecord != null && bibliographicRecord.getSchemaType().equals(SchemaType.UNIMARC);
1✔
516
    if (isUnimarc && (bibliographicRecord.isSubjectTag(getTag()) || bibliographicRecord.isAuthorityTag(getTag()))) {
1✔
517
        fieldIndexer = SchemaFromSubfield2.getInstance();
1✔
518
        return fieldIndexer;
1✔
519
    }
520

521
    // If there is no definition or no source specification type, return null
522
    if (definition == null || definition.getSourceSpecificationType() == null) {
1✔
523
      return null;
1✔
524
    }
525

526
    SourceSpecificationType specificationType = definition.getSourceSpecificationType();
1✔
527
    switch (specificationType) {
1✔
528
      case Indicator1Is7AndSubfield2:
529
        fieldIndexer = SchemaFromInd1OrIf7FromSubfield2.getInstance();
1✔
530
        break;
1✔
531
      case Indicator1IsSpaceAndSubfield2:
532
        fieldIndexer = SchemaFromInd1OrIfEmptyFromSubfield2.getInstance();
1✔
533
        break;
1✔
534
      case Indicator2AndSubfield2:
535
        fieldIndexer = SchemaFromInd2AndSubfield2.getInstance();
1✔
536
        break;
1✔
537
      case Indicator2For055AndSubfield2:
538
        fieldIndexer = SchemaFromInd2For055OrIf7FromSubfield2.getInstance();
×
539
        break;
×
540
      case Subfield2:
541
        fieldIndexer = SchemaFromSubfield2.getInstance();
1✔
542
        break;
1✔
543
      case Indicator2:
544
        fieldIndexer = SchemaFromInd2.getInstance();
1✔
545
        break;
546
    }
547
    return fieldIndexer;
1✔
548
  }
549

550
  public void addFieldIndexer(FieldIndexer indexer) {
551
    if (fieldIndexers == null)
1✔
552
      fieldIndexers = new ArrayList<>();
1✔
553
    if (indexer != null)
1✔
554
      fieldIndexers.add(indexer);
1✔
555
  }
1✔
556

557
  public List<FieldIndexer> getFieldIndexers() {
558
    if (!fieldIndexerInitialized) {
1✔
559
      addFieldIndexer(getFieldIndexer());
1✔
560
      fieldIndexerInitialized = true;
1✔
561
    }
562
    return fieldIndexers;
1✔
563
  }
564

565
  public String resolveInd1() {
566
    if (definition == null) {
1✔
567
      return ind1;
1✔
568
    }
569
    return resolveIndicator(definition.getInd1(), ind1);
1✔
570
  }
571

572
  public String resolveInd2() {
573
    if (definition == null) {
1✔
574
      return ind2;
1✔
575
    }
576
    return resolveIndicator(definition.getInd2(), ind2);
1✔
577
  }
578

579
  /**
580
   * Returns the label of the indicator if it can be found in the definition. Otherwise, returns the indicator code used.
581
   * @param indicatorDefinition The definition of the indicator.
582
   * @param indicator The indicator code.
583
   * @return The label or the indicator code depending on the existence of the indicator in the definition.
584
   */
585
  public String resolveIndicator(Indicator indicatorDefinition, String indicator) {
586
    if (indicatorDefinition == null) {
1✔
587
      return indicator;
×
588
    }
589

590
    if (!indicatorDefinition.exists()) {
1✔
591
      return indicator;
1✔
592
    }
593

594
    if (!indicatorDefinition.hasCode(indicator)) {
1✔
595
      return indicator;
1✔
596
    }
597

598
    EncodedValue indCode = indicatorDefinition.getCode(indicator);
1✔
599
    assert(indCode != null);
1✔
600

601
    // If it's a range, return the label and the indicator
602
    // For instance, code="0-9" -> "Number of parts: 3"
603
    if (indCode.isRange()) {
1✔
604
      return indCode.getLabel() + ": " + indicator;
1✔
605
    }
606

607
    return indCode.getLabel();
1✔
608
  }
609

610
  public String getTag() {
611
    return (definition != null)
1✔
612
      ? definition.getTag()
1✔
613
      : tag;
1✔
614
  }
615

616
  public String getInd1() {
617
    return ind1;
1✔
618
  }
619

620
  public String getInd2() {
621
    return ind2;
1✔
622
  }
623

624
  public List<MarcSubfield> getSubfield(String code) {
625
    return subfieldIndex.getOrDefault(code, null);
1✔
626
  }
627

628
  public List<MarcSubfield> getSubfields() {
629
    return subfields;
1✔
630
  }
631

632
  /**
633
   * Sets subfields without indexing them
634
   * @param subfields Subfields to set
635
   */
636
  public void setSubfields(List<MarcSubfield> subfields) {
637
    this.subfields = subfields;
1✔
638
  }
1✔
639

640
  public DataFieldDefinition getDefinition() {
641
    return definition;
1✔
642
  }
643

644
  public DataFieldKeyGenerator getKeyGenerator(SolrFieldType type) {
645
    return DataFieldKeyGeneratorFactory.create(type, getDefinition());
1✔
646
  }
647

648
  public void addUnhandledSubfields(String code) {
649
    if (unhandledSubfields == null)
×
650
      unhandledSubfields = new ArrayList<>();
×
651
    unhandledSubfields.add(code);
×
652
  }
×
653

654
  public List<String> getUnhandledSubfields() {
655
    return unhandledSubfields;
1✔
656
  }
657

658
  public String getOccurrence() {
659
    return occurrence;
1✔
660
  }
661

662
  public void setOccurrence(String occurrence) {
663
    this.occurrence = occurrence;
1✔
664
  }
1✔
665

666
  public String getTagWithOccurrence() {
667
    if (occurrence == null) {
1✔
668
      return getTag();
1✔
669
    }
670
    return getTag() + "/" + occurrence;
1✔
671
  }
672

673
  @Override
674
  public String toString() {
675

676
    String dataFieldTag;
677

678
    if (StringUtils.isNotBlank(tag)) {
1✔
679
      dataFieldTag = tag;
×
680
    } else if (definition != null) {
1✔
681
      dataFieldTag = definition.getTag();
1✔
682
    } else {
683
      dataFieldTag = "unknown";
×
684
    }
685

686
    return "DataField{"
1✔
687
      + dataFieldTag
688
      + ", ind1='" + ind1 + '\''
689
      + ", ind2='" + ind2 + '\''
690
      + ", subfields=" + subfields
691
      + '}';
692
  }
693
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc