/** * ============================================================================= * * ORCID (R) Open Source * http://orcid.org * * Copyright (c) 2012-2014 ORCID, Inc. * Licensed under an MIT-Style License (MIT) * http://orcid.org/open-source-license * * This copyright and license information (including a link to the full license) * shall be included in its entirety in all copies or substantial portion of * the software. * * ============================================================================= */ package org.orcid.core.profileEvent; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import javax.annotation.Resource; import org.apache.commons.lang3.time.DurationFormatUtils; import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.CmdLineParser; import org.kohsuke.args4j.Option; import org.orcid.core.manager.LoadOptions; import org.orcid.core.manager.OrcidProfileManager; import org.orcid.jaxb.model.message.OrcidProfile; import org.orcid.persistence.dao.GenericDao; import org.orcid.persistence.dao.ProfileDao; import org.orcid.persistence.jpa.entities.ProfileEventEntity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.transaction.support.TransactionTemplate; /** * * @author rcpeters * */ public class ProfileEventManager { static ApplicationContext context; @Resource private ProfileDao profileDao; @Resource private OrcidProfileManager orcidProfileManager; @Resource private GenericDao<ProfileEventEntity, Long> profileEventDao; @Resource private TransactionTemplate transactionTemplate; private static Logger LOG = LoggerFactory.getLogger(ProfileEventManager.class); private static final int CHUNK_SIZE = 1000; @Option(name = "-testSendToOrcids", usage = "Call only on passed ORCID Ids") private String orcs; @Option(name = "-callOnAll", usage = "Calls on all orcids") private String callOnAll; @Option(name = "-bean", usage = "ProfileEvent class to instantiate", required = true) private String bean; ExecutorService pool = Executors.newFixedThreadPool(4); public static void main(String... args) { context = new ClassPathXmlApplicationContext("orcid-core-context.xml"); ProfileEventManager pem = (ProfileEventManager) context.getBean("profileEventManager"); CmdLineParser parser = new CmdLineParser(pem); if (args == null) { parser.printUsage(System.err); } try { parser.parseArgument(args); pem.execute(pem); } catch (CmdLineException e) { System.err.println(e.getMessage()); parser.printUsage(System.err); } System.exit(0); } private void execute(ProfileEventManager pem) { if (callOnAll != null) { try { callOnceOnAll(bean); } catch (InterruptedException e) { LOG.error("InterruptedException ", e); } } else if (orcs != null) { for (String orc : orcs.split(" ")) { OrcidProfile orcidProfile = getOrcidProfileManager().retrieveOrcidProfile(orc); ProfileEvent pe = (ProfileEvent) context.getBean(bean, orcidProfile); try { pe.call(); } catch (Exception e) { LOG.error("Error calling ", e); } } } } private void callOnceOnAll(final String classStr) throws InterruptedException { ProfileEvent dummyPe = (ProfileEvent) context.getBean(classStr, (ProfileEvent) null); long startTime = System.currentTimeMillis(); @SuppressWarnings("unchecked") List<String> orcids = Collections.EMPTY_LIST; int doneCount = 0; do { orcids = getProfileDao().findByMissingEventTypes(CHUNK_SIZE, dummyPe.outcomes(), null, true); Set<ProfileEvent> callables = new HashSet<ProfileEvent>(); for (final String orcid : orcids) { LOG.info("Calling bean " + classStr + " for " + orcid); // TODO: parameterize load options. OrcidProfile orcidProfile = getOrcidProfileManager().retrieveOrcidProfile(orcid,new LoadOptions(true,false,true)); callables.add((ProfileEvent) context.getBean(classStr, orcidProfile)); doneCount++; } List<Future<ProfileEventResult>> futures = pool.invokeAll(callables); for (Future<ProfileEventResult> future : futures) { ProfileEventResult per = null; try { per = future.get(); } catch (ExecutionException e) { LOG.error("failed calling task ", e); } getProfileEventDao().persist(new ProfileEventEntity(per.getOrcidId(), per.getOutcome())); } LOG.info("Current done count: {}", doneCount); } while (!orcids.isEmpty()); long endTime = System.currentTimeMillis(); String timeTaken = DurationFormatUtils.formatDurationHMS(endTime - startTime); LOG.info("Profile Event " + classStr + ": doneCount={}, timeTaken={} (H:m:s.S)", doneCount, timeTaken); } public ProfileDao getProfileDao() { return profileDao; } public void setProfileDao(ProfileDao profileDao) { this.profileDao = profileDao; } public OrcidProfileManager getOrcidProfileManager() { return orcidProfileManager; } public void setOrcidProfileManager(OrcidProfileManager orcidProfileManager) { this.orcidProfileManager = orcidProfileManager; } public GenericDao<ProfileEventEntity, Long> getProfileEventDao() { return profileEventDao; } public void setProfileEventDao(GenericDao<ProfileEventEntity, Long> profileEventDao) { this.profileEventDao = profileEventDao; } }