Downloading extra classes as required...

What I am trying to do is this (in Java 1.1!):

Have a simple (<50k) stub loader class in one jar file (loader.jar).
Have the rest of the game in another jar file (game.jar)

Both of these are UNSIGNED applets.

I would like the loader.jar to then show a load screen and then download game.jar and use classes from this.

The examples I have found so far make a new derived ClassLoader, download the jar as a stream, then read the classes from memory - but this throws a security exception as the applet.

Is there another way to do this? I want to avoid having all the classes seperate (and un-zipped), which is why I want the second jar file.

Is this possible with Java 1.1? If so, how?

  • Dom

It’s been a while since I look at Java 1.1, but couldn’t reflection help you here.

Your launcher app shouldn’t have any object references to classes in the game.jar, but once you’ve shown your loading screen and whatever else you then make some reflective call to Game.class at which point it’ll be loaded by the class loader for you.

Something like this (which is off the top of my head)


Object myGame = Class.forName("Game").newInstance();
myGame.run();

The thing I’m not sure about is that when you specify your two jar files in the html for your applet, does the java plugin (or browser if its on older machines) just load both over the network regardless of if you use classes from both, or is it smart enough to only downlaod the jars when you need a class from within.

I think it may down load both, because how does it know where your Launcher.class is without looking inside the manifest file, or the jar itself.

Not sure if I answered you question completely, but maybe pointed you off in some direction.

Regards,

Andy.

There is no way to bypass the security model. You must sign your jars and download them using a security managed classloader or you’ll get a security exception. And you can’t sign individual classes.

Cas :slight_smile:

I don’t see why downloading a second jar once from the first goes against the security model - I only want to load standard classes so don’t want a new classloader if I can avoid it.
I found a reference to listing multiple jars in the manifest, but Im not 100% sure what this will do…
Hmmm… ???

  • Dom

do you HAVE to have them in jars? If not, put them all in one directory, load your loader class, then use reflection to pull everything else you need later.

It doesn’t matter where you read the class binaries from, the sandbox won’t allow you to define the class.

Specifically, ClassLoader.defineClass(…) is protected, the security manager won’t let you load classes in the java.lang package, you can’t replace the security manager, and the ClassLoader constructor calls this method, so you can’t subclass ClassLoader to access that method.

[edit:]
Hm, YaBB won’t let me link “http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ClassLoader.html#defineClass(java.lang.String, byte[], int, int)”…
It adds a space in the url after “#defin” =/
(no, I’m not typing it like that)

[quote]It doesn’t matter where you read the class binaries from, the sandbox won’t allow you to define the class.
[/quote]
Won’t allow me to define which class ???

I don’t want a new class loader, all I want is a second jar file on the server to load (standard) classes from so I can have a small stub that displays a loading screen while it then downloads the rest of the game instead of a blank grey area that doesn’t even tell the user that its loading anything.

I have resigned myself to the fact that this is impossible to do at the moment :frowning:

A while back i face the same problem…

In the end i did need to use a more modern VM to handle the actual data loading however the microsoft VM was able to load in the classes that i specified, just not the data used by the applet.

The applet in all its bad gui design horror:

www.geocities.com/budgetanime/page8.html

This is the code i used:

(uncommented and meaningless variable names… yay me!)

You will also need to cull large sections related to the loading of the data.


/*
 * Created on 15/09/2003
 *
 * To change the template for this generated file go to
 * Window>Preferences>Java>Code Generation>Code and Comments
 */
/**
 * @author klaebe
 *
 * To change the template for this generated type comment go to
 * Window>Preferences>Java>Code Generation>Code and Comments
 */
import java.applet.*;
import java.awt.*;
import java.awt.event.*;

//public class OrderingAppletLoaderApp extends Frame
//{
//      OrderingAppletLoader oal=new OrderingAppletLoader();
      
      

public class OrderingAppletLoader extends Applet
{
      Object root;
      TextArea ta;
      java.lang.Class loader;
      java.lang.Class orderingApplet;
      boolean loaded;
      int totalLines;
      int lineCount;
      Updater updater;
      String oldText;
      Panel cards;
      //boolean next;
      //Timer timer;
      Object a;
      LoaderThread loaderThread;
      boolean asApplet;

      
      public OrderingAppletLoader()
      {
            
      }
      
