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}