View Javadoc

1   /***
2    * Jetrix TetriNET Server
3    * Copyright (C) 2001-2003  Emmanuel Bourg
4    *
5    * This program is free software; you can redistribute it and/or
6    * modify it under the terms of the GNU General Public License
7    * as published by the Free Software Foundation; either version 2
8    * of the License, or (at your option) any later version.
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with this program; if not, write to the Free Software
17   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18   */
19  
20  package net.jetrix.config;
21  
22  import java.io.*;
23  import java.net.*;
24  import java.util.*;
25  import java.util.logging.*;
26  import java.beans.*;
27  
28  import org.apache.commons.digester.*;
29  import org.apache.commons.beanutils.*;
30  import org.xml.sax.*;
31  
32  import net.jetrix.*;
33  import net.jetrix.winlist.*;
34  import net.jetrix.filter.*;
35  import net.jetrix.commands.*;
36  
37  /***
38   * Server configuration. This objet reads and retains server parameters,
39   * channel definitions and the ban list.
40   *
41   * @author Emmanuel Bourg
42   * @version $Revision: 866 $, $Date: 2010-08-23 17:02:51 +0200 (lun., 23 août 2010) $
43   */
44  public class ServerConfig
45  {
46      private static Logger log = Logger.getLogger("net.jetrix");
47  
48      public static final String ENCODING = "ISO-8859-1";
49  
50      public static final String VERSION = "@version@";
51  
52      public static final int STATUS_OPENED = 0;
53      public static final int STATUS_LOCKED = 1;
54  
55      private String name;
56      private InetAddress host;
57      private int timeout;
58      private int maxChannels;
59      private int maxPlayers;
60      private int maxConnections;
61      private String operatorPassword;
62      private String adminPassword;
63      private String accesslogPath;
64      private String errorlogPath;
65      private String channelsFile = "channels.xml";
66      private String motd;
67      private Locale locale;
68  
69      // private List bans;
70      private List<ChannelConfig> channels = new ArrayList<ChannelConfig>();
71      private List<FilterConfig> globalFilters = new ArrayList<FilterConfig>();
72      private List<Listener> listeners = new ArrayList<Listener>();
73      private List<Service> services = new ArrayList<Service>();
74      private boolean running;
75      private int status;
76      private Statistics statistics = new Statistics();
77  
78      /*** Datasources configuration */
79      private Map<String, DataSourceConfig> datasources = new LinkedHashMap<String, DataSourceConfig>();
80  
81      /*** Mail session configuration */
82      private MailSessionConfig mailSessionConfig;
83  
84      /*** Extended properties */
85      private Properties properties = new Properties();
86  
87      private URL serverConfigURL;
88      private URL channelsConfigURL;
89  
90      /***
91       * Load the configuration
92       */
93      public void load(File file)
94      {
95          try
96          {
97              load(file.toURI().toURL());
98          }
99          catch (MalformedURLException e)
100         {
101             log.log(Level.SEVERE, "Unable to load the configuration", e);
102         }
103     }
104 
105     /***
106      * Load the configuration.
107      */
108     public void load(URL serverConfigURL)
109     {
110         this.serverConfigURL = serverConfigURL;
111 
112         try
113         {
114             // parse the server configuration
115             Digester digester = new Digester();
116             digester.register("-//LFJR//Jetrix TetriNET Server//EN", findResource("tetrinet-server.dtd").toString());
117             digester.setValidating(true);
118             digester.addRuleSet(new ServerRuleSet());
119             digester.push(this);
120             Reader reader = new InputStreamReader(serverConfigURL.openStream(), ENCODING);
121             digester.parse(new InputSource(reader));
122             reader.close();
123 
124             // parse the channel configuration
125             digester = new Digester();
126             digester.register("-//LFJR//Jetrix Channels//EN", findResource("tetrinet-channels.dtd").toString());
127             digester.setValidating(true);
128             digester.addRuleSet(new ChannelsRuleSet());
129             digester.push(this);
130             channelsConfigURL = new URL(serverConfigURL, channelsFile);
131             reader = new InputStreamReader(channelsConfigURL.openStream(), ENCODING);
132             digester.parse(new InputSource(reader));
133             reader.close();
134         }
135         catch (Exception e)
136         {
137             log.log(Level.SEVERE, "Unable to load the configuration", e);
138         }
139     }
140 
141     /***
142      * Save the configuration.
143      */
144     public void save() throws IOException
145     {
146         // todo make a backup copy of the previous configuration files
147 
148         // save the server.xml file
149         PrintWriter out = null;
150 
151         try
152         {
153             File file = new File(serverConfigURL.toURI());
154             out = new PrintWriter(file, ENCODING);
155         }
156         catch (URISyntaxException e)
157         {
158             log.log(Level.SEVERE, e.getMessage(), e);
159         }
160 
161         out.println("<?xml version=\"1.0\"?>");
162         out.println("<!DOCTYPE tetrinet-server PUBLIC \"-//LFJR//Jetrix TetriNET Server//EN\" \"http://jetrix.sourceforge.net/dtd/tetrinet-server.dtd\">");
163         out.println();
164         out.println("<tetrinet-server host=\"" +  (host == null ? "[ALL]" : host.getHostAddress()) + "\">");
165         out.println();
166         out.println("  <!-- Server name -->");
167         out.println("  <name>" + getName() + "</name>");
168         out.println();
169         out.println("  <!-- Server default language (using an ISO-639 two-letter language code) -->");
170         out.println("  <language>" + getLocale().getLanguage() + "</language>");
171         out.println();
172         out.println("  <!-- How many seconds of inactivity before timeout occurs -->");
173         out.println("  <timeout>" + getTimeout() + "</timeout>");
174         out.println();
175         out.println("  <!-- How many channels should be available on the server -->");
176         out.println("  <max-channels>" + getMaxChannels() + "</max-channels>");
177         out.println();
178         out.println("  <!-- Maximum number of players on the server -->");
179         out.println("  <max-players>" + getMaxPlayers() + "</max-players>");
180         out.println();
181         out.println("  <!-- Maximum number of simultaneous connections allowed from the same IP -->");
182         out.println("  <max-connections>" + getMaxConnections() + "</max-connections>");
183         out.println();
184         out.println("  <!-- Typing /op <thispassword> will give player operator status -->");
185         out.println("  <op-password>" + getOpPassword() + "</op-password>");
186         out.println();
187         out.println("  <!-- Use this password to log on the administration console -->");
188         out.println("  <admin-password>" + getAdminPassword() + "</admin-password>");
189         out.println();
190         out.println("  <!-- Access Log, where requests are logged to -->");
191         out.println("  <access-log path=\"" + getAccessLogPath() + "\" />");
192         out.println();
193         out.println("  <!-- Error Log, where errors are logged to -->");
194         out.println("  <error-log  path=\"" + getErrorLogPath() + "\" />");
195         out.println();
196         out.println("  <!-- Path to the channels descriptor file (relative to the current configuration file) -->");
197         out.println("  <channels path=\"" + getChannelsFile() + "\"/>");
198         out.println();
199         out.println("  <!-- Client listeners -->");
200         out.println("  <listeners>");
201         for (Listener listener : getListeners())
202         {
203             String autostart = !listener.isAutoStart() ? " auto-start=\"false\"" : "";
204             out.println("    <listener class=\"" + listener.getClass().getName() + "\" port=\"" + listener.getPort() + "\"" + autostart + "/>");
205         }
206         out.println("  </listeners>");
207         out.println();
208 
209         out.println("  <!-- Services -->");
210         out.println("  <services>");
211         for (Service service : getServices())
212         {
213             try
214             {
215                 // get the parameters
216                 Map<String, Object> params = PropertyUtils.describe(service);
217 
218                 String autostart = !service.isAutoStart() ? "auto-start=\"false\"" : "";
219                 String classname = "class=\"" + service.getClass().getName() + "\"";
220 
221                 if (params.size() <= 4)
222                 {
223                     out.println("    <service " + classname + " " + autostart + "/>");
224                 }
225                 else
226                 {
227                     out.println("    <service " + classname + " " + autostart + ">");
228                     for (String param : params.keySet())
229                     {
230                         PropertyDescriptor desc = PropertyUtils.getPropertyDescriptor(service, param);
231                         if (!"autoStart".equals(param) && desc.getWriteMethod() != null)
232                         {
233                             out.println("      <param name=\"" + param + "\" value=\"" + params.get(param) + "\"/>");
234                         }
235                     }
236                     out.println("    </service>");
237                 }
238             }
239             catch (Exception e)
240             {
241                 e.printStackTrace();
242             }
243         }
244         out.println("  </services>");
245         out.println();
246 
247         out.println("  <!-- Server commands -->");
248         out.println("  <commands>");
249         Iterator<Command> commands = CommandManager.getInstance().getCommands(AccessLevel.ADMINISTRATOR);
250         while (commands.hasNext())
251         {
252             try
253             {
254                 Command command = commands.next();
255                 String hidden = command.isHidden() ? " hidden=\"true\"" : "";
256                 Command command2 = command.getClass().newInstance();
257                 String level = command2.getAccessLevel() != command.getAccessLevel() ? " access-level=\"" + command.getAccessLevel() + "\"" : "";
258                 out.println("    <command class=\"" + command.getClass().getName() + "\"" + hidden + level + "/>");
259             }
260             catch (Exception e)
261             {
262                 log.log(Level.WARNING, e.getMessage(), e);
263             }
264         }
265         out.println("  </commands>");
266         out.println();
267 
268         out.println("  <ban>");
269         Iterator<Banlist.Entry> entries = Banlist.getInstance().getBanlist();
270         while (entries.hasNext())
271         {
272             Banlist.Entry entry = entries.next();
273             out.println("    <host>" + entry.pattern + "</host>");
274         }
275         out.println("  </ban>");
276         out.println();
277 
278         if (!datasources.isEmpty())
279         {
280             out.println("  <!-- Database connection parameters -->");
281             out.println("  <datasources>");
282             out.println();
283 
284             for (DataSourceConfig datasource : datasources.values())
285             {
286                 out.println("    <datasource name=\"" + datasource.getName() + "\">");
287                 out.println("      <!-- The class of the JDBC driver used -->");
288                 out.println("      <driver>" + datasource.getDriver() + "</driver>");
289                 out.println();
290                 out.println("      <!-- The URL of the database (jdbc:<type>://<hostname>:<port>/<database>) -->");
291                 out.println("      <url>" + datasource.getUrl() + "</url>");
292                 out.println();
293                 out.println("      <!-- The username connecting to the database -->");
294                 out.println("      <username>" + datasource.getUsername() + "</username>");
295                 out.println();
296                 out.println("      <!-- The password of the user -->");
297                 if (datasource.getPassword() != null)
298                 {
299                     out.println("      <password>" + datasource.getPassword() + "</password>");
300                 }
301                 else
302                 {
303                     out.println("      <password/>");
304                 }
305                 if (datasource.getMinIdle() != DataSourceManager.DEFAULT_MIN_IDLE)
306                 {
307                     out.println();
308                     out.println("      <!-- The minimum number of idle connections -->");
309                     out.println("      <min-idle>" + datasource.getMinIdle() + "</min-idle>");
310                 }
311                 if (datasource.getMaxActive() != DataSourceManager.DEFAULT_MAX_ACTIVE)
312                 {
313                     out.println();
314                     out.println("      <!-- The maximum number of active connections -->");
315                     out.println("      <max-active>" + datasource.getMaxActive() + "</max-active>");
316                 }
317                 out.println("    </datasource>");
318                 out.println();
319             }
320             out.println("  </datasources>");
321             out.println();
322         }
323 
324         if (mailSessionConfig != null)
325         {
326             StringBuilder buffer = new StringBuilder();
327             buffer.append("  <mailserver host=\"").append(mailSessionConfig.getHostname()).append("\"");
328             buffer.append(" port=\"").append(mailSessionConfig.getPort()).append("\"");
329             if (mailSessionConfig.isAuth())
330             {
331                 buffer.append(" auth=\"true\"");
332                 buffer.append(" username=\"").append(mailSessionConfig.getUsername()).append("\"");
333                 buffer.append(" password=\"").append(mailSessionConfig.getPassword()).append("\"");
334             }
335             if (mailSessionConfig.isDebug())
336             {
337                 buffer.append(" debug=\"true\"");
338             }
339             buffer.append("/>");
340 
341             out.println("  <!-- Mail server parameters -->");
342             out.println(buffer.toString());
343             out.println();
344         }
345 
346         if (properties != null && !properties.isEmpty())
347         {
348             out.println("  <!-- Extended properties -->");
349             out.println("  <properties>");
350             for (String key : properties.stringPropertyNames())
351             {
352                 out.println("    <property name=\"" + key + "\" value=\"" + properties.getProperty(key) + "\">");
353             }
354             out.println("  </properties>");
355             out.println();
356         }
357         
358         out.println("</tetrinet-server>");
359 
360         out.flush();
361         out.close();
362 
363         // save the channels.xml file
364         try
365         {
366             File file = new File(channelsConfigURL.toURI());
367             out = new PrintWriter(file, ENCODING);
368         }
369         catch (URISyntaxException e)
370         {
371             log.log(Level.SEVERE, e.getMessage(), e);
372         }
373 
374         out.println("<?xml version=\"1.0\"?>");
375         out.println("<!DOCTYPE tetrinet-channels PUBLIC \"-//LFJR//Jetrix Channels//EN\" \"http://jetrix.sourceforge.net/dtd/tetrinet-channels.dtd\">");
376         out.println();
377         out.println("<tetrinet-channels>");
378         out.println();
379         out.println("  <!-- Message Of The Day -->");
380         out.println("  <motd><![CDATA[");
381         out.println(getMessageOfTheDay());
382         out.println("  ]]></motd>");
383         out.println();
384 
385         // filter definitions
386         Map<String, String> aliases = FilterManager.getInstance().getFilterAliases();
387         out.println("  <!-- Channel filters -->");
388         out.println("  <filter-definitions>");
389         for (String alias : aliases.keySet())
390         {
391             out.println("    <alias name=\"" + alias + "\" class=\"" + aliases.get(alias) + "\"/>");
392         }
393         out.println("  </filter-definitions>");
394         out.println();
395 
396         // global filters
397         out.println("  <!-- Global filters -->");
398         out.println("  <default-filters>");
399         for (FilterConfig filter : globalFilters)
400         {
401             saveFilter(filter, out, "    ");
402         }
403         out.println("  </default-filters>");
404         out.println();
405 
406         // winlists
407         out.println("  <!-- Winlists -->");
408         out.println("  <winlists>");
409         for (Winlist winlist : WinlistManager.getInstance().getWinlists())
410         {
411             WinlistConfig config = winlist.getConfig();
412             Properties props = config.getProperties();
413             if (props == null || props.isEmpty())
414             {
415                 out.println("    <winlist name=\"" + winlist.getId() + "\" class=\"" + winlist.getClass().getName() + "\"/>");
416             }
417             else
418             {
419                 out.println("    <winlist name=\"" + winlist.getId() + "\" class=\"" + winlist.getClass().getName() + "\">");
420                 for (Object name : props.keySet())
421                 {
422                     out.println("      <param name=\"" + name + "\" value=\"" + props.get(name) + "\"/>");
423                 }
424                 out.println("    </winlist>");
425             }
426         }
427         out.println("  </winlists>");
428         out.println();
429 
430         // default settings
431         Settings settings = Settings.getDefaultSettings();
432 
433         out.println("  <!-- Default game settings -->");
434         out.println("  <default-settings>");
435         out.println("    <!-- What level each player starts at -->");
436         out.println("    <starting-level>" + settings.getStartingLevel() + "</starting-level>");
437         out.println();
438         out.println("    <!-- How many lines to make before player level increases -->");
439         out.println("    <lines-per-level>" + settings.getLinesPerLevel() + "</lines-per-level>");
440         out.println();
441         out.println("    <!-- Number of levels to increase each time -->");
442         out.println("    <level-increase>" + settings.getLevelIncrease() + "</level-increase>");
443         out.println();
444         out.println("    <!-- Lines to make to get a special block -->");
445         out.println("    <lines-per-special>" + settings.getLinesPerSpecial() + "</lines-per-special>");
446         out.println();
447         out.println("    <!-- Number of special blocks added each time -->");
448         out.println("    <special-added>" + settings.getSpecialAdded() + "</special-added>");
449         out.println();
450         out.println("    <!-- Capacity of Special block inventory -->");
451         out.println("    <special-capacity>" + settings.getSpecialCapacity() + "</special-capacity>");
452         out.println();
453         out.println("    <!-- Play by classic rules? -->");
454         out.println("    <classic-rules>" + (settings.getClassicRules() ? "true" : "false") + "</classic-rules>");
455         out.println();
456         out.println("    <!-- Average together all player's game level? -->");
457         out.println("    <average-levels>" + (settings.getAverageLevels() ? "true" : "false") + "</average-levels>");
458         out.println();
459         out.println("    <!-- Same sequence of blocks for all players? (tetrinet 1.14 clients only) -->");
460         out.println("    <same-blocks>" + (settings.getSameBlocks() ? "true" : "false") + "</same-blocks>");
461         out.println();
462         out.println("    <block-occurancy>");
463         for (Block block : Block.values())
464         {
465             out.println("      <" + block.getCode() + ">" + settings.getOccurancy(block) + "</" + block.getCode() + ">");
466         }
467         out.println("    </block-occurancy>");
468         out.println();
469         out.println("    <special-occurancy>");
470         for (Special special : Special.values())
471         {
472             out.println("      <" + special.getCode() + ">" + settings.getOccurancy(special) + "</" + special.getCode() + ">");
473         }
474         out.println("    </special-occurancy>");
475         out.println();
476         out.println("    <!-- Sudden death parameters -->");
477         out.println("    <sudden-death>");
478         out.println("      <!-- Time in seconds before the sudden death begins, 0 to disable the sudden death -->");
479         out.println("      <time>" + settings.getSuddenDeathTime() + "</time>");
480         out.println();
481         out.println("      <!-- The message displayed when the sudden death begins. Use \"key:\" prefix to display an internationalized message -->");
482         out.println("      <message>" + settings.getSuddenDeathMessage() + "</message>");
483         out.println();
484         out.println("      <!-- The delay in seconds between lines additions -->");
485         out.println("      <delay>" + settings.getSuddenDeathDelay() + "</delay>");
486         out.println();
487         out.println("      <!-- The number of lines added -->");
488         out.println("      <lines-added>" + settings.getSuddenDeathLinesAdded() + "</lines-added>");
489         out.println("    </sudden-death>");
490         out.println();
491         out.println("  </default-settings>");
492         out.println();
493         out.println();
494 
495         out.println("  <channels>");
496         for (Channel channel : ChannelManager.getInstance().channels())
497         {
498             ChannelConfig config = channel.getConfig();
499 
500             if (config.isPersistent())
501             {
502                 out.println("    <channel name=\"" + config.getName() + "\">");
503                 if (config.getDescription() != null)
504                 {
505                     String description = config.getDescription();
506                     description = description.contains("<") ? "<![CDATA[" + description + "]]>" : description;
507                     out.println("      <description>" + description + "</description>");
508                 }
509                 
510                 if (config.getTopic() != null && config.getTopic().trim().length() > 0)
511                 {
512                     out.println("      <topic>");
513                     out.println("<![CDATA[");
514                     out.println(config.getTopic());
515                     out.println("]]>");
516                     out.println("      </topic>");
517                 }
518                 
519                 if (config.getSpeed() != Speed.MIXED)
520                 {
521                     out.println("      <speed>" + config.getSpeed().name().toLowerCase() + "</speed>");
522                 }
523                 
524                 if (config.isPasswordProtected())
525                 {
526                     out.println("      <password>" + config.getPassword() + "</password>");
527                 }
528 
529                 if (config.getAccessLevel() != AccessLevel.PLAYER)
530                 {
531                     out.println("      <access-level>" + config.getAccessLevel() + "</access-level>");
532                 }
533 
534                 if (config.isIdleAllowed())
535                 {
536                     out.println("      <idle>true</idle>");
537                 }
538 
539                 if (!config.isVisible())
540                 {
541                     out.println("      <visible>false</visible>");
542                 }
543 
544                 if (config.getMaxPlayers() != ChannelConfig.PLAYER_CAPACITY)
545                 {
546                     out.println("      <max-players>" + config.getMaxPlayers() + "</max-players>");
547                 }
548 
549                 if (config.getMaxSpectators() != ChannelConfig.SPECTATOR_CAPACITY)
550                 {
551                     out.println("      <max-spectators>" + config.getMaxSpectators() + "</max-spectators>");
552                 }
553 
554                 if (config.getWinlistId() != null)
555                 {
556                     out.println("      <winlist name=\"" + config.getWinlistId() + "\"/>");
557                 }
558 
559                 // channel settings
560                 settings = config.getSettings();
561                 if (!settings.useDefaultSettings())
562                 {
563                     out.println("      <settings>");
564                     if (!settings.isDefaultStartingLevel())
565                     {
566                         out.println("        <starting-level>" + settings.getStartingLevel() + "</starting-level>");
567                     }
568                     if (!settings.isDefaultLinesPerLevel())
569                     {
570                         out.println("        <lines-per-level>" + settings.getLinesPerLevel() + "</lines-per-level>");
571                     }
572                     if (!settings.isDefaultLevelIncrease())
573                     {
574                         out.println("        <level-increase>" + settings.getLevelIncrease() + "</level-increase>");
575                     }
576                     if (!settings.isDefaultLinesPerSpecial())
577                     {
578                         out.println("        <lines-per-special>" + settings.getLinesPerSpecial() + "</lines-per-special>");
579                     }
580                     if (!settings.isDefaultSpecialAdded())
581                     {
582                         out.println("        <special-added>" + settings.getSpecialAdded() + "</special-added>");
583                     }
584                     if (!settings.isDefaultSpecialCapacity())
585                     {
586                         out.println("        <special-capacity>" + settings.getSpecialCapacity() + "</special-capacity>");
587                     }
588                     if (!settings.isDefaultClassicRules())
589                     {
590                         out.println("        <classic-rules>" + (settings.getClassicRules() ? "true" : "false") + "</classic-rules>");
591                     }
592                     if (!settings.isDefaultAverageLevels())
593                     {
594                         out.println("        <average-levels>" + (settings.getAverageLevels() ? "true" : "false") + "</average-levels>");
595                     }
596                     if (!settings.isDefaultSameBlocks())
597                     {
598                         out.println("        <same-blocks>" + (settings.getSameBlocks() ? "true" : "false") + "</same-blocks>");
599                     }
600 
601                     if (!settings.isDefaultBlockOccurancy())
602                     {
603                         out.println("        <block-occurancy>");
604                         for (Block block : Block.values())
605                         {
606                             if (settings.getOccurancy(block) != 0)
607                             {
608                                 out.println("          <" + block.getCode() + ">" + settings.getOccurancy(block) + "</" + block.getCode() + ">");
609                             }
610 
611                         }
612                         out.println("        </block-occurancy>");
613                     }
614 
615                     if (!settings.isDefaultSpecialOccurancy())
616                     {
617                         out.println("        <special-occurancy>");
618                         for (Special special : Special.values())
619                         {
620                             if (settings.getOccurancy(special) != 0)
621                             {
622                                 out.println("          <" + special.getCode() + ">" + settings.getOccurancy(special) + "</" + special.getCode() + ">");
623                             }
624                         }
625                         out.println("        </special-occurancy>");
626                     }
627                     
628                     // sudden death settings
629                     if (!settings.isDefaultSuddenDeath())
630                     {
631                         out.println("        <sudden-death>");
632                         if (!settings.isDefaultSuddenDeathTime())
633                         {
634                             out.println("          <time>" + settings.getSuddenDeathTime() + "</time>");
635                         }
636                         if (!settings.isDefaultSuddenDeathMessage())
637                         {
638                             out.println("          <message>" + settings.getSuddenDeathMessage() + "</message>");
639                         }
640                         if (!settings.isDefaultSuddenDeathDelay())
641                         {
642                             out.println("          <delay>" + settings.getSuddenDeathDelay() + "</delay>");
643                         }
644                         if (!settings.isDefaultSuddenDeathLinesAdded())
645                         {
646                             out.println("          <lines-added>" + settings.getSuddenDeathLinesAdded() + "</lines-added>");
647                         }
648                         out.println("        </sudden-death>");
649                     }
650                     
651                     out.println("      </settings>");
652                 }
653                 
654                 // local filters
655                 Collection<MessageFilter> filters = channel.getLocalFilters();
656                 if (!filters.isEmpty())
657                 {
658                     out.println("      <filters>");
659                     for (MessageFilter filter : filters)
660                     {
661                         saveFilter(filter.getConfig(), out, "        ");
662                     }
663                     out.println("      </filters>");
664                 }
665                 
666                 out.println("    </channel>");
667                 out.println();
668             }
669         }
670         
671         out.println("  </channels>");
672         out.println();
673         out.println("</tetrinet-channels>");
674         
675         out.close();
676     }
677 
678     /***
679      * Write the configuration of the specified filter.
680      */
681     private void saveFilter(FilterConfig filter, PrintWriter out, String indent)
682     {
683         Properties props = filter.getProperties();
684         if (props == null || props.isEmpty())
685         {
686             if (filter.getName() != null)
687             {
688                 out.println(indent + "<filter name=\"" + filter.getName() + "\"/>");
689             }
690             else
691             {
692                 out.println(indent + "<filter class=\"" + filter.getClassname() + "\"/>");
693             }
694         }
695         else
696         {
697             if (filter.getName() != null)
698             {
699                 out.println(indent + "<filter name=\"" + filter.getName() + "\">");
700             }
701             else
702             {
703                 out.println(indent + "<filter class=\"" + filter.getClassname() + "\">");
704             }
705 
706             for (Object name : props.keySet())
707             {
708                 out.println(indent + "  <param name=\"" + name + "\" value=\"" + props.get(name) + "\"/>");
709             }
710             out.println(indent + "</filter>");
711         }
712     }
713 
714     /***
715      * Locate the specified resource by searching in the classpath and in
716      * the current directory.
717      *
718      * @param name the name of the resource
719      * @return the URL of the resource, or null if it cannot be found
720      * @since 0.2
721      */
722     private URL findResource(String name) throws MalformedURLException
723     {
724         ClassLoader loader = ServerConfig.class.getClassLoader();
725         URL url = loader.getResource(name);
726 
727         if (url == null)
728         {
729             File file = new File(name);
730             url = file.toURI().toURL();
731         }
732 
733         return url;
734     }
735 
736     public String getName()
737     {
738         return name;
739     }
740 
741     public void setName(String name)
742     {
743         this.name = name;
744     }
745 
746     public InetAddress getHost()
747     {
748         return host;
749     }
750 
751     public void setHost(InetAddress host)
752     {
753         this.host = host;
754     }
755 
756     public void setHost(String hostname)
757     {
758         // a value of "[ALL]" stands for any IP
759         if (!"[ALL]".equals(hostname))
760         {
761             try
762             {
763                 host = InetAddress.getByName(hostname);
764             }
765             catch (UnknownHostException e)
766             {
767                 log.log(Level.WARNING, e.getMessage(), e);
768             }
769         }
770         else
771         {
772             host = null;
773         }
774     }
775 
776     public Locale getLocale()
777     {
778         return locale;
779     }
780 
781     public void setLocale(Locale locale)
782     {
783         this.locale = locale;
784     }
785 
786     public void setLocale(String language)
787     {
788         this.locale = new Locale(language);
789     }
790 
791     public int getTimeout()
792     {
793         return timeout;
794     }
795 
796     public void setTimeout(int timeout)
797     {
798         this.timeout = timeout;
799     }
800 
801     public int getMaxChannels()
802     {
803         return maxChannels;
804     }
805 
806     public void setMaxChannels(int maxChannels)
807     {
808         this.maxChannels = maxChannels;
809     }
810 
811     public int getMaxPlayers()
812     {
813         return maxPlayers;
814     }
815 
816     public void setMaxPlayers(int maxPlayers)
817     {
818         this.maxPlayers = maxPlayers;
819     }
820 
821     public int getMaxConnections()
822     {
823         return maxConnections;
824     }
825 
826     public void setMaxConnections(int maxConnections)
827     {
828         this.maxConnections = maxConnections;
829     }
830 
831     public String getOpPassword()
832     {
833         return operatorPassword;
834     }
835 
836     public void setOpPassword(String oppass)
837     {
838         this.operatorPassword = oppass;
839     }
840 
841     public String getAdminPassword()
842     {
843         return adminPassword;
844     }
845 
846     public void setAdminPassword(String adminPassword)
847     {
848         this.adminPassword = adminPassword;
849     }
850 
851     public String getAccessLogPath()
852     {
853         return accesslogPath;
854     }
855 
856     public void setAccessLogPath(String accesslogPath)
857     {
858         this.accesslogPath = accesslogPath;
859     }
860 
861     public String getErrorLogPath()
862     {
863         return errorlogPath;
864     }
865 
866     public void setErrorLogPath(String errorlogPath)
867     {
868         this.errorlogPath = errorlogPath;
869     }
870 
871     public String getChannelsFile()
872     {
873         return channelsFile;
874     }
875 
876     public void setChannelsFile(String channelsFile)
877     {
878         this.channelsFile = channelsFile;
879     }
880 
881     public String getMessageOfTheDay()
882     {
883         return motd;
884     }
885 
886     public void setMessageOfTheDay(String motd)
887     {
888         this.motd = motd;
889     }
890 
891     public boolean isRunning()
892     {
893         return running;
894     }
895 
896     public void setRunning(boolean running)
897     {
898         this.running = running;
899     }
900 
901     public int getStatus()
902     {
903         return status;
904     }
905 
906     public void setStatus(int status)
907     {
908         this.status = status;
909     }
910 
911     public Settings getDefaultSettings()
912     {
913         return Settings.getDefaultSettings();
914     }
915 
916     public void setDefaultSettings(Settings defaultSettings)
917     {
918         Settings.setDefaultSettings(defaultSettings);
919     }
920 
921     public List<ChannelConfig> getChannels()
922     {
923         return channels;
924     }
925 
926     public void addChannel(ChannelConfig cconf)
927     {
928         channels.add(cconf);
929     }
930 
931     public Iterator<FilterConfig> getGlobalFilters()
932     {
933         return globalFilters.iterator();
934     }
935 
936     public void addFilter(FilterConfig filterConfig)
937     {
938         filterConfig.setGlobal(true);
939         globalFilters.add(filterConfig);
940     }
941 
942     public void addFilterAlias(String name, String classname)
943     {
944         FilterManager.getInstance().addFilterAlias(name, classname);
945     }
946 
947     public void addWinlist(WinlistConfig config)
948     {
949         WinlistManager.getInstance().addWinlist(config);
950     }
951 
952     public void addCommand(Command command)
953     {
954         CommandManager.getInstance().addCommand(command);
955     }
956 
957     public void addListener(Listener listener)
958     {
959         listeners.add(listener);
960     }
961 
962     public List<Listener> getListeners()
963     {
964         return listeners;
965     }
966 
967     /***
968      * Add a new service to the server. The service is not started
969      * automatically by calling this method.
970      *
971      * @param service the service to add
972      * @since 0.2
973      */
974     public void addService(Service service)
975     {
976         services.add(service);
977     }
978 
979     /***
980      * Return the list of services currently registered on the server
981      *
982      * @since 0.2
983      */
984     public List<Service> getServices()
985     {
986         return services;
987     }
988 
989     public void addBannedHost(String host)
990     {
991         Banlist.getInstance().ban(host);
992     }
993 
994     /***
995      * Return the server statistics.
996      */
997     public Statistics getStatistics()
998     {
999         return statistics;
1000     }
1001 
1002     /***
1003      * @since 0.3
1004      */
1005     public Collection<DataSourceConfig> getDataSources()
1006     {
1007         return datasources.values();
1008     }
1009 
1010     /***
1011      * @since 0.3
1012      */
1013     public void addDataSource(DataSourceConfig datasource)
1014     {
1015         datasources.put(datasource.getName(), datasource);
1016     }
1017 
1018     /***
1019      * @since 0.3
1020      */
1021     public MailSessionConfig getMailSessionConfig()
1022     {
1023         return mailSessionConfig;
1024     }
1025 
1026     /***
1027      * @since 0.3
1028      */
1029     public void setMailSessionConfig(MailSessionConfig mailSessionConfig)
1030     {
1031         this.mailSessionConfig = mailSessionConfig;
1032     }
1033 
1034     /***
1035      * @since 0.3
1036      */
1037     public String getProperty(String key)
1038     {
1039         return properties != null ? properties.getProperty(key) : null;
1040     }
1041 
1042     /***
1043      * @since 0.3
1044      */
1045     public void setProperty(String key, String value)
1046     {
1047         properties.setProperty(key, value);
1048     }
1049 }