/**
* @todo Shouldn't this be in the "edu.harvard.iq.dataverse.api" package? Is the only one that isn't.
*/
package edu.harvard.iq.dataverse.mydata;
import edu.harvard.iq.dataverse.DataverseRoleServiceBean;
import edu.harvard.iq.dataverse.DataverseSession;
import edu.harvard.iq.dataverse.DvObjectServiceBean;
import edu.harvard.iq.dataverse.RoleAssigneeServiceBean;
import edu.harvard.iq.dataverse.search.SearchServiceBean;
import edu.harvard.iq.dataverse.search.SolrQueryResponse;
import edu.harvard.iq.dataverse.search.SolrSearchResult;
import edu.harvard.iq.dataverse.api.AbstractApiBean;
import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean;
import edu.harvard.iq.dataverse.authorization.DataverseRole;
import edu.harvard.iq.dataverse.authorization.DataverseRolePermissionHelper;
//import edu.harvard.iq.dataverse.authorization.MyDataQueryHelperServiceBean;
import edu.harvard.iq.dataverse.authorization.groups.GroupServiceBean;
import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
import edu.harvard.iq.dataverse.engine.command.DataverseRequest;
import edu.harvard.iq.dataverse.search.SearchConstants;
import edu.harvard.iq.dataverse.search.SearchException;
import edu.harvard.iq.dataverse.search.SearchFields;
import edu.harvard.iq.dataverse.search.SortBy;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.inject.Inject;
import javax.json.Json;
import javax.json.JsonArrayBuilder;
import javax.json.JsonObjectBuilder;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import org.apache.commons.lang.StringUtils;
/**
*
* @author rmp553
*
* The primary method here is this API endpoint: retrieveMyDataAsJsonString
*
* - This method validates the current logged in user
*
*/
@Path("mydata")
public class DataRetrieverAPI extends AbstractApiBean {
private static final Logger logger = Logger.getLogger(DataRetrieverAPI.class.getCanonicalName());
public static final String retrieveDataFullAPIPath = "/api/mydata/retrieve";
private static final String retrieveDataPartialAPIPath = "retrieve";
@Inject
DataverseSession session;
@EJB
DataverseRoleServiceBean dataverseRoleService;
@EJB
RoleAssigneeServiceBean roleAssigneeService;
@EJB
DvObjectServiceBean dvObjectServiceBean;
@EJB
SearchServiceBean searchService;
@EJB
AuthenticationServiceBean authenticationService;
//@EJB
//MyDataQueryHelperServiceBean myDataQueryHelperServiceBean;
@EJB
GroupServiceBean groupService;
private List<DataverseRole> roleList;
private DataverseRolePermissionHelper rolePermissionHelper;
private List<String> defaultDvObjectTypes = MyDataFilterParams.defaultDvObjectTypes;
private MyDataFinder myDataFinder;
private SolrQueryResponse solrQueryResponse;
private AuthenticatedUser authUser = null;
public static final String JSON_SUCCESS_FIELD_NAME = "success";
public static final String JSON_ERROR_MSG_FIELD_NAME = "error_message";
public static final String JSON_DATA_FIELD_NAME = "data";
public static final String MSG_NO_RESULTS_FOUND = "Sorry, no results were found.";
/**
* Constructor
*
*/
public DataRetrieverAPI(){
}
private int randInt(int min, int max) {
Random rand = new Random();
return rand.nextInt((max - min) + 1) + min;
}
public String getRetrieveDataFullAPIPath(){
return DataRetrieverAPI.retrieveDataFullAPIPath;
}
public Pager getRandomPagerPager(Integer selectedPage){
if (selectedPage == null){
selectedPage = 1;
}
int itemsPerPage = 10;
int numResults = 108;//randInt(1,200);
int numPages = numResults / itemsPerPage;
if ((numResults % itemsPerPage) > 0){
numPages++;
}
int chosenPage = 1;
if ((selectedPage > numPages)||(selectedPage < 1)){
chosenPage = 1;
}else{
chosenPage = selectedPage;
}
//int chosenPage = max(randInt(0, numPages), 1);
return new Pager(numResults, itemsPerPage, chosenPage);
}
/*
@Path("test-it2")
@GET
@Produces({"application/json"})
public String retrieveTestPager(@QueryParam("selectedPage") int selectedPage){
return this.getRandomPagerPager(selectedPage).asJSONString();
}
*/
//private String getUserIdentifier()
public boolean isSuperuser(){
// Is this an authenticated user?
//
if ((session.getUser() == null)||(!session.getUser().isAuthenticated())){
return false;
}
// Is this a user?
//
authUser = (AuthenticatedUser)session.getUser();
if (authUser==null){
return false;
}
// Is this a superuser?
//
return authUser.isSuperuser();
}
private AuthenticatedUser getUserFromIdentifier(String userIdentifier){
if ((userIdentifier==null)||(userIdentifier.isEmpty())){
return null;
}
return authenticationService.getAuthenticatedUser(userIdentifier);
}
public Map<String, Long> getTotalCountsFromSolrAsJavaMap(DataverseRequest dataverseRequest, MyDataFinder myDataFinder ){
//msgt("getTotalCountsFromSolrAsJavaMap: " + searchUser.getIdentifier());
SolrQueryResponse solrQueryResponseForCounts = getTotalCountsFromSolr(dataverseRequest, myDataFinder);
if (solrQueryResponseForCounts == null){
logger.severe("DataRetrieverAPI.getTotalCountsFromSolrAsJSON: solrQueryResponseForCounts should not be null");
return null;
}
return solrQueryResponseForCounts.getDvObjectCounts();
}
public JsonObjectBuilder getTotalCountsFromSolrAsJSON(DataverseRequest dataverseRequest, MyDataFinder myDataFinder ){
SolrQueryResponse solrQueryResponseForCounts = getTotalCountsFromSolr(dataverseRequest, myDataFinder);
if (solrQueryResponseForCounts == null){
logger.severe("DataRetrieverAPI.getTotalCountsFromSolrAsJSON: solrQueryResponseForCounts should not be null");
return null;
}
return solrQueryResponseForCounts.getDvObjectCountsAsJSON();
}
private SolrQueryResponse getTotalCountsFromSolr(DataverseRequest dataverseRequest, MyDataFinder myDataFinder){
//msgt("getTotalCountsFromSolr: " + searchUser.getIdentifier());
if (myDataFinder == null){
throw new NullPointerException("myDataFinder cannot be null");
}
if (dataverseRequest == null){
throw new NullPointerException("dataverseRequest cannot be null");
}
// -------------------------------------------------------
// Create new filter params that only check by the User
// -------------------------------------------------------
MyDataFilterParams filterParams = new MyDataFilterParams(dataverseRequest, myDataFinder.getRolePermissionHelper());
if (filterParams.hasError()){
logger.severe("getTotalCountsFromSolr. filterParams error: " + filterParams.getErrorMessage());
return null;
}
// -------------------------------------------------------
// Re-run all of the entity queries (sigh)
// -------------------------------------------------------
myDataFinder.initFields();
myDataFinder.runFindDataSteps(filterParams);
if (myDataFinder.hasError()){
logger.severe("getTotalCountsFromSolr. myDataFinder error: " + myDataFinder.getErrorMessage());
return null;
}
// -------------------------------------------------------
// Generate filterQueries for total counts
// -------------------------------------------------------
List<String> filterQueries = myDataFinder.getSolrFilterQueriesForTotalCounts();
if (filterQueries==null){
logger.severe("getTotalCountsFromSolr. filterQueries was null!");
return null;
}
//msgt("getTotalCountsFromSolr");
//msgt(StringUtils.join(filterQueries, " AND "));
// -------------------------------------------------------
// Run Solr
// -------------------------------------------------------
SolrQueryResponse solrQueryResponseForCounts;
try {
solrQueryResponseForCounts = searchService.search(
dataverseRequest,
null, // subtree, default it to Dataverse for now
"*", // Get everything--always
filterQueries,//filterQueries,
SearchFields.NAME_SORT, SortBy.ASCENDING,
//SearchFields.RELEASE_OR_CREATE_DATE, SortBy.DESCENDING,
0, //paginationStart,
true, // dataRelatedToMe
SearchConstants.NUM_SOLR_DOCS_TO_RETRIEVE //10 // SearchFields.NUM_SOLR_DOCS_TO_RETRIEVE
);
} catch (SearchException ex) {
logger.severe("Search for total counts failed with filter query");
logger.severe("filterQueries: " + StringUtils.join(filterQueries, "(separator)"));
return null;
}
return solrQueryResponseForCounts;
}
private String getJSONErrorString(String jsonMsg, String optionalLoggerMsg){
if (jsonMsg == null){
throw new NullPointerException("jsonMsg cannot be null");
}
if (optionalLoggerMsg != null){
logger.severe(optionalLoggerMsg);
}
JsonObjectBuilder jsonData = Json.createObjectBuilder();
jsonData.add(DataRetrieverAPI.JSON_SUCCESS_FIELD_NAME, false);
jsonData.add(DataRetrieverAPI.JSON_ERROR_MSG_FIELD_NAME, jsonMsg);
return jsonData.build().toString();
}
/**
* @todo This should support the "X-Dataverse-key" header like the other
* APIs.
*/
@Path(retrieveDataPartialAPIPath)
@GET
@Produces({"application/json"})
public String retrieveMyDataAsJsonString(@QueryParam("dvobject_types") List<String> dvobject_types,
@QueryParam("published_states") List<String> published_states,
@QueryParam("selected_page") Integer selectedPage,
@QueryParam("mydata_search_term") String searchTerm,
@QueryParam("role_ids") List<Long> roleIds,
@QueryParam("userIdentifier") String userIdentifier,
@QueryParam("key") String apiToken) { //String myDataParams) {
//System.out.println("_YE_OLDE_QUERY_COUNTER_");
//msgt("_YE_OLDE_QUERY_COUNTER_"); // for debug purposes
boolean DEBUG_MODE = false;
boolean OTHER_USER = false;
// For, superusers, the searchUser may differ from the authUser
//
AuthenticatedUser searchUser = null;
if (DEBUG_MODE==true){ // DEBUG: use userIdentifier
authUser = getUserFromIdentifier(userIdentifier);
if (authUser == null){
return this.getJSONErrorString("Requires authentication", "retrieveMyDataAsJsonString. User not found! Shouldn't be using this anyway");
}
} else if ((session.getUser() != null)&&(session.getUser().isAuthenticated())){
authUser = (AuthenticatedUser)session.getUser();
// If person is a superuser, see if a userIdentifier has been specified
// and use that instead
if ((authUser.isSuperuser())&&(userIdentifier != null)&&(!userIdentifier.isEmpty())){
searchUser = getUserFromIdentifier(userIdentifier);
if (searchUser != null){
authUser = searchUser;
OTHER_USER = true;
}else{
return this.getJSONErrorString("No user found for: \"" + userIdentifier + "\"", null);
}
}
} else if (apiToken != null) { // Is this being accessed by an API Token?
authUser = findUserByApiToken(apiToken);
if (authUser == null){
return this.getJSONErrorString("Requires authentication. Please login.", "retrieveMyDataAsJsonString. User not found! Shouldn't be using this anyway");
}else{
// If person is a superuser, see if a userIdentifier has been specified
// and use that instead
if ((authUser.isSuperuser())&&(userIdentifier != null)&&(!userIdentifier.isEmpty())){
searchUser = getUserFromIdentifier(userIdentifier);
if (searchUser != null){
authUser = searchUser;
OTHER_USER = true;
}else{
return this.getJSONErrorString("No user found for: \"" + userIdentifier + "\"", null);
}
}
}
} else{
return this.getJSONErrorString("Requires authentication. Please login.", "retrieveMyDataAsJsonString. User not found! Shouldn't be using this anyway");
}
roleList = dataverseRoleService.findAll();
rolePermissionHelper = new DataverseRolePermissionHelper(roleList);
List<String> dtypes;
if (dvobject_types != null){
dtypes = dvobject_types;
}else{
dtypes = MyDataFilterParams.defaultDvObjectTypes;
}
List<String> pub_states = null;
if (published_states != null){
pub_states = published_states;
}
// ---------------------------------
// (1) Initialize filterParams and check for Errors
// ---------------------------------
DataverseRequest dataverseRequest = createDataverseRequest(authUser);
MyDataFilterParams filterParams = new MyDataFilterParams(dataverseRequest, dtypes, pub_states, roleIds, searchTerm);
if (filterParams.hasError()){
return this.getJSONErrorString(filterParams.getErrorMessage(), filterParams.getErrorMessage());
}
// ---------------------------------
// (2) Initialize MyDataFinder and check for Errors
// ---------------------------------
myDataFinder = new MyDataFinder(rolePermissionHelper,
roleAssigneeService,
dvObjectServiceBean,
groupService);
this.myDataFinder.runFindDataSteps(filterParams);
if (myDataFinder.hasError()){
return this.getJSONErrorString(myDataFinder.getErrorMessage(), myDataFinder.getErrorMessage());
}
// ---------------------------------
// (3) Make Solr Query
// ---------------------------------
int paginationStart = 1;
if (selectedPage != null){
paginationStart = selectedPage;
}
int solrCardStart = (paginationStart - 1) * SearchConstants.NUM_SOLR_DOCS_TO_RETRIEVE;
// Default the searchUser to the authUser.
// The exception: for logged-in superusers, the searchUser may differ from the authUser
//
if (searchUser == null){
searchUser = authUser;
}
//msg("search with user: " + searchUser.getIdentifier());
List<String> filterQueries = this.myDataFinder.getSolrFilterQueries();
if (filterQueries==null){
logger.fine("No ids found for this search");
return this.getJSONErrorString(DataRetrieverAPI.MSG_NO_RESULTS_FOUND, null);
}
//msgt("myDataFinder.getSolrFilterQueries(): " + myDataFinder.getSolrFilterQueries().toString());
//msg("Selected paginationStart: " + paginationStart);
try {
solrQueryResponse = searchService.search(
dataverseRequest,
null, // subtree, default it to Dataverse for now
filterParams.getSearchTerm(), //"*", //
filterQueries,//filterQueries,
//SearchFields.NAME_SORT, SortBy.ASCENDING,
SearchFields.RELEASE_OR_CREATE_DATE, SortBy.DESCENDING,
solrCardStart, //paginationStart,
true, // dataRelatedToMe
SearchConstants.NUM_SOLR_DOCS_TO_RETRIEVE //10 // SearchFields.NUM_SOLR_DOCS_TO_RETRIEVE
);
//msgt("getResultsStart: " + this.solrQueryResponse.getResultsStart());
//msgt("getNumResultsFound: " + this.solrQueryResponse.getNumResultsFound());
//msgt("getSolrSearchResults: " + this.solrQueryResponse.getSolrSearchResults().toString());
if (this.solrQueryResponse.getNumResultsFound()==0){
return this.getJSONErrorString(DataRetrieverAPI.MSG_NO_RESULTS_FOUND, null);
}
} catch (SearchException ex) {
solrQueryResponse = null;
this.logger.severe("Solr SearchException: " + ex.getMessage());
}
if (solrQueryResponse==null){
return this.getJSONErrorString("Sorry! There was an error with the search service.", "Sorry! There was a SOLR Error");
}
// ---------------------------------
// (4) Build JSON document including:
// - Pager
// - Formatted solr docs
// - Num results found
// - Search term
// - DvObject counts
// ---------------------------------
// Initialize JSON response
JsonObjectBuilder jsonData = Json.createObjectBuilder();
Pager pager = new Pager(solrQueryResponse.getNumResultsFound().intValue(),
SearchConstants.NUM_SOLR_DOCS_TO_RETRIEVE,
paginationStart);
RoleTagRetriever roleTagRetriever = new RoleTagRetriever(this.rolePermissionHelper, this.roleAssigneeSvc, this.dvObjectServiceBean);
roleTagRetriever.loadRoles(dataverseRequest, solrQueryResponse);
jsonData.add(DataRetrieverAPI.JSON_SUCCESS_FIELD_NAME, true)
.add(DataRetrieverAPI.JSON_DATA_FIELD_NAME,
Json.createObjectBuilder()
.add("pagination", pager.asJsonObjectBuilder())
//.add(SearchConstants.SEARCH_API_ITEMS, this.formatSolrDocs(solrQueryResponse, filterParams, this.myDataFinder))
.add(SearchConstants.SEARCH_API_ITEMS, this.formatSolrDocs(solrQueryResponse, roleTagRetriever))
.add(SearchConstants.SEARCH_API_TOTAL_COUNT, solrQueryResponse.getNumResultsFound())
.add(SearchConstants.SEARCH_API_START, solrQueryResponse.getResultsStart())
.add("search_term", filterParams.getSearchTerm())
.add("dvobject_counts", this.getDvObjectTypeCounts(solrQueryResponse))
.add("pubstatus_counts", this.getPublicationStatusCounts(solrQueryResponse))
.add("selected_filters", this.myDataFinder.getSelectedFilterParamsAsJSON())
);
// ---------------------------------------------------------
// We're doing ~another~ solr query here
// NOTE! Do not reuse this.myDataFinder after this step!! It is being passed new filterParams
// ---------------------------------------------------------
//jsonData.add("total_dvobject_counts", getTotalCountsFromSolrAsJSON(searchUser, this.myDataFinder));
if (OTHER_USER==true){
jsonData.add("other_user", searchUser.getIdentifier());
}
return jsonData.build().toString();
}
private JsonObjectBuilder getDvObjectTypeCounts(SolrQueryResponse solrResponse) {
if (solrQueryResponse == null) {
logger.severe("DataRetrieverAPI.getDvObjectTypeCounts: solrQueryResponse should not be null");
return null;
}
return solrResponse.getDvObjectCountsAsJSON();
}
private JsonObjectBuilder getPublicationStatusCounts(SolrQueryResponse solrResponse) {
if (solrQueryResponse == null) {
logger.severe("DataRetrieverAPI.getDvObjectTypeCounts: solrQueryResponse should not be null");
return null;
}
return solrResponse.getPublicationStatusCountsAsJSON();
}
/**
* Using RoleTagRetriever to find role names for each card
* Trying to minimize extra queries
*
* @param solrResponse
* @param roleTagRetriever
* @return
*/
private JsonArrayBuilder formatSolrDocs(SolrQueryResponse solrResponse, RoleTagRetriever roleTagRetriever ){
if (solrResponse == null){
throw new NullPointerException("DataRetrieverAPI.formatSolrDocs: solrResponse should not be null");
}
if(roleTagRetriever==null){
throw new NullPointerException("DataRetrieverAPI.formatSolrDocs: roleTagRetriever should not be null");
}
JsonArrayBuilder jsonSolrDocsArrayBuilder = Json.createArrayBuilder();
JsonObjectBuilder myDataCardInfo;
JsonArrayBuilder rolesForCard;
for (SolrSearchResult doc : solrQueryResponse.getSolrSearchResults()){
// -------------------------------------------
// (a) Get core card data from solr
// -------------------------------------------
myDataCardInfo = doc.getJsonForMyData();
// -------------------------------------------
// (b) Add role info
// -------------------------------------------
rolesForCard = roleTagRetriever.getRolesForCardAsJSON(doc.getEntityId());
if (rolesForCard!=null){
myDataCardInfo.add("user_roles", rolesForCard);
}
// -------------------------------------------
// (c) Add final MyData JSON to array
// -------------------------------------------
jsonSolrDocsArrayBuilder.add(myDataCardInfo);
}
return jsonSolrDocsArrayBuilder;
}
/*private JsonArrayBuilder formatSolrDocs(SolrQueryResponse solrResponse, MyDataFilterParams filterParams, MyDataFinder finder ){
if (solrResponse == null){
logger.severe("DataRetrieverAPI.getDvObjectTypeCounts: formatSolrDocs should not be null");
return null;
}
JsonArrayBuilder jsonSolrDocsArrayBuilder = Json.createArrayBuilder();
for (SolrSearchResult doc : solrQueryResponse.getSolrSearchResults()){
if( authUser!= null){
doc.setUserRole(myDataQueryHelperServiceBean.getRolesOnDVO(authUser, doc.getEntityId(), filterParams.getRoleIds(), finder));
}
jsonSolrDocsArrayBuilder.add(doc.getJsonForMyData());
}
return jsonSolrDocsArrayBuilder;
}
*/
/*
@Path("test-it")
@Produces({"application/json"})
@GET
public String retrieveMyData(@QueryParam("key") String keyValue){ //String myDataParams) {
final JsonObjectBuilder jsonData = Json.createObjectBuilder();
jsonData.add("name", keyValue);
return jsonData.build().toString();
}
*/
private void msg(String s){
//System.out.println(s);
}
private void msgt(String s){
msg("-------------------------------");
msg(s);
msg("-------------------------------");
}
}