001/** 002 * GRANITE DATA SERVICES 003 * Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S. 004 * 005 * This file is part of the Granite Data Services Platform. 006 * 007 * *** 008 * 009 * Community License: GPL 3.0 010 * 011 * This file is free software: you can redistribute it and/or modify 012 * it under the terms of the GNU General Public License as published 013 * by the Free Software Foundation, either version 3 of the License, 014 * or (at your option) any later version. 015 * 016 * This file is distributed in the hope that it will be useful, but 017 * WITHOUT ANY WARRANTY; without even the implied warranty of 018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 019 * GNU General Public License for more details. 020 * 021 * You should have received a copy of the GNU General Public License 022 * along with this program. If not, see <http://www.gnu.org/licenses/>. 023 * 024 * *** 025 * 026 * Available Commercial License: GraniteDS SLA 1.0 027 * 028 * This is the appropriate option if you are creating proprietary 029 * applications and you are not prepared to distribute and share the 030 * source code of your application under the GPL v3 license. 031 * 032 * Please visit http://www.granitedataservices.com/license for more 033 * details. 034 */ 035package org.granite.client.tide.impl; 036 037import java.util.Map; 038 039import org.granite.client.messaging.events.Event; 040import org.granite.client.messaging.events.Event.Type; 041import org.granite.client.messaging.events.FailureEvent; 042import org.granite.client.messaging.events.FaultEvent; 043import org.granite.client.messaging.events.IssueEvent; 044import org.granite.client.messaging.events.TimeoutEvent; 045import org.granite.client.messaging.messages.responses.FaultMessage; 046import org.granite.client.messaging.messages.responses.FaultMessage.Code; 047import org.granite.client.tide.Context; 048import org.granite.client.tide.server.ComponentListener; 049import org.granite.client.tide.server.ExceptionHandler; 050import org.granite.client.tide.server.Fault; 051import org.granite.client.tide.server.ServerSession; 052import org.granite.client.tide.server.TideFaultEvent; 053import org.granite.client.tide.server.TideResponder; 054import org.granite.logging.Logger; 055 056/** 057 * Implementation of fault handler 058 * 059 * @author William DRAI 060 */ 061public class FaultHandler<T> implements Runnable { 062 063 private static final Logger log = Logger.getLogger(FaultHandler.class); 064 065 private final ServerSession serverSession; 066 private final Context sourceContext; 067 @SuppressWarnings("unused") 068 private final String componentName; 069 @SuppressWarnings("unused") 070 private final String operation; 071 private final Event event; 072 @SuppressWarnings("unused") 073 private final Object info; 074 private final TideResponder<T> tideResponder; 075 private final ComponentListener<T> componentListener; 076 private boolean executed = false; 077 078 079 public FaultHandler(ServerSession serverSession, String componentName, String operation) { 080 this.serverSession = serverSession; 081 this.sourceContext = null; 082 this.componentName = componentName; 083 this.operation = operation; 084 this.event = null; 085 this.info = null; 086 this.tideResponder = null; 087 this.componentListener = null; 088 } 089 090 public FaultHandler(ServerSession serverSession, Context sourceContext, String componentName, String operation, Event event, Object info, 091 TideResponder<T> tideResponder, ComponentListener<T> componentListener) { 092 this.serverSession = serverSession; 093 this.sourceContext = sourceContext; 094 this.componentName = componentName; 095 this.operation = operation; 096 this.event = event; 097 this.info = info; 098 this.tideResponder = tideResponder; 099 this.componentListener = componentListener; 100 } 101 102 public void run() { 103 if (executed) 104 return; 105 executed = true; 106 107 log.error("fault %s", event.toString()); 108 109 // TODO: conversation contexts 110// var sessionId:String = faultEvent.message.headers[Tide.SESSION_ID_TAG]; 111// var conversationId:String = null; 112// if (faultEvent.message.headers[Tide.IS_LONG_RUNNING_CONVERSATION_TAG]) 113// conversationId = faultEvent.message.headers[Tide.CONVERSATION_TAG]; 114// var wasConversationCreated:Boolean = faultEvent.message.headers[Tide.WAS_LONG_RUNNING_CONVERSATION_CREATED_TAG] != null; 115// var wasConversationEnded:Boolean = faultEvent.message.headers[Tide.WAS_LONG_RUNNING_CONVERSATION_ENDED_TAG] != null; 116// 117// var context:Context = _contextManager.retrieveContext(sourceContext, conversationId, wasConversationCreated, wasConversationEnded); 118 119 Context context = sourceContext.getContextManager().retrieveContext(sourceContext, null, false, false); 120 121 FaultMessage emsg = null; 122 Map<String, Object> extendedData = null; 123 if (event instanceof FaultEvent) { 124 emsg = ((FaultEvent)event).getMessage(); 125 FaultMessage m = emsg; 126 extendedData = emsg != null ? emsg.getExtended() : null; 127 do { 128 if (m != null && m.getCode() != null && m.isSecurityFault()) { 129 emsg = m; 130 extendedData = emsg != null ? emsg.getExtended() : null; 131 break; 132 } 133 // TODO: check WTF we should do here 134 if (m != null && m.getCause() instanceof FaultEvent) 135 m = (FaultMessage)((FaultEvent)m.getCause()).getCause(); 136 else if (m.getCause() instanceof FaultMessage) 137 m = (FaultMessage)m.getCause(); 138 else 139 m = null; 140 } 141 while (m != null); 142 143 serverSession.onFaultEvent((FaultEvent) event, emsg); 144 } 145 else 146 serverSession.onIssueEvent((IssueEvent) event); 147 148 handleFault(context, emsg); 149 150 boolean handled = false; 151 Fault fault = null; 152 if (event instanceof FaultEvent) { 153 fault = new Fault(emsg.getCode(), emsg.getDescription(), emsg.getDetails()); 154 fault.setContent(((FaultEvent)event).getMessage()); 155 fault.setCause(((FaultEvent)event).getCause()); 156 } 157 else if (event.getType() == Type.FAILURE) { 158 fault = new Fault(Code.CLIENT_CALL_FAILED, null, ((FailureEvent)event).getCause() != null ? ((FailureEvent)event).getCause().getMessage() : null); 159 fault.setCause(((FailureEvent)event).getCause()); 160 emsg = new FaultMessage(null, null, Code.CLIENT_CALL_FAILED, null, null, null, null); 161 } 162 else if (event.getType() == Type.TIMEOUT) { 163 fault = new Fault(Code.CLIENT_CALL_TIMED_OUT, null, String.valueOf(((TimeoutEvent)event).getTime())); 164 emsg = new FaultMessage(null, null, Code.CLIENT_CALL_TIMED_OUT, null, null, null, null); 165 } 166 else if (event.getType() == Type.CANCELLED) { 167 fault = new Fault(Code.CLIENT_CALL_CANCELLED, null, null); 168 emsg = new FaultMessage(null, null, Code.CLIENT_CALL_TIMED_OUT, null, null, null, null); 169 } 170 171 TideFaultEvent faultEvent = new TideFaultEvent(context, serverSession, componentListener, fault, extendedData); 172 if (tideResponder != null) { 173 tideResponder.fault(faultEvent); 174 if (faultEvent.isDefaultPrevented()) 175 handled = true; 176 } 177 178 if (!handled) { 179 ExceptionHandler[] exceptionHandlers = context.getContextManager().getContext(null).allByType(ExceptionHandler.class); 180 if (exceptionHandlers != null && emsg != null) { 181 // Lookup for a suitable exception handler 182 for (ExceptionHandler handler : exceptionHandlers) { 183 if (handler.accepts(emsg)) { 184 handler.handle(context, emsg, faultEvent); 185 handled = true; 186 break; 187 } 188 } 189 if (!handled) 190 log.error("Unhandled fault: " + emsg.getCode() + ": " + emsg.getDescription()); 191 } 192 else if (exceptionHandlers != null && exceptionHandlers.length > 0 && event instanceof FaultEvent) { 193 // Handle fault with default exception handler 194 exceptionHandlers[0].handle(context, ((FaultEvent)event).getMessage(), faultEvent); 195 } 196 else { 197 log.error("Unknown fault: " + event.toString()); 198 } 199 } 200 201 if (!handled && !serverSession.isLogoutInProgress()) 202 context.getEventBus().raiseEvent(context, ServerSession.CONTEXT_FAULT, event instanceof FaultEvent ? ((FaultEvent)event).getMessage() : null); 203 204 serverSession.tryLogout(); 205 } 206 207 208 public void handleFault(Context context, FaultMessage emsg) { 209 } 210}