001    /**
002     * Jetrix TetriNET Server
003     * Copyright (C) 2001-2004  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;
021    
022    import java.io.File;
023    import java.io.FileOutputStream;
024    import java.io.IOException;
025    import java.net.URL;
026    import java.net.URLClassLoader;
027    import java.net.DatagramPacket;
028    import java.net.DatagramSocket;
029    import java.net.InetAddress;
030    import java.util.ArrayList;
031    import java.util.List;
032    import java.util.jar.JarOutputStream;
033    import java.util.jar.Pack200;
034    
035    /**
036     * An application launcher executing a specified class and building dynamically
037     * its class path.
038     *
039     * @author Emmanuel Bourg
040     * @version $Revision: 794 $, $Date: 2009-02-17 20:08:39 +0100 (Tue, 17 Feb 2009) $
041     */
042    public class Launcher {
043    
044        public static final String MAIN_CLASS = "net.jetrix.Server";
045    
046        /**
047         * Server entry point. All classes, jar and zip files in the lib
048         * subdirectory are automatically added to the classpath.
049         *
050         * @param args start parameters
051         */
052        public static void main(String[] args) throws Exception
053        {
054            if (args.length == 1 && "stop".equals(args[0]))
055            {
056                stop();
057            }
058            else
059            {
060                start(args);
061            }
062        }
063    
064        private static void start(String[] args) throws Exception
065        {
066            // get the files in the lib directory
067            File repository = new File("lib/");
068    
069            // decompress the pack200 files
070            unpack(repository);
071    
072            ClassLoader loader = createClassLoader(repository, new File("lang/"));
073    
074            Thread.currentThread().setContextClassLoader(loader);
075    
076            // run the main method of the specified class
077            Class serverClass = loader.loadClass(MAIN_CLASS);
078            serverClass.getMethod("main", String[].class).invoke(null, new Object[] { args });
079        }
080    
081        /**
082         * Unpack the pack200 files in the specified directory
083         *
084         * @param directory   the directory containing the files to be unpacked 
085         */
086        private static void unpack(File directory) throws IOException
087        {
088            File[] files = directory.listFiles();
089    
090            for (File file : files)
091            {
092                String filename = file.getAbsolutePath();
093                if (filename.endsWith(".pack"))
094                {
095                    // remove the .pack extension at the end of the unpacked file
096                    String unpackedName = filename.substring(0, filename.lastIndexOf(".pack"));
097                    JarOutputStream out = new JarOutputStream(new FileOutputStream(unpackedName));
098    
099                    Pack200.newUnpacker().unpack(file, out);
100    
101                    out.flush();
102                    out.close();
103    
104                    // delete the packed file
105                    file.delete();
106                }
107            }
108        }
109    
110        /**
111         * Build a classloader including the jar and zip files in the specified
112         * directories. The directories are also included in the classpath.
113         * 
114         * @param directories   the directories containing the jars to be mounted in the classpath
115         */
116        private static ClassLoader createClassLoader(File... directories) throws Exception
117        {
118            List<URL> urls = new ArrayList<URL>();
119    
120            for (File directory : directories)
121            {
122                // add the jar and zip files in the directory to the classpath
123                File[] files = directory.listFiles();
124    
125                for (File file : files)
126                {
127                    String filename = file.getAbsolutePath();
128                    if (filename.endsWith(".jar") || filename.endsWith(".zip"))
129                    {
130                        urls.add(file.toURI().toURL());
131                    }
132                }
133    
134                // add the directory to the classpath
135                urls.add(directory.toURI().toURL());
136            }
137    
138            // create the classloader
139            return new URLClassLoader(urls.toArray(new URL[urls.size()]), null);
140        }
141    
142        private static void stop() throws Exception
143        {
144            // send the "shutdown" to the UDP port 31457
145            byte[] msg = "shutdown".getBytes("UTF8");
146            DatagramPacket packet = new DatagramPacket(msg, msg.length);
147            packet.setAddress(InetAddress.getLocalHost());
148            packet.setPort(31457);
149    
150            DatagramSocket socket = new DatagramSocket();
151            try
152            {
153                socket.send(packet);
154            }
155            finally
156            {
157                socket.close();
158            }
159        }
160    
161    }