com.sshtools.ssh.message.SshMessageStore Maven / Gradle / Ivy
The newest version!
/**
* Copyright 2003-2016 SSHTOOLS Limited. All Rights Reserved.
*
* For product documentation visit https://www.sshtools.com/
*
* This file is part of J2SSH Maverick.
*
* J2SSH Maverick is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* J2SSH Maverick 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.
*
* You should have received a copy of the GNU General Public License
* along with J2SSH Maverick. If not, see .
*/
package com.sshtools.ssh.message;
import java.io.EOFException;
import java.io.IOException;
import java.io.InterruptedIOException;
import com.sshtools.logging.Log;
import com.sshtools.ssh.SshException;
/**
*
* This class is the central storage location for channel messages; each channel
* has its own message store and the message pump delivers them here where they
* are stored in a lightweight linked list.
*
*
* @author Lee David Painter
*/
public class SshMessageStore implements MessageStore {
public static final int NO_MESSAGES = -1;
SshAbstractChannel channel;
SshMessageRouter manager;
boolean closed = false;
SshMessage header = new SshMessage();
int size = 0;
MessageObserver stickyMessageObserver;
boolean verbose = Boolean.valueOf(
System.getProperty("maverick.verbose", "false")).booleanValue();
public SshMessageStore(SshMessageRouter manager,
SshAbstractChannel channel, MessageObserver stickyMessageObserver) {
this.manager = manager;
this.channel = channel;
this.stickyMessageObserver = stickyMessageObserver;
header.next = header.previous = header;
}
/**
*
* @param messagefilter
* @param timeout
* @return SshMessage
* @throws IOException
* @throws InterruptedIOException
*/
public SshMessage nextMessage(MessageObserver observer, long timeout)
throws SshException, EOFException {
try {
SshMessage msg = manager.nextMessage(channel, observer, timeout);
if (Log.isDebugEnabled()) {
if (verbose) {
Log.debug(this, "got managers next message");
}
}
if (msg != null) {
synchronized (header) {
if (stickyMessageObserver.wantsNotification(msg)) {
return msg;
}
remove(msg);
return msg;
}
}
} catch (InterruptedException ex) {
throw new SshException("The thread was interrupted",
SshException.INTERNAL_ERROR);
}
throw new EOFException(
"The required message could not be found in the message store");
}
public boolean isClosed() {
synchronized (header) {
return closed;
}
}
private void remove(SshMessage e) {
if (e == header) {
throw new IndexOutOfBoundsException();
}
e.previous.next = e.next;
e.next.previous = e.previous;
size--;
}
public Message hasMessage(MessageObserver observer) {
if (Log.isDebugEnabled()) {
if (verbose) {
Log.debug(this, "waiting for header lock");
}
}
synchronized (header) {
// this would not seem to take account of header being null, or
// header.next.next being null, perhaps because these states are not
// possible? if so document, if not fix.
SshMessage e = header.next;
if (e == null) {
if (Log.isDebugEnabled()) {
if (verbose) {
Log.debug(this, "header.next is null");
}
}
return null;
}
// cycle through the linked list until we reach the start point
// (header),
// checking to see if the message is of a type that the observer is
// interested in.
// ??don't seem to look at header though!??
for (; e != header; e = e.next) {
if (observer.wantsNotification(e)) {
if (Log.isDebugEnabled()) {
if (verbose) {
Log.debug(this, "found message");
}
}
return e;
}
}
if (Log.isDebugEnabled()) {
if (verbose) {
Log.debug(this, "no messages");
}
}
return null;
}
}
public void close() {
synchronized (header) {
closed = true;
}
}
void addMessage(SshMessage msg) {
synchronized (header) {
// insert this message between header and header.previous, and
// change their links appropriately
msg.next = header;
msg.previous = header.previous;
// change message before header
msg.previous.next = msg;
// change header
msg.next.previous = msg;
size++;
}
}
}