Source code: org/objectstyle/cayenne/util/RequestQueue.java
1 /* ====================================================================
2 *
3 * The ObjectStyle Group Software License, Version 1.0
4 *
5 * Copyright (c) 2002-2003 The ObjectStyle Group
6 * and individual authors of the software. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution, if
21 * any, must include the following acknowlegement:
22 * "This product includes software developed by the
23 * ObjectStyle Group (http://objectstyle.org/)."
24 * Alternately, this acknowlegement may appear in the software itself,
25 * if and wherever such third-party acknowlegements normally appear.
26 *
27 * 4. The names "ObjectStyle Group" and "Cayenne"
28 * must not be used to endorse or promote products derived
29 * from this software without prior written permission. For written
30 * permission, please contact andrus@objectstyle.org.
31 *
32 * 5. Products derived from this software may not be called "ObjectStyle"
33 * nor may "ObjectStyle" appear in their names without prior written
34 * permission of the ObjectStyle Group.
35 *
36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
48 * ====================================================================
49 *
50 * This software consists of voluntary contributions made by many
51 * individuals on behalf of the ObjectStyle Group. For more
52 * information on the ObjectStyle Group, please see
53 * <http://objectstyle.org/>.
54 *
55 */
56 package org.objectstyle.cayenne.util;
57
58 import java.util.ArrayList;
59 import java.util.Collections;
60 import java.util.List;
61
62 import org.apache.log4j.Logger;
63
64 /**
65 * RequestQueue implements a FIFO queue for threads waiting for a
66 * particular event, resource, etc. Each thread will wait
67 * in the queue until either of the following events happen:
68 *
69 * <ul>
70 * <li>Thread is already #1 in the queue and an awaited event occurrs.</li>
71 * <li>Thread timeout interval expired.</li>
72 * <li>Thread was interrupted (this is a quick way to remove thread from the queue).</li>
73 * </ul>
74 *
75 * If any of the conditions above ocurrs, thread will be removed from the queue.
76 *
77 * @author Andrei Adamchik
78 */
79 public class RequestQueue {
80 private static Logger logObj = Logger.getLogger(RequestQueue.class);
81
82 protected List queue;
83 protected int maxSize;
84 protected int timeout;
85
86 /**
87 * Constructor for RequestQueue.
88 *
89 * @param maxSize - maximum allowed number of threads in the queue.
90 * @param timeout - timeout in milliseconds that determines maximum possible
91 * wait time in the queue.
92 */
93 public RequestQueue(int maxSize, int timeout) {
94 this.maxSize = maxSize;
95 this.timeout = timeout;
96 this.queue = Collections.synchronizedList(new ArrayList());
97 }
98
99 public int getSize() {
100 synchronized (queue) {
101 return queue.size();
102 }
103 }
104
105 /**
106 * Queues current thread. This will block
107 * the caller till the thread is dequeued as a result
108 * of another thread calling <code>dequeueFirst</code>
109 * or as a result of a timeout.
110 *
111 * @return an object that represents an event or resource that
112 * caused
113 */
114 public RequestDequeue queueThread() {
115 RequestDequeue result = new RequestDequeue(Thread.currentThread().getName());
116
117 // queue up request
118 synchronized (queue) {
119 if (maxSize > 0 && queue.size() >= maxSize) {
120 result.setDequeueEventCode(RequestDequeue.QUEUE_FULL);
121 return result;
122 }
123
124 queue.add(result);
125 }
126
127 // wait
128 synchronized (result) {
129 boolean interrupted = false;
130 try {
131
132 if (logObj.isDebugEnabled()) {
133 logObj.debug(
134 "thread [" + result.getName() + "] queued for " + timeout);
135 }
136
137 // release lock and wait
138 result.wait(timeout);
139 } catch (InterruptedException e) {
140 interrupted = true;
141 }
142
143 // wait is over, remove itself from the queue
144 if (result.getDequeueEventCode() != RequestDequeue.DEQUEUE_SUCCESS) {
145
146 // timeout or interrupted
147 synchronized (queue) {
148 queue.remove(result);
149 int code =
150 (interrupted)
151 ? RequestDequeue.INTERRUPTED
152 : RequestDequeue.TIMED_OUT;
153 result.setDequeueEventCode(code);
154 }
155 }
156
157 return result;
158 }
159 }
160
161 /**
162 * Releases the first thread in the queue.
163 */
164 public boolean dequeueFirst(Object dequeuedObj) {
165 RequestDequeue first = null;
166 // Make sure we avoid nested locks - locking both queue & result object
167 // at the same time - this is a potential deadlock.
168
169 synchronized (queue) {
170 if (queue.size() > 0) {
171 first = (RequestDequeue) queue.get(0);
172 queue.remove(0);
173 }
174 }
175
176 // this is true when the queue contained at least one object
177 if (first != null) {
178 synchronized (first) {
179 first.setDequeueEventObject(dequeuedObj);
180 first.setDequeueEventCode(RequestDequeue.DEQUEUE_SUCCESS);
181 first.notifyAll();
182 if (logObj.isDebugEnabled()) {
183 logObj.debug("Dequeued thread: " + first.getName());
184 }
185 }
186
187 return true;
188 } else {
189 return false;
190 }
191 }
192 }