Java tutorial
/* * @(#)$Id: Scheduler.java 3619 2008-03-26 07:23:03Z yui $ * * Copyright 2006-2008 Makoto YUI * * 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. * * Contributors: * Makoto YUI - initial implementation */ package xbird.engine.sched; import java.rmi.RemoteException; import java.util.*; import java.util.concurrent.ExecutorService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import xbird.config.Settings; import xbird.engine.*; import xbird.engine.Request.Signature; import xbird.util.concurrent.ExecutorFactory; import xbird.util.system.SystemUtils; /** * Scheduler runs in a thread. * <DIV lang="en"></DIV> * <DIV lang="ja"></DIV> * * @author Makoto YUI (yuin405+xbird@gmail.com) */ public abstract class Scheduler implements Runnable { private static final Log LOG = LogFactory.getLog(Scheduler.class); private static final int MAX_BACKENDS; static { int maxPerProc = Integer.parseInt(Settings.get("xbird.sched.max_backends_per_proc", "8")); MAX_BACKENDS = maxPerProc * SystemUtils.availableProcessors(); } protected final ResponseListener _resHandler; protected final List<ScheduledEventListener> _listeners; protected boolean _paused = false; private final Object _pauseLock = new Object(); private final ExecutorService _executors; Scheduler(ResponseListener resHandler) { this._resHandler = resHandler; this._listeners = new ArrayList<ScheduledEventListener>(4); this._executors = ExecutorFactory.newBoundedWorkQueueThreadPool(4, MAX_BACKENDS, 60L, "BackendProc"); // TODO REVIEWME max threads } Scheduler(ResponseListener resHandler, ScheduledEventListener... listeners) { this._resHandler = resHandler; final List<ScheduledEventListener> list = new ArrayList<ScheduledEventListener>(listeners.length + 2); for (ScheduledEventListener listener : listeners) { list.add(listener); } this._listeners = list; this._executors = ExecutorFactory.newBoundedWorkQueueThreadPool(4, MAX_BACKENDS, 60L, "BackendProc"); // TODO REVIEWME max threads } public final void addListener(ScheduledEventListener listener) { _listeners.add(listener); } /** run as a thread and wait for notify */ public final void standby() { if (_listeners.isEmpty()) { throw new IllegalStateException("no listener is registered"); } final Thread thread = new Thread(this, "Sched"); thread.start(); } /** * @see #addTask(RequestContext) */ public void run() { while (true) { togglePause(true); // wait for task added processTask(); } } protected void togglePause(boolean pause) { if (pause == _paused) { return; } synchronized (_pauseLock) { if (pause) { this._paused = true; try { _pauseLock.wait(); } catch (InterruptedException e) { LOG.warn("could not acquire the thread lock", e); } } else if (_paused) { _pauseLock.notifyAll(); this._paused = false; } } } public abstract void addTask(RequestContext rctxt); public abstract void removeTask(Request request); protected abstract void processTask(); protected void invokeFire(final RequestContext rc) { final Request request = rc.getRequest(); final Signature rtype = request.getSignature(); boolean fired = false; for (ScheduledEventListener listener : _listeners) { final Signature ltype = listener.associatedWith(); if (ltype == rtype) { final long timeout = request.getTimeout(); if (timeout != Request.NO_TIMEOUT) { execute(rc, listener, timeout); } else { execute(rc, listener); } fired = true; break; } } if (!fired) { final String errmsg = "No listener is found for " + request; LOG.error(errmsg); rc.setFault(new SchedulerException(errmsg)); try { _resHandler.onResponse(rc); } catch (RemoteException e) { LOG.error("onResponse failed: " + request, e); throw new IllegalStateException(e); } } } private final void execute(final RequestContext rc, final ScheduledEventListener listener, final long timeout) { if (timeout <= 0) { throw new IllegalArgumentException("Illegal timeout value: " + timeout); } final Request request = rc.getRequest(); final TimerTask cancel = new TimerTask() { public void run() { try { listener.cancel(rc); } catch (RemoteException e) { LOG.warn("canceling task is failed: " + request.getIdentifier(), e); } } }; final Timer timer = new Timer("SchedTimeout"); timer.schedule(cancel, timeout); execute(rc, listener); timer.cancel(); } private final void execute(final RequestContext rc, final ScheduledEventListener listener) { final Request request = rc.getRequest(); final Runnable r = new Runnable() { public void run() { try { listener.fire(rc); } catch (RemoteException e) { LOG.error("Request failed: " + request.getIdentifier(), e); } } }; _executors.execute(r); } }