View Javadoc

1   /***
2    * Jetrix TetriNET Server
3    * Copyright (C) 2001-2004  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;
21  
22  import java.util.*;
23  
24  import net.jetrix.config.*;
25  import net.jetrix.messages.ShutdownMessage;
26  
27  /***
28   * Manages Channels
29   *
30   * @author Emmanuel Bourg
31   * @version $Revision: 860 $, $Date: 2010-05-06 13:21:05 +0200 (jeu., 06 mai 2010) $
32   */
33  public class ChannelManager
34  {
35      private List<Channel> channels;
36      private Map<String, Channel> channelMap;
37      private static ChannelManager instance = new ChannelManager();
38  
39      private ChannelManager()
40      {
41          channels = new ArrayList<Channel>();
42          channelMap = new TreeMap<String, Channel>();
43      }
44  
45      public static ChannelManager getInstance()
46      {
47          return instance;
48      }
49  
50      /***
51       * Create a channel and start it immediately.
52       *
53       * @param config the channel configuration
54       */
55      public Channel createChannel(ChannelConfig config)
56      {
57          return createChannel(config, true);
58      }
59  
60      /***
61       * Create a channel initialized with the specified configuration.
62       *
63       * @param config the channel configuration
64       * @param start  initial state
65       */
66      public Channel createChannel(ChannelConfig config, boolean start)
67      {
68          Channel channel = new Channel(config);
69          channel.setName("channel: " + config.getName());
70          if (start)
71          {
72              channel.start();
73          }
74          channels.add(channel);
75          channelMap.put(config.getName().toLowerCase(), channel);
76          return channel;
77      }
78  
79      /***
80       * Remove a channel.
81       */
82      public void removeChannel(String name)
83      {
84          // get the channel
85          Channel channel = getChannel(name);
86          
87          removeChannel(channel);
88          
89          // close it as soon as the last client leaves
90          channel.getConfig().setPersistent(false);
91          channel.send(new ShutdownMessage());
92      }
93  
94      /***
95       * Remove a channel.
96       */
97      public void removeChannel(Channel channel)
98      {
99          String name = channel.getConfig().getName().toLowerCase();
100 
101         // unregister the channel
102         channels.remove(channel);
103         channelMap.remove(name.toLowerCase());
104     }
105 
106     /***
107      * Returns the number of existing channels.
108      */
109     public int getChannelCount()
110     {
111         return channels.size();
112     }
113 
114     /***
115      * Returns an iterator over the channels available.
116      */
117     public Collection<Channel> channels()
118     {
119         return channels;
120     }
121 
122     /***
123      * Looks for a channel with room left.
124      *
125      * @return <tt>null</tt> if there is no room left in all available channels
126      *
127      * @deprecated
128      */
129     public Channel getOpenedChannel()
130     {
131         Channel channel = null;
132         Iterator<Channel> it = channels.iterator();
133         while (it.hasNext() && channel == null)
134         {
135             Channel channel2 = it.next();
136             if (!channel2.isFull())
137             {
138                 channel = channel2;
139             }
140         }
141 
142         return channel;
143     }
144 
145     /***
146      * Return the most suitable home channel for a player newly connected,
147      * that's the first accessible channel with players to play with.
148      *
149      * The channel selected matches the following criteria:
150      * <ul>
151      *   <li>it must be accessible for the specified access level</li>
152      *   <li>it must not be password protected</li>
153      *   <li>it must have room left</li>
154      *   <li>it should not be empty</li>
155      * </ul>
156      *
157      * @since 0.2
158      *
159      * @param level the access level of the player added in the channel
160      * @param protocol the name of the protocol used
161      */
162     public Channel getHomeChannel(int level, String protocol)
163     {
164         Channel channel = null;
165         Channel emptyChannel = null;
166 
167         Iterator<Channel> it = channels.iterator();
168         while (it.hasNext() && channel == null)
169         {
170             Channel chan = it.next();
171 
172             if (chan.getConfig().getAccessLevel() <= level
173                     && !chan.getConfig().isPasswordProtected()
174                     && !chan.isFull()
175                     && chan.getConfig().isProtocolAccepted(protocol))
176             {
177                 if (chan.isEmpty())
178                 {
179                     emptyChannel = (emptyChannel != null) ? emptyChannel : chan;
180                 }
181                 else
182                 {
183                     channel = chan;
184                 }
185             }
186         }
187 
188         return channel != null ? channel : emptyChannel;
189     }
190 
191     /***
192      * Tells if a non private channel is available for a client using the specified protocol.
193      * 
194      * @param protocol the name of the protocol used
195      * @since 0.3
196      */
197     public boolean hasCompatibleChannels(String protocol)
198     {
199         for (Channel chan : channels)
200         {
201             if (!chan.getConfig().isPasswordProtected() && chan.getConfig().isProtocolAccepted(protocol))
202             {
203                 return true;
204             }
205         }
206         
207         return false;
208     }
209 
210     /***
211      * Return the channel with the specified name. The leading # is removed from
212      * the name before searching. The name is not case sensitive.
213      *
214      * @param name the name of the channel to find
215      * @return
216      */
217     public Channel getChannel(String name)
218     {
219         return getChannel(name, false);
220     }
221 
222     /***
223      * Returns the channel with the specified name. The leading # is removed from
224      * the name before searching. The name is not case sensitive. If no channel
225      * matches the name specified, it can return the first channel starting
226      * with the name if the <code>partial</code> parameter is set to
227      * <code>true</code>.
228      *
229      * @param name    the name of the channel to find
230      * @param partial use the partial name matching
231      *
232      * @return instance of the specified channel, <tt>null</tt> if not found
233      */
234     public Channel getChannel(String name, boolean partial)
235     {
236         // stripping leading #
237         name = name.replaceFirst("#", "").toLowerCase();
238 
239         Channel channel = channelMap.get(name);
240 
241         if (channel == null && partial)
242         {
243             // match a partial name
244             Iterator<String> names = channelMap.keySet().iterator();
245             while (channel == null && names.hasNext())
246             {
247                 String name2 = names.next();
248                 if (name2.startsWith(name))
249                 {
250                     channel = channelMap.get(name2);
251                 }
252             }
253         }
254 
255         return channel;
256     }
257 
258     /***
259      * Clear the channel list.
260      */
261     public void clear()
262     {
263         channels.clear();
264         channelMap.clear();
265     }
266 
267     /***
268      * Close all channels.
269      */
270     public void closeAll()
271     {
272         for (Channel channel : channels)
273         {
274             try
275             {
276                 channel.close();
277             }
278             catch (Exception e)
279             {
280                 e.printStackTrace();
281             }
282         }
283     }
284 
285     /***
286      * Get a channel by number in the list.
287      */
288     public Channel getChannel(int num)
289     {
290         return ((num >= 0 && num < channels.size()) ? channels.get(num) : null);
291     }
292 
293 }