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.logging.Logger;
025: import org.jboss.portal.portlet.PortletInvokerException;
026: import org.jboss.portal.portlet.impl.jsr168.PortletUtils;
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.PortletInvocationResponse;
030: import org.jboss.portal.portlet.spi.InstanceContext;
031: import org.jboss.portal.portlet.spi.WindowContext;
032: import org.jboss.portal.wsrp.core.InvalidCookieFault;
033: import org.jboss.portal.wsrp.core.InvalidRegistrationFault;
034: import org.jboss.portal.wsrp.core.InvalidSessionFault;
035: import org.jboss.portal.wsrp.core.OperationFailedFault;
036: import org.jboss.portal.wsrp.core.RuntimeContext;
037: import org.jboss.portal.wsrp.core.UserContext;
038:
039: import javax.xml.namespace.QName;
040: import javax.xml.rpc.soap.SOAPFaultException;
041: import java.rmi.RemoteException;
042:
043: /**
044: * @author <a href="mailto:chris.laprun@jboss.com">Chris Laprun</a>
045: * @version $Revision: 8784 $
046: * @since 2.4 (May 31, 2006)
047: */
048: public abstract class InvocationHandler {
049: protected WSRPConsumerImpl consumer;
050:
051: protected static Logger log = Logger
052: .getLogger(InvocationHandler.class);
053:
054: /**
055: * Value indicating that we should not try further (unrecoverable error) for getMarkup and
056: * processBlockingInteraction
057: */
058: private static final int DO_NOT_RETRY = -1;
059:
060: /** Maximum number of tries before giving up. */
061: private static final int MAXIMUM_RETRY_NUMBER = 3;
062:
063: public InvocationHandler(WSRPConsumerImpl consumer) {
064: this .consumer = consumer;
065: }
066:
067: PortletInvocationResponse handle(PortletInvocation invocation)
068: throws PortletInvokerException {
069: // Extracts basic required information from invocation
070: RequestPrecursor requestPrecursor = new RequestPrecursor(
071: consumer, invocation);
072:
073: // create the specific request
074: Object request = prepareRequest(requestPrecursor, invocation);
075:
076: // Perform the request
077: Object response = performRequest(request, invocation);
078: if (response instanceof ErrorResponse) {
079: return unwrapWSRPError((ErrorResponse) response);
080: }
081:
082: return processResponse(response, invocation, requestPrecursor);
083: }
084:
085: protected Object performRequest(Object request,
086: PortletInvocation invocation)
087: throws PortletInvokerException {
088: int retryCount = 0;
089: Object response = null;
090:
091: // as long as we don't get a non-null response and we're allowed to try again, try to perform the request
092: while (response == null && retryCount++ <= MAXIMUM_RETRY_NUMBER) {
093: log.debug("performRequest: " + retryCount
094: + " attempt(s) out of " + MAXIMUM_RETRY_NUMBER
095: + " possible");
096: SessionHandler sessionHandler = consumer
097: .getSessionHandler();
098:
099: // prepare everything for the request
100: updateRegistrationContext(request);
101: RuntimeContext runtimeContext = getRuntimeContextFrom(request);
102:
103: WindowContext windowContext = invocation.getWindowContext();
104: runtimeContext
105: .setNamespacePrefix(getNamespaceFrom(windowContext));
106:
107: InstanceContext instanceContext = invocation
108: .getInstanceContext();
109: runtimeContext
110: .setPortletInstanceKey(instanceContext == null ? null
111: : instanceContext.getId());
112:
113: updateUserContext(request, consumer.getUserContextFrom(
114: invocation, runtimeContext));
115: consumer.setTemplatesIfNeeded(invocation, runtimeContext);
116:
117: try {
118: sessionHandler.initCookieIfNeeded(invocation);
119:
120: // if we need cookies, set the current group id
121: sessionHandler
122: .initProducerSessionInformation(invocation);
123:
124: response = performRequest(request);
125:
126: sessionHandler.updateCookiesIfNeeded(invocation);
127: } catch (Exception e) {
128: ErrorResponse errorResponse = dealWithError(e,
129: invocation, runtimeContext);
130: if (errorResponse != null) {
131: return errorResponse;
132: }
133: } finally {
134: // we're done: reset currently held information
135: sessionHandler.resetCurrentlyHeldInformation();
136: }
137: }
138:
139: if (retryCount >= MAXIMUM_RETRY_NUMBER) {
140: return new ErrorResponse(
141: new RuntimeException(
142: "Tried to perform request "
143: + MAXIMUM_RETRY_NUMBER
144: + " times before giving up. This usually happens if an error in the WS stack prevented the messages to be "
145: + "properly transmitted. Look at server.log for clues as to what happened..."));
146: }
147:
148: log.debug("performRequest finished. Response is "
149: + (response != null ? response.getClass().getName()
150: : null));
151: return response;
152: }
153:
154: protected String getNamespaceFrom(WindowContext windowContext) {
155: return windowContext == null ? null : PortletUtils
156: .generateNamespaceFrom(windowContext.getId());
157: }
158:
159: /**
160: * Deals with common error conditions.
161: *
162: * @param error the error that is to be dealt with
163: * @param invocation the invocation that caused the error to occur
164: * @param runtimeContext the current WSRP RuntimeContext
165: * @return an ErrorResponse if the error couldn't be dealt with or <code>null</code> if the error was correctly
166: * handled
167: */
168: private ErrorResponse dealWithError(Exception error,
169: PortletInvocation invocation, RuntimeContext runtimeContext)
170: throws PortletInvokerException {
171: log.error("The portlet threw an exception", error);
172:
173: SessionHandler sessionHandler = consumer.getSessionHandler();
174:
175: // recoverable errors
176: if (error instanceof InvalidCookieFault) {
177: // we need to re-init the cookies
178: log
179: .debug("Re-initializing cookies after InvalidCookieFault.");
180: // force a producer info refresh because the invalid cookie might be due to a change of cookie policy on the producer
181: consumer.refreshProducerInfo();
182: try {
183: sessionHandler.initCookieIfNeeded(invocation);
184: } catch (Exception e) {
185: log.debug("Couldn't init cookie: "
186: + e.getLocalizedMessage());
187: return new ErrorResponse(e);
188: }
189: } else if (error instanceof InvalidSessionFault) {
190: log
191: .debug("Session invalidated after InvalidSessionFault, will re-send session-stored information.");
192: sessionHandler.handleInvalidSessionFault(invocation,
193: runtimeContext);
194: } else if (error instanceof InvalidRegistrationFault) {
195: log.debug("Invalid registration");
196: consumer.handleInvalidRegistrationFault();
197: } else if (error instanceof RemoteException) {
198: // todo: remove when we upgrade to 1.0.3+ see: http://jira.jboss.com/jira/browse/JBWS-955
199: RemoteException re = (RemoteException) error;
200: Throwable detail = re.detail;
201: if (detail instanceof SOAPFaultException) {
202: SOAPFaultException faultException = (SOAPFaultException) detail;
203: QName faultCode = faultException.getFaultCode();
204: if (faultCode != null) {
205: String localPart = faultCode.getLocalPart();
206: if ("InvalidRegistration"
207: .equalsIgnoreCase(localPart)) {
208: consumer.handleInvalidRegistrationFault();
209: } else if ("InvalidSession"
210: .equalsIgnoreCase(localPart)) {
211: sessionHandler.handleInvalidSessionFault(
212: invocation, runtimeContext);
213: } else {
214: return new ErrorResponse(error);
215: }
216: }
217: }
218: } else {
219: // other errors cannot be dealt with: we have an error condition
220: return new ErrorResponse(error);
221: }
222: return null;
223: }
224:
225: protected ErrorResponse unwrapWSRPError(ErrorResponse errorResponse) {
226: Throwable cause = errorResponse.getCause();
227: if (cause != null) {
228: // unwrap original exception...
229: if (cause instanceof OperationFailedFault
230: && cause.getCause() != null) {
231: cause = cause.getCause();
232: } else if (cause instanceof RemoteException) {
233: cause = ((RemoteException) cause).detail;
234: }
235: log.debug("Invocation of action failed: "
236: + cause.getMessage(), cause); // fix-me?
237: return new ErrorResponse(cause);
238: } else {
239: log.debug("Invocation of action failed: "
240: + errorResponse.getMessage());
241: return errorResponse;
242: }
243: }
244:
245: protected abstract void updateUserContext(Object request,
246: UserContext userContext);
247:
248: protected abstract void updateRegistrationContext(Object request)
249: throws PortletInvokerException;
250:
251: protected abstract RuntimeContext getRuntimeContextFrom(
252: Object request);
253:
254: protected abstract Object performRequest(Object request)
255: throws Exception;
256:
257: protected abstract Object prepareRequest(
258: RequestPrecursor requestPrecursor,
259: PortletInvocation invocation);
260:
261: protected abstract PortletInvocationResponse processResponse(
262: Object response, PortletInvocation invocation,
263: RequestPrecursor requestPrecursor)
264: throws PortletInvokerException;
265:
266: }
|