3DzzD - Applet Boot V2 updated

here is the new version V2 of the Applet booter ( that was made related to lastest Java 1.6-u19 sucks plugin release… )

Online demo here : http://demo.dzzd.net/BootV2/

Download of boot.jar here : http://demo.dzzd.net/BootV2/boot.jar

Full demo download here : http://demo.dzzd.net/BootV2/boot.zip

sidenote : I believe that to avoid those scary mixed code popup lot of people will just sign and add full rights to everything… this is why the Oracle Upadate 6u19 is so stupid…

HTML sample use below :

It load the applet “jar.MyJarApplet” and set “myJarApplet.jar;someOtherJar.jar” to its classpath, the applet should start imediatly as only boot.jar is loaded at start (approx 5KB load).

If you request to use signed an unsigned jar than you should simply have to self-sign boot.jar and you should be done, let me know… (NB: for simplicity you may make & keep two version of the boot.jar : unsignedBoot.jar and signedBoot.jar that you will use depending if you request or not signed jar)


<applet
	archive = "boot.jar"
	code	= "Boot"
	width	= "500"
	height	= "300">
	<PARAM NAME="BOOTCLASS" VALUE="jar.MyJarApplet">
	<PARAM NAME="BOOTJARS" VALUE="myJarApplet.jar;someOtherJar.jar">
	<PARAM NAME="BOOTFGCOLOR" VALUE="000000">				
	<PARAM NAME="BOOTBGCOLOR" VALUE="ffffff">	
	<PARAM NAME="BOOTTOSTART" VALUE="TRUE">
	<PARAM NAME="boxbgcolor" VALUE="#ffffff">
	<PARAM name="java_arguments" value="-Dsun.awt.noerasebackground=true">			
</applet>

source :

/*
* This file is part of 3DzzD http://dzzd.net/.
*
* Released under LGPL
*
* 3DzzD is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 3DzzD is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with 3DzzD.  If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2005 - 20010 Bruno Augier
*/


import java.awt.*;
import java.applet.*;
import java.awt.image.*;
import java.net.*;
import java.security.*;
import java.security.cert.*;
import java.util.*;

/**
 * Boot
 *
 * An Applet Boot class
 * 
 * @author Bruno Augier
 * @website: http://dzzd.net/
 * @version 2.00 2010/04/12
 */
public final class Boot extends Applet implements Runnable,AppletStub
{
	public static final long serialVersionUID = 0x00000001;
			
	private volatile int nbStart=0;
	private volatile Graphics g;		
	private volatile int bgColor;		
	private volatile int fgColor;
	private volatile Container c;
	private volatile boolean loaded;
	private volatile Thread t;
	private volatile Applet a;
	private volatile boolean bootToStart=false;
	private volatile Image bImage;
	private volatile Graphics bg;
	
		
	private int w()
	{
		return this.getSize().width;
	}
	
	private int h()
	{
		return this.getSize().height;
	}	 	
	 
	private int blend(int color1,int color2, int factor)
	{
	 int f1=256-factor;
	 return ((((color1&0xFF00FF)*f1 + (color2&0xFF00FF)*factor )  &0xFF00FF00  )  | (   ( (color1&0x00FF00)*f1 + (color2&0x00FF00)*factor )  &0x00FF0000  )   ) >>>8;
	}
	
	private volatile int nb=0;
	private volatile long lTime;
	public void run()
	{			
		try
		{
			this.lTime=System.currentTimeMillis();
			while(!this.loaded)
			{
				Color color=new Color(this.bgColor);
				this.c.setBackground(color);	
				this.bg.setColor(color);
				this.bg.fillRect(0,0,w(),h());
		
				int cx=this.w()>>1;
				int cy=this.h()>>1;
				for(int n=0;n<360;n++)
				{
					/*
					int b=75+n>>1;//255;
					int v=75+n>>1;//165+(n>>2);
					int r=75+n>>1;
					r^=255;
					v^=255;
					b^=255;
					r+=0;
					v+=0;
					b+=0;
					*/
					int RGB=blend(this.fgColor,this.bgColor,(255*n)/360);
					
					
					this.bg.setColor(new Color(RGB));
					double a=(nb-n*0.5)*Math.PI/180.0;
					double ca=Math.cos(a);
					double sa=Math.sin(a);
					int x=cx+(int)(8.0*ca);
					int y=cy+(int)(8.0*sa);
					
					int x2=cx+(int)(12.0*ca);
					int y2=cy+(int)(12.0*sa);
					this.bg.drawLine(x,y,x2,y2);
				}
				
				this.g.drawImage(this.bImage,0,0,null);
				
				nb+=6;
				long time=System.currentTimeMillis();
				long delta=time-lTime;
				lTime=time;
				//if(delta<20)
					//Thread.sleep(20-delta);
				Thread.sleep(5);
				Thread.yield();	
					//System.out.println (nb);
			}
		}
		catch(InterruptedException ie)
		{
			ie.printStackTrace();
		}
		
	}
	
