package org.jscsi.target.connection.phase; import java.io.IOException; import java.security.DigestException; import java.util.concurrent.Callable; import javax.naming.OperationNotSupportedException; import org.jscsi.exception.InternetSCSIException; import org.jscsi.parser.ProtocolDataUnit; import org.jscsi.target.connection.Connection; import org.jscsi.target.settings.SettingsException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Instances of this class represent a connection's phase (see {@link Connection} for a description of * the relationship between * stages, phases, connections, and sessions). * <p> * To start a phase, one of the <i>execute</i> methods must be called, which one is sub-class-specific. * * @author Andreas Ergenzinger, University of Konstanz */ public abstract class TargetPhase implements Callable<Boolean> { enum PHASE_EXEC_STATUS { DONE, CLOSE, GO_ON}; private static final Logger LOGGER = LoggerFactory.getLogger(TargetPhase.class); /** * The connection this phase is a part of. */ protected final Connection connection; /** * The target server this phase is a part of. */ private final String threadName; /** * The abstract constructor. * * @param connection * the connection is phase is a part of */ public TargetPhase(Connection connection) { this.connection = connection; this.threadName = "iSCSI connection from " + connection.getSenderWorkerPeerInfo(); } /** * Throws an {@link OperationNotSupportedException} unless overwritten. * * @param pdu * the first PDU to be processes as part of the phase * @return <code>true</code> if and only if the phase was completed * successfully * @throws OperationNotSupportedException * if the method is not overwritten * @throws IOException * if an I/O error occurs * @throws InterruptedException * if the current Thread is interrupted * @throws InternetSCSIException * if a iSCSI protocol violation is detected * @throws DigestException * if a PDU digest error is detected * @throws SettingsException * if the target tries to access a parameter that has not been * declared or negotiated and that has no default value */ public PHASE_EXEC_STATUS execute(ProtocolDataUnit pdu) throws OperationNotSupportedException, IOException, InterruptedException, InternetSCSIException, DigestException, SettingsException { throw new OperationNotSupportedException(); } /** * Throws an {@link OperationNotSupportedException} unless overwritten. * * @return <code>true</code> if and only if the phase was completed * successfully * @throws OperationNotSupportedException * if the method is not overwritten * @throws IOException * if an I/O error occurs * @throws InterruptedException * if the current Thread is interrupted * @throws InternetSCSIException * if a iSCSI protocol violation is detected * @throws DigestException * if a PDU digest error is detected * @throws SettingsException * if the target tries to access a parameter that has not been * declared or negotiated and that has no default value */ public boolean execute() throws OperationNotSupportedException, InternetSCSIException, DigestException, IOException, InterruptedException, SettingsException { throw new OperationNotSupportedException(); } /** * Getting the related connection * * @return the connection */ public Connection getTargetConnection() { return connection; } // OODRIVE target phase became callable public final Boolean call() throws Exception { // OODRIVE: change the name of the current thread final Thread myThread = Thread.currentThread(); final String prevThreadName = myThread.getName(); myThread.setName(threadName); try { ProtocolDataUnit pdu = null; PHASE_EXEC_STATUS status = PHASE_EXEC_STATUS.GO_ON; next: while (status == PHASE_EXEC_STATUS.GO_ON) { status = execute(pdu); if (status == PHASE_EXEC_STATUS.DONE) { connection.enableRead(); return true; } else if (status == PHASE_EXEC_STATUS.GO_ON) { pdu = connection.receivePdu(100); if (pdu != null) { continue next; } connection.enableRead(); return true; } else if (status == PHASE_EXEC_STATUS.CLOSE) { connection.close(); LOGGER.debug("closed connection"); return false; } else { throw new AssertionError("status=" + status); } } // Unreachable throw new AssertionError(); } catch (Throwable t) { LOGGER.error("Exception thrown", t); connection.close(); return false; } finally { myThread.setName(prevThreadName); } } }