/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.rest;
import org.apache.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.ItemService;
import org.dspace.content.service.MetadataFieldService;
import org.dspace.content.service.MetadataSchemaService;
import org.dspace.content.service.SiteService;
import org.dspace.rest.exceptions.ContextException;
import org.dspace.rest.common.ItemFilter;
import org.dspace.rest.common.ItemFilterQuery;
import org.dspace.rest.filter.ItemFilterSet;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.usage.UsageEvent;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.HttpHeaders;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
/*
* This class retrieves items by a constructed metadata query evaluated against a set of Item Filters.
*
* @author Terry Brady, Georgetown University
*/
@Path("/filtered-items")
public class FilteredItemsResource extends Resource {
protected ItemService itemService = ContentServiceFactory.getInstance().getItemService();
protected MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService();
protected MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance().getMetadataSchemaService();
protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
protected SiteService siteService = ContentServiceFactory.getInstance().getSiteService();
protected ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
private static Logger log = Logger.getLogger(FilteredItemsResource.class);
/**
* Return instance of collection with passed id. You can add more properties
* through expand parameter.
*
* @param expand
* String in which is what you want to add to returned instance
* of collection. Options are: "all", "parentCommunityList",
* "parentCommunity", "items", "license" and "logo". If you want
* to use multiple options, it must be separated by commas.
* @param limit
* Limit value for items in list in collection. Default value is
* 100.
* @param offset
* Offset of start index in list of items of collection. Default
* value is 0.
* @param user_ip
* User's IP address.
* @param user_agent
* User agent string (specifies browser used and its version).
* @param xforwardedfor
* When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param filters
* Comma separated list of Item Filters to use to evaluate against
* the items in a collection
* @param query_field
* List of metadata fields to evaluate in a metadata query.
* Each list value is used in conjunction with a query_op and query_field.
* @param query_op
* List of metadata operators to use in a metadata query.
* Each list value is used in conjunction with a query_field and query_field.
* @param query_val
* List of metadata values to evaluate in a metadata query.
* Each list value is used in conjunction with a query_value and query_op.
* @param collSel
* List of collections to query.
* @param headers
* If you want to access the collection as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request
* Servlet's HTTP request object.
* @param servletContext
* Context of the servlet container.
* @return Return instance of collection. It can also return status code
* NOT_FOUND(404) if id of collection is incorrect or status code
* UNATHORIZED(401) if user has no permission to read collection.
* @throws WebApplicationException
* It is thrown when was problem with database reading
* (SQLException) or problem with creating
* context(ContextException). It is thrown by NOT_FOUND and
* UNATHORIZED status codes, too.
*/
@GET
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public org.dspace.rest.common.ItemFilter getItemQuery(@QueryParam("expand") String expand,
@QueryParam("limit") @DefaultValue("100") Integer limit, @QueryParam("offset") @DefaultValue("0") Integer offset,
@QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor,
@QueryParam("filters") @DefaultValue("is_item,all_filters") String filters,
@QueryParam("query_field[]") @DefaultValue("dc.title") List<String> query_field,
@QueryParam("query_op[]") @DefaultValue("exists") List<String> query_op,
@QueryParam("query_val[]") @DefaultValue("") List<String> query_val,
@QueryParam("collSel[]") @DefaultValue("") List<String> collSel,
@Context HttpHeaders headers, @Context HttpServletRequest request, @Context ServletContext servletContext) {
org.dspace.core.Context context = null;
ItemFilterSet itemFilterSet = new ItemFilterSet(filters, true);
ItemFilter result = itemFilterSet.getAllFiltersFilter();
try {
context = createContext();
if (!configurationService.getBooleanProperty("rest.reporting-authenticate", true)) {
context.turnOffAuthorisationSystem();
}
int index = Math.min(query_field.size(), Math.min(query_op.size(), query_val.size()));
List<ItemFilterQuery> itemFilterQueries = new ArrayList<ItemFilterQuery>();
for(int i=0; i<index; i++){
itemFilterQueries.add(new ItemFilterQuery(query_field.get(i), query_op.get(i), query_val.get(i)));
}
String regexClause = configurationService.getProperty("rest.regex-clause");
if (regexClause == null) {
regexClause = "";
}
List<UUID> uuids = getUuidsFromStrings(collSel);
List<List<MetadataField>> listFieldList = getMetadataFieldsList(context, query_field);
Iterator<org.dspace.content.Item> childItems = itemService.findByMetadataQuery(context, listFieldList, query_op, query_val, uuids, regexClause, offset, limit);
int count = itemFilterSet.processSaveItems(context, servletContext, childItems, true, expand);
writeStats(siteService.findSite(context), UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, headers, request, context);
result.annotateQuery(query_field, query_op, query_val);
result.setUnfilteredItemCount(count);
context.complete();
} catch (IOException e) {
processException(e.getMessage(), context);
} catch (SQLException e) {
processException(e.getMessage(), context);
} catch (AuthorizeException e) {
processException(e.getMessage(), context);
} catch (ContextException e) {
processException("Unauthorized filtered item query. " + e.getMessage(), context);
} finally {
processFinally(context);
}
return result;
}
private List<List<MetadataField>> getMetadataFieldsList(org.dspace.core.Context context, List<String> query_field) throws SQLException {
List<List<MetadataField>> listFieldList = new ArrayList<List<MetadataField>>();
for(String s: query_field) {
ArrayList<MetadataField> fields = new ArrayList<MetadataField>();
listFieldList.add(fields);
if (s.equals("*")) {
continue;
}
String schema = "";
String element = "";
String qualifier = null;
String[] parts = s.split("\\.");
if (parts.length>0) {
schema = parts[0];
}
if (parts.length>1) {
element = parts[1];
}
if (parts.length>2) {
qualifier = parts[2];
}
if (Item.ANY.equals(qualifier)) {
for(MetadataField mf: metadataFieldService.findFieldsByElementNameUnqualified(context, schema, element)){
fields.add(mf);
}
} else {
MetadataField mf = metadataFieldService.findByElement(context, schema, element, qualifier);
if (mf != null) {
fields.add(mf);
}
}
}
return listFieldList;
}
private List<UUID> getUuidsFromStrings(List<String> collSel) {
List<UUID> uuids = new ArrayList<UUID>();
for(String s: collSel) {
try {
uuids.add(UUID.fromString(s));
} catch (IllegalArgumentException e) {
log.warn("Invalid collection UUID: " + s);
}
}
return uuids;
}
}