All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.norconex.jef4.job.group.AsyncJobGroup Maven / Gradle / Ivy

/* Copyright 2010-2014 Norconex Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.norconex.jef4.job.group;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

import com.norconex.jef4.JEFException;
import com.norconex.jef4.job.IJob;
import com.norconex.jef4.job.JobException;
import com.norconex.jef4.suite.JobSuite;

/**
 * Job responsible for running a group of jobs asynchronously.  All jobs
 * are started at the same time, in different threads.  The progress of this
 * group reflects the average progress of all its jobs.  This job group
 * is considered completed and will only return when all its jobs are
 * done executing.  An exception in one job will not stop the other jobs
 * in the group from running.  On the other hand, one or more exception will
 * result in this group to fail.
 *
 * @author Pascal Essiembre
 */
@SuppressWarnings("nls")
public class AsyncJobGroup extends AbstractJobGroup {

    /** Logger. */
    private static final Logger LOG =
            LogManager.getLogger(AsyncJobGroup.class);

    private final int maxThread;
    
    /**
     * Constructor.
     * @param id unique identifier for this job group
     * @param jobs jobs making up this group
     */
    public AsyncJobGroup(final String id, final IJob... jobs) {
        this(id, jobs.length, jobs);
    }
    
    /**
     * Constructor.
     * @param id unique identifier for this job group
     * @param maxThreads maximum number of threads (jobs) executing at the
     *        same time
     * @param jobs jobs making up this group
     */
    public AsyncJobGroup(
            final String id, int maxThreads, final IJob... jobs) {
        super(id, jobs);
        this.maxThread = maxThreads;
    }

    @Override
    public void executeGroup(final JobSuite suite) {
        final Collection failedJobs =
                Collections.synchronizedCollection(new ArrayList());
        IJob[] jobs = getJobs();
        int realMaxThread = Math.min(maxThread, jobs.length);
        final CountDownLatch latch = new CountDownLatch(jobs.length);
        ExecutorService pool = Executors.newFixedThreadPool(realMaxThread);
        for (final IJob job : jobs) {
            pool.execute(new Runnable() {
                @Override
                public void run() {
                    runJob(job, suite, failedJobs, latch);
                }
            });
        }

        try {
            latch.await();
            pool.shutdown();
        } catch (InterruptedException e) {
             throw new JEFException(e);
        }
        if (LOG.isDebugEnabled()) {
            LOG.debug("All threads finished for async group\"" 
                    + getId() + "\".");
        }

        if (!failedJobs.isEmpty()) {
            throw new JobException(
                    failedJobs.size() + " out of " + jobs.length
                  + " jobs failed in async group \"" + getId() + "\"");
        }
    }
    
    private void runJob(IJob job, JobSuite suite, Collection failedJobs,
            CountDownLatch latch) {
        Thread.currentThread().setName(job.getId());
        JobSuite.setCurrentJobId(job.getId());

        try {
            if (LOG.isDebugEnabled()) {
                LOG.debug("Thread from " + AsyncJobGroup.this.getId()
                    + " started and about to run: " + job.getId());
            }
            if (!suite.runJob(job)) {
                synchronized (failedJobs) {
                    LOG.error(job.getId() + " failed.");
                    failedJobs.add(job);
                }
            } else if (LOG.isDebugEnabled()) {
                LOG.debug(job.getId() + " succeeded.");
            }
            JobSuite.setCurrentJobId(AsyncJobGroup.this.getId());
            if (LOG.isDebugEnabled()) {
                LOG.debug("Thread from " + AsyncJobGroup.this.getId()
                    + " finished to run: " + job.getId());
            }
        } finally {
            latch.countDown();
        }
        
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy