001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.server.dispatch;
031:
032: import com.caucho.lifecycle.Lifecycle;
033: import com.caucho.util.LruCache;
034: import com.caucho.vfs.Dependency;
035:
036: import javax.annotation.PostConstruct;
037: import java.util.ArrayList;
038: import java.util.HashMap;
039: import java.util.Iterator;
040: import java.util.logging.Logger;
041:
042: /**
043: * The dispatch server is responsible for building Invocations,
044: * specifically for creating the FilterChain for the invocation.
045: */
046: public class DispatchServer implements Dependency {
047: private String _serverId = "";
048:
049: private DispatchBuilder _dispatchBuilder;
050:
051: // Cache of uri -> invocation maps
052: private LruCache<Object, Invocation> _invocationCache;
053:
054: private InvocationDecoder _invocationDecoder;
055:
056: private HashMap<String, Object> _attributeMap = new HashMap<String, Object>();
057:
058: private ArrayList<ServerListener> _listeners = new ArrayList<ServerListener>();
059:
060: private int _invocationCacheSize = 64 * 1024;
061: private int _maxURLLength = 256;
062:
063: private final Lifecycle _lifecycle = new Lifecycle();
064:
065: /**
066: * Gets the server's id.
067: */
068: public String getServerId() {
069: return _serverId;
070: }
071:
072: /**
073: * Gets the server's id.
074: */
075: public void setServerId(String serverId) {
076: _serverId = serverId;
077: }
078:
079: /**
080: * Gets the class loader.
081: */
082: public ClassLoader getClassLoader() {
083: return null;
084: }
085:
086: /**
087: * Sets the dispatch builder.
088: */
089: public void setDispatchBuilder(DispatchBuilder builder) {
090: _dispatchBuilder = builder;
091: }
092:
093: /**
094: * Gets the dispatch builder.
095: */
096: public DispatchBuilder getDispatchBuilder() {
097: return _dispatchBuilder;
098: }
099:
100: /**
101: * Return true for ignoring client disconnect.
102: */
103: public boolean isIgnoreClientDisconnect() {
104: return true;
105: }
106:
107: /**
108: * Sets the invocation cache size.
109: */
110: public void setInvocationCacheSize(int size) {
111: _invocationCacheSize = size;
112:
113: if (_invocationCacheSize <= 16)
114: _invocationCacheSize = 16;
115: }
116:
117: /**
118: * Sets the max url length.
119: */
120: public void setInvocationCacheMaxURLLength(int length) {
121: _maxURLLength = length;
122: }
123:
124: /**
125: * Initializes the server.
126: */
127: @PostConstruct
128: public void init() {
129: _invocationCache = new LruCache<Object, Invocation>(
130: _invocationCacheSize);
131: }
132:
133: /**
134: * Returns the InvocationDecoder.
135: */
136: public InvocationDecoder getInvocationDecoder() {
137: if (_invocationDecoder == null)
138: _invocationDecoder = new InvocationDecoder();
139:
140: return _invocationDecoder;
141: }
142:
143: /**
144: * Sets URL encoding.
145: */
146: public String getURLCharacterEncoding() {
147: return getInvocationDecoder().getEncoding();
148: }
149:
150: /**
151: * Returns the invocation decoder for configuration.
152: */
153: public InvocationDecoder createInvocationDecoder() {
154: return getInvocationDecoder();
155: }
156:
157: /**
158: * Returns the cached invocation.
159: */
160: public final Invocation getInvocation(Object protocolKey) {
161: Invocation invocation = null;
162:
163: // XXX: see if can remove this
164: LruCache<Object, Invocation> invocationCache = _invocationCache;
165:
166: if (invocationCache != null)
167: invocation = invocationCache.get(protocolKey);
168:
169: if (invocation == null)
170: return null;
171: else if (invocation.isModified()) {
172: return null;
173: } else {
174: return invocation;
175: }
176: }
177:
178: /**
179: * Creates an invocation.
180: */
181: public Invocation createInvocation() {
182: return new Invocation();
183: }
184:
185: /**
186: * Builds the invocation, saving its value keyed by the protocol key.
187: *
188: * @param protocolKey protocol-specific key to save the invocation in
189: * @param invocation the invocation to build.
190: */
191: public Invocation buildInvocation(Object protocolKey,
192: Invocation invocation) throws Throwable {
193: invocation = buildInvocation(invocation);
194:
195: // XXX: see if can remove this, and rely on the invocation cache existing
196: LruCache<Object, Invocation> invocationCache = _invocationCache;
197:
198: if (invocationCache != null) {
199: synchronized (invocationCache) {
200: Invocation oldInvocation;
201: oldInvocation = invocationCache.get(protocolKey);
202:
203: // server/10r2
204: if (oldInvocation != null
205: && !oldInvocation.isModified())
206: return oldInvocation;
207:
208: if (invocation.getURLLength() < _maxURLLength) {
209: invocationCache.put(protocolKey, invocation);
210: }
211: }
212: }
213:
214: return invocation;
215: }
216:
217: /**
218: * Builds the invocation.
219: */
220: public Invocation buildInvocation(Invocation invocation)
221: throws Throwable {
222: return getDispatchBuilder().buildInvocation(invocation);
223: }
224:
225: /**
226: * Clears the proxy cache.
227: */
228: public void clearCache() {
229: // XXX: see if can remove this, and rely on the invocation cache existing
230: LruCache<Object, Invocation> invocationCache = _invocationCache;
231:
232: if (invocationCache != null) {
233: synchronized (invocationCache) {
234: invocationCache.clear();
235: }
236: }
237: }
238:
239: /**
240: * Clears matching entries.
241: */
242: protected void invalidateMatchingInvocations(
243: InvocationMatcher matcher) {
244: // XXX: see if can remove this, and rely on the invocation cache existing
245: LruCache<Object, Invocation> invocationCache = _invocationCache;
246:
247: if (invocationCache != null) {
248: synchronized (invocationCache) {
249: Iterator<LruCache.Entry<Object, Invocation>> iter;
250: iter = invocationCache.iterator();
251:
252: while (iter.hasNext()) {
253: LruCache.Entry<Object, Invocation> entry = iter
254: .next();
255: Invocation value = entry.getValue();
256:
257: if (value != null && matcher.isMatch(value)) {
258: iter.remove();
259: }
260: }
261: }
262: }
263: }
264:
265: /**
266: * Returns the invocations.
267: */
268: public ArrayList<Invocation> getInvocations() {
269: // XXX: see if can remove this, and rely on the invocation cache existing
270: LruCache<Object, Invocation> invocationCache = _invocationCache;
271:
272: if (invocationCache != null) {
273: ArrayList<Invocation> invocationList = new ArrayList<Invocation>();
274:
275: synchronized (invocationCache) {
276: Iterator<Invocation> iter;
277: iter = invocationCache.values();
278:
279: while (iter.hasNext()) {
280: invocationList.add(iter.next());
281: }
282: }
283:
284: return invocationList;
285: }
286:
287: return null;
288: }
289:
290: /**
291: * Returns the invocation cache hit count.
292: */
293: public long getInvocationCacheHitCount() {
294: LruCache<Object, Invocation> invocationCache = _invocationCache;
295:
296: if (invocationCache != null)
297: return invocationCache.getHitCount();
298: else
299: return 0;
300: }
301:
302: /**
303: * Returns the invocation cache hit count.
304: */
305: public long getInvocationCacheMissCount() {
306: LruCache<Object, Invocation> invocationCache = _invocationCache;
307:
308: if (invocationCache != null)
309: return invocationCache.getMissCount();
310: else
311: return 0;
312: }
313:
314: /**
315: * Returns the named attribute.
316: *
317: * @param key the attribute key
318: *
319: * @return the attribute value
320: */
321: public synchronized Object getAttribute(String key) {
322: return _attributeMap.get(key);
323: }
324:
325: /**
326: * Returns an iteration of attribute names.
327: *
328: * @return the iteration of names
329: */
330: public synchronized Iterator getAttributeNames() {
331: return _attributeMap.keySet().iterator();
332: }
333:
334: /**
335: * Sets the named attribute.
336: *
337: * @param key the attribute key
338: * @param value the attribute value
339: *
340: * @return the old attribute value
341: */
342: public synchronized Object setAttribute(String key, Object value) {
343: return _attributeMap.put(key, value);
344: }
345:
346: /**
347: * Removes the named attribute.
348: *
349: * @param key the attribute key
350: *
351: * @return the old attribute value
352: */
353: public synchronized Object removeAttribute(String key) {
354: return _attributeMap.remove(key);
355: }
356:
357: /**
358: * Returns true if the server has been modified and needs restarting.
359: */
360: public boolean isModified() {
361: return false;
362: }
363:
364: /**
365: * Log the reason for modification.
366: */
367: public boolean logModified(Logger log) {
368: return false;
369: }
370:
371: /**
372: * Adds a listener.
373: */
374: public void addServerListener(ServerListener listener) {
375: _listeners.add(listener);
376: }
377:
378: /**
379: * Returns true if the server is destroyed.
380: */
381: public boolean isDestroyed() {
382: return _lifecycle.isDestroyed();
383: }
384:
385: /**
386: * Closes the server.
387: */
388: public void update() {
389: destroy();
390: }
391:
392: /**
393: * Closes the server.
394: */
395: public void restart() {
396: destroy();
397: }
398:
399: /**
400: * Closes the server.
401: */
402: public void destroy() {
403: ArrayList<ServerListener> listeners;
404: listeners = new ArrayList<ServerListener>(_listeners);
405: _listeners.clear();
406:
407: for (int i = 0; i < listeners.size(); i++) {
408: ServerListener listener = listeners.get(i);
409:
410: listener.closeEvent(this);
411: }
412:
413: _invocationCache = null;
414: }
415: }
|