/** * Copyright (c) 2009 - 2012 Red Hat, Inc. * * This software is licensed to you under the GNU General Public License, * version 2 (GPLv2). There is NO WARRANTY for this software, express or * implied, including the implied warranties of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 * along with this software; if not, see * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. * * Red Hat trademarks are not licensed under GPLv2. No permission is * granted to use or replicate Red Hat trademarks that are incorporated * in this software or its documentation. */ package org.candlepin.pinsetter.tasks; import static org.quartz.JobBuilder.newJob; import org.candlepin.common.filter.LoggingFilter; import org.candlepin.controller.PoolManager; import org.candlepin.model.Owner; import org.candlepin.model.OwnerCurator; import org.candlepin.pinsetter.core.RetryJobException; import org.candlepin.pinsetter.core.model.JobStatus; import org.candlepin.service.SubscriptionServiceAdapter; import org.candlepin.util.Util; import com.google.inject.Inject; import org.apache.log4j.MDC; import org.quartz.JobDataMap; import org.quartz.JobDetail; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.sql.SQLException; import javax.persistence.PersistenceException; /** * Asynchronous job for refreshing the entitlement pools for specific * {@link Owner}. */ public class RefreshPoolsJob extends UniqueByEntityJob { private static Logger log = LoggerFactory.getLogger(RefreshPoolsJob.class); protected OwnerCurator ownerCurator; protected PoolManager poolManager; protected SubscriptionServiceAdapter subAdapter; public static final String LAZY_REGEN = "lazy_regen"; public static final String JOB_NAME_PREFIX = "refresh_pools_"; @Inject public RefreshPoolsJob(OwnerCurator ownerCurator, PoolManager poolManager, SubscriptionServiceAdapter subAdapter) { this.ownerCurator = ownerCurator; this.poolManager = poolManager; this.subAdapter = subAdapter; } /** * {@inheritDoc} * * Executes {@link PoolManager#refreshPools(org.candlepin.model.Owner)} * as a pinsetter job. * * @param context the job's execution context */ public void toExecute(JobExecutionContext context) throws JobExecutionException { try { JobDataMap map = context.getMergedJobDataMap(); String ownerKey = map.getString(JobStatus.TARGET_ID); Boolean lazy = map.getBoolean(LAZY_REGEN); Owner owner = ownerCurator.lookupByKey(ownerKey); if (owner == null) { context.setResult("Nothing to do. Owner no longer exists"); return; } // Assume that we verified the request in the resource layer: poolManager.getRefresher(subAdapter, lazy).setUnitOfWork(unitOfWork).add(owner).run(); context.setResult("Pools refreshed for owner " + owner.getDisplayName()); } catch (PersistenceException e) { throw new RetryJobException("RefreshPoolsJob encountered a problem.", e); } catch (RuntimeException e) { Throwable cause = e.getCause(); while (cause != null) { if (SQLException.class.isAssignableFrom(cause.getClass())) { log.warn("Caught a runtime exception wrapping an SQLException."); throw new RetryJobException("RefreshPoolsJob encountered a problem.", e); } cause = cause.getCause(); } // Otherwise throw as we would normally for any generic Exception: log.error("RefreshPoolsJob encountered a problem.", e); context.setResult(e.toString()); throw new JobExecutionException(e.toString(), e, false); } // Catch any other exception that is fired and re-throw as a // JobExecutionException so that the job will be properly // cleaned up on failure. catch (Exception e) { log.error("RefreshPoolsJob encountered a problem.", e); context.setResult(e.toString()); throw new JobExecutionException(e.toString(), e, false); } } /** * Creates a {@link JobDetail} that runs this job for the given {@link Owner}. * * @param owner the owner to refresh * @return a {@link JobDetail} that describes the job run */ public static JobDetail forOwner(Owner owner, Boolean lazy) { JobDataMap map = new JobDataMap(); map.put(JobStatus.OWNER_ID, owner.getKey()); map.put(JobStatus.TARGET_TYPE, JobStatus.TargetType.OWNER); map.put(JobStatus.TARGET_ID, owner.getKey()); map.put(LAZY_REGEN, lazy); map.put(JobStatus.CORRELATION_ID, MDC.get(LoggingFilter.CSID)); // Not sure if this is the best way to go: // Give each job a UUID to ensure that it is unique JobDetail detail = newJob(RefreshPoolsJob.class) .withIdentity(JOB_NAME_PREFIX + Util.generateUUID()) .requestRecovery(true) // recover the job upon restarts .usingJobData(map) .storeDurably(true) // required if we have to postpone the job .build(); return detail; } }