001    /**
002     * Jetrix TetriNET Server
003     * Copyright (C) 2001-2003  Emmanuel Bourg
004     *
005     * This program is free software; you can redistribute it and/or
006     * modify it under the terms of the GNU General Public License
007     * as published by the Free Software Foundation; either version 2
008     * of the License, or (at your option) any later version.
009     *
010     * This program is distributed in the hope that it will be useful,
011     * but WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013     * GNU General Public License for more details.
014     *
015     * You should have received a copy of the GNU General Public License
016     * along with this program; if not, write to the Free Software
017     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
018     */
019    
020    package net.jetrix.config;
021    
022    import java.io.*;
023    import java.net.*;
024    import java.util.*;
025    import java.util.logging.*;
026    import java.beans.*;
027    
028    import org.apache.commons.digester.*;
029    import org.apache.commons.beanutils.*;
030    import org.xml.sax.*;
031    
032    import net.jetrix.*;
033    import net.jetrix.winlist.*;
034    import net.jetrix.filter.*;
035    import net.jetrix.commands.*;
036    
037    /**
038     * Server configuration. This objet reads and retains server parameters,
039     * channel definitions and the ban list.
040     *
041     * @author Emmanuel Bourg
042     * @version $Revision: 866 $, $Date: 2010-08-23 17:02:51 +0200 (lun., 23 août 2010) $
043     */
044    public class ServerConfig
045    {
046        private static Logger log = Logger.getLogger("net.jetrix");
047    
048        public static final String ENCODING = "ISO-8859-1";
049    
050        public static final String VERSION = "@version@";
051    
052        public static final int STATUS_OPENED = 0;
053        public static final int STATUS_LOCKED = 1;
054    
055        private String name;
056        private InetAddress host;
057        private int timeout;
058        private int maxChannels;
059        private int maxPlayers;
060        private int maxConnections;
061        private String operatorPassword;
062        private String adminPassword;
063        private String accesslogPath;
064        private String errorlogPath;
065        private String channelsFile = "channels.xml";
066        private String motd;
067        private Locale locale;
068    
069        // private List bans;
070        private List<ChannelConfig> channels = new ArrayList<ChannelConfig>();
071        private List<FilterConfig> globalFilters = new ArrayList<FilterConfig>();
072        private List<Listener> listeners = new ArrayList<Listener>();
073        private List<Service> services = new ArrayList<Service>();
074        private boolean running;
075        private int status;
076        private Statistics statistics = new Statistics();
077    
078        /** Datasources configuration */
079        private Map<String, DataSourceConfig> datasources = new LinkedHashMap<String, DataSourceConfig>();
080    
081        /** Mail session configuration */
082        private MailSessionConfig mailSessionConfig;
083    
084        /** Extended properties */
085        private Properties properties = new Properties();
086    
087        private URL serverConfigURL;
088        private URL channelsConfigURL;
089    
090        /**
091         * Load the configuration
092         */
093        public void load(File file)
094        {
095            try
096            {
097                load(file.toURI().toURL());
098            }
099            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    }