org.apache.roller.weblogger.business.referrers.ReferrerQueueManagerImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.roller.weblogger.business.referrers.ReferrerQueueManagerImpl.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  The ASF licenses this file to You
 * 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.  For additional information regarding
 * copyright in this work, please see the NOTICE file in the top level
 * directory of this distribution.
 */

package org.apache.roller.weblogger.business.referrers;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.roller.weblogger.WebloggerException;
import org.apache.roller.weblogger.business.Weblogger;
import org.apache.roller.weblogger.business.runnable.ContinuousWorkerThread;
import org.apache.roller.weblogger.business.runnable.WorkerThread;
import org.apache.roller.weblogger.config.WebloggerConfig;

/**
 * The base implementation of the ReferrerQueueManager.
 * 
 * This class is implemented using the singleton pattern to ensure that only
 * one instance exists at any given time.
 *
 * This implementation can be configured to handle referrers in 2 ways ...
 *  1. synchronously.  referrers are processed immediately.
 *  2. asynchronously.  referrers are queued for later processing.
 *
 * Users can control the referrer queue mode via properties in the static
 * roller.properties configuration file.
 *
 * In asynchronous processing mode we start some number of worker threads which
 * run continously to process any referrers that have been queued.  Each worker
 * processes queued referrers until the queue is empty, then sleeps for a given
 * amount of time.  The number of workers used and their sleep time can be set
 * via properties of the static roller.properties file.
 *
 * @author Allen Gilliland
 */
@com.google.inject.Singleton
public class ReferrerQueueManagerImpl implements ReferrerQueueManager {

    private static Log mLogger = LogFactory.getLog(ReferrerQueueManagerImpl.class);

    private final Weblogger roller;

    private boolean asyncMode = false;
    private int numWorkers = 1;
    private int sleepTime = 10000;
    private List workers = null;
    private List referrerQueue = null;

    // private because we are a singleton
    @com.google.inject.Inject
    protected ReferrerQueueManagerImpl(Weblogger roller) {

        mLogger.info("Instantiating Referrer Queue Manager");

        this.roller = roller;

        // lookup config options
        this.asyncMode = WebloggerConfig.getBooleanProperty("referrers.asyncProcessing.enabled");

        mLogger.info("Asynchronous referrer processing = " + this.asyncMode);

        if (this.asyncMode) {

            String num = WebloggerConfig.getProperty("referrers.queue.numWorkers");
            String sleep = WebloggerConfig.getProperty("referrers.queue.sleepTime");

            try {
                this.numWorkers = Integer.parseInt(num);

                if (numWorkers < 1)
                    this.numWorkers = 1;

            } catch (NumberFormatException nfe) {
                mLogger.warn("Invalid num workers [" + num + "], using default");
            }

            try {
                // multiply by 1000 because we expect input in seconds
                this.sleepTime = Integer.parseInt(sleep) * 1000;
            } catch (NumberFormatException nfe) {
                mLogger.warn("Invalid sleep time [" + sleep + "], using default");
            }

            // create the processing queue
            this.referrerQueue = Collections.synchronizedList(new ArrayList());

            // start up workers
            this.workers = new ArrayList();
            ContinuousWorkerThread worker = null;
            QueuedReferrerProcessingJob job = null;
            for (int i = 0; i < this.numWorkers; i++) {
                job = new QueuedReferrerProcessingJob();
                worker = new ContinuousWorkerThread("ReferrerWorker" + i, job, this.sleepTime);
                workers.add(worker);
                worker.start();
            }
        }
    }

    /**
     * Process an incoming referrer.
     *
     * If we are doing asynchronous referrer processing then the referrer will
     * just go into the queue for later processing.  If not then we process it
     * now.
     */
    public void processReferrer(IncomingReferrer referrer) {

        if (this.asyncMode) {
            mLogger.debug("QUEUING: " + referrer.getRequestUrl());

            // add to queue
            this.enqueue(referrer);
        } else {
            // process now
            ReferrerProcessingJob job = new ReferrerProcessingJob();

            // setup input
            HashMap inputs = new HashMap();
            inputs.put("referrer", referrer);
            job.input(inputs);

            // execute
            job.execute();

            try {
                // flush changes
                roller.flush();
            } catch (WebloggerException ex) {
                mLogger.error("ERROR commiting referrer", ex);
            }
        }

    }

    /**
     * Place a referrer in the queue.
     */
    public void enqueue(IncomingReferrer referrer) {
        this.referrerQueue.add(referrer);

        if (this.referrerQueue.size() > 250) {
            mLogger.warn("Referrer queue is rather full. queued=" + this.referrerQueue.size());
        }
    }

    /**
     * Retrieve the next referrer in the queue.
     */
    public synchronized IncomingReferrer dequeue() {

        if (!this.referrerQueue.isEmpty()) {
            return (IncomingReferrer) this.referrerQueue.remove(0);
        }

        return null;
    }

    /**
     * clean up.
     */
    public void shutdown() {

        if (this.workers != null && this.workers.size() > 0) {
            mLogger.info("stopping all ReferrerQueue worker threads");

            // kill all of our threads
            WorkerThread worker = null;
            Iterator it = this.workers.iterator();
            while (it.hasNext()) {
                worker = (WorkerThread) it.next();
                worker.interrupt();
            }
        }

    }

}