001: /*
002: * Copyright 2005-2007 Noelios Consulting.
003: *
004: * The contents of this file are subject to the terms of the Common Development
005: * and Distribution License (the "License"). You may not use this file except in
006: * compliance with the License.
007: *
008: * You can obtain a copy of the license at
009: * http://www.opensource.org/licenses/cddl1.txt See the License for the specific
010: * language governing permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL HEADER in each file and
013: * include the License file at http://www.opensource.org/licenses/cddl1.txt If
014: * applicable, add the following below this CDDL HEADER, with the fields
015: * enclosed by brackets "[]" replaced with your own identifying information:
016: * Portions Copyright [yyyy] [name of copyright owner]
017: */
018:
019: package org.restlet.util;
020:
021: import java.util.List;
022: import java.util.Random;
023: import java.util.concurrent.CopyOnWriteArrayList;
024:
025: import org.restlet.Restlet;
026: import org.restlet.Route;
027: import org.restlet.data.Request;
028: import org.restlet.data.Response;
029:
030: /**
031: * Modifiable list of routes with some helper methods. Note that this class
032: * implements the java.util.List interface using the Route class as the generic
033: * type. This allows you to use an instance of this class as any other
034: * java.util.List, in particular all the helper methods in
035: * java.util.Collections.<br/> <br/> Note that structural changes to this list
036: * are thread-safe, using an underlying
037: * {@link java.util.concurrent.CopyOnWriteArrayList}.
038: *
039: * @author Jerome Louvel (contact@noelios.com)
040: * @see java.util.Collections
041: * @see java.util.List
042: */
043: public final class RouteList extends WrapperList<Route> {
044: /** The index of the last route used in the round robin mode. */
045: private int lastIndex;
046:
047: /**
048: * Constructor.
049: */
050: public RouteList() {
051: super (new CopyOnWriteArrayList<Route>());
052: this .lastIndex = -1;
053: }
054:
055: /**
056: * Constructor.
057: *
058: * @param delegate
059: * The delegate list.
060: */
061: public RouteList(List<Route> delegate) {
062: super (new CopyOnWriteArrayList<Route>(delegate));
063: this .lastIndex = -1;
064: }
065:
066: /**
067: * Returns the best route match for a given call.
068: *
069: * @param request
070: * The request to score.
071: * @param response
072: * The response to score.
073: * @param requiredScore
074: * The minimum score required to have a match.
075: * @return The best route match or null.
076: */
077: public Route getBest(Request request, Response response,
078: float requiredScore) {
079: Route result = null;
080: float bestScore = 0F;
081: float score;
082: for (Route current : this ) {
083: score = current.score(request, response);
084:
085: if ((score > bestScore) && (score >= requiredScore)) {
086: bestScore = score;
087: result = current;
088: }
089: }
090:
091: return result;
092: }
093:
094: /**
095: * Returns the first route match for a given call.
096: *
097: * @param request
098: * The request to score.
099: * @param response
100: * The response to score.
101: * @param requiredScore
102: * The minimum score required to have a match.
103: * @return The first route match or null.
104: */
105: public Route getFirst(Request request, Response response,
106: float requiredScore) {
107: for (Route current : this ) {
108: if (current.score(request, response) >= requiredScore)
109: return current;
110: }
111:
112: // No match found
113: return null;
114: }
115:
116: /**
117: * Returns the last route match for a given call.
118: *
119: * @param request
120: * The request to score.
121: * @param response
122: * The response to score.
123: * @param requiredScore
124: * The minimum score required to have a match.
125: * @return The last route match or null.
126: */
127: public Route getLast(Request request, Response response,
128: float requiredScore) {
129: for (int j = size() - 1; (j >= 0); j--) {
130: Route route = get(j);
131: if (route.score(request, response) >= requiredScore)
132: return route;
133: }
134:
135: // No match found
136: return null;
137: }
138:
139: /**
140: * Returns a next route match in a round robin mode for a given call.
141: *
142: * @param request
143: * The request to score.
144: * @param response
145: * The response to score.
146: * @param requiredScore
147: * The minimum score required to have a match.
148: * @return A next route or null.
149: */
150: public Route getNext(Request request, Response response,
151: float requiredScore) {
152: if (!isEmpty()) {
153: for (int initialIndex = lastIndex++; initialIndex != lastIndex; lastIndex++) {
154: if (lastIndex >= size()) {
155: lastIndex = 0;
156: }
157:
158: Route route = get(lastIndex);
159: if (route.score(request, response) >= requiredScore)
160: return route;
161: }
162: }
163:
164: // No match found
165: return null;
166: }
167:
168: /**
169: * Returns a random route match for a given call.
170: *
171: * @param request
172: * The request to score.
173: * @param response
174: * The response to score.
175: * @param requiredScore
176: * The minimum score required to have a match.
177: * @return A random route or null.
178: */
179: public Route getRandom(Request request, Response response,
180: float requiredScore) {
181: int length = size();
182: if (length > 0) {
183: int j = new Random().nextInt(length);
184: Route route = get(j);
185: if (route.score(request, response) >= requiredScore)
186: return route;
187:
188: boolean loopedAround = false;
189: do {
190: if (j == length && loopedAround == false) {
191: j = 0;
192: loopedAround = true;
193: }
194: route = get(j++);
195: if (route.score(request, response) >= requiredScore)
196: return route;
197: } while (j < length || !loopedAround);
198: }
199:
200: // No match found
201: return null;
202: }
203:
204: /**
205: * Removes all routes routing to a given target.
206: *
207: * @param target
208: * The target Restlet to detach.
209: */
210: public void removeAll(Restlet target) {
211: for (int i = size() - 1; i >= 0; i--) {
212: if (get(i).getNext() == target)
213: remove(i);
214: }
215: }
216:
217: /**
218: * Returns a view of the portion of this list between the specified
219: * fromIndex, inclusive, and toIndex, exclusive.
220: *
221: * @param fromIndex
222: * The start position.
223: * @param toIndex
224: * The end position (exclusive).
225: * @return The sub-list.
226: */
227: public RouteList subList(int fromIndex, int toIndex) {
228: return new RouteList(getDelegate().subList(fromIndex, toIndex));
229: }
230: }
|