Java tutorial
/** * 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.io.IOException; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.app.cris.configuration.RelationPreferenceConfiguration; import org.dspace.app.cris.model.CrisConstants; import org.dspace.app.cris.model.RelationPreference; import org.dspace.app.cris.model.ResearcherPage; import org.dspace.app.cris.model.RestrictedField; import org.dspace.app.cris.service.ApplicationService; import org.dspace.app.cris.service.RelationPreferenceService; import org.dspace.app.cris.util.ResearcherPageUtils; import org.dspace.authorize.AuthorizeException; import org.dspace.browse.BrowseEngine; import org.dspace.browse.BrowseException; import org.dspace.browse.BrowseIndex; import org.dspace.browse.BrowseInfo; import org.dspace.browse.BrowseItem; import org.dspace.browse.BrowserScope; import org.dspace.content.DCValue; import org.dspace.content.Item; import org.dspace.content.ItemIterator; import org.dspace.content.MetadataField; import org.dspace.content.MetadataSchema; import org.dspace.content.authority.AuthorityDAO; import org.dspace.content.authority.AuthorityDAOFactory; import org.dspace.content.authority.ChoiceAuthority; import org.dspace.content.authority.Choices; import org.dspace.core.ConfigurationManager; import org.dspace.core.Context; import org.dspace.core.LogManager; import org.dspace.core.PluginManager; import org.dspace.eperson.EPerson; import org.dspace.storage.rdbms.DatabaseManager; import org.dspace.storage.rdbms.TableRow; import org.dspace.utils.DSpace; /** * Utility class for performing Item to ReseacherPage binding * * @author cilea * */ public class BindItemToRP { /** the logger */ private static Logger log = Logger.getLogger(BindItemToRP.class); /** * the name of the browse index where lookup for potential matches. * Configured in the dspace.cfg with the property * <code>researcherpage.browseindex</code> */ private static final String researcherPotentialMatchLookupBrowserIndex = ConfigurationManager .getProperty(CrisConstants.CFG_MODULE, "researcherpage.browseindex"); private RelationPreferenceService relationPreferenceService; public static int automaticClaim(Context context, ResearcherPage rp) throws SQLException, AuthorizeException { context.turnOffAuthorisationSystem(); DSpace dspace = new DSpace(); ApplicationService applicationService = dspace.getServiceManager().getServiceByName("applicationService", ApplicationService.class); RelationPreferenceService relationPreferenceService = dspace.getServiceManager().getServiceByName( "org.dspace.app.cris.service.RelationPreferenceService", RelationPreferenceService.class); List<RelationPreference> rejected = new ArrayList<RelationPreference>(); for (RelationPreferenceConfiguration configuration : relationPreferenceService.getConfigurationService() .getList()) { if (configuration.getRelationConfiguration().getRelationClass().equals(Item.class)) { rejected = applicationService.findRelationsPreferencesByUUIDByRelTypeAndStatus(rp.getUuid(), configuration.getRelationConfiguration().getRelationName(), RelationPreference.UNLINKED); } } EPerson eperson = EPerson.find(context, rp.getEpersonID()); ItemIterator items = Item.findBySubmitter(context, eperson); List<MetadataField> mfs = metadataFieldWithAuthorityRP(context); int count = 0; while (items.hasNext()) { Item item = items.next(); if (rejected == null || !rejected.contains(item.getID())) { boolean found = false; for (MetadataField mf : mfs) { String schema = MetadataSchema.find(context, mf.getSchemaID()).getName(); String element = mf.getElement(); String qualifier = mf.getQualifier(); DCValue[] values = item.getMetadata(schema, element, qualifier, Item.ANY); item.clearMetadata(schema, element, qualifier, Item.ANY); for (DCValue val : values) { if (val.authority == null && val.value != null && StringUtils.containsIgnoreCase(val.value, eperson.getLastName().trim())) { val.authority = ResearcherPageUtils.getPersistentIdentifier(rp); val.confidence = Choices.CF_ACCEPTED; found = true; } item.addMetadata(schema, element, qualifier, val.language, val.value, val.authority, val.confidence); } } if (found) { item.update(); count++; } } } context.restoreAuthSystemState(); return count; } public static int countPotentialMatch(Context context, ResearcherPage rp) throws SQLException, AuthorizeException, IOException { return getPotentialMatch(context, rp).size(); } public static long countPendingMatch(Context context, ResearcherPage rp) throws SQLException { AuthorityDAO dao = AuthorityDAOFactory.getInstance(context); return dao.countIssuedItemsByAuthorityValueInAuthority(RPAuthority.RP_AUTHORITY_NAME, ResearcherPageUtils.getPersistentIdentifier(rp)); } public static Set<Integer> getPotentialMatch(Context context, ResearcherPage researcher) throws SQLException, AuthorizeException, IOException { Set<Integer> invalidIds = new HashSet<Integer>(); ItemIterator iter = null; try { iter = getPendingMatch(context, researcher); while (iter.hasNext()) { invalidIds.add(iter.nextID()); } } finally { if (iter != null) iter.close(); } DSpace dspace = new DSpace(); ApplicationService applicationService = dspace.getServiceManager().getServiceByName("applicationService", ApplicationService.class); RelationPreferenceService relationPreferenceService = dspace.getServiceManager().getServiceByName( "org.dspace.app.cris.service.RelationPreferenceService", RelationPreferenceService.class); List<RelationPreference> rejected = new ArrayList<RelationPreference>(); for (RelationPreferenceConfiguration configuration : relationPreferenceService.getConfigurationService() .getList()) { if (configuration.getRelationConfiguration().getRelationClass().equals(Item.class)) { rejected = applicationService.findRelationsPreferencesByUUIDByRelTypeAndStatus(researcher.getUuid(), configuration.getRelationConfiguration().getRelationName(), RelationPreference.UNLINKED); } } for (RelationPreference relationPreference : rejected) { invalidIds.add(relationPreference.getItemID()); } List<NameResearcherPage> names = new LinkedList<NameResearcherPage>(); String authority = researcher.getCrisID(); int id = researcher.getId(); NameResearcherPage name = new NameResearcherPage(researcher.getFullName(), authority, id, invalidIds); names.add(name); RestrictedField field = researcher.getPreferredName(); if (field != null && field.getValue() != null && !field.getValue().isEmpty()) { NameResearcherPage name_1 = new NameResearcherPage(field.getValue(), authority, id, invalidIds); names.add(name_1); } field = researcher.getTranslatedName(); if (field != null && field.getValue() != null && !field.getValue().isEmpty()) { NameResearcherPage name_2 = new NameResearcherPage(field.getValue(), authority, id, invalidIds); names.add(name_2); } for (RestrictedField r : researcher.getVariants()) { if (r != null && r.getValue() != null && !r.getValue().isEmpty()) { NameResearcherPage name_3 = new NameResearcherPage(r.getValue(), authority, id, invalidIds); names.add(name_3); } } Set<Integer> result = new HashSet<Integer>(); try { BrowseIndex bi = BrowseIndex.getBrowseIndex(researcherPotentialMatchLookupBrowserIndex); // now start up a browse engine and get it to do the work for us BrowseEngine be = new BrowseEngine(context); int count = 1; for (NameResearcherPage tempName : names) { log.debug("work on " + tempName.getName() + " with identifier " + tempName.getPersistentIdentifier() + " (" + count + " of " + names.size() + ")"); // set up a BrowseScope and start loading the values into it BrowserScope scope = new BrowserScope(context); scope.setBrowseIndex(bi); // scope.setOrder(order); scope.setFilterValue(tempName.getName()); // scope.setFilterValueLang(valueLang); // scope.setJumpToItem(focus); // scope.setJumpToValue(valueFocus); // scope.setJumpToValueLang(valueFocusLang); // scope.setStartsWith(startsWith); // scope.setOffset(offset); scope.setResultsPerPage(Integer.MAX_VALUE); // scope.setSortBy(sortBy); scope.setBrowseLevel(1); // scope.setEtAl(etAl); BrowseInfo binfo = be.browse(scope); log.debug("Find " + binfo.getResultCount() + "item(s) in browsing..."); for (BrowseItem bitem : binfo.getBrowseItemResults()) { if (!invalidIds.contains(bitem.getID())) { result.add(bitem.getID()); } } } } catch (BrowseException be) { log.error(LogManager.getHeader(context, "getPotentialMatch", "researcher=" + researcher.getCrisID()), be); } return result; } private static List<MetadataField> metadataFieldWithAuthorityRP(Context context) throws SQLException { // find all metadata with authority support MetadataField[] fields = MetadataField.findAll(context); List<MetadataField> fieldsWithAuthoritySupport = new LinkedList<MetadataField>(); for (MetadataField mf : fields) { String schema = (MetadataSchema.find(context, mf.getSchemaID())).getName(); String mdstring = schema + "." + mf.getElement() + (mf.getQualifier() == null ? "" : "." + mf.getQualifier()); String choicesPlugin = ConfigurationManager.getProperty("choices.plugin." + mdstring); if (choicesPlugin != null) { choicesPlugin = choicesPlugin.trim(); } if ((RPAuthority.RP_AUTHORITY_NAME.equals(choicesPlugin))) { fieldsWithAuthoritySupport.add(mf); } } return fieldsWithAuthoritySupport; } public static ItemIterator getPendingMatch(Context context, ResearcherPage rp) throws SQLException, AuthorizeException, IOException { AuthorityDAO dao = AuthorityDAOFactory.getInstance(context); return dao.findIssuedByAuthorityValueInAuthority(RPAuthority.RP_AUTHORITY_NAME, ResearcherPageUtils.getPersistentIdentifier(rp)); } /** * Search potential matches for all the ResearcherPage supplied. The * algorithm search for any researcher page and any researcher's name * (regardless the visibility attribute) all the items published in DSpace * using the Browse System (@link * using the Browse System (@link #researcherPotentialMatchLookupBrowserIndex}, if a match is found * and there is not an existent authority key for the metadata then the rp * identifier of the matching researcher page is used as authority key and a * confidence value is attributed as follow: * <ul> * <li>{@link Choices.CF_UNCERTAIN} if there is only a potential matching * researcher page</li> * <li>{@link Choices.CF_AMBIGUOUS} if there are more than one potential * matching reseacher pages</li> * </ul> * * @param rps * the list of ResearcherPage * @param applicationService * the ApplicationService * * @see #researcherPotentialMatchLookupBrowserIndex * @see Choices#CF_UNCERTAIN * @see Choices#CF_AMBIGUOUS * */ public static void work(List<ResearcherPage> rps, RelationPreferenceService relationPreferenceService) { log.debug("Working...building names list"); List<NameResearcherPage> names = new LinkedList<NameResearcherPage>(); for (ResearcherPage researcher : rps) { Set<Integer> invalidIds = new HashSet<Integer>(); List<RelationPreference> rejected = new ArrayList<RelationPreference>(); for (RelationPreferenceConfiguration configuration : relationPreferenceService.getConfigurationService() .getList()) { if (configuration.getRelationConfiguration().getRelationClass().equals(Item.class)) { rejected = relationPreferenceService.findRelationsPreferencesByUUIDByRelTypeAndStatus( researcher.getUuid(), configuration.getRelationConfiguration().getRelationName(), RelationPreference.UNLINKED); } } for (RelationPreference relationPreference : rejected) { invalidIds.add(relationPreference.getItemID()); } String authority = researcher.getCrisID(); int id = researcher.getId(); NameResearcherPage name = new NameResearcherPage(researcher.getFullName(), authority, id, invalidIds); names.add(name); RestrictedField field = researcher.getPreferredName(); if (field != null && field.getValue() != null && !field.getValue().isEmpty()) { NameResearcherPage name_1 = new NameResearcherPage(field.getValue(), authority, id, invalidIds); names.add(name_1); } field = researcher.getTranslatedName(); if (field != null && field.getValue() != null && !field.getValue().isEmpty()) { NameResearcherPage name_2 = new NameResearcherPage(field.getValue(), authority, id, invalidIds); names.add(name_2); } for (RestrictedField r : researcher.getVariants()) { if (r != null && r.getValue() != null && !r.getValue().isEmpty()) { NameResearcherPage name_3 = new NameResearcherPage(r.getValue(), authority, id, invalidIds); names.add(name_3); } } } log.debug("...DONE building names list size " + names.size()); log.debug("Create DSpace context and use browse indexing"); Context context = null; try { context = new Context(); context.setIgnoreAuthorization(true); List<MetadataField> fieldsWithAuthoritySupport = metadataFieldWithAuthorityRP(context); BrowseIndex bi = BrowseIndex.getBrowseIndex(researcherPotentialMatchLookupBrowserIndex); // now start up a browse engine and get it to do the work for us BrowseEngine be = new BrowseEngine(context); int count = 1; for (NameResearcherPage tempName : names) { log.info("work on " + tempName.getName() + " with identifier " + tempName.getPersistentIdentifier() + " (" + count + " of " + names.size() + ")"); // set up a BrowseScope and start loading the values into it BrowserScope scope = new BrowserScope(context); scope.setBrowseIndex(bi); // scope.setOrder(order); scope.setFilterValue(tempName.getName()); // scope.setFilterValueLang(valueLang); // scope.setJumpToItem(focus); // scope.setJumpToValue(valueFocus); // scope.setJumpToValueLang(valueFocusLang); // scope.setStartsWith(startsWith); // scope.setOffset(offset); scope.setResultsPerPage(Integer.MAX_VALUE); // scope.setSortBy(sortBy); scope.setBrowseLevel(1); // scope.setEtAl(etAl); BrowseInfo binfo = be.browse(scope); log.info("Find " + binfo.getResultCount() + "item(s) in browsing..."); bindItemsToRP(relationPreferenceService, context, fieldsWithAuthoritySupport, tempName, binfo.getItemResults(context)); count++; } } catch (Exception e) { log.error(e.getMessage(), e); throw new RuntimeException(e.getMessage(), e); } finally { if (context != null && context.isValid()) { context.abort(); } } } public static void bindItemsToRP(RelationPreferenceService relationPreferenceService, Context context, ResearcherPage researcher, Item[] items) throws SQLException, BrowseException, AuthorizeException { String authority = researcher.getCrisID(); int id = researcher.getId(); List<NameResearcherPage> names = new LinkedList<NameResearcherPage>(); Set<Integer> invalidIds = new HashSet<Integer>(); List<RelationPreference> rejected = new ArrayList<RelationPreference>(); for (RelationPreferenceConfiguration configuration : relationPreferenceService.getConfigurationService() .getList()) { if (configuration.getRelationConfiguration().getRelationClass().equals(Item.class)) { rejected = relationPreferenceService.findRelationsPreferencesByUUIDByRelTypeAndStatus( researcher.getUuid(), configuration.getRelationConfiguration().getRelationName(), RelationPreference.UNLINKED); } } for (RelationPreference relationPreference : rejected) { invalidIds.add(relationPreference.getItemID()); } NameResearcherPage name = new NameResearcherPage(researcher.getFullName(), authority, id, invalidIds); names.add(name); RestrictedField field = researcher.getPreferredName(); if (field != null && field.getValue() != null && !field.getValue().isEmpty()) { NameResearcherPage name_1 = new NameResearcherPage(field.getValue(), authority, id, invalidIds); names.add(name_1); } field = researcher.getTranslatedName(); if (field != null && field.getValue() != null && !field.getValue().isEmpty()) { NameResearcherPage name_2 = new NameResearcherPage(field.getValue(), authority, id, invalidIds); names.add(name_2); } for (RestrictedField r : researcher.getVariants()) { if (r != null && r.getValue() != null && !r.getValue().isEmpty()) { NameResearcherPage name_3 = new NameResearcherPage(r.getValue(), authority, id, invalidIds); names.add(name_3); } } List<MetadataField> fieldsWithAuthoritySupport = metadataFieldWithAuthorityRP(context); for (NameResearcherPage tmpname : names) { bindItemsToRP(relationPreferenceService, context, fieldsWithAuthoritySupport, tmpname, items); } } private static void bindItemsToRP(RelationPreferenceService relationPreferenceService, Context context, List<MetadataField> fieldsWithAuthoritySupport, NameResearcherPage tempName, Item[] items) throws BrowseException, SQLException, AuthorizeException { context.turnOffAuthorisationSystem(); Map<String, Integer> cacheCount = new HashMap<String, Integer>(); for (Item item : items) { if (tempName.getRejectItems() != null && tempName.getRejectItems().contains(item.getID())) { log.warn("Item has been reject for this authority - itemID " + item.getID()); } else { boolean modified = false; DCValue[] values = null; for (MetadataField md : fieldsWithAuthoritySupport) { String schema = (MetadataSchema.find(context, md.getSchemaID())).getName(); values = item.getMetadata(schema, md.getElement(), md.getQualifier(), Item.ANY); item.clearMetadata(schema, md.getElement(), md.getQualifier(), Item.ANY); for (DCValue value : values) { int matches = 0; if (value.authority == null && (value.value.equals(tempName.getName()) || value.value.startsWith(tempName.getName() + ";"))) { matches = countNamesMatching(cacheCount, tempName.getName()); item.addMetadata(value.schema, value.element, value.qualifier, value.language, tempName.getName(), tempName.getPersistentIdentifier(), matches >= 1 ? Choices.CF_AMBIGUOUS : matches == 1 ? Choices.CF_UNCERTAIN : Choices.CF_NOTFOUND); modified = true; } else { item.addMetadata(value.schema, value.element, value.qualifier, value.language, value.value, value.authority, value.confidence); } } values = null; } if (modified) { log.debug("Update item with id " + item.getID()); item.update(); } context.commit(); context.clearCache(); } } context.restoreAuthSystemState(); } private static int countNamesMatching(Map<String, Integer> cacheCount, String name) { if (cacheCount.containsKey(name)) { return cacheCount.get(name); } ChoiceAuthority ca = (ChoiceAuthority) PluginManager.getNamedPlugin(ChoiceAuthority.class, RPAuthority.RP_AUTHORITY_NAME); Choices choices = ca.getBestMatch(null, name, 0, null); cacheCount.put(name, choices.total); return choices.total; } private static void generatePotentialMatches(Context context, ResearcherPage researcher) throws SQLException, AuthorizeException, IOException { Set<Integer> ids = getPotentialMatch(context, researcher); DatabaseManager.updateQuery(context, "delete from potentialmatches where rp like ?", researcher.getCrisID()); for (Integer id : ids) { TableRow pmTableRow = DatabaseManager.create(context, "potentialmatches"); pmTableRow.setColumn("rp", researcher.getCrisID()); pmTableRow.setColumn("item_id", id); DatabaseManager.update(context, pmTableRow); } context.commit(); } public static void generatePotentialMatches(ApplicationService applicationService, Context context, String rp) throws SQLException, AuthorizeException, IOException { ResearcherPage researcher = applicationService.getResearcherByAuthorityKey(rp); if (researcher == null) { return; } generatePotentialMatches(context, researcher); } public static void generatePotentialMatches(ResearcherPage researcher) { Context context = null; try { context = new Context(); generatePotentialMatches(context, researcher); context.complete(); } catch (Exception e) { log.error(e.getMessage(), e); } finally { if (context != null && context.isValid()) context.abort(); } } } /** * Support class to build the full list of names to process in the BindItemToRP * work method * * @author cilea * */ class NameResearcherPage { /** the name form to lookup for */ private String name; /** the rp identifier */ private String persistentIdentifier; private int id; /** the ids of previous rejected matches */ private Set<Integer> rejectItems; public NameResearcherPage(String name, String authority, int id, Set<Integer> rejectItems) { this.name = name; this.persistentIdentifier = authority; this.id = id; this.rejectItems = rejectItems; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPersistentIdentifier() { return persistentIdentifier; } public void setPersistentIdentifier(String persistentIdentifier) { this.persistentIdentifier = persistentIdentifier; } public int getId() { return id; } public void setId(int id) { this.id = id; } public Set<Integer> getRejectItems() { return rejectItems; } public void setRejectItems(Set<Integer> rejectItems) { this.rejectItems = rejectItems; } }