Link to home
Start Free TrialLog in
Avatar of felgen
felgen

asked on

Class loading

If I load two classes A and B with the method
Class.forName("Classname"), first class A and then class B
will then the Classloader of a browser load class A again
because it is used by class B.
If tried to load classes with the method loadClass from
the abstract class Classloader.
Within the applet I've got the browsers Classloader with
Classloader loader = getClass().getClassLoader()
but when I've tried to use loader.loadClass("Classname")
I've got the compilation error
there is now method loadClass(String) defined in Classloader. I don't won't to subclass Classloader, just
using the loadClass-method of the browsers Classloader.

I am doing the whole thing, because I want to track the
loading of the classes my applet uses. If there is another
solution or if you know what I am doing wrong let me know.
ASKER CERTIFIED SOLUTION
Avatar of malexiev
malexiev

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of felgen
felgen

ASKER

You can't subclass your ClassLoader within applet, because of security restrictions.

I dont`t do that, I think.
If I get the browsers Classloader with

getClass().getClassLoader()

I do not subclass, because the browsers allready does it.
Why do I get the compilation error.
ClassLoader.getClass() is protected method.
you have to ovveride this method when you write your own ClassLoader.
as you can see in the documentation
" .... The method loadClass() is called by the virtual machine.  ...."

usuall you load classes using something like
Class cl = Class.forName("java.lang.Thread");

from the docs
'public static native Class forName(String className) throws ClassNotFoundException
  Returns the Class object associated with the class with the given string name. Given the fully-qualified name for a class or interface, this method attempts to locate, load and link the class. If it succeeds, returns the Class object representing the class. If it fails, the method throws a ClassNotFoundException. '

so Class.forName is what you really need.
Avatar of felgen

ASKER

ClassLoader.getClass() is protected method.
you have to ovveride this method when you write your own ClassLoader.
as you can see in the documentation
" .... The method loadClass() is called by the virtual machine.  ...."

That means, if I want to use loadClass I have to write my
own Classloader and I can't use the loadClass of the
browsers Classloader?
this mean that you SHOULD use
Class cl = Class.forName("java.lang.Thread");

(which makes the VM call the loadClass method of the current classloader withthe appropriate parameters . loadClass is pretty low-level stuff.)

once again:
use this code
Class cl = Class.forName("java.lang.Thread");

As heyhey mentions above you don't have to use loadClass(String) to load class.
(This method is for VM, not for java developers)

The only way to track classes is Class.forName("class name");

Writing your own ClassLoader won't help you, because you can't use it in applet.
See this for more information:
http://www.javasoft.com/security/hypermail/java-security-archive-2/0087.html

Best regards.
Avatar of felgen

ASKER

I've tested the code with a application similar to
the appletviewer that has its own classloader.

With this one I found that the classes of the second Applet
are loaded before I load them with forName.
When the forName method is performed the classloader
do not perform its loadclass method.

Docs of jdk1.0.x:

* Returns the runtime Class descriptor for the specified Class.
* For example, the following code fragment returns the runtime
* Class descriptor for the Class named java.lang.Thread:
* <pre>
*            Class t = Class.forName("java.lang.Thread")
* </pre>
* @param className      the fully qualified name of the desired Class
* @exception      ClassNotFoundException If the Class could not be found.

The classloader of navigator and IE certainly behave not like
my own one. But I have doubts that I can track class loading
with forName, because the VM loads the class before forName is
called when there is any reference to the class in the code.
Avatar of felgen

ASKER

I think the only way to track class loading is to know
which classes are allready loaded by the classloader.
Hi,

Let your classes be class1, class2, . . .classN, and your applet is yourApplet and let yourApplet has a default constructor (without parameters).

public class Tracker extends Applet {
 
  Applet app;  //It's beter to be an interface name here, not an Applet!
  init() {
    Class.forName("class1");
    Class.forName("class2");
    ...
    app = (Applet)Class.forName("yourApplet").newInstance();
    app.init();
  }
  public void start() { app.start(); }  
  public void stop() { app.stop(); }
  public void destroy() { app.destroy(); }
}

You'll have to load classes in special order. For example if class1 extends class2 you'll have to load class2 first and then class1, because if you load class1 first, class2 will be loaded too, as a superclass of class1.

This code not pretend to be universal, it's just an idea or pattern, but if you post some code may be it will be more clear for us to track your classes.

Best regards.
Avatar of felgen

ASKER

The Problem is that I want to display something to
the user. Here is some code:

import java.applet.*;
import java.awt.*;
import java.io.PrintStream;
import java.net.MalformedURLException;
import java.net.URL;
import pvWinJ.PVButton;
import pvWinJ.PVImageButton;
import symantec.itools.awt.util.ProgressBar;

public class Start extends Applet
    implements Runnable, AppletStub
{

    public void init()
    {
        super.init();

        context = getAppletContext();
        loader = getClass().getClassLoader();




        setLayout(null);
        resize(780, 530);
        browser = System.getProperty("java.vendor");
        host = getParameter("host");
        port = getParameter("port");
        target = getParameter("target");
        /*host ="mom";
        port="2222";
        target="";*/
        imageName1 = new String[19];
        imageName2 = new String[19];
        imageName3 = new String[19];
        buttonFont = new String[19];
        buttonStyle = new String[19];
        buttonSize = new String[19];
        label = new String[19];
        labelPos = new String[19];
        buttonR = new String[19];
        buttonG = new String[19];
        buttonB = new String[19];
        for(int i = 1; i <= 18; i++)
        {
            imageName1[i] = "";
            imageName2[i] = "";
            imageName3[i] = "";
            buttonFont[i] = "";
            buttonStyle[i] = "";
            buttonSize[i] = "";
            label[i] = "";
            labelPos[i] = "";
            buttonR[i] = "";
            buttonG[i] = "";
            buttonB[i] = "";
        }

        inhalt = new String[69];
        textFont = new String[69];
        textSize = new String[69];
        textStyle = new String[69];
        for(int i = 1; i <= 68; i++)
            inhalt[i] = "";


        StartConnect connect = new StartConnect();


        connect.getDesign();
        tracker = new MediaTracker(this);
        try
        {
            base = new URL(getCodeBase() + "images/");
            dummyURL = new URL(base + "dummy.gif");
        }
        catch(MalformedURLException ex) {}
        java.awt.Image image1 = Toolkit.getDefaultToolkit().getImage(dummyURL);
        java.awt.Image image2 = Toolkit.getDefaultToolkit().getImage(dummyURL);
        java.awt.Image image3 = Toolkit.getDefaultToolkit().getImage(dummyURL);
        try
        {
            if(imageName1[1].compareTo("") != 0)
            {
                image1 = Toolkit.getDefaultToolkit().getImage(new URL(base + imageName1[1]));
                tracker.addImage(image1, 1);
            }
            if(imageName2[1].compareTo("") != 0)
            {
                image2 = Toolkit.getDefaultToolkit().getImage(new URL(base + imageName2[1]));
                tracker.addImage(image2, 2);
            }
            if(imageName3[1].compareTo("") != 0)
            {
                image3 = Toolkit.getDefaultToolkit().getImage(new URL(base + imageName3[1]));
                tracker.addImage(image3, 3);
            }
            try
            {
                tracker.waitForAll();
            }
            catch(InterruptedException ex) {}
        }
        catch(Exception ex) {}
        setBackground(new Color(StartConnect.decode(appletR).intValue(), StartConnect.decode(appletG).intValue(), StartConnect.decode(appletB).intValue()));

        if(appletStyle.compareTo("Standard") == 0)
            style = 0;
        else if(appletStyle.compareTo("Fett") == 0)
            style = 1;
        else if(appletStyle.compareTo("Kursiv") == 0)
            style = 2;
        else if(appletStyle.compareTo("Kursiv Fett") == 0)
            style = Font.BOLD|Font.ITALIC;

        if(appletStyleB.compareTo("Standard") == 0)
            styleB = 0;
        else if(appletStyleB.compareTo("Fett") == 0)
            styleB = 1;
        else if(appletStyleB.compareTo("Kursiv") == 0)
            styleB = 2;
        else if(appletStyleB.compareTo("Kursiv Fett") == 0)
            styleB = Font.BOLD|Font.ITALIC;

        font = new Font(appletFont, style, StartConnect.decode(appletSize).intValue());
        metric = getFontMetrics(font);
        setFont(font);
        textField2 = new TextField();
        textField2.reshape(((780 + new Float(Math.max(new Integer(metric.stringWidth(inhalt[2])).floatValue(), new Integer(metric.stringWidth(inhalt[3])).floatValue())).intValue() + 17) - 168) / 2, 264, 168, 24);
        textField2.setEchoCharacter('*');
        add(textField2);
        textField1 = new TextField();
        textField1.reshape(((780 + new Float(Math.max(new Integer(metric.stringWidth(inhalt[2])).floatValue(), new Integer(metric.stringWidth(inhalt[3])).floatValue())).intValue() + 17) - 168) / 2, 216, 168, 24);
        add(textField1);
        label3 = new Label(inhalt[3]);
        label3.reshape((780 - new Float(Math.max(new Integer(metric.stringWidth(inhalt[2])).floatValue(), new Integer(metric.stringWidth(inhalt[3])).floatValue())).intValue() - 17 - 188) / 2, 264, metric.stringWidth(inhalt[2]) + 17, 24);
        add(label3);
        label2 = new Label(inhalt[2]);
        label2.reshape((780 - new Float(Math.max(new Integer(metric.stringWidth(inhalt[2])).floatValue(), new Integer(metric.stringWidth(inhalt[3])).floatValue())).intValue() - 17 - 188) / 2, 216, metric.stringWidth(inhalt[2]) + 17, 24);
        add(label2);
        button4 = new PVImageButton("", 11, 0);
        button4.reshape(355, 350, 70, 48);
        if(labelPos[1].compareTo("zentriert") == 0)
            button4.setTextAlignment(4);
        else
            button4.setTextAlignment(3);
        button4.setImage(image1, 2);
        button4.setImage(image2, 0);
        button4.setImage(image3, 1);
        button4.setBackgroundColor(new Color(StartConnect.decode(buttonR[1]).intValue(), StartConnect.decode(buttonG[1]).intValue(), StartConnect.decode(buttonB[1]).intValue()));
        add(button4);
        label1 = new Label(inhalt[1]);
        label1.reshape((780 - metric.stringWidth(inhalt[1]) - 17) / 2, 156, metric.stringWidth(inhalt[1]) + 17, 36);
        add(label1);
    }

    public void run()
    {

        Class appletClass;




        try
        {

            progressBar1 = new symantec.itools.awt.util.ProgressBar();
                progressBar1.reshape(12,500,120,24);
                add(progressBar1);



            if (Start.browser.compareTo("Netscape Communications Corporation")==0 && loader != null)
                {


                Class.forName("Connect");
                progressBar1.setValue(2);
            Class.forName("Kategorie");
                progressBar1.setValue(5);
            Class.forName("BackgroundImage");
            progressBar1.setValue(7);
            Class.forName("Navigation");
            progressBar1.setValue(10);
            Class.forName("Logo");
            progressBar1.setValue(12);
            Class.forName("ImageLabel");
            progressBar1.setValue(15);
            Class.forName("KategorieButton");
            progressBar1.setValue(17);
            Class.forName("Banner");
            progressBar1.setValue(20);
            Class.forName("Anzeige");
            progressBar1.setValue(22);
                Class.forName("BestaetigungsAnzeige");
            progressBar1.setValue(25);
            Class.forName("BestellAnzeige");
            progressBar1.setValue(27);
            Class.forName("CheckAnzahl");
            progressBar1.setValue(30);
            Class.forName("ExtendImageViewer");
            progressBar1.setValue(32);
            Class.forName("InfoAnzeige2");
            progressBar1.setValue(35);
            Class.forName("InfoAnzeige3");
            progressBar1.setValue(37);
            Class.forName("LangAnzeige");
            progressBar1.setValue(40);
            Class.forName("ProduktAnzeige");
            progressBar1.setValue(42);
            Class.forName("ProduktListe");
            progressBar1.setValue(45);
            Class.forName("SuchAnzeige");
            progressBar1.setValue(47);
            Class.forName("WarenkorbAnzeige");
            progressBar1.setValue(50);
            Class.forName("WarenkorbStatus");
            progressBar1.setValue(52);
            Class.forName("pvTableJ.PVBorder");
            progressBar1.setValue(55);
            Class.forName("pvTableJ.DotRect");
            progressBar1.setValue(57);
            Class.forName("pvTableJ.PVStringBuffer");
            progressBar1.setValue(60);
            Class.forName("pvTableJ.PVRow");
            progressBar1.setValue(62);
            Class.forName("pvTableJ.PVCell");
            progressBar1.setValue(65);
            Class.forName("pvTableJ.PVViewer");
            progressBar1.setValue(67);
            Class.forName("pvTableJ.PVObservation");
            progressBar1.setValue(70);
            Class.forName("pvTableJ.PVColumns");
            progressBar1.setValue(72);
            Class.forName("pvTableJ.PVRows");
            progressBar1.setValue(75);
            Class.forName("pvTableJ.PVColumn");
            progressBar1.setValue(77);
            Class.forName("pvTableJ.drawString");
            progressBar1.setValue(80);
            Class.forName("pvTableJ.pvListNode");
            progressBar1.setValue(82);
            Class.forName("pvTableJ.PVDataModel");
            progressBar1.setValue(85);
            Class.forName("pvTableJ.PVTextField");
            progressBar1.setValue(87);
            Class.forName("pvTableJ.Layout");
            progressBar1.setValue(90);
            Class.forName("pvTableJ.pvList");
            progressBar1.setValue(92);
            pvTableMy = Class.forName("pvTableJ.PVTableMy");
            progressBar1.setValue(95);
            appletClass = Class.forName("Client");

            }
            else
            {


            Class.forName("Connect");

                progressBar1.setValue(10);
            Class.forName("Kategorie");
                progressBar1.setValue(20);
            Class.forName("BackgroundImage");
            progressBar1.setValue(30);
            Class.forName("Navigation");
            progressBar1.setValue(40);
            Class.forName("Logo");
            progressBar1.setValue(50);
            Class.forName("ImageLabel");
            progressBar1.setValue(60);
            Class.forName("KategorieButton");
            progressBar1.setValue(70);
            Class.forName("Banner");
            progressBar1.setValue(80);
            Class.forName("Anzeige");
            progressBar1.setValue(90);





            pvTableMy = Class.forName("pvTableJ.PVTableMy");



        }



            appletClass = Class.forName("Client");
            realApplet = (Client)appletClass.newInstance();
            realApplet.setStub(this);
            realApplet.init();
            realApplet.start();
            started = true;
            /*progressBar1 = new symantec.itools.awt.util.ProgressBar();
                progressBar1.reshape(330,410,120,24);
                add(progressBar1);*/
                progressBar1.setValue(100);
            complete = true;
        }
        catch(InstantiationException e)
        {
            System.out.println(e);
        }
        catch(ClassNotFoundException err)
        {
            System.out.println(err);
        }
        catch(IllegalAccessException error)
        {
            System.out.println(error);
        }
        validate();
    }

    public void start()
    {
        appletThread = new Thread(this);
        appletThread.start();
    }

    public void stop()
    {
        appletThread.stop();
        appletThread = null;
    }

    public void appletResize(int width, int height)
    {
        resize(width, height);
    }

    public boolean handleEvent(Event event)
    {
        if(event.id == 1001 && event.target == button4 && unpressed && started)
        {

            unpressed=false;
            showStatus("Loading Data.");
            while(!started) ;
            Kategorie kat = realApplet.kat;
            if(textField1.getText().compareTo("") == 0 && textField2.getText().compareTo("") == 0)
            {
                realApplet.banner.warenkorbStatus = new WarenkorbStatus();
                Connect connect = new Connect(false);
                connect.getStatus(0);
                connect = new Connect(false);
                connect.getTop(kat.katId[1]);
                kat.getKategorie(0);
                realApplet.anzeige.kunde = false;
            }
            else
            {
                try
                {
                    Connect.decode(textField2.getText());
                    Connect connect = new Connect(false);
                    if(connect.getKunde(textField1.getText(), textField2.getText()))
                    {
                        realApplet.banner.warenkorbStatus = new WarenkorbStatus();
                        connect = new Connect(false);
                        connect.getStatus(0);
                        connect = new Connect(false);
                        connect.getTop(kat.katId[1]);
                        kat.getKategorie(0);
                        realApplet.anzeige.kunde = true;
                    }
                    else
                    {
                        label1.setText("Sie haben ein falsches Passwort bzw. den falschen Kundennamen eingegeben. Versuchen Sie es bitte erneut.");
                    }
                }
                catch(NumberFormatException ex) {}
            }
            removeAll();
            add(realApplet);
            context.showStatus("");
        }
        return super.handleEvent(event);
    }



    Thread appletThread;
    static boolean started;
    static boolean complete;
    static Client realApplet;
    static ProgressBar progressBar1;
    static AppletContext context;
    ClassLoader loader;
    boolean unpressed=true;
    static Class pvTableMy;
    static int style;
    static int styleB;
    static Font font;
    static FontMetrics metric;
    static TextField textField1;
    static TextField textField2;
    static Label label1;
    static Label label2;
    static Label label3;
    PVImageButton button4;
    static MediaTracker tracker;
    static URL base;
    static URL dummyURL;
    static int sessionId;


    static String browser;
    static String host = "";
    static String port = "";
    static String target = "";
    static String appletR = "";
    static String appletG = "";
    static String appletB = "";
    static String appletFont = "";
    static String appletStyle = "";
    static String appletSize = "";
    static String kdNr = "";
    static String imageName1[];
    static String imageName2[];
    static String imageName3[];
    static String buttonFont[];
    static String buttonStyle[];
    static String buttonSize[];
    static String label[];
    static String buttonR[];
    static String buttonG[];
    static String buttonB[];
    static String labelPos[];
    static String inhalt[];
    static String textFont[];
    static String textSize[];
    static String textStyle[];
    static String image1 = "";
    static String image2 = "";
    static String image3 = "";
    static String bannerImage = "";
    static String appletFR = "";
    static String appletFG = "";
    static String appletFB = "";
    static String appletFRB = "";
    static String appletFGB = "";
    static String appletFBB = "";
    static String appletRB = "";
    static String appletGB = "";
    static String appletBB = "";
    static String appletFontB = "";
    static String appletStyleB = "";
    static String appletSizeB = "";
}

You can see that I'm doing some GUI in the init method to
display the tracking informations and to react on user input.
The class Startconnect performs the connection to a Server-
application. The class loading with forName is done in the run method of the applet. I think the browsers classloader starts
loading the class Client before I do it with forName because
the class Client is referenced in Start. When the class Client
is loaded all classes referenced in Client are loaded to and
the classes in that classes too. So if I do my forName
the classes are maybe already loaded and the tracking does not
make sense.
Hi again,

You have to remove declaration
  static Client realClient;
The classLoader loads class Client before run() method, because this is a global variable.
The classes of all global variables are loaded by class loader. I'm not sure about local variables. So I don't know if you have (local variable in your handleEvent() method):
  Connect connect = new Connect(false);
who exactly will load that class, but I suspect that is VM's classloader again.
I can suggest you to define an interface (class loader will load this interface) which has the same methods as your class Client. Say this is ClientInterface and let your class Client implements it. So your declaration will become:
  ClientInterface realApplet;
To avoid your classes's use as local variables in your methods you can add new methods in ClientInterface and to put the code in Client class. For example, you have to change handleEvent() method so you can create 2 methods in Client:
  public void connect1() {
     banner.warenkorbStatus = new WarenkorbStatus();
     Connect connect = new Connect(false);
     connect.getStatus(0);
     connect = new Connect(false);
     connect.getTop(kat.katId[1]);
     kat.getKategorie(0);
     anzeige.kunde = false;
  }
 public void  connect2(String tf1, String tf2, Label label1) {
    try {
      Connect.decode(tf2.getText());
      Connect connect = new Connect(false);
      if(connect.getKunde(tf1, tf2)) {
        banner.warenkorbStatus = new WarenkorbStatus();
        connect = new Connect(false);
        connect.getStatus(0);
        connect = new Connect(false);
        connect.getTop(kat.katId[1]);
        kat.getKategorie(0);
        anzeige.kunde = true;
      }
      else  {
         label1.setText("Sie haben ein falsches Passwort bzw. den falschen Kundennamen             eingegeben. Versuchen Sie
            es bitte erneut.");
       }
     }
     catch(NumberFormatException ex) {}                    
 }

and then your handleEvent will look like this :

public void handleEvent(Event event) {
  if(event.id == 1001 && event.target == button4 && unpressed && started)  {
    unpressed=false;
    showStatus("Loading Data.");
    while(!started) ;
    if(textField1.getText().compareTo("") == 0 && textField2.getText().compareTo("") == 0)
    {
       realApplet.connect1();
    }
    else  {
       realApplet.connect2(textField1.getText(), textField2.getText(), label1);
    }
    removeAll();
    add(realApplet);
    context.showStatus("");
  }
  return super.handleEvent(event);
}

Be carefull on choosing the class loading order. If Class1 has a global variable of Class2 and Class2 has a global variable of Class1, you can't load them separately. Loading Class1 will load Class2 and vice versa. But if Class2 has no global variable of Class1, you should load Class2 first and then Class1. That's why VM loads all classes in Client class before you run() method and that's why you have to load that class at the end of the tracking order..

Consider this.

Best regards.