/**
* 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
*
* https://github.com/CILEA/dspace-cris/wiki/License
*/
package org.dspace.app.cris.integration;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.solr.client.solrj.util.ClientUtils;
import org.dspace.app.cris.model.CrisConstants;
import org.dspace.app.cris.model.ResearcherPage;
import org.dspace.app.cris.model.RestrictedField;
import org.dspace.app.cris.model.VisibilityConstants;
import org.dspace.app.cris.service.ApplicationService;
import org.dspace.app.cris.service.RelationPreferenceService;
import org.dspace.app.cris.util.ResearcherPageUtils;
import org.dspace.content.DCPersonName;
import org.dspace.content.DSpaceObject;
import org.dspace.content.authority.AuthorityVariantsSupport;
import org.dspace.content.authority.Choice;
import org.dspace.content.authority.ChoiceAuthority;
import org.dspace.content.authority.Choices;
import org.dspace.content.authority.NotificableAuthority;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.dspace.discovery.DiscoverQuery;
import org.dspace.discovery.DiscoverResult;
import org.dspace.discovery.SearchService;
import org.dspace.services.ConfigurationService;
import org.dspace.utils.DSpace;
/**
* This class is the main point of integration beetween the Researcher Pages and
* DSpace. It implements the contract of the Authority Control Framework
* providing full support for the variants facility. It implements also the
* callback interface to "record" rejection of potential matches.
*
* @author cilea
*/
public class RPAuthority extends CRISAuthority implements
AuthorityVariantsSupport, NotificableAuthority
{
/** The logger */
private static Logger log = Logger.getLogger(RPAuthority.class);
/** The name as this ChoiceAuthority MUST be configurated */
public final static String RP_AUTHORITY_NAME = "RPAuthority";
/** The RPs database service layer */
private ApplicationService applicationService;
/** The RPs search service layer */
private SearchService searchService;
private ConfigurationService configurationService;
private RelationPreferenceService relationPreferenceService;
/**
* Make sure that the class is fully initialized before use it
*/
private void init()
{
if (applicationService == null && searchService == null)
{
DSpace dspace = new DSpace();
applicationService = dspace.getServiceManager().getServiceByName(
"applicationService", ApplicationService.class);
searchService = dspace.getServiceManager().getServiceByName(
"org.dspace.discovery.SearchService", SearchService.class);
configurationService = dspace.getServiceManager().getServiceByName(
"org.dspace.services.ConfigurationService",
ConfigurationService.class);
relationPreferenceService = dspace
.getServiceManager()
.getServiceByName(
"org.dspace.app.cris.service.RelationPreferenceService",
RelationPreferenceService.class);
}
}
/**
* Empty constructor needed by the DSpace plugin facility.
*/
public RPAuthority()
{
// nothing to do, initialization is provided by the IoC Spring Frameword
}
/**
* Return a list of choices performing a lucene query on the RPs names index
* appending the wildchar to every word in the query (i.e. if the query
* string is Chan Tse the search will be perfomed with Chan* Tse*). For any
* matching RP will be returned choices for every variants form.
*
* {@link ChoiceAuthority#getMatches(String, int, int, int, String)}
*
* @param query
* the lookup string
* @param collection
* (not used by this Authority)
* @param locale
* (not used by this Authority)
* @param start
* (not used by this Authority)
* @param limit
* (not used by this Authority)
* @param locale
* (not used by this Authority)
*
* @return a Choices of RPs where a name form match the query string
*/
@Override
public Choices getMatches(String field, String query, int collection,
int start, int limit, String locale)
{
try
{
init();
if (query != null && query.length() > 2)
{
DCPersonName tmpPersonName = new DCPersonName(
query.toLowerCase());
String luceneQuery = "";
if (StringUtils.isNotBlank(tmpPersonName.getLastName()))
{
luceneQuery += ClientUtils.escapeQueryChars(tmpPersonName
.getLastName().trim())
+ (StringUtils.isNotBlank(tmpPersonName
.getFirstNames()) ? "" : "*");
}
if (StringUtils.isNotBlank(tmpPersonName.getFirstNames()))
{
luceneQuery += (luceneQuery.length() > 0 ? " " : "")
+ ClientUtils.escapeQueryChars(tmpPersonName
.getFirstNames().trim()) + "*";
}
luceneQuery = luceneQuery.replaceAll("\\\\ ", " ");
DiscoverQuery discoverQuery = new DiscoverQuery();
discoverQuery.setDSpaceObjectFilter(CrisConstants.RP_TYPE_ID);
String filter = configurationService.getProperty("cris."
+ RP_AUTHORITY_NAME
+ ((field != null && !field.isEmpty()) ? "." + field
: "") + ".filter");
if (filter != null)
{
discoverQuery.addFilterQueries(filter);
}
discoverQuery
.setQuery("{!lucene q.op=AND df=crisauthoritylookup}("
+ luceneQuery
+ ") OR (\""
+ luceneQuery.substring(0,
luceneQuery.length() - 1) + "\")");
discoverQuery.setMaxResults(50);
DiscoverResult result = searchService.search(null,
discoverQuery, true);
List<Choice> choiceList = new ArrayList<Choice>();
for (DSpaceObject dso : result.getDspaceObjects())
{
ResearcherPage rp = (ResearcherPage) dso;
choiceList
.add(new Choice(ResearcherPageUtils
.getPersistentIdentifier(rp), rp
.getFullName(), ResearcherPageUtils
.getLabel(rp.getFullName(), rp)));
if (rp.getTranslatedName() != null
&& rp.getTranslatedName().getVisibility() == VisibilityConstants.PUBLIC
&& rp.getTranslatedName().getValue() != null)
{
choiceList.add(new Choice(ResearcherPageUtils
.getPersistentIdentifier(rp), rp
.getTranslatedName().getValue(),
ResearcherPageUtils.getLabel(rp
.getTranslatedName().getValue(), rp)));
}
for (RestrictedField variant : rp.getVariants())
{
if (variant.getValue() != null
&& variant.getVisibility() == VisibilityConstants.PUBLIC)
{
choiceList.add(new Choice(ResearcherPageUtils
.getPersistentIdentifier(rp), variant
.getValue(), ResearcherPageUtils.getLabel(
variant.getValue(), rp)));
}
}
}
Choice[] results = new Choice[choiceList.size()];
results = choiceList.toArray(results);
return new Choices(results, 0, results.length,
Choices.CF_AMBIGUOUS, false, 0);
}
return new Choices(false);
}
catch (Exception e)
{
log.error("Error quering the RPAuthority - " + e.getMessage(), e);
return new Choices(true);
}
}
/**
* Return a list of choices performing an exact query on the RP names (full,
* Chinese, academinc, variants). For any matching RP will be returned
* choices for every variants form, the default choice will be which that
* match with the "query" string. This method is used by unattended
* submssion only, interactive submission will use the
* {@link RPAuthority#getMatches(String, String, int, int, int, String)}.
* The confidence value of the returned Choices will be
* {@link Choices#CF_UNCERTAIN} if there is only a RP that match with the
* lookup string or {@link Choices#CF_AMBIGUOUS} if there are more RPs.
*
* {@link ChoiceAuthority#getMatches(String, String, int, int, int, String)}
*
* @param field
* (not used by this Authority)
* @param text
* the lookup string
* @param collection
* (not used by this Authority)
* @param locale
* (not used by this Authority)
* @return a Choices of RPs that have an exact string match between a name
* forms and the text lookup string
*/
@Override
public Choices getBestMatch(String field, String text, int collection,
String locale)
{
try
{
init();
List<Choice> choiceList = new ArrayList<Choice>();
int totalResult = 0;
if (text != null && text.length() > 2)
{
DiscoverQuery discoverQuery = new DiscoverQuery();
discoverQuery.setDSpaceObjectFilter(CrisConstants.RP_TYPE_ID);
String filter = configurationService.getProperty("cris."
+ RP_AUTHORITY_NAME + ".filter");
if (filter != null)
{
discoverQuery.addFilterQueries(filter);
}
discoverQuery
.setQuery("{!lucene q.op=AND df=crisauthoritylookup}\""
+ ClientUtils.escapeQueryChars(text.trim())
+ "\"");
discoverQuery.setMaxResults(50);
DiscoverResult result = searchService.search(null,
discoverQuery, true);
totalResult = (int) result.getTotalSearchResults();
for (DSpaceObject dso : result.getDspaceObjects())
{
ResearcherPage rp = (ResearcherPage) dso;
choiceList
.add(new Choice(rp.getCrisID(), text,
ResearcherPageUtils.getLabel(
rp.getFullName(), rp)));
}
}
Choice[] results = new Choice[choiceList.size()];
if (choiceList.size() > 0)
{
results = choiceList.toArray(results);
if (totalResult == 1)
{
return new Choices(results, 0, totalResult,
Choices.CF_UNCERTAIN, false, 0);
}
else
{
return new Choices(results, 0, totalResult,
Choices.CF_AMBIGUOUS, false, 0);
}
}
else
{
return new Choices(false);
}
}
catch (Exception e)
{
log.error("Error quering the HKUAuthority - " + e.getMessage(), e);
return new Choices(true);
}
}
/**
* Return a list of all not null "public" forms of the RP name.
*
* @param key
* the researcher identifier (i.e. rp00024)
* @param locale
* (not used by this Authority)
*
* @return a list of all not null "public" forms of the RP name.
*/
public List<String> getVariants(String key, String locale)
{
init();
Integer id = ResearcherPageUtils.getRealPersistentIdentifier(key,
ResearcherPage.class);
if (id == null)
{
log.error(LogManager.getHeader(null, "getLabel",
"invalid key for hkuauthority key " + key));
return null;
}
ResearcherPage rp = applicationService.get(ResearcherPage.class, id);
List<String> publicNames = new ArrayList<String>();
publicNames.add(rp.getFullName());
if (rp.getTranslatedName() != null
&& rp.getTranslatedName().getVisibility() == VisibilityConstants.PUBLIC)
{
String value = rp.getTranslatedName().getValue();
if (StringUtils.isNotBlank(value))
{
publicNames.add(value);
}
}
if (rp.getPreferredName() != null
&& rp.getPreferredName().getVisibility() == VisibilityConstants.PUBLIC)
{
String value = rp.getPreferredName().getValue();
if (StringUtils.isNotBlank(value))
{
publicNames.add(value);
}
}
List<RestrictedField> variants = rp.getVariants();
if (variants != null)
{
for (RestrictedField v : variants)
{
if (v.getVisibility() == VisibilityConstants.PUBLIC)
{
String value = v.getValue();
if (StringUtils.isNotBlank(value))
{
publicNames.add(value);
}
}
}
}
return publicNames;
}
/**
* Record the reject of a potential match so to avoid the same proposal to
* happen in future.
*
* @param itemID
* the id of the item that has been rejected
* @param authorityKey
* the researcher identifier (i.e. rp00024)
*/
public void reject(int itemID, String authorityKey)
{
init();
ResearcherPage cris = applicationService
.getResearcherByAuthorityKey(authorityKey);
Context context = null;
try
{
context = new Context();
context.turnOffAuthorisationSystem();
List<String> list = new ArrayList<String>();
list.add(String.valueOf(itemID));
relationPreferenceService.unlink(context, cris, "publications",
list);
context.restoreAuthSystemState();
}
catch (SQLException e)
{
log.error(e.getMessage(), e);
}
finally
{
if(context!=null && context.isValid()) {
context.abort();
}
}
}
/**
* Record the reject of a potential match so to avoid the same proposal to
* happen in future.
*
* @param itemIDs
* the id of the items that has been rejected
* @param authorityKey
* the researcher identifier (i.e. rp00024)
*/
public void reject(int[] itemIDs, String authorityKey)
{
init();
ResearcherPage cris = applicationService
.getResearcherByAuthorityKey(authorityKey);
Context context = null;
try
{
context = new Context();
context.turnOffAuthorisationSystem();
List<String> list = new ArrayList<String>();
for(int itemID : itemIDs) {
list.add(String.valueOf(itemID));
}
relationPreferenceService.unlink(context, cris, "publications",
list);
context.restoreAuthSystemState();
}
catch (SQLException e)
{
log.error(e.getMessage(), e);
}
finally
{
if(context!=null && context.isValid()) {
context.abort();
}
}
}
@Override
protected int getCRISTargetTypeID()
{
return CrisConstants.RP_TYPE_ID;
}
@Override
protected Class<ResearcherPage> getCRISTargetClass()
{
return ResearcherPage.class;
}
}