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

pkiraly / metadata-qa-marc / #1527

22 Aug 2025 02:21PM UTC coverage: 90.345%. Remained the same
#1527

push

pkiraly
Improve timeline handling

5191 of 6416 new or added lines in 219 files covered. (80.91%)

886 existing lines in 78 files now uncovered.

36717 of 40641 relevant lines covered (90.34%)

0.9 hits per line

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

66.67
/src/main/java/de/gwdg/metadataqa/marc/cli/SerialScore.java
1
package de.gwdg.metadataqa.marc.cli;
2

3
import de.gwdg.metadataqa.marc.analysis.serial.Marc21Serial;
4
import de.gwdg.metadataqa.marc.analysis.serial.MarcSerial;
5
import de.gwdg.metadataqa.marc.analysis.serial.SerialFields;
6
import de.gwdg.metadataqa.marc.analysis.serial.UnimarcSerial;
7
import de.gwdg.metadataqa.marc.cli.parameters.CommonParameters;
8
import de.gwdg.metadataqa.marc.cli.parameters.SerialScoreParameters;
9
import de.gwdg.metadataqa.marc.cli.processor.BibliographicInputProcessor;
10
import de.gwdg.metadataqa.marc.cli.utils.RecordIterator;
11
import de.gwdg.metadataqa.marc.dao.MarcLeader;
12
import de.gwdg.metadataqa.marc.dao.record.BibliographicRecord;
13
import de.gwdg.metadataqa.marc.dao.record.Marc21Record;
14
import de.gwdg.metadataqa.marc.dao.record.MarcRecord;
15
import de.gwdg.metadataqa.marc.dao.record.UnimarcRecord;
16
import de.gwdg.metadataqa.marc.model.validation.ValidationError;
17
import org.apache.commons.cli.HelpFormatter;
18
import org.apache.commons.cli.Options;
19
import org.apache.commons.cli.ParseException;
20
import org.apache.commons.io.FileUtils;
21
import org.apache.commons.lang3.StringUtils;
22
import org.marc4j.marc.Record;
23

24
import java.io.File;
25
import java.io.IOException;
26
import java.io.Serializable;
27
import java.nio.charset.StandardCharsets;
28
import java.nio.file.Files;
29
import java.nio.file.Path;
30
import java.nio.file.Paths;
31
import java.util.HashMap;
32
import java.util.List;
33
import java.util.Map;
34
import java.util.logging.Level;
35
import java.util.logging.Logger;
36

37
import static de.gwdg.metadataqa.marc.Utils.createRow;
38
import static de.gwdg.metadataqa.marc.Utils.quote;
39

40
/**
41
 * usage:
42
 * java -cp target/qa-catalogue-0.1-SNAPSHOT-jar-with-dependencies.jar \
43
 * de.gwdg.metadataqa.marc.cli.SerialScore [MARC21 file]
44
 *
45
 * @author Péter Király <peter.kiraly at gwdg.de>
46
 */
