001: /*
002: * The Apache Software License, Version 1.1
003: *
004: * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution, if
019: * any, must include the following acknowlegement:
020: * "This product includes software developed by the
021: * Caucho Technology (http://www.caucho.com/)."
022: * Alternately, this acknowlegement may appear in the software itself,
023: * if and wherever such third-party acknowlegements normally appear.
024: *
025: * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
026: * endorse or promote products derived from this software without prior
027: * written permission. For written permission, please contact
028: * info@caucho.com.
029: *
030: * 5. Products derived from this software may not be called "Resin"
031: * nor may "Resin" appear in their names without prior written
032: * permission of Caucho Technology.
033: *
034: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
035: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
036: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
037: * DISCLAIMED. IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS
038: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
039: * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
040: * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
041: * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
042: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
043: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
044: * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
045: *
046: * @author Sam
047: */
048:
049: package com.caucho.portal.generic;
050:
051: import javax.portlet.PortletMode;
052: import javax.portlet.WindowState;
053: import java.util.Locale;
054:
055: /**
056: * XXX: Cache implementation currently not complete.
057: *
058: * The ConnectionContext should start building a CacheKey
059: * as soon as it sees a window with expiration-cache != 0.
060: * It should do this in the action stage, because each window is
061: * seen in the action stage.
062: * It should add parameters for every child namespace encountered, to whatever
063: * depth.
064: *
065: * Then when it gets to the render stage, it can use the CacheKey
066: * to see if a cached value is available.
067: *
068: * If not, it inserts a CachingPortletWriteStream, and fills the cache.
069: */
070: public class CacheKey {
071: private String _namespace;
072: private int _namespaceValue;
073:
074: private PortletMode _portletMode;
075: private int _portletModeValue;
076:
077: private WindowState _windowState;
078: private int _windowStateValue;
079:
080: private long _value1, _value2; // parameters
081:
082: private String _contentType;
083: private int _contentTypeValue;
084: private Locale _locale;
085: private int _localeValue;
086: private boolean _isPrivate = true;
087: private String _sessionId;
088:
089: private String _stringValue;
090:
091: public void setNamespace(String namespace) {
092: _stringValue = null;
093: _namespace = namespace;
094: _namespaceValue = namespace.hashCode();
095: }
096:
097: public void setPortletMode(PortletMode portletMode) {
098: _stringValue = null;
099: _portletMode = portletMode;
100: _portletModeValue = portletMode.hashCode();
101: }
102:
103: public void setWindowState(WindowState windowState) {
104: _stringValue = null;
105: _windowState = windowState;
106: _windowStateValue = windowState.hashCode();
107: }
108:
109: private void add(String name, String value) {
110: _stringValue = null;
111: int v = (name == null ? 65353 : name.hashCode());
112:
113: _value1 += v;
114: _value2 += v + (value == null ? 65353 : value.hashCode());
115: }
116:
117: public void addParameter(String name, String[] values) {
118: _stringValue = null;
119: if (values == null || values.length == 0)
120: add(name, null);
121: else {
122: int i = values.length;
123:
124: while (i-- > 0)
125: add(name, values[i]);
126: }
127: }
128:
129: public void setContentType(String contentType) {
130: _stringValue = null;
131: _contentType = contentType;
132: _contentTypeValue = contentType.hashCode();
133: }
134:
135: /**
136: * When a cache key is created to check for a cached response the locale
137: * is set to the value of request.getLocale().
138: * A cache should first check the cache for an entry with the cacheKey
139: * as it is received, and then call cacheKey.setLocale(null) and try again.
140: *
141: * When a cache key is created to cache a response the locale is only set in
142: * the cache key if a portlet has called request.getLocale() or
143: * request.getLocales() or request.setLocale() method. It is set to the locale
144: * set by the portlet with response.setLocale(), or if the portlet does not
145: * call response.setLocale(), the value of request.getLocale().
146: */
147: public void setLocale(Locale locale) {
148: _stringValue = null;
149: _locale = locale;
150: _localeValue = locale.hashCode();
151: }
152:
153: public void setPrivate(boolean isPrivate) {
154: _isPrivate = isPrivate;
155: }
156:
157: public void setRequestedSessionId(String sessionId) {
158: _stringValue = null;
159: _sessionId = sessionId;
160: }
161:
162: public boolean isPrivate() {
163: return _isPrivate;
164: }
165:
166: public String getNamespace() {
167: return _namespace;
168: }
169:
170: public PortletMode getPortletMode() {
171: return _portletMode;
172: }
173:
174: public WindowState getWindowState() {
175: return _windowState;
176: }
177:
178: public String getContentType() {
179: return _contentType;
180: }
181:
182: public Locale getLocale() {
183: return _locale;
184: }
185:
186: /**
187: * Return a session id if isPrivate() is true, null if isPrivate() is false.
188: */
189: public String getRequestedSessionId() {
190: return _isPrivate ? _sessionId : null;
191: }
192:
193: /**
194: * Reset to a state similar to that following construction.
195: */
196: public void reset() {
197: _stringValue = null;
198:
199: _namespace = null;
200: _namespaceValue = 0;
201: _portletMode = null;
202: _portletModeValue = 0;
203: _windowState = null;
204: _windowStateValue = 0;
205: _value1 = 0;
206: _value2 = 0;
207:
208: _localeValue = 0;
209: _locale = null;
210: _contentTypeValue = 0;
211: _contentType = null;
212:
213: _isPrivate = true;
214: _sessionId = null;
215: }
216:
217: public int hashCode() {
218: int isPrivateValue = _isPrivate ? 31 : 33331;
219:
220: int sessionIdValue = _isPrivate && _sessionId != null ? _sessionId
221: .hashCode()
222: : 7331;
223: return (int) ((long) _namespaceValue * _portletModeValue
224: * _windowStateValue * _localeValue * _contentTypeValue
225: * isPrivateValue * sessionIdValue * _value1 * _value2);
226: }
227:
228: public boolean equals(Object o) {
229: if (o == null || !(o instanceof CacheKey))
230: return false;
231:
232: CacheKey other = (CacheKey) o;
233:
234: return (_namespaceValue == other._namespaceValue)
235: && (_portletModeValue == other._portletModeValue)
236: && (_windowStateValue == other._windowStateValue)
237: && (_value1 == other._value1)
238: && (_value2 == other._value2)
239: && (_localeValue == other._localeValue)
240: && (_contentTypeValue == other._contentTypeValue)
241: && (_isPrivate == other._isPrivate)
242: && (_isPrivate ? _sessionId != null : true)
243: && (_isPrivate ? _sessionId.equals(other._sessionId)
244: : true);
245: }
246:
247: static private void encode(long number, StringBuffer buf) {
248: int code;
249: char ch = '-';
250:
251: do {
252: code = ((int) number) & 0x3f; // 6 bits
253:
254: if (code < 26)
255: ch = (char) ('a' + code);
256: else if (code < 52)
257: ch = (char) ('A' + code - 26);
258: else if (code < 62)
259: ch = (char) ('0' + code - 52);
260: else if (code == 62 || code == 63)
261: ch = '_';
262: else
263: ch = 'z';
264:
265: number = number >> 6;
266:
267: } while (number != 0);
268: }
269:
270: /**
271: * Return a string that uniquely identifies this CacheKey.
272: * The set of characters that form the string is "A-Z a-z 0-9 _".
273: * That means the returned string is suitable as a file name, for example.
274: */
275: public String toString() {
276: if (_stringValue != null)
277: return _stringValue;
278:
279: StringBuffer buf = new StringBuffer();
280:
281: encode(_value1, buf);
282: encode(_value2, buf);
283:
284: int valuesIndex = buf.length();
285:
286: encode(_namespaceValue, buf);
287: encode(_portletModeValue, buf);
288: encode(_windowStateValue, buf);
289: encode(_localeValue, buf);
290: encode(_contentTypeValue, buf);
291:
292: if (_isPrivate)
293: buf.append(getRequestedSessionId());
294:
295: // mix up the string so that if it is truncated by the cache
296: // there is less likelyhood of significant loss
297:
298: int len = buf.length();
299: int half = len / 2;
300:
301: int i = valuesIndex;
302: int j = len - 1;
303:
304: while (i < half) {
305: char ch = buf.charAt(i);
306: buf.setCharAt(i, buf.charAt(j));
307: buf.setCharAt(j, ch);
308: i += 3;
309: j -= 3;
310: }
311:
312: i = valuesIndex;
313: j = half > i ? half : len;
314:
315: while (j < len) {
316: char ch = buf.charAt(i);
317: buf.setCharAt(i, buf.charAt(j));
318: buf.setCharAt(j, ch);
319: i += 5;
320: j += 5;
321: }
322:
323: // return the string
324:
325: _stringValue = buf.toString();
326:
327: return _stringValue;
328: }
329: } // CacheKey
|