Source Code Cross Referenced for LlamaChatServer.java in  » Chat » LlamaChat » server » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Chat » LlamaChat » server 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*- LlamaChatServer.java ------------------------------------------+
002:         |                                                                 |
003:         |  Copyright (C) 2002-2003 Joseph Monti, LlamaChat                |
004:         |                     countjoe@users.sourceforge.net              |
005:         |                     http://www.42llamas.com/LlamaChat/          |
006:         |                                                                 |
007:         | This program is free software; you can redistribute it and/or   |
008:         | modify it under the terms of the GNU General Public License     |
009:         | as published by the Free Software Foundation; either version 2  |
010:         | of the License, or (at your option) any later version           |
011:         |                                                                 |
012:         | This program is distributed in the hope that it will be useful, |
013:         | but WITHOUT ANY WARRANTY; without even the implied warranty of  |
014:         | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   |
015:         | GNU General Public License for more details.                    |
016:         |                                                                 |
017:         | A copy of the GNU General Public License may be found in the    |
018:         | installation directory named "GNUGPL.txt"                       |
019:         |                                                                 |
020:         +-----------------------------------------------------------------+
021:         */
022:
023:        package server;
024:
025:        import java.io.IOException;
026:        import javax.net.ssl.*;
027:        import java.util.Calendar;
028:        import java.util.Enumeration;
029:        import java.util.Hashtable;
030:        import java.util.LinkedList;
031:        import java.io.BufferedOutputStream;
032:        import java.io.File;
033:        import java.io.FileNotFoundException;
034:        import java.io.FileOutputStream;
035:        import java.io.PrintWriter;
036:        import java.io.BufferedReader;
037:        import java.io.FileReader;
038:        import org.xml.sax.*;
039:        import org.xml.sax.helpers.DefaultHandler;
040:        import javax.xml.parsers.SAXParserFactory;
041:        import javax.xml.parsers.ParserConfigurationException;
042:        import javax.xml.parsers.SAXParser;
043:
044:        import common.*;
045:        import common.sd.*;
046:
047:        /* -------------------- JavaDoc Information ----------------------*/
048:        /**
049:         * The main class for the LlamaChat server
050:         * @author Joseph Monti <a href="mailto:countjoe@users.sourceforge.net">countjoe@users.sourceforge.net</a>
051:         * @version 0.8
052:         */
053:        public final class LlamaChatServer extends Thread {
054:
055:            private static LlamaChatServer listeningServer;
056:            public static int PORT = 42412;
057:            public static String sysLogFile = "llamachat.log";
058:            public static String adminPass = "llamachat";
059:            public static LinkedList connectingUsers;
060:            public static Hashtable connectedUsers;
061:            public static boolean running;
062:            public static boolean allowAdmin = true;
063:            private static PrintWriter sysLogOut;
064:            public static String chatLogPath = ".";
065:            private static Hashtable channelFiles;
066:            public static String userExportFile = null;
067:            public static ChannelManager channels;
068:            public static String welcomeMessage = null;
069:            public static String serverConfigFile = "llamachatconf.xml";
070:
071:            /**
072:             * called when a new user has connected.
073:             * @param s	the secure socket that the user connected on
074:             */
075:            synchronized public void newUser(SSLSocket s) {
076:                ClientConnection cc = new ClientConnection(this , s);
077:                connectingUsers.add(cc);
078:            }
079:
080:            /**
081:             * finalizes the connection to the client by setting its username
082:             * and updating all lists of users by sending the new user to all the
083:             * connected users and sending the user list to the new user, also
084:             * checks the validity of the username
085:             * @param uname	the desired user name for the new user
086:             * @param cc	the object representing the connecting user
087:             * @return		true on success, false otherwise
088:             */
089:            synchronized public boolean finalizeUser(String uname,
090:                    ClientConnection cc) {
091:                if (connectedUsers.containsKey(uname)
092:                        || connectedUsers.contains(cc)) {
093:                    cc
094:                            .writeObject(new SD_Error(
095:                                    "Already a user of that name or "
096:                                            + "already connected. \nType \\rename &lt;new name&gt; to "
097:                                            + "choose a different name"));
098:                    log(cc, "failed [duplicate exists]");
099:                    return false;
100:                } else if (uname.length() > 10) {
101:                    cc.writeObject(new SD_Error("Username too long.\n"
102:                            + "Type \\rename &lt;new name&gt; to choose "
103:                            + "a different name"));
104:                    log(cc, "failed [bad name]");
105:                    return false;
106:                } else if (uname.equals("server")
107:                        || !uname.matches("[\\w_-]+?")) {
108:                    cc.writeObject(new SD_Error("Invalid username " + uname
109:                            + ".\n"
110:                            + "Type \\rename &lt;new name&gt; to choose "
111:                            + "a different name"));
112:                    log(cc, "failed [bad name]");
113:                    return false;
114:                } else if (connectingUsers.remove(cc)) {
115:                    cc.writeObject(new SD_ServerCap(SD_ServerCap.T_CREATE,
116:                            new Character(channels.allowUserChannels)));
117:                    if (welcomeMessage != null) {
118:                        cc.writeObject(new SD_Chat("server", welcomeMessage));
119:                    }
120:                    cc.writeObject(new SD_Channel(false, cc.channel, null));
121:                    sendUserList(cc);
122:                    Enumeration e = channels.enumerate();
123:                    while (e.hasMoreElements()) {
124:                        String channel = (String) e.nextElement();
125:                        cc.writeObject(new SD_Channel(true, channel, channels
126:                                .channelHasPass(channel)));
127:                    }
128:                    connectedUsers.put(uname, cc);
129:                    broadcast(new SD_UserAdd(uname), uname, cc.channel);
130:                    updateUserExport();
131:                    log(cc, "connected as " + uname);
132:                    return true;
133:                }
134:
135:                cc.writeObject(new SD_Error(
136:                        "invalid connection procedure, please try again"));
137:                return false;
138:            }
139:
140:            /**
141:             * sends the current user listing to the specified user
142:             * @param cc	the user requesting the list
143:             */
144:            synchronized public void sendUserList(ClientConnection cc) {
145:                Enumeration e = connectedUsers.keys();
146:                while (e.hasMoreElements()) {
147:                    String un = (String) e.nextElement();
148:                    if (cc.name.equals(un)) {
149:                        continue;
150:                    }
151:                    ClientConnection o = (ClientConnection) connectedUsers
152:                            .get(un);
153:                    if (o.channel.equals(cc.channel)) {
154:                        cc.writeObject(new SD_UserAdd(un));
155:                        if (o.isAdmin()) {
156:                            cc.writeObject(new SD_AdminAdd(un));
157:                        }
158:                    }
159:                }
160:                cc.writeObject(new SD_UserAdd(null)); // send End of List
161:            }
162:
163:            /**
164:             * sends the specified SocketData to the client, to
165:             * @param sd	the SocketData object to be sent
166:             * @param to	the user to be sent the data
167:             * @return 	status of the sendTo
168:             */
169:            synchronized public boolean sendTo(SocketData sd, String to) {
170:                ClientConnection o = (ClientConnection) connectedUsers.get(to);
171:                if (o != null) {
172:                    o.writeObject(sd);
173:                    return true;
174:                } else {
175:                    return false;
176:                }
177:            }
178:
179:            /**
180:             * broadcases a message to all connected user except from
181:             * @param sd	the SocketData object to be sent
182:             * @param from	the user to be avoided when sending data
183:             *				(usually the user sending the data)
184:             */
185:            synchronized public void broadcast(SocketData sd, String from) {
186:                Enumeration e = connectedUsers.keys();
187:                while (e.hasMoreElements()) {
188:                    String to = (String) e.nextElement();
189:                    if (!to.equals(from)) {
190:                        ClientConnection o = (ClientConnection) connectedUsers
191:                                .get(to);
192:                        o.writeObject(sd);
193:                    }
194:                }
195:            }
196:
197:            /**
198:             * broadcases a message to all connected user except from
199:             * and is a member of c
200:             * @param sd	the SocketData object to be sent
201:             * @param from	the user to be avoided when sending data
202:             *				(usually the user sending the data)
203:             * @param c		the channel the user is connected to
204:             */
205:            synchronized public void broadcast(SocketData sd, String from,
206:                    String c) {
207:                Enumeration e = connectedUsers.keys();
208:                while (e.hasMoreElements()) {
209:                    String to = (String) e.nextElement();
210:                    if (!to.equals(from)) {
211:                        ClientConnection o = (ClientConnection) connectedUsers
212:                                .get(to);
213:                        if (o.channel.equals(c)) {
214:                            o.writeObject(sd);
215:
216:                        }
217:                    }
218:                }
219:            }
220:
221:            /**
222:             * sends a SD_UserDel object to all users announcing that un has left
223:             * the building
224:             * @param cc	the user leaving
225:             */
226:            synchronized public void delete(ClientConnection cc) {
227:                broadcast(new SD_UserDel(cc.name), null, cc.channel);
228:            }
229:
230:            /**
231:             * Removes a user from the list of connected users and calls delete
232:             * @param cc	the associated ClientConnection.
233:             * @see #delete(ClientConnection cc)
234:             */
235:            synchronized public void kill(ClientConnection cc) {
236:                try {
237:                    if (cc.name != null && connectedUsers.remove(cc.name) == cc) {
238:                        log(cc, cc.name + " disconnected");
239:                        updateUserExport();
240:                        if (channels.userDel(cc.channel)) {
241:                            broadcast(new SD_Channel(true, cc.channel, null),
242:                                    null);
243:                            chatLog(cc, false);
244:                        }
245:                        delete(cc);
246:                    }
247:                } catch (NullPointerException e) {
248:                    e.printStackTrace();
249:                    if (cc != null) {
250:                        log("null pointer on kill: " + cc.name + " ("
251:                                + cc.channel + ")");
252:                    } else {
253:                        log("got sent a null cc");
254:                    }
255:                }
256:            }
257:
258:            /**
259:             * gets the current date/time of the form MM/DD/YY HH:MM:SS
260:             * used for loggin purposes
261:             * @return a string specifying the current date/time
262:             */
263:            public static String getTimestamp() {
264:                Calendar rightNow = Calendar.getInstance();
265:                return rightNow.get(Calendar.MONTH) + "/"
266:                        + rightNow.get(Calendar.DATE) + "/"
267:                        + rightNow.get(Calendar.YEAR) + " "
268:                        + rightNow.get(Calendar.HOUR_OF_DAY) + ":"
269:                        + rightNow.get(Calendar.MINUTE) + ":"
270:                        + rightNow.get(Calendar.SECOND);
271:            }
272:
273:            /**
274:             * writes to the servers log file preceded by a timestamp
275:             * @param s	the string to be logged
276:             */
277:            synchronized private void log(String s) {
278:                if (sysLogOut != null) {
279:                    sysLogOut.println(getTimestamp() + " - " + s);
280:                    sysLogOut.flush();
281:                }
282:            }
283:
284:            /**
285:             * a public method used by clients to send log data
286:             * @param cc	the client sending the log, used to identify
287:             				the logger in the log
288:             * @param s		the string to be logged
289:             */
290:            public void log(ClientConnection cc, String s) {
291:                log(cc.ip + " - " + s);
292:            }
293:
294:            /**
295:             * manages the chat log
296:             * <br><br><i>do something about channels</i>
297:             * @param cc	the client attempting to change the log status. used to
298:             *				determine what channel to work with, if null close all
299:             * @param start	enables chat logging when true, stops otherwise
300:             * @return true on succes
301:             */
302:            synchronized public boolean chatLog(ClientConnection cc,
303:                    boolean start) {
304:                if (cc == null) {
305:                    Enumeration e = channelFiles.keys();
306:                    while (e.hasMoreElements()) {
307:                        String name = (String) e.nextElement();
308:                        ChatFileItem item = (ChatFileItem) channelFiles
309:                                .get(name);
310:                        closeLog(null, item);
311:                    }
312:                    return true;
313:                }
314:                ChatFileItem currentWriter = (ChatFileItem) channelFiles
315:                        .get(cc.channel);
316:                if (start) {
317:                    if (currentWriter != null && currentWriter.logging) {
318:                        cc.writeObject(new SD_Error("already logging "
319:                                + cc.channel));
320:                        return false;
321:                    }
322:                    if (currentWriter == null) {
323:                        currentWriter = new ChatFileItem();
324:                        channelFiles.put(cc.channel, currentWriter);
325:                    }
326:                    String fname = chatLogPath
327:                            + System.getProperty("file.separator") + "chat-"
328:                            + cc.channel + ".log";
329:                    try {
330:                        currentWriter.chatOut = new PrintWriter(
331:                                new BufferedOutputStream(new FileOutputStream(
332:                                        new File(fname), true)));
333:                        currentWriter.chatOut.println("log started by "
334:                                + (cc != null ? cc.name : "server") + " at "
335:                                + getTimestamp());
336:                        currentWriter.chatOut
337:                                .println("====================================================");
338:                        currentWriter.chatOut.flush();
339:                        currentWriter.logging = true;
340:                    } catch (FileNotFoundException e) {
341:                        cc.writeObject(new SD_Error("error opening " + fname));
342:                        listeningServer.running = false;
343:                        return false;
344:                    }
345:                    return true;
346:                }
347:
348:                return closeLog(cc, currentWriter);
349:            }
350:
351:            /**
352:             * utility method to close a specified log
353:             * @param cc	the client attempting to close
354:             * @param currentWriter	the ChatFileItem to close
355:             * @return true on success, false on failure
356:             */
357:            private boolean closeLog(ClientConnection cc,
358:                    ChatFileItem currentWriter) {
359:                if (currentWriter == null || currentWriter.chatOut == null) {
360:                    //cc.writeObject(new SD_Error("not logging"));
361:                    return false;
362:                }
363:                currentWriter.chatOut
364:                        .println("====================================================");
365:                currentWriter.chatOut.println("log stopped by "
366:                        + (cc != null ? cc.name : "server") + " at "
367:                        + getTimestamp());
368:                currentWriter.chatOut
369:                        .println("====================================================");
370:                currentWriter.chatOut.flush();
371:                currentWriter.chatOut.close();
372:                currentWriter.chatOut = null;
373:                currentWriter.logging = false;
374:                if (cc != null) {
375:                    channelFiles.remove(cc.channel);
376:                }
377:                return true;
378:            }
379:
380:            /**
381:             * logs the specified chat message
382:             * @param cc		the client chatting
383:             * @param message	the message to be sent
384:             */
385:            synchronized public void chatLog(ClientConnection cc, String message) {
386:                ChatFileItem currentWriter = (ChatFileItem) channelFiles
387:                        .get(cc.channel);
388:                if (currentWriter != null && currentWriter.logging
389:                        && currentWriter.chatOut != null) {
390:                    currentWriter.chatOut.println(cc.name + ": " + message);
391:                    currentWriter.chatOut.flush();
392:                }
393:            }
394:
395:            /**
396:             * allows for the user listing (newline separated) to be exported
397:             * to the filesystem, should be called whenever users are added or
398:             * removed or renamed
399:             * @return true on succes, false otherwise
400:             */
401:            synchronized static public boolean updateUserExport() {
402:                if (userExportFile == null) {
403:                    return false;
404:                }
405:                try {
406:                    PrintWriter pw = new PrintWriter(new BufferedOutputStream(
407:                            new FileOutputStream(new File(userExportFile),
408:                                    false)));
409:                    Enumeration e = connectedUsers.keys();
410:                    int i;
411:                    for (i = 0; e.hasMoreElements(); i++) {
412:                        String usr = (String) e.nextElement();
413:                        ClientConnection o = (ClientConnection) connectedUsers
414:                                .get(usr);
415:                        pw.println(usr + " (" + o.channel + ")");
416:                    }
417:
418:                    if (i == 0) {
419:                        pw.println("(no connected users)");
420:                    }
421:
422:                    pw.close();
423:                } catch (FileNotFoundException e) {
424:                    System.err.println("unable to access userExportFile: "
425:                            + userExportFile);
426:                    userExportFile = null;
427:                }
428:                return true;
429:            }
430:
431:            /**
432:             * creates a new channel, assuming the channel can be created
433:             * @param name	the name of the channel to be craeted
434:             * @param pass  the password for the channel
435:             * @param cc	the client requesting the channel
436:             * @return true if created
437:             */
438:            synchronized public String newChannel(String name, String pass,
439:                    ClientConnection cc) {
440:                String ret;
441:                if ((ret = channels.addUserChannel(name, pass, cc)) != null) {
442:                    return ret;
443:                }
444:                broadcast(
445:                        new SD_Channel(true, name, (pass == null ? null : "")),
446:                        null);
447:                return null;
448:            }
449:
450:            /**
451:             * checks to see if the specified channel exists
452:             * @param name	the name of the channel
453:             * @return true if name exists exists
454:             */
455:            synchronized public boolean channelExists(String name) {
456:                return channels.channelExists(name);
457:            }
458:
459:            /**
460:             * the main loop to recieving incoming clients listens on a secure
461:             * server socket creates a shutdown hook to catch a server kill
462:             * and exit gracefully
463:             */
464:            public void run() {
465:                Runtime.getRuntime().addShutdownHook(new ShutdownThread(this ));
466:                try {
467:                    SSLServerSocketFactory factory = (SSLServerSocketFactory) SSLServerSocketFactory
468:                            .getDefault();
469:                    SSLServerSocket sslIncoming = (SSLServerSocket) factory
470:                            .createServerSocket(PORT);
471:                    String[] enabledCipher = sslIncoming
472:                            .getSupportedCipherSuites();
473:                    sslIncoming.setEnabledCipherSuites(enabledCipher);
474:
475:                    log("Server Started");
476:                    while (running) {
477:                        SSLSocket s = (SSLSocket) sslIncoming.accept();
478:                        newUser(s);
479:                    }
480:                } catch (IOException e) {
481:                    System.out.println("Error: " + e);
482:                }
483:                log("Server Stopped");
484:            }
485:
486:            /**
487:             * a useless constructor
488:             */
489:            LlamaChatServer() {
490:                running = true;
491:            }
492:
493:            /**
494:             * main method for class; initializes lists and system log file
495:             * @param args the command line arguments
496:             */
497:            public static void main(String args[]) {
498:                listeningServer = new LlamaChatServer();
499:                //listeningServer.running = true;
500:
501:                connectingUsers = new LinkedList();
502:                connectedUsers = new Hashtable();
503:                channels = new ChannelManager();
504:                channelFiles = new Hashtable();
505:
506:                try {
507:                    DefaultHandler handler = new ConfigParser(listeningServer);
508:                    SAXParserFactory factory = SAXParserFactory.newInstance();
509:                    SAXParser saxParser = factory.newSAXParser();
510:                    saxParser.parse(new File(serverConfigFile), handler);
511:                } catch (Throwable t) {
512:                    System.err.println("error parsing " + serverConfigFile);
513:                    running = false;
514:                }
515:
516:                try {
517:                    sysLogOut = new PrintWriter(new BufferedOutputStream(
518:                            new FileOutputStream(new File(sysLogFile), true)));
519:                } catch (FileNotFoundException e) {
520:                    System.err.println(sysLogFile + " not found.");
521:                    running = false;
522:                }
523:
524:                updateUserExport();
525:
526:                listeningServer.start();
527:                try {
528:                    listeningServer.join();
529:                } catch (InterruptedException e) {
530:                }
531:            }
532:
533:            /**
534:             * A class to enable gracefull shutdown when unexpectadly killed
535:             */
536:            public class ShutdownThread extends Thread {
537:                private LlamaChatServer lcs;
538:
539:                ShutdownThread(LlamaChatServer l) {
540:                    lcs = l;
541:                }
542:
543:                public void run() {
544:                    log("Server Stopped");
545:                    sysLogOut.close();
546:                    chatLog(null, false);
547:                }
548:            }
549:
550:            /**
551:             * a class to hold logging information on a Hashtable
552:             */
553:            private class ChatFileItem {
554:                public boolean logging;
555:                public PrintWriter chatOut;
556:
557:                ChatFileItem() {
558:                    logging = false;
559:                    chatOut = null;
560:                }
561:            }
562:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.