001: /******************************************************************************
002: * JBoss, a division of Red Hat *
003: * Copyright 2006, Red Hat Middleware, LLC, and individual *
004: * contributors as indicated by the @authors tag. See the *
005: * copyright.txt in the distribution for a full listing of *
006: * individual contributors. *
007: * *
008: * This is free software; you can redistribute it and/or modify it *
009: * under the terms of the GNU Lesser General Public License as *
010: * published by the Free Software Foundation; either version 2.1 of *
011: * the License, or (at your option) any later version. *
012: * *
013: * This software is distributed in the hope that it will be useful, *
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of *
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
016: * Lesser General Public License for more details. *
017: * *
018: * You should have received a copy of the GNU Lesser General Public *
019: * License along with this software; if not, write to the Free *
020: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
021: * 02110-1301 USA, or see the FSF site: http://www.fsf.org. *
022: ******************************************************************************/package org.jboss.portal.wsrp.consumer;
023:
024: import org.jboss.portal.common.net.URLTools;
025: import org.jboss.portal.common.util.Tools;
026: import org.jboss.portal.portlet.PortletInvokerException;
027: import org.jboss.portal.portlet.invocation.PortletInvocation;
028: import org.jboss.portal.portlet.invocation.response.ErrorResponse;
029: import org.jboss.portal.portlet.invocation.response.FragmentResponse;
030: import org.jboss.portal.portlet.invocation.response.PortletInvocationResponse;
031: import org.jboss.portal.portlet.spi.PortletInvocationContext;
032: import org.jboss.portal.wsrp.WSRPPortletURL;
033: import org.jboss.portal.wsrp.WSRPResourceURL;
034: import org.jboss.portal.wsrp.WSRPRewritingConstants;
035: import org.jboss.portal.wsrp.WSRPTypeFactory;
036: import org.jboss.portal.wsrp.core.CacheControl;
037: import org.jboss.portal.wsrp.core.GetMarkup;
038: import org.jboss.portal.wsrp.core.MarkupContext;
039: import org.jboss.portal.wsrp.core.MarkupResponse;
040: import org.jboss.portal.wsrp.core.PortletContext;
041: import org.jboss.portal.wsrp.core.RuntimeContext;
042: import org.jboss.portal.wsrp.core.UserContext;
043:
044: import java.io.PrintWriter;
045:
046: /**
047: * @author <a href="mailto:chris.laprun@jboss.com">Chris Laprun</a>
048: * @version $Revision: 8784 $
049: * @since 2.4 (May 31, 2006)
050: */
051: public class RenderHandler extends InvocationHandler {
052:
053: /** The separator constant. */
054: private static final String SEPARATOR = "_";
055:
056: /** . */
057: private final ThreadLocal wsrpURLRewriterLocal = new ThreadLocal() {
058: protected Object initialValue() {
059: return new WSRPURLRewriter();
060: }
061: };
062:
063: /** . */
064: private final ThreadLocal resourceURLRewriterLocal = new ThreadLocal() {
065: protected Object initialValue() {
066: return new ResourceURLRewriter();
067: }
068: };
069:
070: public RenderHandler(WSRPConsumerImpl consumer) {
071: super (consumer);
072: }
073:
074: protected Object prepareRequest(RequestPrecursor requestPrecursor,
075: PortletInvocation invocation) {
076: // Create the markup request
077: PortletContext portletContext = requestPrecursor
078: .getPortletContext();
079: log.debug("Consumer about to attempt rendering portlet '"
080: + portletContext.getPortletHandle() + "'");
081: return WSRPTypeFactory.createMarkupRequest(portletContext,
082: requestPrecursor.runtimeContext,
083: requestPrecursor.markupParams);
084: }
085:
086: protected PortletInvocationResponse processResponse(
087: Object response, PortletInvocation invocation,
088: RequestPrecursor requestPrecursor) {
089: MarkupResponse markupResponse = (MarkupResponse) response;
090: log.debug("Starting processing response");
091:
092: // process the response
093: consumer.getSessionHandler().updateSessionIfNeeded(
094: markupResponse.getSessionContext(), invocation,
095: requestPrecursor.getPortletHandle());
096:
097: MarkupContext markupContext = markupResponse.getMarkupContext();
098: String markup = markupContext.getMarkupString();
099: byte[] binary = markupContext.getMarkupBinary();
100: if (markup != null && binary != null) {
101: return new ErrorResponse(
102: new IllegalArgumentException(
103: "Markup response cannot contain both string and binary "
104: + "markup. Per Section 6.1.10 of the WSRP specification, this is a Producer error."));
105: }
106:
107: if (markup == null && binary == null) {
108: if (markupContext.getUseCachedMarkup().booleanValue()) {
109: //todo: deal with cache
110: } else {
111: return new ErrorResponse(
112: new IllegalArgumentException(
113: "Markup response must contain at least string or binary"
114: + " markup. Per Section 6.1.10 of the WSRP specification, this is a Producer error."));
115: }
116: }
117:
118: if (markup != null && markup.length() > 0) {
119: markup = processMarkup(markup, invocation, Boolean.TRUE
120: .equals(markupContext.getRequiresUrlRewriting()));
121: } else {
122: // todo: need to deal with binary
123: }
124:
125: FragmentResponse result = new FragmentResponse();
126:
127: String mimeType = markupContext.getMimeType();
128: if (mimeType == null || mimeType.length() == 0) {
129: return new ErrorResponse(new IllegalArgumentException(
130: "No MIME type was provided for portlet content."));
131: }
132: result.setContentType(mimeType);
133:
134: result.setTitle(markupContext.getPreferredTitle());
135:
136: // cache markup if possible
137: cacheMarkupIfNeeded(markupContext, result);
138:
139: PrintWriter writer = result.getWriter();
140: writer.write(markup);
141:
142: log.debug("Response processed");
143: return result;
144: }
145:
146: protected void updateUserContext(Object request,
147: UserContext userContext) {
148: getRenderRequest(request).setUserContext(userContext);
149: }
150:
151: protected void updateRegistrationContext(Object request)
152: throws PortletInvokerException {
153: getRenderRequest(request).setRegistrationContext(
154: consumer.getRegistrationContext());
155: }
156:
157: protected RuntimeContext getRuntimeContextFrom(Object request) {
158: return getRenderRequest(request).getRuntimeContext();
159: }
160:
161: protected Object performRequest(Object request) throws Exception {
162: GetMarkup renderRequest = getRenderRequest(request);
163: log.debug("getMarkup on '"
164: + renderRequest.getPortletContext().getPortletHandle()
165: + "'");
166: return consumer.getMarkupService().getMarkup(renderRequest);
167: }
168:
169: private GetMarkup getRenderRequest(Object request) {
170: if (request instanceof GetMarkup) {
171: return (GetMarkup) request;
172: }
173:
174: throw new IllegalArgumentException(
175: "RenderHandler: Request is not a GetMarkup request!");
176: }
177:
178: private String processMarkup(String markup,
179: PortletInvocation invocation, boolean rewriteURLs) {
180: // fix-me: how to deal with fragment header? => interceptor?
181: String prefix = getNamespaceFrom(invocation.getWindowContext())
182: + SEPARATOR;
183:
184: markup = Tools.replace(markup,
185: WSRPRewritingConstants.WSRP_REWRITE_TOKEN, prefix);
186:
187: if (rewriteURLs) {
188: WSRPURLRewriter rewriter = (WSRPURLRewriter) wsrpURLRewriterLocal
189: .get();
190: rewriter.setContext(invocation.getPortletContext());
191: rewriter.setSecure(invocation.getSecurityContext()
192: .isSecure());
193: String userId = invocation.getUserContext().getId();
194: rewriter.setAuthenticated(userId != null); // is this correct?
195: markup = URLTools.replaceURLsBy(markup, rewriter);
196: }
197:
198: // means that the producer generated the URLs, so handle resources...
199: ResourceURLRewriter rewriter = (ResourceURLRewriter) resourceURLRewriterLocal
200: .get();
201: return URLTools.replaceURLsBy(markup, rewriter);
202: }
203:
204: private void cacheMarkupIfNeeded(MarkupContext markupContext,
205: FragmentResponse result) {
206: CacheControl cacheControl = markupContext.getCacheControl();
207: int expires;
208: if (cacheControl != null) {
209: expires = cacheControl.getExpires();
210: String userScope = cacheControl.getUserScope();
211:
212: // check that we support the user scope...
213: if (consumer.supportsUserScope(userScope)) {
214: log
215: .debug("RenderHandler.processRenderRequest: trying to cache markup "
216: + userScope
217: + " for "
218: + expires
219: + " seconds.");
220: result.setExpirationSecs(expires);
221: }
222: }
223: }
224:
225: private static class WSRPURLRewriter extends
226: URLTools.URLReplacementGenerator {
227: private PortletInvocationContext context;
228: private Boolean secure;
229: private Boolean authenticated;
230:
231: public void setContext(PortletInvocationContext context) {
232: this .context = context;
233: }
234:
235: public void setSecure(boolean secure) {
236: this .secure = Boolean.valueOf(secure);
237: }
238:
239: public void setAuthenticated(boolean authenticated) {
240: this .authenticated = Boolean.valueOf(authenticated);
241: }
242:
243: public String getReplacementFor(int currentIndex,
244: URLTools.URLMatch currentMatch) {
245: String urlAsString = currentMatch.getURLAsString();
246: if (urlAsString
247: .startsWith(WSRPRewritingConstants.BEGIN_WSRP_REWRITE)) {
248: WSRPPortletURL portletURL = WSRPPortletURL
249: .create(urlAsString);
250: if (portletURL instanceof WSRPResourceURL) {
251: log
252: .debug("URL '"
253: + urlAsString
254: + "' seems to refer to a resource which are not currently supported. "
255: + "Trying to use the raw URL but this probably won't work...");
256: return portletURL.toString();
257: }
258:
259: return context.renderURL(portletURL, secure,
260: authenticated, true);
261: }
262: return urlAsString;
263: }
264: }
265:
266: public static class ResourceURLRewriter extends
267: URLTools.URLReplacementGenerator {
268: public String getReplacementFor(int currentIndex,
269: URLTools.URLMatch currentMatch) {
270: String urlAsString = currentMatch.getURLAsString();
271: String prefix = WSRPRewritingConstants.FAKE_RESOURCE_START;
272: if (urlAsString.startsWith(prefix)) {
273: int index = urlAsString
274: .indexOf(WSRPRewritingConstants.FAKE_RESOURCE_REQ_REW);
275: String requireRewriteStr = urlAsString.substring(index
276: + WSRPRewritingConstants.FAKE_RESOURCE_REQ_REW
277: .length());
278: boolean requireRewrite = Boolean.valueOf(
279: requireRewriteStr).booleanValue();
280:
281: urlAsString = urlAsString.substring(prefix.length(),
282: index);
283: if (requireRewrite) {
284: // FIX-ME: do something
285: log
286: .debug("Required re-writing but this is not yet implemented...");
287: }
288: return URLTools.decodeXWWWFormURL(urlAsString);
289: }
290:
291: return urlAsString;
292: }
293: }
294: }
|