package edu.harvard.iq.dataverse.harvest.server.xoai;
import com.lyncode.xml.exceptions.XmlWriteException;
import com.lyncode.xoai.dataprovider.handlers.*;
import com.lyncode.xoai.dataprovider.exceptions.*;
import com.lyncode.xoai.dataprovider.handlers.results.ListItemsResults;
import com.lyncode.xoai.dataprovider.handlers.helpers.ItemHelper;
import com.lyncode.xoai.dataprovider.handlers.helpers.ItemRepositoryHelper;
import com.lyncode.xoai.dataprovider.handlers.helpers.ResumptionTokenHelper;
import com.lyncode.xoai.dataprovider.handlers.helpers.SetRepositoryHelper;
import com.lyncode.xoai.dataprovider.model.Context;
import com.lyncode.xoai.dataprovider.model.Item;
import com.lyncode.xoai.dataprovider.model.MetadataFormat;
import com.lyncode.xoai.dataprovider.model.Set;
import com.lyncode.xoai.model.oaipmh.*;
import com.lyncode.xoai.dataprovider.parameters.OAICompiledRequest;
import com.lyncode.xoai.dataprovider.repository.Repository;
import com.lyncode.xoai.xml.XSLPipeline;
import com.lyncode.xoai.xml.XmlWriter;
import edu.harvard.iq.dataverse.Dataset;
import javax.xml.stream.XMLStreamException;
import javax.xml.transform.TransformerException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
/**
*
* @author Leonid Andreev
*
* This is Dataverse's own implementation of ListRecords Verb Handler
* (used instead of the ListRecordsHandler provided by XOAI).
* It is customized to support the optimizations that allows
* Dataverse to directly output pre-exported metadata records to the output
* stream, bypassing expensive XML parsing and writing.
*/
public class XlistRecordsHandler extends VerbHandler<ListRecords> {
private static java.util.logging.Logger logger = java.util.logging.Logger.getLogger("XlistRecordsHandler");
private final ItemRepositoryHelper itemRepositoryHelper;
private final SetRepositoryHelper setRepositoryHelper;
public XlistRecordsHandler(Context context, Repository repository) {
super(context, repository);
this.itemRepositoryHelper = new ItemRepositoryHelper(getRepository().getItemRepository());
this.setRepositoryHelper = new SetRepositoryHelper(getRepository().getSetRepository());
}
@Override
public ListRecords handle(OAICompiledRequest parameters) throws OAIException, HandlerException {
XlistRecords res = new XlistRecords();
int length = getRepository().getConfiguration().getMaxListRecords();
if (parameters.hasSet() && !getRepository().getSetRepository().supportSets())
throw new DoesNotSupportSetsException();
int offset = getOffset(parameters);
ListItemsResults result;
if (!parameters.hasSet()) {
if (parameters.hasFrom() && !parameters.hasUntil())
result = itemRepositoryHelper.getItems(getContext(), offset,
length, parameters.getMetadataPrefix(),
parameters.getFrom());
else if (!parameters.hasFrom() && parameters.hasUntil())
result = itemRepositoryHelper.getItemsUntil(getContext(), offset,
length, parameters.getMetadataPrefix(),
parameters.getUntil());
else if (parameters.hasFrom() && parameters.hasUntil())
result = itemRepositoryHelper.getItems(getContext(), offset,
length, parameters.getMetadataPrefix(),
parameters.getFrom(), parameters.getUntil());
else
result = itemRepositoryHelper.getItems(getContext(), offset,
length, parameters.getMetadataPrefix());
} else {
if (!setRepositoryHelper.exists(getContext(), parameters.getSet())) {
// throw new NoMatchesException();
}
if (parameters.hasFrom() && !parameters.hasUntil())
result = itemRepositoryHelper.getItems(getContext(), offset,
length, parameters.getMetadataPrefix(),
parameters.getSet(), parameters.getFrom());
else if (!parameters.hasFrom() && parameters.hasUntil())
result = itemRepositoryHelper.getItemsUntil(getContext(), offset,
length, parameters.getMetadataPrefix(),
parameters.getSet(), parameters.getUntil());
else if (parameters.hasFrom() && parameters.hasUntil())
result = itemRepositoryHelper.getItems(getContext(), offset,
length, parameters.getMetadataPrefix(),
parameters.getSet(), parameters.getFrom(),
parameters.getUntil());
else
result = itemRepositoryHelper.getItems(getContext(), offset,
length, parameters.getMetadataPrefix(),
parameters.getSet());
}
List<Item> results = result.getResults();
if (results.isEmpty()) throw new NoMatchesException();
for (Item i : results)
res.withRecord(this.createRecord(parameters, i));
ResumptionToken.Value currentResumptionToken = new ResumptionToken.Value();
if (parameters.hasResumptionToken()) {
currentResumptionToken = parameters.getResumptionToken();
} else if (result.hasMore()) {
currentResumptionToken = parameters.extractResumptionToken();
}
XresumptionTokenHelper resumptionTokenHelper = new XresumptionTokenHelper(currentResumptionToken,
getRepository().getConfiguration().getMaxListRecords());
res.withResumptionToken(resumptionTokenHelper.resolve(result.hasMore()));
return res;
}
private int getOffset(OAICompiledRequest parameters) {
if (!parameters.hasResumptionToken())
return 0;
if (parameters.getResumptionToken().getOffset() == null)
return 0;
return parameters.getResumptionToken().getOffset().intValue();
}
private Record createRecord(OAICompiledRequest parameters, Item item)
throws BadArgumentException, CannotDisseminateRecordException,
OAIException, NoMetadataFormatsException, CannotDisseminateFormatException {
MetadataFormat format = getContext().formatForPrefix(parameters.getMetadataPrefix());
Header header = new Header();
Dataset dataset = ((Xitem)item).getDataset();
Xrecord xrecord = new Xrecord().withFormatName(parameters.getMetadataPrefix()).withDataset(dataset);
header.withIdentifier(item.getIdentifier());
ItemHelper itemHelperWrap = new ItemHelper(item);
header.withDatestamp(item.getDatestamp());
for (Set set : itemHelperWrap.getSets(getContext(), getRepository().getFilterResolver()))
header.withSetSpec(set.getSpec());
if (item.isDeleted())
header.withStatus(Header.Status.DELETED);
xrecord.withHeader(header);
xrecord.withMetadata(item.getMetadata());
return xrecord;
}
private XSLPipeline toPipeline(Item item) throws XmlWriteException, XMLStreamException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
XmlWriter writer = new XmlWriter(output);
Metadata metadata = item.getMetadata();
metadata.write(writer);
writer.close();
return new XSLPipeline(new ByteArrayInputStream(output.toByteArray()), true);
}
}