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
85 Channel channel = getChannel(name);
86
87 removeChannel(channel);
88
89
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
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
237 name = name.replaceFirst("#", "").toLowerCase();
238
239 Channel channel = channelMap.get(name);
240
241 if (channel == null && partial)
242 {
243
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 }