      public void init()
      {
            cards=new Panel(new CardLayout());
            Panel p =new Panel();
            //p.setSize(640,480);
            ta=new TextArea();
            //ta.append("YO!");
            p.setLayout(new GridLayout(1,1));
            setLayout(new GridLayout(1,1));
            p.add(ta);
            cards.add("Main",p);
            loaded=false;
            totalLines=1;
            lineCount=1;
            updater=new Updater(this);
      ///      timer=new Timer();
      
            //repaint(1);
            asApplet=true;
            loaderThread=new LoaderThread(this);
      }
      public void start()
      {
            root=this;
            ((Applet) root).add(cards);
            
      //      process();
            (new Thread(loaderThread,"LoaderThread")).start();
      }
      
      public static void main(String[] args) 
      {
            Frame frame= new Frame();
            frame.setSize(640,480);

            OrderingAppletLoader oal=new OrderingAppletLoader();
            oal.root=frame;
            oal.init();

            ((Frame) oal.root).add(oal.cards);
            

            frame.setVisible(true);
            
            
            Loader loader =new Loader();
            oal.asApplet=false;
            loader.init(oal);
            loader.loadSeries();
            while (loader.str!=null) loader.loadSeries();
            loader.loadOST();
            while (loader.str!=null) loader.loadOST();
            loader.loadMovies();
            while (loader.str!=null) loader.loadMovies();
            
            OrderingApplet aa= new OrderingApplet();
            
            Panel p1=new Panel(new GridLayout(1,1));
            p1.add((Component) aa);
            oal.cards.add("Applet",p1);
            
            aa.setup(loader);
            aa.init();
            
            
            frame.addWindowListener(new WindowAdapter() {
                  public void windowClosing(WindowEvent e) {
                        System.exit(0);
                  }
            });

                  
            ((CardLayout) oal.cards.getLayout()).show(oal.cards,"Applet");

      }
      
      public void runApplet(Object a)
      {
            try
            {
            
                  Object aa =orderingApplet.newInstance();
                  Panel p1=new Panel(new GridLayout(1,1));
                  p1.add((Component) aa);
                  cards.add("Applet",p1);
                  Class[] ee=new Class[1];
                  ee[0]=loader;
                  Object[] dd= new Object[1];
                  dd[0]=a;
                        
                                          
                                          
                  java.lang.reflect.Method bb=orderingApplet.getMethod("setup",ee);
                  Object cc =bb.invoke(aa,dd);
                        
                        
                  bb=orderingApplet.getMethod("init",null);
                  cc =bb.invoke(aa,null);
                        
                  ((CardLayout)cards.getLayout()).show(cards,"Applet");

                  
                  
                  
            } 
            catch (Exception e)
            {
            System.out.println(e);
                  e.printStackTrace();
                  //System.out.println(e.);
            }
            //System.out.println("2");
      }
}

class LoaderThread implements Runnable
{
      OrderingAppletLoader oal;
      
      public LoaderThread(OrderingAppletLoader oal1)
      {
            oal=oal1;
      }
      
