169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/*
269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Javassist, a Java-bytecode translator toolkit.
369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The contents of this file are subject to the Mozilla Public License Version
669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1.1 (the "License"); you may not use this file except in compliance with
769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the License.  Alternatively, the contents of this file may be used under
869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the terms of the GNU Lesser General Public License Version 2.1 or later.
969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Software distributed under the License is distributed on an "AS IS" basis,
1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * for the specific language governing rights and limitations under the
1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * License.
1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpackage javassist.tools.web;
1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.io.*;
1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.net.*;
2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/**
2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * A sample applet viewer.
2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>This is a sort of applet viewer that can run any program even if
2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the main class is not a subclass of <code>Applet</code>.
2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * This viewwer first calls <code>main()</code> in the main class.
2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>To run, you should type:
2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <ul><code>% java javassist.tools.web.Viewer <i>host port</i> Main arg1, ...</code></ul>
3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>This command calls <code>Main.main()</code> with <code>arg1,...</code>
3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * All classes including <code>Main</code> are fetched from
3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * a server http://<i>host</i>:<i>port</i>.
3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Only the class file for <code>Viewer</code> must exist
3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * on a local file system at the client side; even other
3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <code>javassist.*</code> classes are not needed at the client side.
3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <code>Viewer</code> uses only Java core API classes.
3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>Note: since a <code>Viewer</code> object is a class loader,
4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * a program loaded by this object can call a method in <code>Viewer</code>.
4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * For example, you can write something like this:
4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <ul><pre>
4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Viewer v = (Viewer)this.getClass().getClassLoader();
4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * String port = v.getPort();
4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * </pre></ul>
4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic class Viewer extends ClassLoader {
5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private String server;
5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private int port;
5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Starts a program.
5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public static void main(String[] args) throws Throwable {
5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (args.length >= 3) {
5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Viewer cl = new Viewer(args[0], Integer.parseInt(args[1]));
6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            String[] args2 = new String[args.length - 3];
6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            System.arraycopy(args, 3, args2, 0, args.length - 3);
6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            cl.run(args[2], args2);
6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else
6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            System.err.println(
6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        "Usage: java javassist.tools.web.Viewer <host> <port> class [args ...]");
6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Constructs a viewer.
7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param host              server name
7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param p                 port number
7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Viewer(String host, int p) {
7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        server = host;
7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        port = p;
7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns the server name.
8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public String getServer() { return server; }
8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns the port number.
8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public int getPort() { return port; }
8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Invokes main() in the class specified by <code>classname</code>.
9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param classname         executed class
9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param args              the arguments passed to <code>main()</code>.
9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void run(String classname, String[] args)
9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws Throwable
9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Class c = loadClass(classname);
10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            c.getDeclaredMethod("main", new Class[] { String[].class })
10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                .invoke(null, new Object[] { args });
10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (java.lang.reflect.InvocationTargetException e) {
10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw e.getTargetException();
10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Requests the class loader to load a class.
11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    protected synchronized Class loadClass(String name, boolean resolve)
11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws ClassNotFoundException
11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Class c = findLoadedClass(name);
11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (c == null)
11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            c = findClass(name);
11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (c == null)
12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new ClassNotFoundException(name);
12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (resolve)
12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            resolveClass(c);
12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return c;
12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Finds the specified class.  The implementation in this class
13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * fetches the class from the http server.  If the class is
13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * either <code>java.*</code>, <code>javax.*</code>, or
13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <code>Viewer</code>, then it is loaded by the parent class
13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * loader.
13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>This method can be overridden by a subclass of
13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <code>Viewer</code>.
13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    protected Class findClass(String name) throws ClassNotFoundException {
13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Class c = null;
14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (name.startsWith("java.") || name.startsWith("javax.")
14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            || name.equals("javassist.tools.web.Viewer"))
14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            c = findSystemClass(name);
14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (c == null)
14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            try {
14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                byte[] b = fetchClass(name);
14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                if (b != null)
14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    c = defineClass(name, b, 0, b.length);
14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (Exception e) {
15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return c;
15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Fetches the class file of the specified class from the http
15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * server.
15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    protected byte[] fetchClass(String classname) throws Exception
16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        byte[] b;
16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        URL url = new URL("http", server, port,
16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                          "/" + classname.replace('.', '/') + ".class");
16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        URLConnection con = url.openConnection();
16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        con.connect();
16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int size = con.getContentLength();
16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        InputStream s = con.getInputStream();
16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (size <= 0)
17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            b = readStream(s);
17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else {
17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            b = new byte[size];
17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int len = 0;
17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            do {
17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                int n = s.read(b, len, size - len);
17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                if (n < 0) {
17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    s.close();
17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    throw new IOException("the stream was closed: "
17969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                          + classname);
18069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                }
18169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                len += n;
18269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            } while (len < size);
18369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
18469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
18569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        s.close();
18669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return b;
18769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
18869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
18969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private byte[] readStream(InputStream fin) throws IOException {
19069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        byte[] buf = new byte[4096];
19169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int size = 0;
19269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int len = 0;
19369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        do {
19469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            size += len;
19569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (buf.length - size <= 0) {
19669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                byte[] newbuf = new byte[buf.length * 2];
19769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                System.arraycopy(buf, 0, newbuf, 0, size);
19869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                buf = newbuf;
19969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
20069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
20169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            len = fin.read(buf, size, buf.length - size);
20269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        } while (len >= 0);
20369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
20469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        byte[] result = new byte[size];
20569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        System.arraycopy(buf, 0, result, 0, size);
20669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return result;
20769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
20869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
209