View Javadoc

1   /**
2    * Copyright (c) 2012, University of Konstanz, Distributed Systems Group All rights reserved.
3    * 
4    * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
5    * following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of
6    * conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice,
7    * this list of conditions and the following disclaimer in the documentation and/or other materials provided with the
8    * distribution. * Neither the name of the University of Konstanz nor the names of its contributors may be used to
9    * endorse or promote products derived from this software without specific prior written permission.
10   * 
11   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
12   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
13   * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
14   * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
15   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
16   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
17   * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18   */
19  package org.jscsi.initiator;
20  
21  
22  import java.net.InetSocketAddress;
23  import java.nio.ByteBuffer;
24  import java.util.Hashtable;
25  import java.util.Map;
26  import java.util.concurrent.ExecutionException;
27  import java.util.concurrent.Future;
28  
29  import org.jscsi.exception.NoSuchSessionException;
30  import org.jscsi.exception.TaskExecutionException;
31  import org.jscsi.initiator.connection.Session;
32  import org.slf4j.Logger;
33  import org.slf4j.LoggerFactory;
34  
35  
36  /**
37   * <h1>Initiator</h1>
38   * <p>
39   * This class represents an initiator, which request messages to a target defined by the iSCSI Protocol (RFC3720).
40   * 
41   * @author Volker Wildi, University of Konstanz
42   * @author Sebastian Graf, University of Konstanz
43   */
44  public final class Initiator {
45  
46      // --------------------------------------------------------------------------
47      // --------------------------------------------------------------------------
48  
49      /** The Logger interface. */
50      private static final Logger LOGGER = LoggerFactory.getLogger(Initiator.class);
51  
52      // --------------------------------------------------------------------------
53      // --------------------------------------------------------------------------
54  
55      /** Stores all configuration parameters. */
56      private final Configuration configuration;
57  
58      /** Stores all opened sessions. */
59      private final Map<String , Session> sessions;
60  
61      /** Stores all configuration parameters. */
62      private final LinkFactory factory;
63  
64      /**
65       * Constructor to create an empty <code>Initiator</code> object with the given configuration.
66       * 
67       * @param initConfiguration The user-defined configuration file.
68       */
69      public Initiator (final Configuration initConfiguration) {
70  
71          configuration = initConfiguration;
72          sessions = new Hashtable<String , Session>(1);
73          factory = new LinkFactory(this);
74      }
75  
76      // --------------------------------------------------------------------------
77      // --------------------------------------------------------------------------
78  
79      /**
80       * Creates a new session with the given target name, which is read from the configuration file.
81       * 
82       * @param targetName The name of the iSCSI Target to connect.
83       * @throws NoSuchSessionException if no session was found
84       * 
85       */
86      public final void createSession (final String targetName) throws NoSuchSessionException {
87  
88          createSession(configuration.getTargetAddress(targetName), targetName);
89      }
90  
91      /**
92       * Creates a new session to a target with the given Internet address and port. The target has the name
93       * <code>targetName</code>.
94       * 
95       * @param targetAddress The Internet address and Port of the target.
96       * @param targetName Name of the target, to which a connection should be created.
97       * @throws Exception if any error occurs.
98       */
99      public final void createSession (final InetSocketAddress targetAddress, final String targetName) {
100 
101         final Session session = factory.getSession(configuration, targetName, targetAddress);
102         sessions.put(session.getTargetName(), session);
103         LOGGER.info("Created the session with iSCSI Target '" + targetName + "' at " + targetAddress.getHostName() + " on port " + targetAddress.getPort() + ".");
104     }
105 
106     /**
107      * Closes all opened connections within this session to the given target.
108      * 
109      * @param targetName The name of the target, which connection should be closed.
110      * @throws NoSuchSessionException if no session is accessible
111      * @throws TaskExecutionException if logout fails.
112      */
113     public final void closeSession (final String targetName) throws NoSuchSessionException , TaskExecutionException {
114 
115         getSession(targetName).logout();
116         // TODO Test the removal from the map.
117         sessions.remove(targetName);
118 
119         LOGGER.info("Closed the session to the iSCSI Target '" + targetName + "'.");
120     }
121 
122     // --------------------------------------------------------------------------
123     // --------------------------------------------------------------------------
124 
125     /**
126      * Invokes a read operation for the session <code>targetName</code> and store the read bytes in the buffer
127      * <code>dst</code>. Start reading at the logical block address and request <code>transferLength</code> blocks.
128      * 
129      * 
130      * @param targetName The name of the session to invoke this read operation.
131      * @param dst The buffer to store the read data.
132      * @param logicalBlockAddress The logical block address of the beginning.
133      * @param transferLength Number of bytes to read.
134      * @throws Exception if any error occurs.
135      * 
136      * @return FutureObject for MultiThreadedReads
137      * @throws TaskExecutionException if execution fails
138      * @throws NoSuchSessionException if session is not found
139      */
140     public final Future<Void> multiThreadedRead (final String targetName, final ByteBuffer dst, final int logicalBlockAddress, final long transferLength) throws NoSuchSessionException , TaskExecutionException {
141 
142         final Future<Void> returnVal = getSession(targetName).read(dst, logicalBlockAddress, transferLength);
143         return returnVal;
144     }
145 
146     /**
147      * Invokes a read operation for the session <code>targetName</code> and store the read bytes in the buffer
148      * <code>dst</code>. Start reading at the logical block address and request <code>transferLength</code> blocks.
149      * 
150      * 
151      * @param targetName The name of the session to invoke this read operation.
152      * @param dst The buffer to store the read data.
153      * @param logicalBlockAddress The logical block address of the beginning.
154      * @param transferLength Number of bytes to read.
155      * @throws TaskExecutionException if execution fails
156      * @throws NoSuchSessionException if session is not found
157      */
158     public final void read (final String targetName, final ByteBuffer dst, final int logicalBlockAddress, final long transferLength) throws NoSuchSessionException , TaskExecutionException {
159         try {
160             multiThreadedRead(targetName, dst, logicalBlockAddress, transferLength).get();
161         } catch (final InterruptedException exc) {
162             throw new TaskExecutionException(exc);
163         } catch (final ExecutionException exc) {
164             throw new TaskExecutionException(exc);
165         }
166     }
167 
168     /**
169      * Invokes a write operation for the session <code>targetName</code> and transmits the bytes in the buffer
170      * <code>dst</code>. Start writing at the logical block address and transmit <code>transferLength</code> blocks.
171      * 
172      * 
173      * @param targetName The name of the session to invoke this write operation.
174      * @param src The buffer to transmit.
175      * @param logicalBlockAddress The logical block address of the beginning.
176      * @param transferLength Number of bytes to write.
177      * @throws Exception if any error occurs.
178      * @return FutureObject for the multi-threaded write operation
179      * @throws TaskExecutionException if execution fails
180      * @throws NoSuchSessionException if session is not found
181      */
182     public final Future<Void> multiThreadedWrite (final String targetName, final ByteBuffer src, final int logicalBlockAddress, final long transferLength) throws NoSuchSessionException , TaskExecutionException {
183 
184         return getSession(targetName).write(src, logicalBlockAddress, transferLength);
185     }
186 
187     /**
188      * Invokes a write operation for the session <code>targetName</code> and transmits the bytes in the buffer
189      * <code>dst</code>. Start writing at the logical block address and transmit <code>transferLength</code> blocks.
190      * 
191      * 
192      * @param targetName The name of the session to invoke this write operation.
193      * @param src The buffer to transmit.
194      * @param logicalBlockAddress The logical block address of the beginning.
195      * @param transferLength Number of bytes to write.
196      * @throws TaskExecutionException if execution fails
197      * @throws NoSuchSessionException if session is not found
198      */
199     public final void write (final String targetName, final ByteBuffer src, final int logicalBlockAddress, final long transferLength) throws NoSuchSessionException , TaskExecutionException {
200 
201         try {
202             multiThreadedWrite(targetName, src, logicalBlockAddress, transferLength).get();
203         } catch (final InterruptedException exc) {
204             throw new TaskExecutionException(exc);
205         } catch (final ExecutionException exc) {
206             throw new TaskExecutionException(exc);
207         }
208     }
209 
210     // --------------------------------------------------------------------------
211     // --------------------------------------------------------------------------
212 
213     /**
214      * Returns the used block size (in bytes) of the iSCSI Target.
215      * 
216      * @param targetName The name of the session to invoke this capacity operation.
217      * @return the used block size (in bytes) of the connected iSCSI Target.
218      * @throws NoSuchSessionException if the session connected to the target is yet not open.
219      */
220     public final long getBlockSize (final String targetName) throws NoSuchSessionException {
221 
222         return getSession(targetName).getBlockSize();
223     }
224 
225     /**
226      * Returns the capacity (in blocks) of the iSCSI Target.
227      * 
228      * @param targetName The name of the session to invoke this capacity operation.
229      * @return the capacity in blocks of the connected iSCSI Target.
230      * @throws NoSuchSessionException if the session connected to the target is yet not open.
231      */
232     public final long getCapacity (final String targetName) throws NoSuchSessionException {
233 
234         return getSession(targetName).getCapacity();
235     }
236 
237     // --------------------------------------------------------------------------
238     // --------------------------------------------------------------------------
239 
240     /**
241      * Returns the <code>Session</code> instance of the iSCSI Target with the given name.
242      * 
243      * @param targetName The name of the session, which instance you want.
244      * @return The requested <code>Session</code> instance.
245      */
246     private final Session getSession (final String targetName) throws NoSuchSessionException {
247 
248         final Session session = sessions.get(targetName);
249 
250         if (session != null) {
251             return session;
252         } else {
253             throw new NoSuchSessionException("Session " + targetName + " not found!");
254         }
255     }
256 
257     /**
258      * Removes the <code>Session</code> instances form the sessions queue.
259      * 
260      * @param sessionReq The Session to remove
261      * @throws NoSuchSessionException if the Session does not exist in the Map
262      */
263     public final void removeSession (final Session sessionReq) throws NoSuchSessionException {
264 
265         final Session session = sessions.get(sessionReq.getTargetName());
266 
267         if (session != null) {
268             sessions.remove(sessionReq.getTargetName());
269         } else {
270             throw new NoSuchSessionException("Session " + sessionReq.getTargetName() + " not found!");
271         }
272     }
273 
274     /**
275      * TODO Search a better solution for this. How can we notify the Application, that all Sessions are closed (and all
276      * Tasks are finished)
277      */
278     /**
279      * is the Sessions Map empty?.
280      * 
281      * @return true if it is empty
282      */
283     public final Boolean noSessions () {
284 
285         return (sessions.size() == 0);
286     }
287 
288     // --------------------------------------------------------------------------
289     // --------------------------------------------------------------------------
290     // --------------------------------------------------------------------------
291     // --------------------------------------------------------------------------
292 
293 }