47
public class SerialScore extends QACli<SerialScoreParameters> implements BibliographicInputProcessor, Serializable {
48

49
  private static final Logger logger = Logger.getLogger(
1✔
50
    SerialScore.class.getCanonicalName()
1✔
51
  );
52
  private final Options options;
53
  private final boolean readyToProcess;
54
  private File output = null;
1✔
55
  private Map<Integer, Integer> histogram = new HashMap<>();
1✔
56

57
  public SerialScore(String[] args) throws ParseException {
1✔
58
    parameters = new SerialScoreParameters(args);
1✔
59
    options = parameters.getOptions();
1✔
60
    readyToProcess = true;
1✔
61
  }
1✔
62

63
  public static void main(String[] args) {
64
    BibliographicInputProcessor processor = null;
1✔
65
    try {
66
      processor = new SerialScore(args);
1✔
UNCOV
67
    } catch (ParseException e) {
×
NEW
68
      logger.severe("ERROR. " + e.getLocalizedMessage());
×
UNCOV
69
      System.exit(1);
×
70
    }
1✔
71

72
    if (processor.getParameters().getArgs().length < 1) {
1✔
NEW
73
      logger.severe("Please provide a MARC file name!");
×
UNCOV
74
      System.exit(0);
×
75
    }
76
    if (processor.getParameters().doHelp()) {
1✔
77
      processor.printHelp(processor.getParameters().getOptions());
×
78
      System.exit(0);
×
79
    }
80

81
    RecordIterator iterator = new RecordIterator(processor);
1✔
82
    iterator.setProcessWithErrors(processor.getParameters().getProcessRecordsWithoutId());
1✔
83
    iterator.start();
1✔
84
  }
1✔
85

86
  @Override
87
  public CommonParameters getParameters() {
88
    return parameters;
1✔
89
  }
90

91
  @Override
92
  public void beforeIteration() {
93
    logger.info(() -> parameters.formatParameters());
1✔
94
    printFields();
1✔
95

96
    output = new File(parameters.getOutputDir(), parameters.getFileName());
1✔
97
    if (output.exists()) {
1✔
98
      try {
99
        Files.delete(output.toPath());
1✔
NEW
100
      } catch (IOException e) {
×
NEW
101
        logger.log(Level.SEVERE, "The output file ({}) has not been deleted", output.getAbsolutePath());
×
102
      }
1✔
103
    }
104

105
    print(createRow(MarcSerial.getHeaders()));
1✔
106
  }
1✔
107

108
  @Override
109
  public void fileOpened(Path path) {
110
    // do nothing
111
  }
1✔
112

113
  @Override
114
  public void processRecord(Record marc4jRecord, int recordNumber) {
115
    // do nothing
116
  }
1✔
117

118
  @Override
119
  public void processRecord(BibliographicRecord bibliographicRecord, int recordNumber, List<ValidationError> errors) throws IOException {
NEW
120
    processRecord(bibliographicRecord, recordNumber);
×
UNCOV
121
  }
×
122

123
  @Override
124
  public void processRecord(BibliographicRecord bibliographicRecord, int recordNumber) {
125
    if (!(bibliographicRecord instanceof MarcRecord)) {
1✔
NEW
126
      return;
×
127
    }
128

129
    MarcRecord marcRecord = (MarcRecord) bibliographicRecord;
1✔
130
    if (!marcRecord.getType().equals(MarcLeader.Type.CONTINUING_RESOURCES)) {
1✔
NEW
131
      return;
×
132
    }
133

134
    if (parameters.getRecordIgnorator().isIgnorable(marcRecord)) {
1✔
NEW
135
      return;
×
136
    }
137

138
    MarcSerial serial;
139
    if (marcRecord instanceof Marc21Record) {
1✔
140
      serial = new Marc21Serial((Marc21Record) marcRecord);
1✔
141
    } else {
142
      serial = new UnimarcSerial((UnimarcRecord) marcRecord);
1✔
143
    }
144

145
    // Count the scores
146
    List<Integer> scores = serial.determineRecordQualityScore();
1✔
147

148
    // Create the histogram message
149
    String message = createRow(
1✔
150
      quote(marcRecord.getId().trim()), StringUtils.join(scores, ",")
1✔
151
    );
152
    print(message);
1✔
153
  }
1✔
154

155
  @Override
156
  public void fileProcessed() {
157
    // do nothing
UNCOV
158
  }
×
159

160
  @Override
161
  public void afterIteration(int numberOfprocessedRecords, long duration) {
162
    printHistogram();
1✔
163
    saveParameters("serials.params.json", parameters, Map.of("numberOfprocessedRecords", numberOfprocessedRecords, "duration", duration));
1✔
164
  }
1✔
165

166
  private void printHistogram() {
167
    // FIXME histogram is never updated
168
    Path path;
169
    path = Paths.get(parameters.getOutputDir(), "serial-histogram.csv");
1✔
170
    try (var writer = Files.newBufferedWriter(path)) {
1✔
171
      writer.write(createRow("score", "frequency"));
1✔
172
      histogram
1✔
173
        .entrySet()
1✔
174
        .stream()
1✔
175
        .sorted(Map.Entry.comparingByKey())
1✔
176
        .forEach(
1✔
177
          entry -> {
178
            try {
UNCOV
179
              writer.write(createRow(entry.getKey(), entry.getValue()));
×
UNCOV
180
            } catch (IOException e) {
×
UNCOV
181
              logger.log(Level.SEVERE, "printHistogram", e);
×
UNCOV
182
            }
×
UNCOV
183
          }
×
184
        );
UNCOV
185
    } catch (IOException e) {
×
UNCOV
186
      logger.log(Level.SEVERE, "printHistogram", e);
×
187
    }
1✔
188
  }
1✔
189

190
  @Override
191
  public boolean readyToProcess() {
192
    return readyToProcess;
1✔
193
  }
194

195
  public void printHelp(Options options) {
UNCOV
196
    HelpFormatter formatter = new HelpFormatter();
×
UNCOV
197
    String message = String.format(
×
198
      "java -cp qa-catalogue.jar %s [options] [file]",
UNCOV
199
      this.getClass().getCanonicalName()
×
200
    );
UNCOV
201
    formatter.printHelp(message, options);
×
UNCOV
202
  }
×
203

204
  private void print(String message) {
205
    try {
206
      FileUtils.writeStringToFile(output, message, StandardCharsets.UTF_8, true);
1✔
UNCOV
207
    } catch (IOException e) {
×
208
      logger.log(Level.SEVERE, "print", e);
×
209
    }
1✔
210
  }
1✔
211

212
  private void printFields() {
213
    var path = Paths.get(parameters.getOutputDir(), "serial-score-fields.csv");
1✔
214
    try (var writer = Files.newBufferedWriter(path)) {
1✔
215
      writer.write(createRow("name", "transformed"));
1✔
216
      for (SerialFields field : SerialFields.values()) {
1✔
217
        try {
218
          writer.write(createRow(quote(field.getLabel()), field.getMachine()));
1✔
UNCOV
219
        } catch (IOException e) {
×
UNCOV
220
          logger.log(Level.SEVERE, "printFields", e);
×
221
        }
1✔
222
      }
UNCOV
223
    } catch (IOException e) {
×
UNCOV
224
      logger.log(Level.SEVERE, "printFields", e);
×
225
    }
1✔
226
  }
1✔
227
}
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