001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: * $Header:$
018: */
019: package org.apache.beehive.netui.pageflow.scoping;
020:
021: import org.apache.beehive.netui.pageflow.scoping.internal.ScopedRequestImpl;
022: import org.apache.beehive.netui.pageflow.scoping.internal.ScopedResponseImpl;
023: import org.apache.beehive.netui.util.logging.Logger;
024: import org.apache.struts.upload.MultipartRequestWrapper;
025:
026: import javax.servlet.http.HttpServletRequest;
027: import javax.servlet.http.HttpServletResponse;
028: import javax.servlet.http.HttpSession;
029: import javax.servlet.ServletContext;
030: import javax.servlet.ServletRequest;
031: import javax.servlet.ServletRequestWrapper;
032: import javax.servlet.ServletResponse;
033: import javax.servlet.ServletResponseWrapper;
034:
035: import java.net.URI;
036: import java.net.URISyntaxException;
037:
038: /**
039: * Utilities for creating scoped wrapper versions of HttpRequest, HttpResponse, ServletContext. These
040: * wrappers are the basis for a scoped servlet environment, which can be used to scope the Struts
041: * framework.
042: */
043: public class ScopedServletUtils {
044: public static final String SCOPE_ID_PARAM = "jpfScopeID";
045:
046: static final String ATTR_PREFIX = "_netui:";
047: private static final String OVERRIDE_REQUEST_ATTR = ATTR_PREFIX
048: + "overrideRequest";
049: private static final String OVERRIDE_RESPONSE_ATTR = ATTR_PREFIX
050: + "overrideResponse";
051:
052: private static final Logger logger = Logger
053: .getInstance(ScopedServletUtils.class);
054:
055: /**
056: * Get the cached ScopedRequest wrapper. If none exists, creates one and caches it.
057: * @deprecated Use {@link #getScopedRequest(HttpServletRequest, String, ServletContext, Object, boolean)}.
058: *
059: * @param realRequest the "real" (outer) HttpServletRequest, which will be wrapped.
060: * @param overrideURI the request-URI for the wrapped object. This URI must begin with the context path.
061: * @param servletContext the current ServletContext.
062: * @param scopeKey the scope-key associated with the new (or looked-up) scoped request.
063: * @return the cached (or newly-created) ScopedRequest.
064: */
065: public static ScopedRequest getScopedRequest(
066: HttpServletRequest realRequest, String overrideURI,
067: ServletContext servletContext, Object scopeKey) {
068: return getScopedRequest(realRequest, overrideURI,
069: servletContext, scopeKey, false);
070: }
071:
072: /**
073: * Get the cached ScopedRequest wrapper. If none exists, creates one and caches it.
074: *
075: * @param realRequest the "real" (outer) HttpServletRequest, which will be wrapped.
076: * @param overrideURI the request-URI for the wrapped object. This URI must begin with the context path.
077: * @param servletContext the current ServletContext.
078: * @param scopeKey the scope-key associated with the new (or looked-up) scoped request.
079: * @param seeOuterRequestAttributes if <code>true</code>, a request attribute will be "seen" in the outer request,
080: * if it is not found within the scoped request; if <code>false</code>, attributes are only seen when
081: * they are present in the scoped request.
082: * @return the cached (or newly-created) ScopedRequest.
083: */
084: public static ScopedRequest getScopedRequest(
085: HttpServletRequest realRequest, String overrideURI,
086: ServletContext servletContext, Object scopeKey,
087: boolean seeOuterRequestAttributes) {
088: assert !(realRequest instanceof ScopedRequest);
089:
090: String requestAttr = getScopedName(OVERRIDE_REQUEST_ATTR,
091: scopeKey);
092: ScopedRequest scopedRequest = (ScopedRequest) realRequest
093: .getAttribute(requestAttr);
094:
095: //
096: // If it doesn't exist, create it and cache it.
097: //
098: if (scopedRequest == null) {
099: //
100: // The override URI must start with a slash -- it's webapp-relative.
101: //
102: if (overrideURI != null && !overrideURI.startsWith("/"))
103: overrideURI = '/' + overrideURI;
104:
105: scopedRequest = new ScopedRequestImpl(realRequest,
106: overrideURI, scopeKey, servletContext,
107: seeOuterRequestAttributes);
108: realRequest.setAttribute(requestAttr, scopedRequest);
109: }
110:
111: return scopedRequest;
112: }
113:
114: /**
115: * Get the cached wrapper servlet response. If none exists, creates one and caches it.
116: *
117: * @param realResponse the "real" (outer) ServletResponse, which will be wrapped.
118: * @param scopedRequest the ScopedRequest returned from {@link #getScopedRequest}.
119: * @return the cached (or newly-created) ScopedResponse.
120: */
121: public static ScopedResponse getScopedResponse(
122: HttpServletResponse realResponse,
123: ScopedRequest scopedRequest) {
124: assert !(realResponse instanceof ScopedResponse);
125:
126: String responseAttr = getScopedName(OVERRIDE_RESPONSE_ATTR,
127: scopedRequest.getScopeKey());
128: HttpServletRequest outerRequest = scopedRequest
129: .getOuterRequest();
130: ScopedResponse scopedResponse = (ScopedResponse) outerRequest
131: .getAttribute(responseAttr);
132:
133: //
134: // If it doesn't exist, create it and cache it.
135: //
136: if (scopedResponse == null) {
137: scopedResponse = new ScopedResponseImpl(realResponse);
138: outerRequest.setAttribute(responseAttr, scopedResponse);
139: }
140:
141: return scopedResponse;
142: }
143:
144: /**
145: * Find all scoped objects ({@link ScopedRequest}, {@link ScopedResponse})
146: * which have a certain scope-key, replaces this scope-key with the new one, and re-caches the objects
147: * the new scope-key.
148: * @param oldScopeKey
149: * @param newScopeKey
150: * @param request the real (outer) request, where the scoped objects are cached.
151: */
152: public static void renameScope(Object oldScopeKey,
153: Object newScopeKey, HttpServletRequest request) {
154: assert !(request instanceof ScopedRequest);
155:
156: String requestAttr = getScopedName(OVERRIDE_REQUEST_ATTR,
157: oldScopeKey);
158: String responseAttr = getScopedName(OVERRIDE_RESPONSE_ATTR,
159: oldScopeKey);
160: ScopedRequest scopedRequest = (ScopedRequest) request
161: .getAttribute(requestAttr);
162: ScopedResponse scopedResponse = (ScopedResponse) request
163: .getAttribute(responseAttr);
164:
165: if (scopedRequest != null) {
166: scopedRequest.renameScope(newScopeKey);
167: request.removeAttribute(requestAttr);
168: requestAttr = getScopedName(OVERRIDE_REQUEST_ATTR,
169: newScopeKey);
170: request.setAttribute(requestAttr, scopedRequest);
171: } else {
172: ScopedRequestImpl.renameSessionScope(oldScopeKey,
173: newScopeKey, request);
174: }
175:
176: if (scopedResponse != null) {
177: request.removeAttribute(responseAttr);
178: responseAttr = getScopedName(OVERRIDE_RESPONSE_ATTR,
179: newScopeKey);
180: request.setAttribute(responseAttr, scopedResponse);
181: }
182: }
183:
184: /**
185: * Get a scoped version of a given name.
186: *
187: * @param baseName the name to be scoped.
188: * @param scopeKey the context key for scoping the name.
189: * @return a scoped version of the given name.
190: */
191: public static String getScopedName(String baseName, Object scopeKey) {
192: return scopeKey + baseName;
193: }
194:
195: /**
196: * Tell whether this is a scoped request.
197: *
198: * @param request the ServletRequest to test.
199: * @return <code>true</code> if the given ServletRequest is a ScopedRequest.
200: */
201: /*
202: public static boolean isScoped( ServletRequest request )
203: {
204:
205: }
206: */
207:
208: /**
209: * Get the outer (unwrapped) request.
210: *
211: * @param request the request to unwrap.
212: * @return the outer request, if the given request is a ScopedRequest (or wraps a ScopedRequest);
213: * otherwise, the given request itself.
214: */
215: public static HttpServletRequest getOuterRequest(
216: HttpServletRequest request) {
217: ScopedRequest scopedRequest = unwrapRequest(request);
218: return scopedRequest != null ? scopedRequest.getOuterRequest()
219: : request;
220: }
221:
222: /**
223: * Get the outer (unwrapped) request.
224: *
225: * @param request the request to unwrap.
226: * @return the outer request, if the given request is a ScopedRequest (or wraps a ScopedRequest);
227: * otherwise, the given request itself.
228: */
229: public static ServletRequest getOuterServletRequest(
230: ServletRequest request) {
231: ScopedRequest scopedRequest = unwrapRequest(request);
232: return scopedRequest != null ? scopedRequest.getOuterRequest()
233: : request;
234: }
235:
236: /**
237: * Unwraps the contained ScopedRequest from the given ServletRequest, which may be a
238: * ServletRequestWrapper.
239: *
240: * @param request the ScopedRequest, or a wrapper (ServletRequestWrapper) around it.
241: * @return the unwrapped ScopedRequest.
242: *
243: * @exclude
244: */
245: public static ScopedRequest unwrapRequest(ServletRequest request) {
246: // Unwrap the multipart request, if there is one.
247: if (request instanceof MultipartRequestWrapper) {
248: request = ((MultipartRequestWrapper) request).getRequest();
249: }
250:
251: while (request instanceof ServletRequestWrapper) {
252: if (request instanceof ScopedRequest) {
253: return (ScopedRequest) request;
254: } else {
255: request = ((ServletRequestWrapper) request)
256: .getRequest();
257: }
258: }
259:
260: return null;
261: }
262:
263: /**
264: * Unwraps the contained ScopedResponseImpl from the given ServletResponse, which may be a
265: * ServletResponseWrapper.
266: *
267: * @param response the ScopedResponse, or a wrapper (ServletResponseWrapper) around it.
268: * @return the unwrapped ScopedResponseImpl.
269: *
270: * @exclude
271: */
272: public static ScopedResponse unwrapResponse(ServletResponse response) {
273: while (response instanceof ServletResponseWrapper) {
274: if (response instanceof ScopedResponse) {
275: return (ScopedResponse) response;
276: } else {
277: response = ((ServletResponseWrapper) response)
278: .getResponse();
279: }
280: }
281:
282: return null;
283: }
284:
285: /**
286: * If the request is a ScopedRequest, this returns an attribute name scoped to
287: * that request's scope-ID; otherwise, it returns the given attribute name.
288: *
289: * @exclude
290: */
291: public static String getScopedSessionAttrName(String attrName,
292: HttpServletRequest request) {
293: String requestScopeParam = request.getParameter(SCOPE_ID_PARAM);
294:
295: if (requestScopeParam != null) {
296: return getScopedName(attrName, requestScopeParam);
297: }
298:
299: ScopedRequest scopedRequest = unwrapRequest(request);
300: return scopedRequest != null ? scopedRequest
301: .getScopedName(attrName) : attrName;
302: }
303:
304: /**
305: * If the request is a ScopedRequest, this returns an attribute whose name is scoped to that request's scope-ID;
306: * otherwise, it is a straight passthrough to {@link HttpSession#getAttribute}.
307: *
308: * @exclude
309: */
310: public static Object getScopedSessionAttr(String attrName,
311: HttpServletRequest request) {
312: HttpSession session = request.getSession(false);
313:
314: if (session != null) {
315: return session.getAttribute(getScopedSessionAttrName(
316: attrName, request));
317: } else {
318: return null;
319: }
320: }
321:
322: /**
323: * If the request is a ScopedRequest, this sets an attribute whose name is scoped to that request's scope-ID;
324: * otherwise, it is a straight passthrough to {@link HttpSession#setAttribute}.
325: *
326: * @exclude
327: */
328: public static void setScopedSessionAttr(String attrName,
329: Object val, HttpServletRequest request) {
330: request.getSession().setAttribute(
331: getScopedSessionAttrName(attrName, request), val);
332: }
333:
334: /**
335: * If the request is a ScopedRequest, this removes an attribute whose name is scoped to that request's scope-ID;
336: * otherwise, it is a straight passthrough to {@link HttpSession#removeAttribute}.
337: *
338: * @exclude
339: */
340: public static void removeScopedSessionAttr(String attrName,
341: HttpServletRequest request) {
342: HttpSession session = request.getSession(false);
343:
344: if (session != null) {
345: session.removeAttribute(getScopedSessionAttrName(attrName,
346: request));
347: }
348: }
349:
350: /**
351: * Get an attribute from the given request, and if it is a {@link ScopedRequest}, ensure that the attribute
352: * is <strong>not</strong> "showing through" from the outer request, even if the ScopedRequest allows that by
353: * default.
354: *
355: * @exclude
356: */
357: public static Object getScopedRequestAttribute(String attrName,
358: ServletRequest request) {
359: if (request instanceof ScopedRequest) {
360: return ((ScopedRequest) request).getAttribute(attrName,
361: false);
362: }
363:
364: return request.getAttribute(attrName);
365: }
366:
367: /**
368: * Get the request URI, relative to the webapp root.
369: *
370: * @param request the current HttpServletRequest.
371: */
372: public static final String getRelativeURI(HttpServletRequest request) {
373: return request.getServletPath();
374: }
375:
376: /**
377: * Get a URI relative to the webapp root.
378: *
379: * @param request the current HttpServletRequest.
380: * @param uri the URI which should be made relative.
381: */
382: public static final String getRelativeURI(
383: HttpServletRequest request, String uri) {
384: return getRelativeURI(request.getContextPath(), uri);
385: }
386:
387: /**
388: * Get a URI relative to a given webapp root.
389: *
390: * @param contextPath the webapp context path, e.g., "/myWebapp"
391: * @param uri the URI which should be made relative.
392: */
393: public static final String getRelativeURI(String contextPath,
394: String uri) {
395: String requestUrl = uri;
396: int overlap = requestUrl.indexOf(contextPath + '/');
397: assert overlap != -1 : "contextPath: " + contextPath
398: + ", uri: " + uri;
399: return requestUrl.substring(overlap + contextPath.length());
400: }
401:
402: /**
403: * Resolve "." and ".." in a URI.
404: * @exclude
405: */
406: public static String normalizeURI(String uri) {
407: //
408: // If it's a relative URI, normalize it. Note that we don't want to create a URI
409: // (very expensive) unless we think we'll need to. "./" catches "../" and "./".
410: //
411: if (uri.indexOf("./") != -1) {
412: try {
413: uri = new URI(uri).normalize().toString();
414: } catch (URISyntaxException e) {
415: logger.error("Could not parse relative URI " + uri);
416: }
417: }
418:
419: return uri;
420: }
421:
422: /**
423: * @exclude
424: */
425: public static String decodeURI(HttpServletRequest request) {
426: return request.getContextPath() + request.getServletPath(); // TODO: always decoded?
427: }
428: }
|