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

IQSS / dataverse / #23889

25 Nov 2024 01:38AM CUT coverage: 22.443% (-0.004%) from 22.447%
#23889

Pull #11049

github

web-flow
Merge 00943e1e2 into f95c1a036
Pull Request #11049: 10982 10909 Allow using OAI-PMH identifiers as persistent ids of harvested datasets

0 of 24 new or added lines in 6 files covered. (0.0%)

1 existing line in 1 file now uncovered.

19386 of 86380 relevant lines covered (22.44%)

0.22 hits per line

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

8.71
/src/main/java/edu/harvard/iq/dataverse/api/imports/ImportGenericServiceBean.java
1
package edu.harvard.iq.dataverse.api.imports;
2

3
import com.google.gson.Gson;
4

5
import edu.harvard.iq.dataverse.Dataset;
6
import edu.harvard.iq.dataverse.DatasetFieldCompoundValue;
7
import edu.harvard.iq.dataverse.DatasetFieldConstant;
8
import edu.harvard.iq.dataverse.DatasetFieldServiceBean;
9
import edu.harvard.iq.dataverse.DatasetFieldType;
10
import edu.harvard.iq.dataverse.DatasetVersion;
11
import edu.harvard.iq.dataverse.ForeignMetadataFieldMapping;
12
import edu.harvard.iq.dataverse.ForeignMetadataFormatMapping;
13
import edu.harvard.iq.dataverse.MetadataBlockServiceBean;
14
import edu.harvard.iq.dataverse.api.dto.*;  
15
import edu.harvard.iq.dataverse.api.dto.FieldDTO;
16
import edu.harvard.iq.dataverse.api.dto.MetadataBlockDTO;
17
import edu.harvard.iq.dataverse.dataset.DatasetTypeServiceBean;
18
import edu.harvard.iq.dataverse.license.LicenseServiceBean;
19
import edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider;
20
import edu.harvard.iq.dataverse.pidproviders.handle.HandlePidProvider;
21
import edu.harvard.iq.dataverse.pidproviders.perma.PermaLinkPidProvider;
22
import edu.harvard.iq.dataverse.settings.SettingsServiceBean;
23
import edu.harvard.iq.dataverse.util.StringUtil;
24
import edu.harvard.iq.dataverse.util.json.JsonParseException;
25
import edu.harvard.iq.dataverse.util.json.JsonParser;
26
import java.io.File;
27
import java.io.FileInputStream;
28
import java.io.FileNotFoundException;
29
import java.io.IOException;
30
import java.io.StringReader;
31
import java.util.*;
32
import java.util.Map;
33
import java.util.logging.Level;
34
import java.util.logging.Logger;
35
import jakarta.ejb.EJB;
36
import jakarta.ejb.EJBException;
37
import jakarta.ejb.Stateless;
38
import jakarta.inject.Named;
39
import jakarta.json.Json;
40
import javax.xml.stream.XMLStreamConstants;
41
import javax.xml.stream.XMLStreamException;
42
import javax.xml.stream.XMLStreamReader;
43
import jakarta.json.JsonObject;
44
import jakarta.json.JsonReader;
45
import jakarta.persistence.EntityManager;
46
import jakarta.persistence.NoResultException;
47
import jakarta.persistence.PersistenceContext;
48
import javax.xml.stream.XMLInputFactory;
49
import net.handle.hdllib.HandleException;
50
import net.handle.hdllib.HandleResolver;
51

52

