package eu.europeana.cloud.service.dls.rest;
import eu.europeana.cloud.common.model.Representation;
import eu.europeana.cloud.common.response.ErrorInfo;
import eu.europeana.cloud.common.response.ResultSlice;
import static eu.europeana.cloud.common.web.ParamConstants.F_DATASET;
import static eu.europeana.cloud.common.web.ParamConstants.F_DATASET_PROVIDER_ID;
import static eu.europeana.cloud.common.web.ParamConstants.F_DATE_FROM;
import static eu.europeana.cloud.common.web.ParamConstants.F_DATE_UNTIL;
import static eu.europeana.cloud.common.web.ParamConstants.F_PERSISTENT;
import static eu.europeana.cloud.common.web.ParamConstants.F_PROVIDER;
import static eu.europeana.cloud.common.web.ParamConstants.F_REPRESENTATIONNAME;
import static eu.europeana.cloud.common.web.ParamConstants.F_START_FROM;
import eu.europeana.cloud.service.dls.RepresentationSearchParams;
import eu.europeana.cloud.service.dls.services.SearchRecordService;
import java.util.Date;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/**
* This resource allows to search representation versions by multiple parameters.
*/
@Path("representations")
@Component
@Scope("request")
public class RepresentationSearchResource {
@Autowired
private SearchRecordService recordService;
@Value("${numberOfElementsOnPage}")
private int numberOfElementsOnPage;
// ISO8601 standard
private static final DateTimeFormatter DATE_FORMAT = ISODateTimeFormat.dateOptionalTimeParser();
private static final String errorCode = "OTHER";
/**
* Searches for representation versions by multiple parameters. Result is returned in slices which contain fixed
* amount of results and reference (token) to next slice of results. To obtain next result slice, all search
* parameters in subsequent requests with consecutive result tokens must be the same as in first request. All search
* parameters are optional but at least one must be provided.
*
* @param providerId
* Identifier of representation version's provider.
* @param dataSetId
* Identifier of data set
* @param dataSetProviderId
* Identivier of data set's provider.
* @param schema
* schema of representation
* @param creationDateFrom
* earliest date of representation version's creation. Must be in ISO8601 format (date with optional
* time): yyyy-MM-dd'T'HH:mm:ss.SSSZZ or yyyy-MM-dd
* @param creationDateUntil
* latest date of representation version's creation. Must be in ISO8601 format (date with optional time):
* yyyy-MM-dd'T'HH:mm:ss.SSSZZ or yyyy-MM-dd
* @param persistent
* Indicator if representation version must be persistent.
* @param startFrom
* Threshold param to indicate result slice
* @return found representation versions (in slices).
* @statuscode 400 If no search parameter is provided.
*
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public ResultSlice<Representation> searchRepresentations( //
@QueryParam(F_PROVIDER) String providerId, //
@QueryParam(F_DATASET) String dataSetId, //
@QueryParam(F_DATASET_PROVIDER_ID) String dataSetProviderId, //
@QueryParam(F_REPRESENTATIONNAME) String schema, //
@QueryParam(F_DATE_FROM) String creationDateFrom, //
@QueryParam(F_DATE_UNTIL) String creationDateUntil, //
@QueryParam(F_PERSISTENT) Boolean persistent, //
@QueryParam(F_START_FROM) String startFrom) {
// at least one parameter must be provided
if (allNull(providerId, dataSetId, dataSetProviderId, schema, creationDateFrom, creationDateUntil, persistent)) {
ErrorInfo errorInfo = new ErrorInfo(errorCode, "At least one parameter must be provided");
throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).entity(errorInfo).build());
}
// parse creation date from
Date creationDateFromParsed = null;
if (creationDateFrom != null) {
creationDateFromParsed = parseDate(creationDateFrom, F_DATE_FROM);
}
// parse creation date until
Date creationDateUntilParsed = null;
if (creationDateUntil != null) {
creationDateUntilParsed = parseDate(creationDateUntil, F_DATE_UNTIL);
}
// create search params object
RepresentationSearchParams params = RepresentationSearchParams.builder().setDataProvider(providerId)//
.setDataSetId(dataSetId) //
.setDataSetProviderId(dataSetProviderId) //
.setFromDate(creationDateFromParsed) //
.setPersistent(persistent) //
.setSchema(schema) //
.setToDate(creationDateUntilParsed) //
.build();
// invoke record service method
return recordService.search(params, startFrom, numberOfElementsOnPage);
}
/**
* Parses a date-time from the given text, returning as a Date. Uses
* {@link ISODateTimeFormat#dateOptionalTimeParser} as a parser.
*
* @param date
* a string to parse
* @param dateParamName
* a name of the parameter which hold a date
* @return the parsed date-time
* @throws WebApplicationException
* if the given date cannot be parsed
*/
private Date parseDate(String date, String dateParamName) {
Date dateParsed = null;
if (date != null) {
try {
dateParsed = DATE_FORMAT.parseDateTime(date).toDate();
} catch (IllegalArgumentException ex) {
ErrorInfo errorInfo = new ErrorInfo(errorCode, dateParamName + " parameter has wrong format: "
+ ex.getMessage());
throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).entity(errorInfo)
.build());
}
}
return dateParsed;
}
/**
* Returns true if all provided objects are null.
*
* @param objects
* @return true if all provided parameters are null, false if at least one parameter is not null.
*/
private boolean allNull(Object... objects) {
for (Object o : objects) {
if (o != null) {
return false;
}
}
return true;
}
}