/* license-start
*
* Copyright (C) 2008 - 2013 Crispico, <http://www.crispico.com/>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
*
* Contributors:
* Crispico - Initial API and implementation
*
* license-end
*/
package org.flowerplatform.communication.channel;
import org.flowerplatform.communication.IPrincipal;
import org.flowerplatform.communication.command.AbstractClientCommand;
import org.flowerplatform.communication.command.CompoundClientCommand;
public abstract class CommunicationChannel {
/**
* If this command is not <code>null</code>, it means that we are on the thread
* that is processing the HTTP request.
*/
protected ThreadLocal<CompoundClientCommand> queueForCurrentResponse = new ThreadLocal<CompoundClientCommand>();
protected long cachedUserId;
/**
* Should be called when we are in the "normal" case. I.e. on the thread that
* is processing the HTTP request (executing a "main" server command). The commands are queued
* and when the "main" server command finishes, the queue is sent to the client, in
* the HTTP response.
*
* <p>
* This method is synchronized because other threads may call this (indirectly, through
* {@link #appendOrSendCommand()}), exactly at the instance when {@link #handleReceivedObjectEnded()}.
*
* @see #handleReceivedObjectEnded()
*/
public void appendCommandToCurrentHttpResponse(AbstractClientCommand command) {
if (queueForCurrentResponse.get() == null) {
throw new IllegalStateException("Trying to append command to current response, but no client request processing in progress!");
} else {
queueForCurrentResponse.get().appendCommand(command);
}
}
/**
* Here, the <code>synchronized</code> shouldn't be necessary, as in theory there cannot
* be 2 threads invoking this method at the same time.
*/
public void handleReceivedObjectWillStart(Object object) {
queueForCurrentResponse.set(new CompoundClientCommand());
}
/**
* The "main" command (in the thread handling the HTTP request) has finished its job, so we want
* to empty the queue and send it to the client, as part of the current HTTP response.
*
* @see #appendCommandToCurrentHttpResponse()
*/
public AbstractClientCommand handleReceivedObjectEnded(Object object) {
AbstractClientCommand result;
if (queueForCurrentResponse.get().getCommandsList().isEmpty()) {
result = null;
} else if (queueForCurrentResponse.get().getCommandsList().size() == 1) {
result = queueForCurrentResponse.get().getCommandsList().get(0);
} else {
result = queueForCurrentResponse.get();
}
queueForCurrentResponse.set(null);
return result;
}
public long getCachedUserId() {
return cachedUserId;
}
public void appendOrSendCommand(AbstractClientCommand command) {
if (queueForCurrentResponse.get() != null) {
appendCommandToCurrentHttpResponse(command);
} else {
sendCommandWithPush(command);
}
}
public abstract void sendCommandWithPush(AbstractClientCommand command);
public abstract Object getId();
public abstract IPrincipal getPrincipal();
/**
* @author Mariana
*/
public abstract void disconnect();
/**
* @author Mariana
*/
public static IPrincipal getCurrentPrincipal() {
throw new UnsupportedOperationException();
}
public abstract boolean isDisposed();
public abstract void dispose();
}