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.io.File;
23  import java.io.IOException;
24  import java.net.InetSocketAddress;
25  import java.net.UnknownHostException;
26  import java.util.Hashtable;
27  import java.util.LinkedHashMap;
28  import java.util.Map;
29  import java.util.concurrent.ConcurrentHashMap;
30  
31  import javax.xml.XMLConstants;
32  import javax.xml.parsers.DocumentBuilder;
33  import javax.xml.parsers.DocumentBuilderFactory;
34  import javax.xml.parsers.ParserConfigurationException;
35  import javax.xml.transform.dom.DOMResult;
36  import javax.xml.transform.dom.DOMSource;
37  import javax.xml.validation.Schema;
38  import javax.xml.validation.SchemaFactory;
39  import javax.xml.validation.Validator;
40  
41  import org.jscsi.exception.ConfigurationException;
42  import org.jscsi.exception.NoSuchSessionException;
43  import org.jscsi.exception.OperationalTextKeyException;
44  import org.jscsi.parser.datasegment.IResultFunction;
45  import org.jscsi.parser.datasegment.OperationalTextKey;
46  import org.jscsi.parser.datasegment.ResultFunctionFactory;
47  import org.jscsi.parser.datasegment.SettingEntry;
48  import org.jscsi.parser.datasegment.SettingsMap;
49  import org.slf4j.Logger;
50  import org.slf4j.LoggerFactory;
51  import org.w3c.dom.Document;
52  import org.w3c.dom.Element;
53  import org.w3c.dom.NamedNodeMap;
54  import org.w3c.dom.Node;
55  import org.w3c.dom.NodeList;
56  import org.xml.sax.SAXException;
57  
58  
59  /**
60   * <h1>Configuration</h1>
61   * <p>
62   * This class stores all informations, which are set during an iSCSI Session, Connection or are set as the default
63   * values. Therefore, this class was implemented as a Singleton Pattern.
64   * 
65   * @author Volker Wildi, University of Konstanz
66   */
67  public final class Configuration {
68  
69      // --------------------------------------------------------------------------
70      // --------------------------------------------------------------------------
71  
72      /** The XML element name of the global settings node. */
73      private static final String ELEMENT_GLOBAL = "global";
74  
75      // --------------------------------------------------------------------------
76      // --------------------------------------------------------------------------
77  
78      /** The XML element name of the target-specific settings nodes. */
79      private static final String ELEMENT_TARGET = "target";
80  
81      /**
82       * The name of the XML attribute of the unique ID within this iSCSI Initiator configuration file.
83       */
84      private static final String ATTRIBUTE_ID = "id";
85  
86      /**
87       * The name of the XML attribute of the connecting address of the iSCSI Target.
88       */
89      private static final String ATTRIBUTE_ADDRESS = "address";
90  
91      /**
92       * The name of the XML attribute of the connecting port of the iSCSI Target.
93       */
94      private static final String ATTRIBUTE_PORT = "port";
95  
96      // --------------------------------------------------------------------------
97      // --------------------------------------------------------------------------
98  
99      /** The name of the XML attribute of the result function of this setting. */
100     private static final String ATTRIBUTE_RESULT = "result";
101 
102     /** The name of the XML attribute of the scope of this setting. */
103     private static final String ATTRIBUTE_SCOPE = "scope";
104 
105     /** The value (session-wide) of the XML attribute scope. */
106     private static final String VALUE_SCOPE_SESSION = "Session";
107 
108     /** The value (connection-only) of the XML attribute scope. */
109     private static final String VALUE_SCOPE_CONNECTION = "Connection";
110 
111     // --------------------------------------------------------------------------
112     // --------------------------------------------------------------------------
113 
114     /**
115      * The relative path (to the project) of the main directory of all configuration files.
116      */
117     private static final File CONFIG_DIR = new File(new StringBuilder("src").append(File.separator).append("main").append(File.separator).append("resources").append(File.separator).toString());
118 
119     /**
120      * The file name of the XML Schema configuration file for the global settings.
121      */
122     private static final File CONFIGURATION_SCHEMA_FILE = new File(CONFIG_DIR, "jscsi.xsd");
123 
124     /** The file name, which contains all global settings. */
125     private static final File CONFIGURATION_CONFIG_FILE = new File(CONFIG_DIR, "jscsi.xml");
126 
127     // --------------------------------------------------------------------------
128     // --------------------------------------------------------------------------
129 
130     /** The Log interface. */
131     private static final Logger LOGGER = LoggerFactory.getLogger(Configuration.class);
132 
133     // --------------------------------------------------------------------------
134     // --------------------------------------------------------------------------
135 
136     /** Contains all global configuration parameters. */
137     private final Map<OperationalTextKey , SettingEntry> globalConfig;
138 
139     /** Contains all session-wide configuration parameters. */
140     private final ConcurrentHashMap<String , SessionConfiguration> sessionConfigs;
141 
142     // --------------------------------------------------------------------------
143     // --------------------------------------------------------------------------
144 
145     /**
146      * Constructor to create a new, empty <code>Configuration</code> object.
147      */
148     public Configuration () {
149         this(new Hashtable<OperationalTextKey , SettingEntry>(), new ConcurrentHashMap<String , SessionConfiguration>(0));
150     }
151 
152     /**
153      * Constructor to create a <code>Configuration</code> object with existing data
154      */
155     public Configuration (final Hashtable<OperationalTextKey , SettingEntry> paramGlobalConfig, final ConcurrentHashMap<String , SessionConfiguration> paramConfig) {
156 
157         globalConfig = paramGlobalConfig;
158         sessionConfigs = paramConfig;
159     }
160 
161     // --------------------------------------------------------------------------
162     // --------------------------------------------------------------------------
163 
164     /**
165      * Creates a instance of a <code>Configuration</code> object, which is initialized with the settings from the
166      * system-wide configuration file.
167      * 
168      * @return A <code>Configuration</code> instance with all settings.
169      * @throws ConfigurationException If this operation is supported but failed for some reason.
170      */
171     public static final Configuration create () throws ConfigurationException {
172 
173         return create(CONFIGURATION_SCHEMA_FILE, CONFIGURATION_CONFIG_FILE);
174     }
175 
176     /**
177      * Creates a instance of a <code>Configuration</code> object, which is initialized with the settings from the
178      * system-wide configuration file.
179      * 
180      * @param configSchemaFileName The file name of the schema to check the configuration file against.s
181      * @param configFileName The file name of the configuration file to use.
182      * @return A <code>Configuration</code> instance with all settings.
183      * @throws ConfigurationException If this operation is supported but failed for some reason.
184      * 
185      */
186     public static final Configuration create (final File configSchemaFileName, final File configFileName) throws ConfigurationException {
187 
188         final Configuration config = new Configuration();
189 
190         final Document doc = config.parse(configSchemaFileName, configFileName);
191         config.parseSettings(doc.getDocumentElement());
192 
193         return config;
194     }
195 
196     /**
197      * Returns the value of a single parameter, instead of all values.
198      * 
199      * @param targetName Name of the iSCSI Target to connect.
200      * @param connectionID The ID of the connection to retrieve.
201      * @param textKey The name of the parameter.
202      * @return The value of the given parameter.
203      * @throws OperationalTextKeyException If the given parameter cannot be found.
204      */
205     public final String getSetting (final String targetName, final int connectionID, final OperationalTextKey textKey) throws OperationalTextKeyException {
206 
207         try {
208             final SessionConfiguration sc;
209             synchronized (sessionConfigs) {
210                 sc = sessionConfigs.get(targetName);
211 
212                 synchronized (sc) {
213                     if (sc != null) {
214                         String value = sc.getSetting(connectionID, textKey);
215                         if (value != null) { return value; }
216                     }
217                 }
218             }
219         } catch (OperationalTextKeyException e) {
220             // we had not find a session/connection entry, so we have to search
221             // in the
222             // global settings
223         }
224 
225         final SettingEntry se;
226         synchronized (globalConfig) {
227             se = globalConfig.get(textKey);
228 
229             synchronized (se) {
230                 if (se != null) { return se.getValue(); }
231             }
232         }
233 
234         throw new OperationalTextKeyException("No OperationalTextKey entry found for key: " + textKey.value());
235     }
236 
237     /**
238      * Unifies all parameters (in the right precedence) and returns one <code>SettingsMap</code>. Right order means:
239      * default, then the session-wide, and finally the connection-wide valid parameters.
240      * 
241      * @param targetName Name of the iSCSI Target to connect.
242      * @param connectionID The ID of the connection to retrieve.
243      * @return All unified parameters in one single <code>SettingsMap</code>.
244      */
245     public final SettingsMap getSettings (final String targetName, final int connectionID) {
246 
247         final SettingsMap sm = new SettingsMap();
248 
249         // set all default settings
250         synchronized (globalConfig) {
251             for (Map.Entry<OperationalTextKey , SettingEntry> e : globalConfig.entrySet()) {
252                 sm.add(e.getKey(), e.getValue().getValue());
253             }
254         }
255 
256         // set all further settings
257         final SessionConfiguration sc;
258         synchronized (sessionConfigs) {
259             sc = sessionConfigs.get(targetName);
260 
261             synchronized (sc) {
262                 if (sc != null) {
263                     final SettingsMap furtherSettings = sc.getSettings(connectionID);
264                     for (Map.Entry<OperationalTextKey , String> e : furtherSettings.entrySet()) {
265                         sm.add(e.getKey(), e.getValue());
266                     }
267                 }
268             }
269         }
270 
271         return sm;
272     }
273 
274     /**
275      * Returns the value of a single parameter. It can only return session and global parameters.
276      * 
277      * @param targetName Name of the iSCSI Target to connect.
278      * @param textKey The name of the parameter.
279      * @return The value of the given parameter.
280      * @throws OperationalTextKeyException If the given parameter cannot be found.
281      */
282 
283     public final String getSessionSetting (final String targetName, final OperationalTextKey textKey) throws OperationalTextKeyException {
284 
285         return getSetting(targetName, -1, textKey);
286     }
287 
288     /**
289      * Returns the <code>InetAddress</code> instance of the connected iSCSI Target.
290      * 
291      * @param targetName The name of the iSCSI Target.
292      * @return The <code>InetAddress</code> instance of the requested iSCSI Target.
293      * @throws NoSuchSessionException if a session with this target name is not open.
294      */
295     public final InetSocketAddress getTargetAddress (final String targetName) throws NoSuchSessionException {
296 
297         final SessionConfiguration sc = sessionConfigs.get(targetName);
298 
299         if (sc == null) { throw new NoSuchSessionException("A session with the ID '" + targetName + "' does not exist."); }
300 
301         return sc.getInetSocketAddress();
302     }
303 
304     /**
305      * Updates the stored settings of a connection with these values from the response of the iSCSI Target.
306      * 
307      * @param targetName The name of the iSCSI Target.
308      * @param connectionID The ID of the connection within this iSCSI Target.
309      * @param response The response settings.
310      * @throws NoSuchSessionException if a session with this target name is not open.
311      */
312     public final void update (final String targetName, final int connectionID, final SettingsMap response) throws NoSuchSessionException {
313 
314         final SessionConfiguration sc;
315         synchronized (sessionConfigs) {
316             sc = sessionConfigs.get(targetName);
317 
318             synchronized (sc) {
319                 if (sc == null) { throw new NoSuchSessionException("A session with the ID '" + targetName + "' does not exist."); }
320 
321                 synchronized (response) {
322                     SettingEntry se;
323                     for (Map.Entry<OperationalTextKey , String> e : response.entrySet()) {
324                         synchronized (globalConfig) {
325                             se = globalConfig.get(e.getKey());
326 
327                             if (se == null) {
328                                 if (LOGGER.isWarnEnabled()) {
329                                     LOGGER.warn("This key " + e.getKey() + " is not in the globalConfig.");
330                                 }
331                                 continue;
332                             }
333 
334                             synchronized (se) {
335                                 if (se.getScope().compareTo(VALUE_SCOPE_SESSION) == 0) {
336                                     sc.updateSessionSetting(e.getKey(), e.getValue(), se.getResult());
337                                 } else if (se.getScope().compareTo(VALUE_SCOPE_CONNECTION) == 0) {
338                                     sc.updateConnectionSetting(connectionID, e.getKey(), e.getValue(), se.getResult());
339                                 }
340                             }
341                         }
342                     }
343                 }
344             }
345         }
346     }
347 
348     // --------------------------------------------------------------------------
349     // --------------------------------------------------------------------------
350 
351     /**
352      * Reads the given configuration file in memory and creates a DOM representation.
353      * 
354      * @throws SAXException If this operation is supported but failed for some reason.
355      * @throws ParserConfigurationException If a <code>DocumentBuilder</code> cannot be created which satisfies the
356      *             configuration requested.
357      * @throws IOException If any IO errors occur.
358      */
359     private final Document parse (final File schemaLocation, final File configFile) throws ConfigurationException {
360         try {
361             final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
362             final Schema schema = schemaFactory.newSchema(schemaLocation);
363 
364             // create a validator for the document
365             final Validator validator = schema.newValidator();
366 
367             final DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
368             domFactory.setNamespaceAware(true); // never forget this
369             final DocumentBuilder builder = domFactory.newDocumentBuilder();
370             final Document doc = builder.parse(configFile);
371 
372             final DOMSource source = new DOMSource(doc);
373             final DOMResult result = new DOMResult();
374 
375             validator.validate(source, result);
376 
377             return (Document) result.getNode();
378         } catch (final SAXException exc) {
379             throw new ConfigurationException(exc);
380         } catch (final ParserConfigurationException exc) {
381             throw new ConfigurationException(exc);
382         } catch (final IOException exc) {
383             throw new ConfigurationException(exc);
384         }
385     }
386 
387     /**
388      * Parses all settings form the main configuration file.
389      * 
390      * @param root The root element of the configuration.
391      */
392     private final void parseSettings (final Element root) {
393 
394         if (root == null) { throw new NullPointerException(); }
395 
396         clear();
397         parseGlobalSettings(root);
398         parseTargetSpecificSettings(root);
399     }
400 
401     /**
402      * Parses all global settings form the main configuration file.
403      * 
404      * @param root The root element of the configuration.
405      */
406     private final void parseGlobalSettings (final Element root) {
407 
408         final NodeList globalConfiguration = root.getElementsByTagName(ELEMENT_GLOBAL);
409 
410         final ResultFunctionFactory resultFunctionFactory = new ResultFunctionFactory();
411         Node parameter;
412         NodeList parameters;
413         NamedNodeMap attributes;
414         SettingEntry key;
415         for (int i = 0; i < globalConfiguration.getLength(); i++) {
416             parameters = globalConfiguration.item(i).getChildNodes();
417 
418             for (int j = 0; j < parameters.getLength(); j++) {
419                 parameter = parameters.item(j);
420 
421                 if (parameter.getNodeType() == Node.ELEMENT_NODE) {
422                     attributes = parameter.getAttributes();
423 
424                     key = new SettingEntry();
425                     key.setScope(attributes.getNamedItem(ATTRIBUTE_SCOPE).getNodeValue());
426                     key.setResult(resultFunctionFactory.create(attributes.getNamedItem(ATTRIBUTE_RESULT).getNodeValue()));
427                     // key.setSender(attributes.getNamedItem(ATTRIBUTE_SENDER).getNodeValue
428                     // ());
429                     key.setValue(parameter.getTextContent());
430 
431                     synchronized (globalConfig) {
432                         globalConfig.put(OperationalTextKey.valueOfEx(parameter.getNodeName()), key);
433                     }
434                 }
435             }
436         }
437     }
438 
439     /**
440      * Parses all target-specific settings form the main configuration file.
441      * 
442      * @param root The root element of the configuration.
443      */
444     private final void parseTargetSpecificSettings (final Element root) {
445 
446         final NodeList targets = root.getElementsByTagName(ELEMENT_TARGET);
447 
448         Node target;
449         Node parameter;
450         NodeList parameters;
451 
452         try {
453             for (int i = 0; i < targets.getLength(); i++) {
454                 target = targets.item(i);
455                 parameters = target.getChildNodes();
456 
457                 // extract target address and the port (if specified)
458                 SessionConfiguration sc = new SessionConfiguration();
459 
460                 sc.setAddress(target.getAttributes().getNamedItem(ATTRIBUTE_ADDRESS).getNodeValue(), Integer.parseInt(target.getAttributes().getNamedItem(ATTRIBUTE_PORT).getNodeValue()));
461 
462                 // extract the parameters for this target
463                 for (int j = 0; j < parameters.getLength(); j++) {
464                     parameter = parameters.item(j);
465 
466                     if (parameter.getNodeType() == Node.ELEMENT_NODE) {
467                         sc.addSessionSetting(OperationalTextKey.valueOfEx(parameter.getNodeName()), parameter.getTextContent());
468                     }
469 
470                 }
471 
472                 synchronized (sessionConfigs) {
473                     sessionConfigs.put(target.getAttributes().getNamedItem(ATTRIBUTE_ID).getNodeValue(), sc);
474                 }
475             }
476         } catch (UnknownHostException e) {
477             if (LOGGER.isErrorEnabled()) {
478                 LOGGER.error("The given host is not reachable: " + e.getLocalizedMessage());
479             }
480         }
481     }
482 
483     // --------------------------------------------------------------------------
484     // --------------------------------------------------------------------------
485 
486     /**
487      * Clears all parameters.
488      */
489     private final void clear () {
490 
491         synchronized (globalConfig) {
492             globalConfig.clear();
493         }
494 
495         synchronized (sessionConfigs) {
496             sessionConfigs.clear();
497         }
498     }
499 
500     // --------------------------------------------------------------------------
501     // --------------------------------------------------------------------------
502     // --------------------------------------------------------------------------
503     // --------------------------------------------------------------------------
504 
505     /**
506      * This class contains a session-wide <code>SettingsMap</code> with one or more connection-specific
507      * <code>SettingsMap</code>.
508      * 
509      * @author Volker Wildi
510      */
511     private final class SessionConfiguration {
512 
513         /** The session-wide settings. */
514         private final SettingsMap sessionConfiguration;
515 
516         /** The connection-specific settings. */
517         private final Map<Integer , SettingsMap> connectionConfiguration;
518 
519         /** The <code>InetSocketAddress</code> of the endpoint. */
520         private InetSocketAddress inetAddress;
521 
522         /**
523          * Default constructor to create a new, empty <code>SessionConfiguration</code> object.
524          */
525         SessionConfiguration () {
526 
527             sessionConfiguration = new SettingsMap();
528             connectionConfiguration = new LinkedHashMap<Integer , SettingsMap>(0);
529         }
530 
531         /**
532          * Adds a session-wide parameter to this <code>SessionConfiguration</code> object.
533          * 
534          * @param textKey The name of the parameter to add
535          * @param textValue The value of the parameter to add.
536          */
537         final void addSessionSetting (final OperationalTextKey textKey, final String textValue) {
538 
539             sessionConfiguration.add(textKey, textValue);
540         }
541 
542         /**
543          * Updates the value of the given <code>OperationTextKey</code> of this session with the response key
544          * <code>textValue</code> and the result function.
545          * 
546          * @param textKey The <code>OperationalTextKey</code> to update.
547          * @param textValue The value of the response.
548          * @param resultFunction The <code>IResultFunction</code> instance to use to obtain the result.
549          */
550         final void updateSessionSetting (final OperationalTextKey textKey, final String textValue, final IResultFunction resultFunction) {
551 
552             sessionConfiguration.update(textKey, textValue, resultFunction);
553         }
554 
555         // /**
556         // * Adds a connection-specific parameter to this
557         // * <code>SessionConfiguration</code> object.
558         // *
559         // * @param connectionID
560         // * The ID of the connection to which this parameter should be
561         // * added.
562         // * @param textKey
563         // * The name of the parameter to add. The name of the
564         // * parameter to add.
565         // * @param textValue
566         // * The value of the parameter to add.
567         // */
568         // final void addConnectionSetting(final int connectionID,
569         // final OperationalTextKey textKey, final String textValue) {
570         //
571         // SettingsMap sm = connectionConfiguration.get(connectionID);
572         // if (sm == null) {
573         // sm = new SettingsMap();
574         // connectionConfiguration.put(connectionID, sm);
575         // }
576         //
577         // sm.add(textKey, textValue);
578         // }
579 
580         /**
581          * Updates the value of the given <code>OperationTextKey</code> of the given connection within this session with
582          * the response key <code>textValue</code> and the result function.
583          * 
584          * @param connectionID The ID of the connection.
585          * @param textKey The <code>OperationalTextKey</code> to update.
586          * @param textValue The value of the response.
587          * @param resultFunction The <code>IResultFunction</code> instance to use to obtain the result.
588          */
589         final void updateConnectionSetting (final int connectionID, final OperationalTextKey textKey, final String textValue, final IResultFunction resultFunction) {
590 
591             SettingsMap sm = connectionConfiguration.get(connectionID);
592             if (sm == null) {
593                 sm = new SettingsMap();
594                 connectionConfiguration.put(connectionID, sm);
595             }
596 
597             sm.update(textKey, textValue, resultFunction);
598         }
599 
600         // /**
601         // * Returns the value of a key-value pair with the given key for this
602         // * session.
603         // *
604         // * @param textKey
605         // * The <code>OperationalTextKey</code> key.
606         // * @return The value of the given <code>textKey</code>.
607         // * @throws Exception
608         // * if any error occurs.
609         // */
610         // final String getSessionSetting(final OperationalTextKey textKey)
611         // throws OperationalTextKeyException {
612         //
613         // String textValue;
614         //
615         // do {
616         // // look for session-specific information
617         // textValue = sessionConfiguration.get(textKey);
618         // if (textValue == null) {
619         // break;
620         // }
621         //
622         // // look for default information
623         // final SettingEntry se = globalConfig.get(textKey);
624         // if (se == null) {
625         // throw new OperationalTextKeyException("The key "
626         // + textKey.value()
627         // + " cannot be found in the global configuration.");
628         // }
629         // } while (false);
630         //
631         // if (textValue == "") {
632         // throw new OperationalTextKeyException("A value of the key "
633         // + textKey.value() + " cannot be returned.");
634         // } else {
635         // return textValue;
636         // }
637         //
638         // }
639 
640         // /**
641         // * Returns the value of a key-value pair with the given key for the
642         // * connection within this session.
643         // *
644         // * @param connectionID
645         // * The ID of the connection.
646         // * @param textKey
647         // * The <code>OperationalTextKey</code> key.
648         // * @return The value of the given <code>textKey</code>.
649         // * @throws Exception
650         // * if any error occurs.
651         // */
652         // final String getConnectionSetting(final int connectionID,
653         // final OperationalTextKey textKey) throws Exception {
654         //
655         // final SettingsMap sm = connectionConfiguration.get(connectionID);
656         // if (sm != null) {
657         // // look for connection-specific information
658         // return sm.get(textKey);
659         // } else {
660         // return getSessionSetting(textKey);
661         // }
662         // }
663 
664         /**
665          * Returns a single setting value of a connection (specified by the ID).
666          * 
667          * @param connectionID The ID of the connection.
668          * @param textKey The name of the parameter.
669          * @return the value of the given parameter of the connection.
670          * @throws OperationalTextKeyException If the given parameter cannot be found.
671          */
672         final String getSetting (final int connectionID, final OperationalTextKey textKey) throws OperationalTextKeyException {
673 
674             final SettingsMap sm = connectionConfiguration.get(connectionID);
675             if (sm != null) {
676                 final String value = sm.get(textKey);
677                 if (value != null) { return value; }
678             }
679 
680             final String value = sessionConfiguration.get(textKey);
681             if (value != null) { return value; }
682 
683             throw new OperationalTextKeyException("No OperationalTextKey entry found for key: " + textKey.value());
684         }
685 
686         /**
687          * Returns all settings of a connection (specified by the ID).
688          * 
689          * @param connectionID The ID of the connection.
690          * @return All session-wide and connection-specific settings of the connection.
691          */
692         final SettingsMap getSettings (final int connectionID) {
693 
694             final SettingsMap sm = new SettingsMap();
695 
696             // set all session settings
697             for (Map.Entry<OperationalTextKey , String> e : sessionConfiguration.entrySet()) {
698                 sm.add(e.getKey(), e.getValue());
699             }
700 
701             // set all connection settings (if any)
702             final SettingsMap connectionSettings = connectionConfiguration.get(connectionID);
703             if (connectionSettings != null) {
704 
705                 for (Map.Entry<OperationalTextKey , String> e : connectionSettings.entrySet()) {
706                     sm.add(e.getKey(), e.getValue());
707                 }
708             }
709             return sm;
710         }
711 
712         /**
713          * Returns the <code>InetAddress</code> of the leading connection of the session.
714          * 
715          * @return An <code>InetAddress</code> instance.
716          */
717         final InetSocketAddress getInetSocketAddress () {
718 
719             return inetAddress;
720         }
721 
722         /**
723          * Sets the <code>InetAddress</code> of the leading connection to the given value.
724          * 
725          * @param newInetAddress The new <code>InetAddress</code> of the leading connection.
726          * @param port The new Port of the leading connection;
727          * @throws UnknownHostException This exception is thrown, when the host with the given <code>InetAddress</code>
728          *             is not reachable.
729          */
730         final void setAddress (final String newInetAddress, final int port) throws UnknownHostException {
731 
732             inetAddress = new InetSocketAddress(newInetAddress, port);
733         }
734     }
735 
736     // --------------------------------------------------------------------------
737     // --------------------------------------------------------------------------
738     // --------------------------------------------------------------------------
739     // --------------------------------------------------------------------------
740 
741     // --------------------------------------------------------------------------
742     // --------------------------------------------------------------------------
743     // --------------------------------------------------------------------------
744     // --------------------------------------------------------------------------
745 
746 }