	public Applet getApplet()
	{
		return this.a;
	}
	
	
	
	
	public void paint(Graphics g)
	{
		
		if(this.nbStart++==0)
		{			
			this.bImage=this.createImage(w(),h());
			this.bg=this.bImage.getGraphics();
			this.bgColor=0xFFFFFF;
			this.fgColor=0x000000;
			/**
			 * Try to enable antialias if possible
			 */
			try
			{
				((Graphics2D)this.bg).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
			}
			catch(Throwable t)
			{
				t.printStackTrace();	
			}
			
			String sBgColor=this.getParameter("BOOTBGCOLOR");
			if(sBgColor!=null)
			{
				try
				{
					this.bgColor=Integer.parseInt(sBgColor,16);
				}
				catch(Throwable t)
				{
					t.printStackTrace();
				}
				
			}	
			String sFgColor=this.getParameter("BOOTFGCOLOR");
			if(sFgColor!=null)
			{
				try
				{
					this.fgColor=Integer.parseInt(sFgColor,16);
				}
				catch(Throwable t)
				{
					t.printStackTrace();
				}
				
			}	
			this.c=this.getParent();
			this.g=this.c.getGraphics();
			this.c.remove(this);	
							
			this.loaded=false;
			this.t=new Thread(this);
			this.t.start();
			
			String bootToStart=this.getParameter("BOOTTOSTART");
			if(bootToStart!=null && bootToStart.equals("TRUE"))
				this.bootToStart=true;
			String bootClass=this.getParameter("BOOTCLASS");
			
			Color color=new Color(this.bgColor);
			this.c.setBackground(color);		
			
			new AppletLoader(bootClass);
		}
	}
	
	/**
	 * Workaround for split previous to Java 1.4
	 */
	private String[] split(String str,char ch)
	{
		if(str==null)
			return null;
			
		if(str.length()==0)
			return new String[]{""};
			
		int nb=1;
		int ofs=str.indexOf(ch);
		while(ofs!=-1)
		{
			nb++;
			ofs=str.indexOf(ch,ofs+1);
		}
		
		String strings[]=new String[nb];
		
		int numString=0;
		int startIndex=-1;
		for(int n=0;n<nb;n++)
		{
			int endIndex=str.indexOf(ch,startIndex+1);
			if(endIndex==-1) endIndex=str.length();
			strings[n]=str.substring(startIndex+1,endIndex);
			startIndex=endIndex;
		}
		
		return strings;
	}
	
	
	URLClassLoader ucl;
	private class AppletLoader implements Runnable
	{
		String name;
		
		AppletLoader(String name)
		{		
			this.name=name;
			Thread t=new Thread(this,"DZZD APPLET BOOT");
			t.start();	
		}
		
		public void run()
		{
			
			try
			{
				Thread.sleep(100);
				String bootArchive=Boot.this.getParameter("BOOTJARS");
				String bootArchives[]=Boot.this.split(bootArchive,';');//.split(";");
				
				URL urlJars[]=new URL[bootArchives.length+1];
				urlJars[0]=Boot.this.getCodeBase();
				
				for(int n=0;n<bootArchives.length;n++)
				{
					URL u=new URL("jar:" + Boot.this.getCodeBase() + bootArchives[n] + "!/");
					urlJars[n+1]=u;	
					System.out.println ("Adding JAR " + u);
				}
				
				URLClassLoader ucl=null;
				try
				{
					ucl=new BootClassLoader(urlJars);
				}
				catch(Throwable t)
				{
					ucl=((URLClassLoader) Thread.currentThread().getContextClassLoader()).newInstance(urlJars);
				}
				
				Boot.this.a=(Applet)ucl.loadClass(this.name).newInstance();
				Boot.this.a.setVisible(false);
				{	
					Boot.this.a.setStub(Boot.this);
					Boot.this.c.add(Boot.this.a);
					Boot.this.a.resize(new Dimension(Boot.this.w(),Boot.this.h()));
					
					Boot.this.a.init();	
					if(!Boot.this.bootToStart)
						Boot.this.a.setVisible(true);				
					Boot.this.a.start();
					if(Boot.this.bootToStart)
						Boot.this.a.setVisible(true);
				}	
							
				Boot.this.loaded=true;
				Boot.this.t.join();
				
							
			}
			catch(Throwable e)
			{
				e.printStackTrace();
			}
				
		}
		
	}
	
