001 /*
002 GRANITE DATA SERVICES
003 Copyright (C) 2012 GRANITE DATA SERVICES S.A.S.
004
005 This file is part of Granite Data Services.
006
007 Granite Data Services is free software; you can redistribute it and/or modify
008 it under the terms of the GNU Library General Public License as published by
009 the Free Software Foundation; either version 2 of the License, or (at your
010 option) any later version.
011
012 Granite Data Services is distributed in the hope that it will be useful, but
013 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015 for more details.
016
017 You should have received a copy of the GNU Library General Public License
018 along with this library; if not, see <http://www.gnu.org/licenses/>.
019 */
020
021 package org.granite.client.tide.impl;
022
023 import java.util.Map;
024
025 import org.granite.client.messaging.events.FaultEvent;
026 import org.granite.client.messaging.messages.responses.FaultMessage;
027 import org.granite.client.tide.Context;
028 import org.granite.client.tide.server.ComponentListener;
029 import org.granite.client.tide.server.ExceptionHandler;
030 import org.granite.client.tide.server.Fault;
031 import org.granite.client.tide.server.ServerSession;
032 import org.granite.client.tide.server.TideFaultEvent;
033 import org.granite.client.tide.server.TideResponder;
034 import org.granite.logging.Logger;
035
036 /**
037 * @private
038 * Implementation of fault handler
039 *
040 * @param sourceContext source context of remote call
041 * @param info fault object
042 * @param componentName component name
043 * @param op remote operation
044 * @param tideResponder Tide responder for the remote call
045 *
046 * @author William DRAI
047 */
048 public class FaultHandler<T> implements Runnable {
049
050 private static final Logger log = Logger.getLogger(FaultHandler.class);
051
052 private final ServerSession serverSession;
053 private final Context sourceContext;
054 private final String componentName;
055 private final String operation;
056 private final FaultEvent event;
057 @SuppressWarnings("unused")
058 private final Object info;
059 private final TideResponder<T> tideResponder;
060 private final ComponentListener<T> componentResponder;
061 private boolean executed = false;
062
063
064 public FaultHandler(ServerSession serverSession, Context sourceContext, String componentName, String operation, FaultEvent event, Object info,
065 TideResponder<T> tideResponder, ComponentListener<T> componentResponder) {
066 this.serverSession = serverSession;
067 this.sourceContext = sourceContext;
068 this.componentName = componentName;
069 this.operation = operation;
070 this.event = event;
071 this.info = info;
072 this.tideResponder = tideResponder;
073 this.componentResponder = componentResponder;
074 }
075
076 public void run() {
077 if (executed)
078 return;
079 executed = true;
080
081 log.error("fault %s", event.toString());
082
083 // TODO: conversation contexts
084 // var sessionId:String = faultEvent.message.headers[Tide.SESSION_ID_TAG];
085 // var conversationId:String = null;
086 // if (faultEvent.message.headers[Tide.IS_LONG_RUNNING_CONVERSATION_TAG])
087 // conversationId = faultEvent.message.headers[Tide.CONVERSATION_TAG];
088 // var wasConversationCreated:Boolean = faultEvent.message.headers[Tide.WAS_LONG_RUNNING_CONVERSATION_CREATED_TAG] != null;
089 // var wasConversationEnded:Boolean = faultEvent.message.headers[Tide.WAS_LONG_RUNNING_CONVERSATION_ENDED_TAG] != null;
090 //
091 // var context:Context = _contextManager.retrieveContext(sourceContext, conversationId, wasConversationCreated, wasConversationEnded);
092
093 Context context = sourceContext.getContextManager().retrieveContext(sourceContext, null, false, false);
094
095 FaultMessage emsg = event.getMessage();
096 FaultMessage m = emsg;
097 Map<String, Object> extendedData = emsg != null ? emsg.getExtended() : null;
098 do {
099 if (m != null && m.getCode() != null && m.isSecurityFault()) {
100 emsg = m;
101 extendedData = emsg != null ? emsg.getExtended() : null;
102 break;
103 }
104 // TODO: check WTF we should do here
105 if (m != null && m.getCause() instanceof FaultEvent)
106 m = (FaultMessage)((FaultEvent)m.getCause()).getCause();
107 else if (m.getCause() instanceof FaultMessage)
108 m = (FaultMessage)m.getCause();
109 else
110 m = null;
111 }
112 while (m != null);
113
114 serverSession.handleFaultEvent(event, emsg);
115
116 serverSession.handleFault(context, componentName, operation, emsg);
117
118 boolean handled = false;
119 Fault fault = new Fault(emsg.getCode(), emsg.getDescription(), emsg.getDetails());
120 fault.setContent(event.getMessage());
121 fault.setCause(event.getCause());
122
123 TideFaultEvent faultEvent = new TideFaultEvent(context, serverSession, componentResponder, fault, extendedData);
124 if (tideResponder != null) {
125 tideResponder.fault(faultEvent);
126 if (faultEvent.isDefaultPrevented())
127 handled = true;
128 }
129
130 if (!handled) {
131 ExceptionHandler[] exceptionHandlers = context.getContextManager().getContext(null).allByType(ExceptionHandler.class);
132 if (exceptionHandlers != null && emsg != null) {
133 // Lookup for a suitable exception handler
134 for (ExceptionHandler handler : exceptionHandlers) {
135 if (handler.accepts(emsg)) {
136 handler.handle(context, emsg, faultEvent);
137 handled = true;
138 break;
139 }
140 }
141 if (!handled)
142 log.error("Unhandled fault: " + emsg.getCode() + ": " + emsg.getDescription());
143 }
144 else if (exceptionHandlers != null && exceptionHandlers.length > 0 && event.getMessage() instanceof FaultMessage) {
145 // Handle fault with default exception handler
146 exceptionHandlers[0].handle(context, (FaultMessage)event.getMessage(), faultEvent);
147 }
148 else {
149 log.error("Unknown fault: " + event.toString());
150 }
151 }
152
153 if (!handled && !serverSession.isLogoutInProgress())
154 context.getEventBus().raiseEvent(context, ServerSession.CONTEXT_FAULT, event.getMessage());
155
156 serverSession.tryLogout();
157 }
158 }