53
/**
54
 *
55
 * @author ellenk
56
 * @author Leonid Andreev
57
 * @author Bob Treacy
58
*/
59
@Stateless
60
@Named
61
public class ImportGenericServiceBean {
62
    private static final Logger logger = Logger.getLogger(ImportGenericServiceBean.class.getCanonicalName());
1✔
63
    
64
    @EJB
65
    DatasetFieldServiceBean datasetfieldService;
66
    
67
    @EJB
68
    DatasetFieldServiceBean datasetFieldSvc;
69
    
70
    @EJB
71
    MetadataBlockServiceBean blockService;
72
    
73
    @EJB
74
    SettingsServiceBean settingsService;
75

76
    @EJB
77
    LicenseServiceBean licenseService;
78

79
    @EJB
80
    DatasetTypeServiceBean datasetTypeService;
81

82
    @PersistenceContext(unitName = "VDCNet-ejbPU")
83
    private EntityManager em;
84
    
85
    public static String DCTERMS = "http://purl.org/dc/terms/";
1✔
86
    
87
    public ForeignMetadataFormatMapping findFormatMappingByName (String name) {
88
        try {
89
            return em.createNamedQuery("ForeignMetadataFormatMapping.findByName", ForeignMetadataFormatMapping.class)
×
90
                    .setParameter("name", name)
×
91
                    .getSingleResult();
×
92
        } catch ( NoResultException nre ) {
×
93
            return null;
×
94
        }
95
    }
96
    
97
    public void importXML(String xmlToParse, String foreignFormat, DatasetVersion datasetVersion) {
98
        
99
        StringReader reader = null;
×
100
        XMLStreamReader xmlr = null;        
×
101

102
        ForeignMetadataFormatMapping mappingSupported = findFormatMappingByName (foreignFormat);
×
103
        if (mappingSupported == null) {
×
104
            throw new EJBException("Unknown/unsupported foreign metadata format "+foreignFormat);
×
105
        }
106
        
107
        try {
108
            reader = new StringReader(xmlToParse);
×
109
            XMLInputFactory xmlFactory = javax.xml.stream.XMLInputFactory.newInstance();
×
110
            xmlr =  xmlFactory.createXMLStreamReader(reader);
×
111
            DatasetDTO datasetDTO = processXML(xmlr, mappingSupported);
×
112
        
113
            Gson gson = new Gson();
×
114
            String json = gson.toJson(datasetDTO.getDatasetVersion());
×
115
            logger.fine(json);
×
116
            JsonReader jsonReader = Json.createReader(new StringReader(json));
×
117
            JsonObject obj = jsonReader.readObject();
×
118
            DatasetVersion dv = new JsonParser(datasetFieldSvc, blockService, settingsService, licenseService, datasetTypeService).parseDatasetVersion(obj, datasetVersion);
×
119
        } catch (XMLStreamException ex) {
×
120
            //Logger.getLogger("global").log(Level.SEVERE, null, ex);
121
            throw new EJBException("ERROR occurred while parsing XML fragment  ("+xmlToParse.substring(0, 64)+"...); ", ex);
×
122
        } catch (JsonParseException ex) {
×
123
            Logger.getLogger(ImportGenericServiceBean.class.getName()).log(Level.SEVERE, null, ex);
×
124
        } finally {
125
            try {
126
                if (xmlr != null) { xmlr.close(); }
×
127
            } catch (XMLStreamException ex) {}
×
128
        }
129
    }
×
130

131
    public DatasetDTO processXML( XMLStreamReader xmlr, ForeignMetadataFormatMapping foreignFormatMapping) throws XMLStreamException {
132
        // init - similarly to what I'm doing in the metadata extraction code? 
133
        DatasetDTO datasetDTO = this.initializeDataset();
×
134

135
        while ( xmlr.next() == XMLStreamConstants.COMMENT ); // skip pre root comments
×
136
//        xmlr.nextTag();
137
        String openingTag = foreignFormatMapping.getStartElement();
×
138
        if (openingTag != null) {
×
139
            xmlr.require(XMLStreamConstants.START_ELEMENT, null, openingTag);
×
140
        } else { 
141
            // TODO: 
142
            // add support for parsing the body regardless of the start element.
143
            // June 20 2014 -- L.A. 
144
            throw new EJBException("No support for format mappings without start element defined (yet)");
×
145
        }
146
                
147
        processXMLElement(xmlr, ":", openingTag, foreignFormatMapping, datasetDTO);
×
148
  
149
        return datasetDTO;
×
150

151
    }
152
    
153
    // Helper methods for importing harvested Dublin Core xml.
154
    // Dublin Core is considered a mandatory, built in metadata format mapping. 
155
    // It is distributed as required content, in reference_data.sql. 
156
    // Note that arbitrary formatting tags are supported for the outer xml
157
    // wrapper. -- L.A. 4.5
158
    public DatasetDTO processOAIDCxml(String DcXmlToParse) throws XMLStreamException {
NEW
159
        return processOAIDCxml(DcXmlToParse, null, false);
×
160
    }
161
    
162
    public DatasetDTO processOAIDCxml(String DcXmlToParse, String oaiIdentifier, boolean preferSuppliedIdentifier) throws XMLStreamException {
163
        // look up DC metadata mapping: 
164
        
165
        ForeignMetadataFormatMapping dublinCoreMapping = findFormatMappingByName(DCTERMS);
×
166
        if (dublinCoreMapping == null) {
×
167
            throw new EJBException("Failed to find metadata mapping for " + DCTERMS);
×
168
        }
169

170
        DatasetDTO datasetDTO = this.initializeDataset();
×
171
        StringReader reader = null;
×
172
        XMLStreamReader xmlr = null;
×
173

174
        try {
175
            reader = new StringReader(DcXmlToParse);
×
176
            XMLInputFactory xmlFactory = javax.xml.stream.XMLInputFactory.newInstance();
×
177
            xmlr = xmlFactory.createXMLStreamReader(reader);
×
178

179
            //while (xmlr.next() == XMLStreamConstants.COMMENT); // skip pre root comments
180
            xmlr.nextTag();
×
181

182
            xmlr.require(XMLStreamConstants.START_ELEMENT, null, OAI_DC_OPENING_TAG);
×
183

184
            processXMLElement(xmlr, ":", OAI_DC_OPENING_TAG, dublinCoreMapping, datasetDTO);
×
185
        } catch (XMLStreamException ex) {
×
186
            throw new EJBException("ERROR occurred while parsing XML fragment  (" + DcXmlToParse.substring(0, 64) + "...); ", ex);
×
187
        }
×
188

189
        
190
        datasetDTO.getDatasetVersion().setVersionState(DatasetVersion.VersionState.RELEASED);
×
191
        
192
        // In some cases, the identifier that we want to use for the dataset is 
193
        // already supplied to the method explicitly. For example, in some 
194
        // harvesting cases we'll want to use the OAI identifier (the identifier 
195
        // from the <header> section of the OAI record) for that purpose, without
196
        // expecting to find a valid persistent id in the body of the DC record:
197
        
198
        String globalIdentifier; 
199
        
NEW
200
        if (oaiIdentifier != null) {
×
NEW
201
            logger.fine("Attempting to use " + oaiIdentifier + " as the persistentId of the imported dataset");
×
202
            
NEW
203
            globalIdentifier = reassignIdentifierAsGlobalId(oaiIdentifier, datasetDTO);
×
204
        } else {
205
            // Our DC import handles the contents of the dc:identifier field 
206
            // as an "other id". Unless we are using an externally supplied 
207
            // global id, we will be using the first such "other id" that we 
208
            // can parse and recognize as the global id for the imported dataset
209
            // (note that this is the default behavior during harvesting),
210
            // so we need to reaassign it accordingly: 
NEW
211
            String identifier = selectIdentifier(datasetDTO.getDatasetVersion(), oaiIdentifier, preferSuppliedIdentifier);
×
NEW
212
            logger.fine("Imported identifier: " + identifier);
×
213

NEW
214
            globalIdentifier = reassignIdentifierAsGlobalId(identifier, datasetDTO);
×
NEW
215
            logger.fine("Detected global identifier: " + globalIdentifier);
×
216
        }
217
        
218
        if (globalIdentifier == null) {
×
NEW
219
            String exceptionMsg = oaiIdentifier == null ? 
×
NEW
220
                    "Failed to find a global identifier in the OAI_DC XML record." : 
×
NEW
221
                    "Failed to parse the supplied identifier as a valid Persistent Id";
×
NEW
222
            throw new EJBException(exceptionMsg);
×
223
        }
224
        
225
        return datasetDTO;
×
226

227
    }
228
    
229
    private void processXMLElement(XMLStreamReader xmlr, String currentPath, String openingTag, ForeignMetadataFormatMapping foreignFormatMapping, DatasetDTO datasetDTO) throws XMLStreamException {
230
        logger.fine("entering processXMLElement; ("+currentPath+")");
×
231

232
        while (xmlr.hasNext()) {
×
233

234
            int event;
235
            try {
236
                event = xmlr.next();
×
237
            } catch (XMLStreamException ex) {
×
238
                logger.warning("Error occurred in the XML parsing : " + ex.getMessage());
×
239
                continue; // Skip Undeclared namespace prefix and Unexpected close tag related to com.ctc.wstx.exc.WstxParsingException
×
240
            }
×
241

242
            if (event == XMLStreamConstants.START_ELEMENT) {
×
243
                String currentElement = xmlr.getLocalName();
×
244
                
245
                ForeignMetadataFieldMapping mappingDefined = datasetfieldService.findFieldMapping(foreignFormatMapping.getName(), currentPath+currentElement);
×
246
                
247
                if (mappingDefined != null) {
×
248
                    DatasetFieldType mappingDefinedFieldType = datasetfieldService.findByNameOpt(mappingDefined.getDatasetfieldName());
×
249
                    boolean compound = mappingDefinedFieldType.isCompound();
×
250
                    DatasetFieldCompoundValue cachedCompoundValue = null; 
×
251
                    String dataverseFieldName = mappingDefined.getDatasetfieldName();
×
252
                    // Process attributes, if any are defined in the mapping:
253
                    if (mappingDefinedFieldType.isCompound()) {
×
254
                        List<HashSet<FieldDTO>> compoundField = new ArrayList<>();
×
255
                        HashSet<FieldDTO> set = new HashSet<>();
×
256
                        for (ForeignMetadataFieldMapping childMapping : mappingDefined.getChildFieldMappings()) {
×
257
                            if (childMapping.isAttribute()) {
×
258
                                String attributeName = childMapping.getForeignFieldXPath();
×
259

260
                                String attributeValue = xmlr.getAttributeValue(null, attributeName);
×
261
                                if (attributeValue != null) {
×
262
                                    String mappedFieldName = childMapping.getDatasetfieldName();
×
263

264
                                    logger.fine("looking up dataset field " + mappedFieldName);
×
265

266
                                    DatasetFieldType mappedFieldType = datasetfieldService.findByNameOpt(mappedFieldName);
×
267
                                    if (mappedFieldType != null) {
×
268
                                        try {
269
                                            addToSet(set, attributeName, attributeValue);
×
270
                                            //FieldDTO value = FieldDTO.createPrimitiveFieldDTO(attributeName, attributeValue);
271
//                                        FieldDTO attribute = FieldDTO.createCompoundFieldDTO(attributeName, value);
272
                                            //MetadataBlockDTO citationBlock = datasetDTO.getDatasetVersion().getMetadataBlocks().get("citation");
273
                                            //citationBlock.getFields().add(value);
274
// TO DO replace database output with Json                                        cachedCompoundValue = createDatasetFieldValue(mappedFieldType, cachedCompoundValue, attributeValue, datasetVersion);
275
                                        } catch (Exception ex) {
×
276
                                            logger.warning("Caught unknown exception when processing attribute " + currentPath + currentElement + "{" + attributeName + "} (skipping);");
×
277
                                        }
×
278
                                    } else {
279
                                        throw new EJBException("Bad foreign metadata field mapping: no such DatasetField " + mappedFieldName + "!");
×
280
                                    }
281
                                }
282
                            }
283
                        }
×
284
                        if (!set.isEmpty()) {
×
285
                            compoundField.add(set);
×
286
                            MetadataBlockDTO citationBlock = datasetDTO.getDatasetVersion().getMetadataBlocks().get(mappingDefinedFieldType.getMetadataBlock().getName());
×
287
                            citationBlock.addField(FieldDTO.createMultipleCompoundFieldDTO(mappingDefined.getDatasetfieldName(), compoundField));
×
288
                        } else{
×
289
                            FieldDTO value = null;
×
290
                            if (mappingDefinedFieldType.isAllowMultiples()){
×
291
                                List<String> values = new ArrayList<>();
×
292
                                values.add(parseText(xmlr));
×
293
                                value = FieldDTO.createMultiplePrimitiveFieldDTO(dataverseFieldName, values);
×
294
                            }else {
×
295
                                value = FieldDTO.createPrimitiveFieldDTO(dataverseFieldName, parseText(xmlr));
×
296
                            }
297
                                
298
                            value = makeDTO(mappingDefinedFieldType, value, dataverseFieldName);
×
299
                            MetadataBlockDTO citationBlock = datasetDTO.getDatasetVersion().getMetadataBlocks().get(mappingDefinedFieldType.getMetadataBlock().getName());
×
300
                            citationBlock.addField(value);
×
301
                        }
302
                    } else // Process the payload of this XML element:
×
303
                    //xxString dataverseFieldName = mappingDefined.getDatasetfieldName();
304
                    if (dataverseFieldName != null && !dataverseFieldName.isEmpty()) {
×
305
                        DatasetFieldType dataverseFieldType = datasetfieldService.findByNameOpt(dataverseFieldName);
×
306
                        FieldDTO value;
307
                        if (dataverseFieldType != null) {
×
308

309
                            if (dataverseFieldType.isControlledVocabulary()) {
×
310
                                value = FieldDTO.createVocabFieldDTO(dataverseFieldName, parseText(xmlr));
×
311
                            } else {
312
                                value = FieldDTO.createPrimitiveFieldDTO(dataverseFieldName, parseText(xmlr));
×
313
                            }
314
                            value = makeDTO(dataverseFieldType, value, dataverseFieldName);
×
315
                            //  value = FieldDTO.createPrimitiveFieldDTO(dataverseFieldName, parseText(xmlr));
316
                            //  FieldDTO dataverseField = FieldDTO.createCompoundFieldDTO(dataverseFieldName, value);
317
                            MetadataBlockDTO citationBlock = datasetDTO.getDatasetVersion().getMetadataBlocks().get(mappingDefinedFieldType.getMetadataBlock().getName());
×
318
                            citationBlock.addField(value);
×
319
                            // TO DO replace database output with Json                             createDatasetFieldValue(dataverseFieldType, cachedCompoundValue, elementTextPayload, datasetVersion);
320
                        } else {
×
321
                            throw new EJBException("Bad foreign metadata field mapping: no such DatasetField " + dataverseFieldName + "!");
×
322
                        }
323
                    }
324
                } else {
×
325
                    // recursively, process the xml stream further down: 
326
                    processXMLElement(xmlr, currentPath+currentElement+":", currentElement, foreignFormatMapping, datasetDTO);
×
327
                }
328
                
329
            } else if (event == XMLStreamConstants.END_ELEMENT) {
×
330
                if (xmlr.getLocalName().equals(openingTag)) return;
×
331
            }
332
        }
×
333
    }
×
334

335
    private FieldDTO makeDTO(DatasetFieldType dataverseFieldType, FieldDTO value, String dataverseFieldName) {
336
        if (dataverseFieldType.isAllowMultiples()){
×
337
            if(dataverseFieldType.isCompound()) {
×
338
                value = FieldDTO.createMultipleCompoundFieldDTO(dataverseFieldName, value);
×
339
            } else if (dataverseFieldType.isControlledVocabulary()) {
×
340
                value = FieldDTO.createMultipleVocabFieldDTO(dataverseFieldName, Arrays.asList(value.getSinglePrimitive()));
×
341
            } else {
342
                value = FieldDTO.createMultiplePrimitiveFieldDTO(dataverseFieldName, Arrays.asList(value.getSinglePrimitive()));
×
343
            }
344
            if (dataverseFieldType.isChild()) {
×
345
                DatasetFieldType parentDatasetFieldType = dataverseFieldType.getParentDatasetFieldType();
×
346
                if (parentDatasetFieldType.isAllowMultiples()) {
×
347
                    value = FieldDTO.createMultipleCompoundFieldDTO(parentDatasetFieldType.getName(), value);
×
348
                    
349
                }
350
            }
×
351
        } else{
352
            if (dataverseFieldType.isCompound()){
×
353
                value = FieldDTO.createCompoundFieldDTO(dataverseFieldName, value);
×
354
            }
355
        }
356
        
357
        // TODO: 
358
        // it looks like the code below has already been executed, in one of the 
359
        // if () blocks above... is this ok to be doing it again?? -- L.A. 4.5
360
        if (dataverseFieldType.isChild()) {
×
361
                                    DatasetFieldType parentDatasetFieldType = dataverseFieldType.getParentDatasetFieldType();
×
362
                                    if (parentDatasetFieldType.isAllowMultiples()) {
×
363
                                        value = FieldDTO.createMultipleCompoundFieldDTO(parentDatasetFieldType.getName(), value);
×
364

365
                                    }
366
        }
367
        return value;
×
368
    }
369
    
370
    private String selectIdentifier(DatasetVersionDTO datasetVersionDTO, String suppliedIdentifier, boolean preferSuppliedIdentifier) {
371
        List<String> otherIds = new ArrayList<>();
×
372
        
NEW
373
        if (suppliedIdentifier != null && preferSuppliedIdentifier) {
×
374
            // This supplied identifier (in practice, his is likely the OAI-PMH 
375
            // identifier from the <record> <header> section) will be our first 
376
            // choice candidate for the pid of the imported dataset:
NEW
377
            otherIds.add(suppliedIdentifier);
×
378
        }
379
        
380
        for (Map.Entry<String, MetadataBlockDTO> entry : datasetVersionDTO.getMetadataBlocks().entrySet()) {
×
381
            String key = entry.getKey();
×
382
            MetadataBlockDTO value = entry.getValue();
×
383
            if ("citation".equals(key)) {
×
384
                for (FieldDTO fieldDTO : value.getFields()) {
×
385
                    if (DatasetFieldConstant.otherId.equals(fieldDTO.getTypeName())) {
×
386
                        for (HashSet<FieldDTO> foo : fieldDTO.getMultipleCompound()) {
×
387
                            for (FieldDTO next : foo) {
×
388
                                if (DatasetFieldConstant.otherIdValue.equals(next.getTypeName())) {
×
389
                                    otherIds.add(next.getSinglePrimitive());
×
390
                                }
391
                            }
×
392
                        }
×
393
                    }
394
                }
×
395
            }
396
        }
×
397
        
NEW
398
        if (suppliedIdentifier != null && !preferSuppliedIdentifier) {
×
399
            // Unless specifically instructed to prefer this extra identifier 
400
            // (in practice, this is likely the OAI-PMH identifier from the 
401
            // <record> <header> section), we will try to use it as the *last*
402
            // possible candidate for the pid, so, adding it to the end of the 
403
            // list:
NEW
404
            otherIds.add(suppliedIdentifier);
×
405
        }
406
        
UNCOV
407
        if (!otherIds.isEmpty()) {
×
408
            // We prefer doi or hdl identifiers like "doi:10.7910/DVN/1HE30F"
409
            for (String otherId : otherIds) {
×
410
                if (otherId.startsWith(AbstractDOIProvider.DOI_PROTOCOL) || otherId.startsWith(HandlePidProvider.HDL_PROTOCOL) || otherId.startsWith(AbstractDOIProvider.DOI_RESOLVER_URL) || otherId.startsWith(HandlePidProvider.HDL_RESOLVER_URL) || otherId.startsWith(AbstractDOIProvider.HTTP_DOI_RESOLVER_URL) || otherId.startsWith(HandlePidProvider.HTTP_HDL_RESOLVER_URL) || otherId.startsWith(AbstractDOIProvider.DXDOI_RESOLVER_URL) || otherId.startsWith(AbstractDOIProvider.HTTP_DXDOI_RESOLVER_URL)) {
×
411
                    return otherId;
×
412
                }
413
            }
×
414
            // But identifiers without hdl or doi like "10.6084/m9.figshare.12725075.v1" are also allowed
415
            for (String otherId : otherIds) {
×
416
                try {
417
                    HandleResolver hr = new HandleResolver();
×
418
                    hr.resolveHandle(otherId);
×
419
                    return HandlePidProvider.HDL_PROTOCOL + ":" + otherId;
×
420
                } catch (HandleException e) {
×
421
                    logger.fine("Not a valid handle: " + e.toString());
×
422
                }
423
            }
×
424
        }
425
        return null;
×
426
    }
427
    
428
    /* This is a general parser that can take DOI and Handle Ids, in their local or
429
     * URL forms (e.g. doi:... or https://doi.org/...) and parse them into
430
     * protocol/authority/identifier parts that are assigned to the datasetDTO.
431
     * The name reflects the original purpose but it is now used in ImportDDIServiceBean as well.
432
     */
433
    
434
    //ToDo - sync with GlobalId.parsePersistentId(String) ? - that currently doesn't do URL forms, but could
435
    public String reassignIdentifierAsGlobalId(String identifierString, DatasetDTO datasetDTO) {
436

437
        int index1 = identifierString.indexOf(':');
1✔
438
        int index2 = identifierString.indexOf('/');
1✔
439
        if (index1==-1) {
1✔
440
            logger.warning("Error parsing identifier: " + identifierString + ". ':' not found in string");
1✔
441
            return null; 
1✔
442
        }  
443
       
444
        String protocol = identifierString.substring(0, index1);
1✔
445
        
446
        if (AbstractDOIProvider.DOI_PROTOCOL.equals(protocol) || HandlePidProvider.HDL_PROTOCOL.equals(protocol) || PermaLinkPidProvider.PERMA_PROTOCOL.equals(protocol)) {
1✔
447
            logger.fine("Processing hdl:- or doi:- or perma:-style identifier : "+identifierString);        
1✔
448
        
449
        } else if ("http".equalsIgnoreCase(protocol) || "https".equalsIgnoreCase(protocol)) {
1✔
450
            
451
            // We also recognize global identifiers formatted as global resolver URLs:
452
            //ToDo - refactor index1 always has -1 here so that we can use index1+1 later
453
            //ToDo - single map of protocol/url, are all three cases the same then?
454
            if (identifierString.startsWith(HandlePidProvider.HDL_RESOLVER_URL) || identifierString.startsWith(HandlePidProvider.HTTP_HDL_RESOLVER_URL)) {
1✔
455
                logger.fine("Processing Handle identifier formatted as a resolver URL: "+identifierString);
1✔
456
                protocol = HandlePidProvider.HDL_PROTOCOL;
1✔
457
                index1 = (identifierString.startsWith(HandlePidProvider.HDL_RESOLVER_URL)) ? HandlePidProvider.HDL_RESOLVER_URL.length() - 1 : HandlePidProvider.HTTP_HDL_RESOLVER_URL.length() - 1;
1✔
458
                index2 = identifierString.indexOf("/", index1 + 1);
1✔
459
            } else if (identifierString.startsWith(AbstractDOIProvider.DOI_RESOLVER_URL) || identifierString.startsWith(AbstractDOIProvider.HTTP_DOI_RESOLVER_URL) || identifierString.startsWith(AbstractDOIProvider.DXDOI_RESOLVER_URL) || identifierString.startsWith(AbstractDOIProvider.HTTP_DXDOI_RESOLVER_URL)) {
1✔
460
                logger.fine("Processing DOI identifier formatted as a resolver URL: "+identifierString);
1✔
461
                protocol = AbstractDOIProvider.DOI_PROTOCOL;
1✔
462
                identifierString = identifierString.replace(AbstractDOIProvider.DXDOI_RESOLVER_URL, AbstractDOIProvider.DOI_RESOLVER_URL);
1✔
463
                identifierString = identifierString.replace(AbstractDOIProvider.HTTP_DXDOI_RESOLVER_URL, AbstractDOIProvider.HTTP_DOI_RESOLVER_URL);
1✔
464
                index1 = (identifierString.startsWith(AbstractDOIProvider.DOI_RESOLVER_URL)) ? AbstractDOIProvider.DOI_RESOLVER_URL.length() - 1 : AbstractDOIProvider.HTTP_DOI_RESOLVER_URL.length() - 1;
1✔
465
                index2 = identifierString.indexOf("/", index1 + 1);
1✔
466
            } else if (identifierString.startsWith(PermaLinkPidProvider.PERMA_RESOLVER_URL + Dataset.TARGET_URL)) {
×
467
                protocol = PermaLinkPidProvider.PERMA_PROTOCOL;
×
468
                index1 = PermaLinkPidProvider.PERMA_RESOLVER_URL.length() + + Dataset.TARGET_URL.length() - 1; 
×
469
                index2 = identifierString.indexOf("/", index1 + 1);
×
470
            } else {
471
                logger.warning("HTTP Url in supplied as the identifier is neither a Handle nor DOI resolver: "+identifierString);
×
472
                return null;
×
473
            }
474
        } else {
475
            logger.warning("Unknown identifier format: "+identifierString);
×
476
            return null; 
×
477
        }
478
        
479
        if (index2 == -1) {
1✔
480
            logger.warning("Error parsing identifier: " + identifierString + ". Second '/' not found in string");
×
481
            return null;
×
482
        }
483

484
        String authority = identifierString.substring(index1 + 1, index2);
1✔
485
        String identifier = identifierString.substring(index2 + 1);
1✔
486

487
        datasetDTO.setProtocol(protocol);
1✔
488
        datasetDTO.setAuthority(authority);
1✔
489
        datasetDTO.setIdentifier(identifier);
1✔
490

491
        // reassemble and return: 
492
        logger.fine("parsed identifier, finalized " + protocol + ":" + authority + "/" + identifier);
1✔
493
        return protocol + ":" + authority + "/" + identifier;
1✔
494
    }
495
        
496
        
497
    public static final String OAI_DC_OPENING_TAG = "dc";
498
    public static final String DCTERMS_OPENING_TAG = "dcterms";
499
    
500
    public static final String SOURCE_DVN_3_0 = "DVN_3_0";
501
    
502
    public static final String NAMING_PROTOCOL_HANDLE = "hdl";
503
    public static final String NAMING_PROTOCOL_DOI = "doi";
504
    public static final String AGENCY_HANDLE = "handle";
505
    public static final String AGENCY_DOI = "DOI";
506
    public static final String REPLICATION_FOR_TYPE = "replicationFor";
507
    public static final String VAR_WEIGHTED = "wgtd";
508
    public static final String VAR_INTERVAL_CONTIN = "contin";
509
    public static final String VAR_INTERVAL_DISCRETE = "discrete";
510
    public static final String CAT_STAT_TYPE_FREQUENCY = "freq";
511
    public static final String VAR_FORMAT_TYPE_NUMERIC = "numeric";
512
    public static final String VAR_FORMAT_SCHEMA_ISO = "ISO";
513
    
514

515
    public static final String EVENT_START = "start";
516
    public static final String EVENT_END = "end";
517
    public static final String EVENT_SINGLE = "single";
518

519
    public static final String LEVEL_DVN = "dvn";
520
    public static final String LEVEL_DV = "dv";
521
    public static final String LEVEL_STUDY = "study";
522
    public static final String LEVEL_FILE = "file";
523
    public static final String LEVEL_VARIABLE = "variable";
524
    public static final String LEVEL_CATEGORY = "category";
525

526
    public static final String NOTE_TYPE_UNF = "VDC:UNF";
527
    public static final String NOTE_SUBJECT_UNF = "Universal Numeric Fingerprint";
528

529
    public static final String NOTE_TYPE_TERMS_OF_USE = "DVN:TOU";
530
    public static final String NOTE_SUBJECT_TERMS_OF_USE = "Terms Of Use";
531

532
    public static final String NOTE_TYPE_CITATION = "DVN:CITATION";
533
    public static final String NOTE_SUBJECT_CITATION = "Citation";
534

535
    public static final String NOTE_TYPE_VERSION_NOTE = "DVN:VERSION_NOTE";
536
    public static final String NOTE_SUBJECT_VERSION_NOTE= "Version Note";
537

538
    public static final String NOTE_TYPE_ARCHIVE_NOTE = "DVN:ARCHIVE_NOTE";
539
    public static final String NOTE_SUBJECT_ARCHIVE_NOTE= "Archive Note";
540

541
    public static final String NOTE_TYPE_ARCHIVE_DATE = "DVN:ARCHIVE_DATE";
542
    public static final String NOTE_SUBJECT_ARCHIVE_DATE= "Archive Date";
543
    
544
    public static final String NOTE_TYPE_EXTENDED_METADATA = "DVN:EXTENDED_METADATA";
545

546
    public static final String NOTE_TYPE_LOCKSS_CRAWL = "LOCKSS:CRAWLING";
547
    public static final String NOTE_SUBJECT_LOCKSS_PERM = "LOCKSS Permission";
548

549
    public static final String NOTE_TYPE_REPLICATION_FOR = "DVN:REPLICATION_FOR";
550
    private XMLInputFactory xmlInputFactory = null;
1✔
551
    private ImportType importType;
552
    public enum ImportType{ NEW, MIGRATION, HARVEST};
×
553

554
    public ImportGenericServiceBean() {
×
555
    }
×
556
     
557
    public ImportGenericServiceBean(ImportType importType) {
1✔
558
        this.importType=importType;
1✔
559
        xmlInputFactory = javax.xml.stream.XMLInputFactory.newInstance();
1✔
560
        xmlInputFactory.setProperty("javax.xml.stream.isCoalescing", java.lang.Boolean.TRUE);
1✔
561

562
    }
1✔
563
    
564
      
565
    public DatasetDTO doImport(String xmlToParse) throws XMLStreamException {
566
        DatasetDTO datasetDTO = this.initializeDataset();
×
567

568
        // Read docDescr and studyDesc into DTO objects.
569
        Map<String, String> fileMap = mapDCTerms(xmlToParse, datasetDTO);
×
570
        if (!importType.equals(ImportType.MIGRATION)) {
×
571
                  //EMK TODO:  Call methods for reading FileMetadata and related objects from xml, return list of FileMetadata objects.
572
                   /*try {
573
            
574
             Map<String, DataTable> dataTableMap = new DataTableImportDDI().processDataDscr(xmlr);
575
             } catch(Exception e) {
576
            
577
             }*/
578
        }
579
        return datasetDTO;
×
580
    }
581
    
582
    public Map<String, String> mapDCTerms(String xmlToParse, DatasetDTO datasetDTO) throws XMLStreamException {
583

584
        Map<String, String> filesMap = new HashMap<>();
×
585
        StringReader reader = new StringReader(xmlToParse);
×
586
        XMLStreamReader xmlr = null;
×
587
        XMLInputFactory xmlFactory = javax.xml.stream.XMLInputFactory.newInstance();
×
588
        xmlr = xmlFactory.createXMLStreamReader(reader);
×
589
        processDCTerms(xmlr, datasetDTO, filesMap);
×
590

591
        return filesMap;
×
592
    }
593
   
594
 
595
    public Map<String, String> mapDCTerms(File ddiFile, DatasetDTO datasetDTO) {
596
        FileInputStream in = null;
×
597
        XMLStreamReader xmlr = null;
×
598
        Map<String, String> filesMap = new HashMap<>();
×
599

600
        try {
601
            in = new FileInputStream(ddiFile);
×
602
            xmlr =  xmlInputFactory.createXMLStreamReader(in);
×
603
            processDCTerms( xmlr,  datasetDTO , filesMap );
×
604
        } catch (FileNotFoundException ex) {
×
605
            Logger.getLogger("global").log(Level.SEVERE, null, ex);
×
606
            throw new EJBException("ERROR occurred in mapDDI: File Not Found!");
×
607
        } catch (XMLStreamException ex) {
×
608
            Logger.getLogger("global").log(Level.SEVERE, null, ex);
×
609
            throw new EJBException("ERROR occurred in mapDDI.", ex);
×
610
        } finally {
611
            try {
612
                if (xmlr != null) { xmlr.close(); }
×
613
            } catch (XMLStreamException ex) {}
×
614

615
            try {
616
                if (in != null) { in.close();}
×
617
            } catch (IOException ex) {}
×
618
        }
619

620
        return filesMap;
×
621
    }
622
    
623
    private void processDCTerms(XMLStreamReader xmlr, DatasetDTO datasetDTO, Map<String, String> filesMap) throws XMLStreamException {
624
       
625
        // make sure we have a codeBook
626
        //while ( xmlr.next() == XMLStreamConstants.COMMENT ); // skip pre root comments
627
        xmlr.nextTag();
×
628
        MetadataBlockDTO citationBlock = datasetDTO.getDatasetVersion().getMetadataBlocks().get("citation");
×
629
     
630
/*         if (codeBookLevelId != null && !codeBookLevelId.equals("")) {
631
            if (citationBlock.getField("otherId")==null) {
632
                // this means no ids were found during the parsing of the 
633
                // study description section. we'll use the one we found in 
634
                // the codeBook entry:
635
                FieldDTO otherIdValue = FieldDTO.createPrimitiveFieldDTO("otherIdValue", codeBookLevelId);
636
                FieldDTO otherId = FieldDTO.createCompoundFieldDTO("otherId", otherIdValue);
637
                citationBlock.getFields().add(otherId);
638
                
639
          } 
640
        }*/ 
641
        
642

643
    }
×
644
    // EMK TODO: update unit test so this doesn't have to be public
645
    public DatasetDTO initializeDataset() {
646
        DatasetDTO  datasetDTO = new DatasetDTO();
×
647
        DatasetVersionDTO datasetVersionDTO = new DatasetVersionDTO();
×
648
        datasetDTO.setDatasetVersion(datasetVersionDTO);
×
649
        HashMap<String, MetadataBlockDTO> metadataBlocks = new HashMap<>();
×
650
        datasetVersionDTO.setMetadataBlocks(metadataBlocks);
×
651
        
652
        datasetVersionDTO.getMetadataBlocks().put("citation", new MetadataBlockDTO());
×
653
        datasetVersionDTO.getMetadataBlocks().get("citation").setFields(new ArrayList<>());
×
654
        datasetVersionDTO.getMetadataBlocks().put("geospatial", new MetadataBlockDTO());
×
655
        datasetVersionDTO.getMetadataBlocks().get("geospatial").setFields(new ArrayList<>());
×
656
        datasetVersionDTO.getMetadataBlocks().put("social_science", new MetadataBlockDTO());
×
657
        datasetVersionDTO.getMetadataBlocks().get("social_science").setFields(new ArrayList<>());
×
658
        datasetVersionDTO.getMetadataBlocks().put("astrophysics", new MetadataBlockDTO());
×
659
        datasetVersionDTO.getMetadataBlocks().get("astrophysics").setFields(new ArrayList<>());
×
660
     
661
        return datasetDTO;
×
662
        
663
    }
664
     private String parseText(XMLStreamReader xmlr) throws XMLStreamException {
665
        return parseText(xmlr,true);
×
666
     }
667

668
     private String parseText(XMLStreamReader xmlr, boolean scrubText) throws XMLStreamException {
669
        String tempString = getElementText(xmlr);
×
670
        if (scrubText) {
×
671
            tempString = tempString.trim().replace('\n',' ');
×
672
        }
673
        return tempString;
×
674
     }
675
     private String parseDate (XMLStreamReader xmlr, String endTag) throws XMLStreamException {
676
        String date = xmlr.getAttributeValue(null, "date");
×
677
        if (date == null) {
×
678
            date = parseText(xmlr);
×
679
        }
680
        return date;
×
681
    } 
682
 /* We had to add this method because the ref getElementText has a bug where it
683
     * would append a null before the text, if there was an escaped apostrophe; it appears
684
     * that the code finds an null ENTITY_REFERENCE in this case which seems like a bug;
685
     * the workaround for the moment is to comment or handling ENTITY_REFERENCE in this case
686
     */
687
    private String getElementText(XMLStreamReader xmlr) throws XMLStreamException {
688
        if(xmlr.getEventType() != XMLStreamConstants.START_ELEMENT) {
×
689
            throw new XMLStreamException("parser must be on START_ELEMENT to read next text", xmlr.getLocation());
×
690
        }
691
        int eventType = xmlr.next();
×
692
        StringBuilder content = new StringBuilder();
×
693
        while(eventType != XMLStreamConstants.END_ELEMENT ) {
×
694
            if(eventType == XMLStreamConstants.CHARACTERS
×
695
            || eventType == XMLStreamConstants.CDATA
696
            || eventType == XMLStreamConstants.SPACE
697
            /* || eventType == XMLStreamConstants.ENTITY_REFERENCE*/) {
698
                content.append(xmlr.getText());
×
699
            } else if(eventType == XMLStreamConstants.PROCESSING_INSTRUCTION
×
700
                || eventType == XMLStreamConstants.COMMENT
701
                || eventType == XMLStreamConstants.ENTITY_REFERENCE) {
702
                // skipping
703
            } else if(eventType == XMLStreamConstants.END_DOCUMENT) {
×
704
                throw new XMLStreamException("unexpected end of document when reading element text content");
×
705
            } else if(eventType == XMLStreamConstants.START_ELEMENT) {
×
706
                throw new XMLStreamException("element text content may not contain START_ELEMENT", xmlr.getLocation());
×
707
            } else {
708
                throw new XMLStreamException("Unexpected event type "+eventType, xmlr.getLocation());
×
709
            }
710
            eventType = xmlr.next();
×
711
        }
712
        return content.toString();
×
713
    }
714
    
715
   
716
    
717
   private Map<String,String> parseCompoundText (XMLStreamReader xmlr, String endTag) throws XMLStreamException {
718
        Map<String,String> returnMap = new HashMap<>();
×
719
        String text = "";
×
720

721
        while (true) {
722
            int event = xmlr.next();
×
723
            if (event == XMLStreamConstants.CHARACTERS) {
×
724
                if (!text.isEmpty()) {
×
725
                    text += "\n";
×
726
                }
727
                text += xmlr.getText().trim().replace('\n',' ');
×
728
            } else if (event == XMLStreamConstants.START_ELEMENT) {
×
729
                if (xmlr.getLocalName().equals("ExtLink")) {
×
730
                    String mapKey  = ("image".equalsIgnoreCase( xmlr.getAttributeValue(null, "role") ) || "logo".equalsIgnoreCase(xmlr.getAttributeValue(null, "title")))? "logo" : "url";
×
731
                    returnMap.put( mapKey, xmlr.getAttributeValue(null, "URI") );
×
732
                    parseText(xmlr, "ExtLink"); // this line effectively just skips though until the end of the tag
×
733
                }
×
734
            } else if (event == XMLStreamConstants.END_ELEMENT) {
×
735
                if (xmlr.getLocalName().equals(endTag)) break;
×
736
            }
737
        }
×
738

739
        returnMap.put( "name", text );
×
740
        return returnMap;
×
741
    }
742
   
743
    private String parseText(XMLStreamReader xmlr, String endTag) throws XMLStreamException {
744
         return (String) parseTextNew(xmlr,endTag);
×
745
     }
746
     
747
     
748
     private Object parseTextNew(XMLStreamReader xmlr, String endTag) throws XMLStreamException {
749
        String returnString = "";
×
750
        Map<String, Object> returnMap = null;
×
751

752
        while (true) {
753
            if (!returnString.isEmpty()) {
×
754
                returnString += "\n";
×
755
            }
756
            int event = xmlr.next();
×
757
            if (event == XMLStreamConstants.CHARACTERS) {
×
758
                returnString += xmlr.getText().trim().replace('\n',' ');
×
759
           } else if (event == XMLStreamConstants.START_ELEMENT) {
×
760
                if (xmlr.getLocalName().equals("p")) {
×
761
                    returnString += "<p>" + parseText(xmlr, "p") + "</p>";
×
762
                } else if (xmlr.getLocalName().equals("emph")) {
×
763
                    returnString += "<em>" + parseText(xmlr, "emph") + "</em>";
×
764
                } else if (xmlr.getLocalName().equals("hi")) {
×
765
                    returnString += "<strong>" + parseText(xmlr, "hi") + "</strong>";
×
766
                } else if (xmlr.getLocalName().equals("ExtLink")) {
×
767
                    String uri = xmlr.getAttributeValue(null, "URI");
×
768
                    String text = parseText(xmlr, "ExtLink").trim();
×
769
                    returnString += "<a href=\"" + uri + "\">" + ( StringUtil.isEmpty(text) ? uri : text) + "</a>";
×
770
                } else if (xmlr.getLocalName().equals("list")) {
×
771
                    returnString += parseText_list(xmlr);
×
772
                } else if (xmlr.getLocalName().equals("citation")) {
×
773
                    if (SOURCE_DVN_3_0.equals(xmlr.getAttributeValue(null, "source")) ) {
×
774
                        returnMap = parseDVNCitation(xmlr);
×
775
                    } else {
776
                        returnString += parseText_citation(xmlr);
×
777
                    }
778
                } else {
779
                    throw new EJBException("ERROR occurred in mapDDI (parseText): tag not yet supported: <" + xmlr.getLocalName() + ">" );
×
780
                }
781
            } else if (event == XMLStreamConstants.END_ELEMENT) {
×
782
                if (xmlr.getLocalName().equals(endTag)) break;
×
783
            }
784
        }
×
785
        
786
        if (returnMap != null) {
×
787
            // this is one of our new citation areas for DVN3.0
788
            return returnMap;
×
789
        }
790
      
791
        // otherwise it's a standard section and just return the String like we always did
792
        return returnString.trim();
×
793
    }
794
     
795
    private String parseNoteByType(XMLStreamReader xmlr, String type) throws XMLStreamException {
796
        if (type.equalsIgnoreCase(xmlr.getAttributeValue(null, "type"))) {
×
797
            return parseText(xmlr);
×
798
        } else {
799
            return null;
×
800
        }
801
    }
802
  private String parseText_list (XMLStreamReader xmlr) throws XMLStreamException {
803
        String listString = null;
×
804
        String listCloseTag = null;
×
805

806
        // check type
807
        String listType = xmlr.getAttributeValue(null, "type");
×
808
        if ("bulleted".equals(listType) ){
×
809
            listString = "<ul>\n";
×
810
            listCloseTag = "</ul>";
×
811
        } else if ("ordered".equals(listType) ) {
×
812
            listString = "<ol>\n";
×
813
            listCloseTag = "</ol>";
×
814
        } else {
815
            // this includes the default list type of "simple"
816
            throw new EJBException("ERROR occurred in mapDDI (parseText): ListType of types other than {bulleted, ordered} not currently supported.");
×
817
        }
818

819
        while (true) {
820
            int event = xmlr.next();
×
821
            if (event == XMLStreamConstants.START_ELEMENT) {
×
822
                if (xmlr.getLocalName().equals("itm")) {
×
823
                    listString += "<li>" + parseText(xmlr,"itm") + "</li>\n";
×
824
                } else {
825
                    throw new EJBException("ERROR occurred in mapDDI (parseText): ListType does not currently supported contained LabelType.");
×
826
                }
827
            } else if (event == XMLStreamConstants.END_ELEMENT) {
×
828
                if (xmlr.getLocalName().equals("list")) break;
×
829
            }
830
        }
×
831

832
        return (listString + listCloseTag);
×
833
    }
834

835
    private String parseText_citation (XMLStreamReader xmlr) throws XMLStreamException {
836
        String citation = "<!--  parsed from DDI citation title and holdings -->";
×
837
        boolean addHoldings = false;
×
838
        String holdings = "";
×
839

840
        while (true) {
841
            int event = xmlr.next();
×
842
            if (event == XMLStreamConstants.START_ELEMENT) {
×
843
                if (xmlr.getLocalName().equals("titlStmt")) {
×
844
                    while (true) {
845
                        event = xmlr.next();
×
846
                        if (event == XMLStreamConstants.START_ELEMENT) {
×
847
                            if (xmlr.getLocalName().equals("titl")) {
×
848
                                citation += parseText(xmlr);
×
849
                            }
850
                        } else if (event == XMLStreamConstants.END_ELEMENT) {
×
851
                            if (xmlr.getLocalName().equals("titlStmt")) break;
×
852
                        }
853
                    }
854
                } else if (xmlr.getLocalName().equals("holdings")) {
×
855
                    String uri = xmlr.getAttributeValue(null, "URI");
×
856
                    String holdingsText = parseText(xmlr);
×
857

858
                    if ( !StringUtil.isEmpty(uri) || !StringUtil.isEmpty(holdingsText)) {
×
859
                        holdings += addHoldings ? ", " : "";
×
860
                        addHoldings = true;
×
861

862
                        if ( StringUtil.isEmpty(uri) ) {
×
863
                            holdings += holdingsText;
×
864
                        } else if ( StringUtil.isEmpty(holdingsText) ) {
×
865
                            holdings += "<a href=\"" + uri + "\">" + uri + "</a>";
×
866
                        } else {
867
                            // both uri and text have values
868
                            holdings += "<a href=\"" + uri + "\">" + holdingsText + "</a>";
×
869
                        }
870
                    }
871
                }
×
872
            } else if (event == XMLStreamConstants.END_ELEMENT) {
×
873
                if (xmlr.getLocalName().equals("citation")) break;
×
874
            }
875
        }
×
876

877
        if (addHoldings) {
×
878
            citation += " (" + holdings + ")";
×
879
        }
880

881
        return citation;
×
882
    }
883
  
884
    private String parseUNF(String unfString) {
885
        if (unfString.contains("UNF:")) {
×
886
            return unfString.substring( unfString.indexOf("UNF:") );
×
887
        } else {
888
            return null;
×
889
        }
890
    }
891
  
892
    private Map<String, Object> parseDVNCitation(XMLStreamReader xmlr) throws XMLStreamException {
893
        Map<String, Object> returnValues = new HashMap<>();
×
894
        
895
        while (true) {
896
            int event = xmlr.next();
×
897
            if (event == XMLStreamConstants.START_ELEMENT) {
×
898
               if (xmlr.getLocalName().equals("IDNo")) {
×
899
                    returnValues.put("idType", xmlr.getAttributeValue(null, "agency") );
×
900
                    returnValues.put("idNumber", parseText(xmlr) );                   
×
901
               }
902
                else if (xmlr.getLocalName().equals("biblCit")) {
×
903
                    returnValues.put("text", parseText(xmlr) );                   
×
904
                }
905
                else if (xmlr.getLocalName().equals("holdings")) {
×
906
                    returnValues.put("url", xmlr.getAttributeValue(null, "URI") );                 
×
907
                }
908
                else if (xmlr.getLocalName().equals("notes")) {
×
909
                    if (NOTE_TYPE_REPLICATION_FOR.equals(xmlr.getAttributeValue(null, "type")) ) {
×
910
                        returnValues.put("replicationData", true);
×
911
                    }
912
                }
913
            } else if (event == XMLStreamConstants.END_ELEMENT) {
×
914
                if (xmlr.getLocalName().equals("citation")) break;
×
915
            }
916
        } 
×
917
        
918
        return returnValues;
×
919
    }    
920
     
921

922
    private void addToSet(HashSet<FieldDTO> set, String typeName, String value ) {
923
        if (value!=null) {
×
924
            set.add(FieldDTO.createPrimitiveFieldDTO(typeName, value));
×
925
        }
926
    }
×
927
    
928
}
929

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

© 2025 Coveralls, Inc