	public void start()
	{
		if(this.a!=null)
			this.a.start();
	}
	
	public void stop()
	{
		if(this.a!=null)
			this.a.stop();
	}
	
	public void destroy()
	{
		if(this.a!=null)
			this.a.destroy();
		this.a=null;
	}
	/*
	public void update(Graphics g)
	{
		
	}*/
		
	public void appletResize(int width, int height) 
	{
		if(this.a!=null)
			this.a.setSize(width,height);
	}
}


WOW ! nice loader ! :slight_smile: Is there any way to load native libraries ?

I mean, the goal of a good applet loader is to make native stuff like a openGL context available… otherwise a loader deserves no real price to the usual applet. :wink: :wink:

yes inded,

not tested but if the boot.jar is signed you will benefit from its classloader rights and should be able to download the native dll/so/others… and load them at runtime with System.load( … )

also not yet implmented but by sliglty modifying the boot class it is possible to make jar loading whenever you need it (by implemeting a loadJar method) , for now all jar are loaded after the boot Applet start and before the sub-applet is launched.

EDIT : if you got a Java version under 1.6-u19 you can see native lib loading at runtime here http://demo.dzzd.net/FPSSample9/

when hitting H key natives libraries (dll, so or other) are downloaded and loaded in memory from the remote applet server to use opengl via JOGL.

I have updated the HTML to make load a little better : added some new plugin stuff


<applet
		archive = "boot.jar"
		code	= "Boot"
		width	= "500"
		height	= "300">
	<PARAM NAME="BOOTCLASS" VALUE="jar.MyJarApplet">
	<PARAM NAME="BOOTJARS" VALUE="myJarApplet.jar;someOtherJar.jar">	
	<PARAM NAME="BOOTBGCOLOR" VALUE="000000">
	<PARAM NAME="BOOTTOSTART" VALUE="TRUE">	
	<PARAM NAME="boxbgcolor" VALUE="#000000">
	<PARAM name="java_arguments" value="-Dsun.awt.noerasebackground=true">
</applet>

not really, I think you missed some others importants points, it also deserve a lot more :

=> a shell to detect several stuff as exception in the sub applet / requiered java version before launch sub-applet / start on any JRE (from old MS 1.1 to lastest Sun 1.6-u19) even if the sub applet requiere lastest and you can display a clean error message
=> fully free the applet at end and can even load another Applet with different jars : for example you can display a select box and ask the user wich applet he would like to load
=> a customizable loading process (for signed aswell as unsigned applet), this demo is not really revelant but if you test it with bigger jar ressource it will enable an imediate start of a customized loading animation while your applet is loading
=> enable signed / unsigned with only one warning popup alert
=> and finally yes also load native libraries and/or others jars at runtime (if boot.jar is signed for natives / sandard jars loading at runtime may work for unsigned)

Looks like great improvements!

You should probably add the suggestions I added here. Mac owners seem very annoyed when their browsers freeze brutally if newer java applet version is attempted to be loaded than what is installed => have to kill browser.

It would be cool if you wanted to upload your stuff to http://wiki.games4j.com/, or just let me know if you want me to do it.

oups tryed to use the signed jar booter and found that boot.java requiere a little update to work in signed mode but the good news is that it work very well and you can load any kind of jar as long as the boot.jar is signed.

code has been updated this way :

URL u=new URL("jar:" + Boot.this.getClass().getResource("./" + bootArchives[n]) + "!/");

replaced by

URL u=new URL("jar:" + Boot.this.getCodeBase() + bootArchives[n]	 + "!/");

dont even requiere any fancy MANIFEST attribute in it

just execute “jarsigner -keypass yourPass boot.jar yourSelfCert” and your done

yes, sorry seems I forgot to do that last time, I will those are nice advice

EDIT:

@broumbroum another nice addition the applet boot bring is that once the user have accept it certificat it wont ask anymore for other applet and then if you got a website with severals signed games (even from different authors) all other will start without any security as long as you use the same applet booter

@jojoh hey very nice wiki !

arf does not seems to work as espected to mix signed/unsigned I think that a working solution is to produce a custom secured classloader inside the signed boot.jar and use it for the whole… (same as the extension loader of 3dzzd…) will look on that later :-\ pfff… once again… thanks Oracle…

ok this work I have implemented my own URLClassLoader that replace the current class loader the result is :

if boot.jar is signed a popup will be shown and depending on user response it will load the applet jars with or without security restriction but in any case it will bring up another popup.

this enable easy mixing of unsigned/signed code without the new scary popup…

here is a demo :
http://demo.dzzd.net/BootV2Signed/

