1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
61
62
63
64
65
66
67 public final class Configuration {
68
69
70
71
72
73 private static final String ELEMENT_GLOBAL = "global";
74
75
76
77
78
79 private static final String ELEMENT_TARGET = "target";
80
81
82
83
84 private static final String ATTRIBUTE_ID = "id";
85
86
87
88
89 private static final String ATTRIBUTE_ADDRESS = "address";
90
91
92
93
94 private static final String ATTRIBUTE_PORT = "port";
95
96
97
98
99
100 private static final String ATTRIBUTE_RESULT = "result";
101
102
103 private static final String ATTRIBUTE_SCOPE = "scope";
104
105
106 private static final String VALUE_SCOPE_SESSION = "Session";
107
108
109 private static final String VALUE_SCOPE_CONNECTION = "Connection";
110
111
112
113
114
115
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
121
122 private static final File CONFIGURATION_SCHEMA_FILE = new File(CONFIG_DIR, "jscsi.xsd");
123
124
125 private static final File CONFIGURATION_CONFIG_FILE = new File(CONFIG_DIR, "jscsi.xml");
126
127
128
129
130
131 private static final Logger LOGGER = LoggerFactory.getLogger(Configuration.class);
132
133
134
135
136
137 private final Map<OperationalTextKey , SettingEntry> globalConfig;
138
139
140 private final ConcurrentHashMap<String , SessionConfiguration> sessionConfigs;
141
142
143
144
145
146
147
148 public Configuration () {
149 this(new Hashtable<OperationalTextKey , SettingEntry>(), new ConcurrentHashMap<String , SessionConfiguration>(0));
150 }
151
152
153
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
166
167
168
169
170
171 public static final Configuration create () throws ConfigurationException {
172
173 return create(CONFIGURATION_SCHEMA_FILE, CONFIGURATION_CONFIG_FILE);
174 }
175
176
177
178
179
180
181
182
183
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
198
199
200
201
202
203
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
221
222
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
239
240
241
242
243
244
245 public final SettingsMap getSettings (final String targetName, final int connectionID) {
246
247 final SettingsMap sm = new SettingsMap();
248
249
250 synchronized (globalConfig) {
251 for (Map.Entry<OperationalTextKey , SettingEntry> e : globalConfig.entrySet()) {
252 sm.add(e.getKey(), e.getValue().getValue());
253 }
254 }
255
256
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
276
277
278
279
280
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
290
291
292
293
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
306
307
308
309
310
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
353
354
355
356
357
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
365 final Validator validator = schema.newValidator();
366
367 final DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
368 domFactory.setNamespaceAware(true);
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
389
390
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
403
404
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
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
441
442
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
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
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
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
507
508
509
510
511 private final class SessionConfiguration {
512
513
514 private final SettingsMap sessionConfiguration;
515
516
517 private final Map<Integer , SettingsMap> connectionConfiguration;
518
519
520 private InetSocketAddress inetAddress;
521
522
523
524
525 SessionConfiguration () {
526
527 sessionConfiguration = new SettingsMap();
528 connectionConfiguration = new LinkedHashMap<Integer , SettingsMap>(0);
529 }
530
531
532
533
534
535
536
537 final void addSessionSetting (final OperationalTextKey textKey, final String textValue) {
538
539 sessionConfiguration.add(textKey, textValue);
540 }
541
542
543
544
545
546
547
548
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
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
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
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
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
688
689
690
691
692 final SettingsMap getSettings (final int connectionID) {
693
694 final SettingsMap sm = new SettingsMap();
695
696
697 for (Map.Entry<OperationalTextKey , String> e : sessionConfiguration.entrySet()) {
698 sm.add(e.getKey(), e.getValue());
699 }
700
701
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
714
715
716
717 final InetSocketAddress getInetSocketAddress () {
718
719 return inetAddress;
720 }
721
722
723
724
725
726
727
728
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 }