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.concurrent.ExecutionException; 038import java.util.concurrent.Future; 039 040import org.granite.client.messaging.RemoteAlias; 041import org.granite.client.messaging.RemoteService; 042import org.granite.client.messaging.channel.ResponseMessageFuture; 043import org.granite.client.messaging.events.CancelledEvent; 044import org.granite.client.messaging.events.FailureEvent; 045import org.granite.client.messaging.events.FaultEvent; 046import org.granite.client.messaging.events.ResultEvent; 047import org.granite.client.messaging.events.TimeoutEvent; 048import org.granite.client.tide.Context; 049import org.granite.client.tide.server.Component; 050import org.granite.client.tide.server.ComponentListener; 051import org.granite.client.tide.server.FaultException; 052import org.granite.client.tide.server.ServerSession; 053import org.granite.client.tide.server.TideResponder; 054import org.granite.tide.invocation.InvocationCall; 055 056/** 057 * @author William DRAI 058 */ 059public class ComponentListenerImpl<T> implements ComponentListener<T> { 060 061 private Context sourceContext; 062 private Component component; 063 private String componentName; 064 private String operation; 065 private Object[] args; 066 private Handler<T> handler; 067 private TideResponder<T> tideResponder; 068 private Object info; 069 private boolean waiting = false; 070 private Runnable responseHandler = null; 071 private T result = null; 072 private Exception exception = null; 073 074 075 public ComponentListenerImpl(Context sourceContext, Handler<T>handler, Component component, String operation, Object[] args, Object info, TideResponder<T> tideResponder) { 076 this.sourceContext = sourceContext; 077 this.handler = handler; 078 this.component = component; 079 this.componentName = component != null ? component.getName() : null; 080 this.operation = operation; 081 this.args = args; 082 this.tideResponder = tideResponder; 083 this.info = info; 084 } 085 086 public String getOperation() { 087 return operation; 088 } 089 090 public Object[] getArgs() { 091 return args; 092 } 093 public void setArgs(Object[] args) { 094 this.args = args; 095 } 096 097 public Context getSourceContext() { 098 return sourceContext; 099 } 100 101 public Component getComponent() { 102 return component; 103 } 104 105 public T getResult() throws InterruptedException, ExecutionException { 106 synchronized (this) { 107 if (responseHandler == null && exception == null) { 108 waiting = true; 109 wait(); 110 } 111 if (responseHandler != null) 112 responseHandler.run(); 113 } 114 if (exception instanceof ExecutionException) 115 throw (ExecutionException)exception; 116 else if (exception instanceof InterruptedException) 117 throw (InterruptedException)exception; 118 return result; 119 } 120 121 public void setResult(T result) { 122 this.result = result; 123 } 124 125 @Override 126 public void onResult(ResultEvent event) { 127 Runnable h = handler.result(sourceContext, event, info, componentName, operation, tideResponder, this); 128 synchronized (this) { 129 responseHandler = h; 130 if (waiting) 131 notifyAll(); 132 else 133 sourceContext.callLater(h); 134 } 135 } 136 137 @Override 138 public void onFault(FaultEvent event) { 139 Runnable h = handler.fault(sourceContext, event, info, componentName, operation, tideResponder, this); 140 synchronized (this) { 141 responseHandler = h; 142 exception = new FaultException(event); 143 if (waiting) 144 notifyAll(); 145 else 146 sourceContext.callLater(h); 147 } 148 } 149 150 @Override 151 public void onFailure(final FailureEvent event) { 152 Runnable h = handler.issue(sourceContext, event, info, componentName, operation, tideResponder, this); 153 synchronized (this) { 154 exception = new ExecutionException(event.getCause()); 155 if (waiting) 156 notifyAll(); 157 else 158 sourceContext.callLater(h); 159 } 160 } 161 162 @Override 163 public void onTimeout(TimeoutEvent event) { 164 Runnable h = handler.issue(sourceContext, event, info, componentName, operation, tideResponder, this); 165 synchronized (this) { 166 exception = new InterruptedException("timeout"); 167 if (waiting) 168 notifyAll(); 169 else 170 sourceContext.callLater(h); 171 } 172 } 173 174 @Override 175 public void onCancelled(CancelledEvent event) { 176 Runnable h = handler.issue(sourceContext, event, info, componentName, operation, tideResponder, this); 177 synchronized (this) { 178 exception = new InterruptedException("cancel"); 179 if (waiting) 180 notifyAll(); 181 else 182 sourceContext.callLater(h); 183 } 184 } 185 186 @Override 187 public Future<T> invoke(ServerSession serverSession) { 188 189 Object[] call = new Object[5]; 190 call[0] = getComponent().getName(); 191 String componentClassName = null; 192 if (getComponent().getClass() != ComponentImpl.class) { 193 RemoteAlias remoteAlias = getComponent().getClass().getAnnotation(RemoteAlias.class); 194 componentClassName = remoteAlias != null ? remoteAlias.value() : getComponent().getClass().getName(); 195 } 196 call[1] = componentClassName; 197 call[2] = getOperation(); 198 call[3] = getArgs(); 199 call[4] = new InvocationCall(); 200 201 RemoteService ro = serverSession.getRemoteService(); 202 ResponseMessageFuture rmf = ro.newInvocation("invokeComponent", call).addListener(this).invoke(); 203 204 serverSession.checkWaitForLogout(); 205 206 return new FutureResult<T>(rmf, this); 207 } 208 209}