if you answer yes than you can switch mouse look using the robot class by pressin the “M” key, you can also switch to JOGL using “H” key (hardware rendering is a little broken for this vrsion but that not the point)

Your current solution is:

  • always an initial security dialog
  • maybe a second security dialog

What are the advantages over signing everything, where you are guaranteed to have only one security dialog?

no, just only one security dialog ( and none if you dont requiere security privilege and then dont sign the boot.jar), never two (I hope),

applet booter offer a lot more and some of its advantages (not related to mixing code) are mentioned above but the one I find interresting about mixing code problem is that it does not requiere to (re)sign all the jar you use (and would become really nice if it can be signed by a real certificat, it also show how the java 6u19 about selfsigned/unsigned warning update is stupid ).

but yes the real thing missing now is how to done it at runtime like before…

some minor improvments :

  • adding parameter for HTML BOOTFGCOLOR to control the appearance of the rotating circle
  • changing catch Exception by Throwable
  • replace use of String.split by custom one to get back to 1.1 compatibility (not tested yet)

next update will be the ability to provide a customized class (to make a custom animation while loading), this will give users full power over loading process and will finish to make this booter a very generic way.

sample :
http://demo.dzzd.net/BootV2/

using parameters :

<PARAM NAME="BOOTCLASS" VALUE="jar.MyJarApplet">
<PARAM NAME="BOOTJARS" VALUE="myJarApplet.jar;someOtherJar.jar">
<PARAM NAME="BOOTFGCOLOR" VALUE="000000">				
<PARAM NAME="BOOTBGCOLOR" VALUE="ffffff">	
<PARAM NAME="BOOTTOSTART" VALUE="TRUE">
<PARAM NAME="boxbgcolor" VALUE="#ffffff">
<PARAM name="java_arguments" value="-Dsun.awt.noerasebackground=true">	

So, what is it?

oups… sorry probably my wrong english… I suppose that I did not said what I wanted ? I was meaning : in no case / never / nada :slight_smile:

sidenote : another interresting use of the booter now that will soon come will be the ability to provide a custom class to animate (maybe advertisment too) while loading the jar of the sub applet rather than an animated gif, for example you can imagine putting a pong game while the biggest game is loading in background

EDIT:
to explain better it is full replacement to the standar java loader : it is more “compatible” (work on all JRE the same no difference between java version and can provide custom loading error handling aswell as better java version checking) enable custom loading and only one security popup, boot.jar can work if it is signed aswell as it is not signed :

in signed mode : there is one security popup and everything run with high privilege or in sandbox depending on user response to security popup.

in unsigned mode : everything run in sandbox (inded without security popup)

in both mode jars are loaded in background

and it can work with all existing applet without the need to recompile them (only requiere HTML modification)

Is this meant to be broken atm? 'cos it doesn’t appear to be working as expected in 1.6.0_18.

I get this to the console:

But no applet repainting occurs at all.
I guess it’s a problem with the Applet being launched rather than your Applet booter itself; What’s the Applet supposed to do?

it just display a blue message over a white screen, but maybe you try while I was updating (my fault, one version was drawing a white text over a white background…)? yours logs seems to show that it have worked well : started the sub applet and paint it.

maybe it is related to a graphic problem try to drag a window over the applet plz to see if it help

Worked perfectly for me with u18 - in Opera 10.5 (shock horror!) And very nice and fast too. Still not as seamless as Flash though.

Cas :slight_smile:

The white background isn’t repainted for me, but the text is, so swapping windows will just display the blue text on whatever was on the screen on that place before. But I guess it is not the cool text you are showing of, but the boot loader :slight_smile: Boot loader works fine, but suffers from the same problem I think (Scrolling, moving browser or alt-tabbing will “smear” the loading animation/screen (now loading so fast I can’t test, but was like that before). Could be solved by drawing on an image and then drawing the image to the container => slightly more CPU use and a slightly larger boot loader.
WinXP, 1.6.0_19, FF 3.5.9

I have already done a hack like that, I might upload the code later if anybody wants it, but it is a slight tradeoff.

DzzD, do you want to add a page on the wiki for this. Forum is great for discussion and wiki is great for conclusions (or at least the latest version). The applet section in the Wiki would be a good place. Just similar to your initial post in the thread.

Wiki or it didn’t happen FTW! :wink:

I will put the final version on the Wiki, it requiere just a little last improvment I would like to add :

the ability to add a custom class for the boot animation & error (given in an HTML parameter).

it will have to extends an interface like BootHandler this will make the boot.jar usable (without the need to always modify its source).

If no BootHandler is provided than it will load as it does currently, but if a BootHandler is provided it will be notified on loading (and will be able to paint while loading) it will also notified about error and more