1 /* Reattore HTTP Server
2
3 Copyright (C) 2002 Michael Hope <michaelh@juju.net.nz>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 $Id: CachingInterceptor.java,v 1.8 2003/03/05 04:31:57 michaelh Exp $
20 */
21
22 package juju.reattore.server.intercept.impl;
23
24 import java.util.*;
25 import java.io.*;
26
27 import juju.reattore.protocol.http.*;
28 import juju.reattore.server.intercept.Interceptor;
29 import juju.reattore.util.GaugeStat;
30 import juju.reattore.util.CounterStat;
31 import juju.reattore.io.*;
32
33 /*** Interceptor that may cache the response from a lower level
34 interceptor.
35
36 @see Cache
37 @see CachableSource
38
39 @tag cache
40 @group Interceptor
41 @children Interceptor
42
43 @todo Lacks tests.
44 */
45 public class CachingInterceptor
46 implements Interceptor, Cache {
47
48 private static GaugeStat allocStat = new GaugeStat(CachingInterceptor.class, "Alloc");
49 private static CounterStat hitsStat = new CounterStat(CachingInterceptor.class, "Hits");
50 private static CounterStat missesStat = new CounterStat(CachingInterceptor.class, "Misses");
51
52 /*** Request path to List of CachableSource */
53 private final Map cache = new HashMap();
54 /*** CachableSource to List of CachableSource */
55 private final Map outstanding = new HashMap();
56
57 private Interceptor child;
58
59 /*** Set the child to cache.
60
61 @param child The child tree to wrap.
62 */
63 public void addChild(Interceptor child) {
64 this.child = child;
65 }
66
67 private List getRow(String req) {
68 List li;
69
70 if ((li = (List)cache.get(req)) == null) {
71 li = new LinkedList();
72 cache.put(req, li);
73 }
74
75 return li;
76 }
77
78 private CachableSource tryGet(String req) {
79 /* Look it up in the cache */
80 List li = getRow(req);
81
82 if (li.size() > 0) {
83 CachableSource ret = (CachableSource)li.remove(0);
84 if (ret.isExpired()) {
85 ret.release();
86 allocStat.dec();
87
88 return null;
89 }
90 else {
91 /* Have one in the cache. Use it. */
92 ret.rewind();
93 return ret;
94 }
95 }
96 else {
97 return null;
98 }
99 }
100
101 /*** @see Cache */
102 public boolean onClose(CachableSource so) {
103 List li = (List)outstanding.get(so);
104
105 li.add(so);
106
107 return false;
108 }
109
110 private boolean subProcess(HttpRequest req, HttpResponse resp) {
111 if (child.process(req, resp)) {
112 /* Child served it - perhaps cache */
113 if (resp.getStatus() == HttpResponse.SC_OK) {
114
115 CachableSource source = (CachableSource)resp.getBody();
116 source.setCacheCallback(this);
117 outstanding.put(source, getRow(req.getPath()));
118 allocStat.inc();
119
120 return true;
121 }
122 else {
123 return true;
124 }
125 }
126 else {
127 return false;
128 }
129 }
130
131 /*** @see Interceptor */
132 public boolean process(HttpRequest req, HttpResponse resp) {
133 String path = req.getPath();
134
135 List row = getRow(path);
136 CachableSource source;
137
138 if ((source = tryGet(path)) != null) {
139
140 resp.setBody((ByteSource)source);
141 resp.setStatus(HttpResponse.SC_OK);
142
143 hitsStat.inc();
144 return true;
145 }
146 else {
147 /* Not in the cache - ask the child and cache. */
148 missesStat.inc();
149 return subProcess(req, resp);
150 }
151 }
152 }
This page was automatically generated by Maven