      public void run()
      {

            
            oal.ta.append("Loading Loader Class...");
            
            
            try
            {
                  oal.loader=getClass().getClassLoader().loadClass("Loader");
                  oal.ta.append("DONE\r\n");
            }
            catch (Exception e)
            {
                  oal.ta.append (" NOT FOUND!!!!\r\n");
                  System.out.println(e);      
            }
            
            oal.ta.append("Loading OrderingApplet Class...");
            try
            {
                  oal.orderingApplet=getClass().getClassLoader().loadClass("OrderingApplet");
                  oal.ta.append("DONE\r\n");
            }
            catch (Exception e)
            {
                  oal.ta.append (" NOT FOUND!!!!\r\n");
                  System.out.println(e);      
            }

//            oal.ta.append("Classes loaded: ");
            oal.oldText=oal.ta.getText();
            
            
      //      (new Thread(timer,"Governor1")).start();
            
            try
            {
                  oal.a =oal.loader.newInstance();
                  Class[] e=new Class[1];
                  e[0]=oal.getClass();
                  Object[] d= new Object[1];
                  d[0]=oal;
                  java.lang.reflect.Method b=oal.loader.getMethod("init",e);
                  Object c =b.invoke(oal.a,d);
                  
                                    
                  b=oal.loader.getMethod("loadSeries",null);
                  c =b.invoke(oal.a,null);
                  
                  
                  java.lang.reflect.Field f=oal.loader.getDeclaredField("totalLines");
                  oal.totalLines=f.getInt(oal.a);

                  f=oal.loader.getDeclaredField("str");
                  String str=(String) f.get(oal.a);

                  
                  f=oal.loader.getDeclaredField("lineCount");
                  oal.lineCount=f.getInt(oal.a);
                  
                  //oal.ta.setText(oal.oldText);
                  //oal.ta.append("DONE\r\n");
                  oal.ta.append("Series Data: ");
                  oal.oldText=oal.ta.getText();
                  
            //      System.out.println("1b");
            
                  (new Thread(oal.updater,"Governor")).start();
                        
                  while (str!=null)
                  {

                        c =b.invoke(oal.a,null);
                        
                        f=oal.loader.getDeclaredField("str");
                        str=(String) f.get(oal.a);

                        f=oal.loader.getDeclaredField("lineCount");
                        oal.lineCount=f.getInt(oal.a);


                        
                        

                        //repaint(1);
                  }
                  str=null;
                                    
                  b=oal.loader.getMethod("loadMovies",null);
                  c =b.invoke(oal.a,null);
                  
                  f=oal.loader.getDeclaredField("totalLines");
                  oal.totalLines=f.getInt(oal.a);

                  f=oal.loader.getDeclaredField("str");
                  str=(String) f.get(oal.a);

                  
                  f=oal.loader.getDeclaredField("lineCount");
                  oal.lineCount=f.getInt(oal.a);
                  
                  oal.ta.setText(oal.oldText);
                  oal.ta.append("DONE\r\n");
                  oal.ta.append("Movie Data: ");
                  oal.oldText=oal.ta.getText();
                  
            //      System.out.println("1c");
                                                      
                  while (str!=null)
                  {
                        c =b.invoke(oal.a,null);
                        f=oal.loader.getDeclaredField("str");
                        str=(String) f.get(oal.a);

                        f=oal.loader.getDeclaredField("lineCount");
                        oal.lineCount=f.getInt(oal.a);

                  //      repaint(1);
                  }
                  str=null;
                  b=oal.loader.getMethod("loadOST",null);
                  c =b.invoke(oal.a,null);
                  
                  f=oal.loader.getDeclaredField("totalLines");
                  oal.totalLines=f.getInt(oal.a);

                  f=oal.loader.getDeclaredField("str");
                  str=(String) f.get(oal.a);
                                    
                  f=oal.loader.getDeclaredField("lineCount");
                  oal.lineCount=f.getInt(oal.a);
                  

                  oal.ta.setText(oal.oldText);
                  oal.ta.append("DONE\r\n");
                  oal.ta.append("OST Data: ");
                  oal.oldText=oal.ta.getText();
                  
      ///            System.out.println("1d");
                                                      
                  while (str!=null)
                  {
                        c =b.invoke(oal.a,null);
                        f=oal.loader.getDeclaredField("str");
                        str=(String) f.get(oal.a);

                        f=oal.loader.getDeclaredField("lineCount");
                        oal.lineCount=f.getInt(oal.a);

                  //      repaint(1);
                  }
                  str=null;
                  
                  oal.ta.setText(oal.oldText);
                  oal.ta.append("DONE\r\n");
                  oal.loaded=true;
                  

                  
                  
                  
            } 
            catch (Exception e)
            {
                  System.out.println(e);
                  e.printStackTrace();
                  //System.out.println(e.);
            }
            
            
            
            //System.out.println("1");
            
            
            
      }
      



      
      
}

class Updater implements Runnable
{
      OrderingAppletLoader oal;
      public Updater(OrderingAppletLoader oal1)
      {
            oal=oal1;
      }
      

      
      public synchronized void run()
      {
            while (!oal.loaded)
            {
                  String temp=""+oal.oldText;
                  temp=temp+(""+((((float) oal.lineCount)/oal.totalLines)*100)+"%\r\n" );
                  oal.ta.setText(temp);
                  //oal.repaint(10);
                  

                  try
                  {
                        wait(500);
                  }
                  catch (InterruptedException e)
                  {
                        e.printStackTrace();
                  }
            }

            oal.runApplet(oal.a);
      }
}

Thanks for that :slight_smile:

However - I think it only lets you load individual classes (uncompressed) which would be too big. I was hoping there was a way to get it to download a second jar file.

  • Dom

I suppose pointing out that Web Start does this for you and more is of no use… 1.1 is far to old, by insisting on using it you are causing your own problems.

Let it go. 1.1 compatibility isn’t worth it.

Hi,
I believe you can specify a comma delimited list of jars in the archive tag of the applet tag.

example:

As long as the local applet class loader loaded the jar from the same soruce as the applet class, it should have no problems with the sandbox. If the jars are residing on different servers, then you’ll have a security problem as the sandbox only allows connections to the server from which the applet came from.

give it a shot.

-Chris