Top
首页 > 老文章 > 正文

从Firefox访问Java Plug-in

从Firefox访问Java Plug-in

在篇文章中,你能学会从Firefox怎样访问Java Plug-in。你也能学到一些关于Java Plug-in文件对象模块(DOM),applet状态持久化,和cookie。除此以外,你还可以学习applet,它在Firefox中的运行。但那仅仅是开始。难道你曾经不想去探求Firefox是怎样与Java Plug-in(在后台)
发布时间:2006-03-15 17:46        来源:        作者:leo173
摘要
这篇文章与Jeff Friesen前一篇关于Java Plug-in的文章"Plug into Java with Java Plug-in" (JavaWorld, 6月 1999)是一个系列的。它专注于Firefox Web浏览器的最近的Java Plug-in其中之一。在篇文章中,你能学会从Firefox怎样访问Java Plug-in。你也能学到一些关于Java Plug-in文件对象模块(DOM),applet状态持久化,和cookie。除此以外,你还可以学习applet,它在Firefox中的运行,这将加强你对这些内容的理解。但那仅仅是开始。难道你曾经不想去探求Firefox是怎样与Java Plug-in(在后台)交互的吗?继续读下去你就会找到答案的。

版权声明:任何获得Matrix授权的网站,转载时请务必保留以下作者信息和链接
作者:Jeff Friesen;leo173(作者的blog:http://blog.matrix.org.cn/page/leo173)
原文:http://www.javaworld.com/javaworld/jw-06-2005/jw-0627-plugin.html
译文:http://www.matrix.org.cn/resource/article/44/44251_Firefox+Java+Plug-in.html
关键字:Firefox;Java;Plug-in

从我在JavaWorld 上写"Plug into Java with Java Plug-in"  开始,9年已经过去了。我的前一篇文章给Java Plug-in下了定义,讲到了怎样在Netscape Communicator 4.5 和 Internet Explorer 3.02 上怎样安装版本1.2,描述了与Java Plug-in相关的Windows注册表设置,了解了Java Plug-in的控制面版,考查了两个java主控台,讨论了HTML 的<embed> 和 <object>标签,还发布了一个基于Swing的用于Demo的applet。

自从我写了那篇文章后,java和Java Plug-in已经相继发布了许多个版本。看来那篇文章已显老态,所以我已经写好它的系列篇,它专注于针对Firefox Web浏览器的最近的Java Plug-in其中之一。这篇文章首先为你讲解从Firefox怎样访问Java Plug-in。然后讨论Java Plug-in文件对象模块(DOM), applet状态持久化   和cookie。比如在Firefox上运行的各种applet,当你在学习这些内容时,将会强化你已经掌握的知识。这篇文章通过探寻Firefox 和Java Plug-in之间的联系,再做归纳。因为对于Java Plug-in而言,在其他地方会比我在这里所讲的要详细得多,所以我建议可以学习Sun的Java Plug-in文档,你将会学到更多的技术。

这篇文章的实验环境是Mozilla Firefox 1.0, J2SE 5.0, 和Windows 98 SE。即使你没有这些软件,我仍然建议你读完这篇文章。真诚地希望你能发现一些对你来说还是未知的有兴趣的东西。

Java Plug-in 和Firefox

Java Plug-in象桥一样服务于浏览器和一个外部的 java运行环境(JRE)之间。Java Plug-in对于在Firefox 中运行的applet而言是相当重要的,因为浏览器不能自身为其提供一个JRE——其中包括一个JVM。因为这篇文章描述的applet会涉及到不同多个不同的Java Plug-in内容,还有就是这些applet都是在Firefox的环境中运行的,所以我们首先应该看一下如何从Firefox中访问Java Plug-in。

对于初学者来说,你必须确认在你的平台上已经安装了J2SE 5.0 和 JRE。在我的windows平台上,我用jdk-1_5_0-windows-i586.exe安装文件把J2SE 和 JRE都安装好了。确定你已经安装了JRE,因为JRE包含了Java Plug-in。
在安装好J2SE 5.0后,连接Firefox 到 Java Plug-in;首先从Firefox的工具菜单中选择Options,然后选择Web Features,最后点击Enable Java checkbox。

一般情况下,标签<embed> 和 <object>应该指向在Java Plug-in下运行的applet。这对Java Plug-in 5.0来说不是必要的,它能运行由简单的<applet>标签指定的applet。在安装时,你有机会屏蔽Internet Explorer 和 Mozilla (Firefox)/Netscape Web浏览器对applet的执行,如果它们遇到了<applet>标签,而转交给Java Plug-in处理。如果你放弃这个选项,迟些时候你可以通过Java Plug-in的控制面版来完成这个变化。比如,打开控制面版,选择标签Advanced。然后点击<APPLET> Tag Support左边的“+”,再选择Mozilla and Netscape选项。关闭这个面版后,当Firefox遇到<applet>标签时,它就会交给Java Plug-in执行。图1给出了这些必要的改变。

image
选择Mozilla and Netscape,所以当Firefox遇到<applet>标签时,它就会交给Java Plug-in执行

提示
我发现在我的平台上选择Mozilla and Netscape不是必须的。我的Firefox Web浏览器不会去管那个复选框的设置,当遇见<applet>时,它就会让Java Plug-in来执行。Java Plug-in 5.0的文档谈到这是个奇怪的行为:“如果Mozilla 和 Netscape 7都被安装好了,负责管理对<APPLET>标签是否支持的Mozilla and Netscape选项没有被选中的情况下,<APPLET>标签中的内容照样可以在Sun VM上运行。这是与Netscape 7的自动扫描功能相关的一个bug。”因为我已经安装过Netscape 6.2.3,所以我认为我找到了这个bug。如果在你的平台上遇到了这个问题,记住这点就行了。

平台上能驻留多个JRE,当Firefox遇到<applet>标签时,到底哪一个JRE来实现Java Plug-in?可以从Java Plug-in控制面版上的Java标签上找到答案。在二选一的情况下,我用来进行版本测试的applet给出了答案,同时也证明了Firefox是连接了 Java Plug-in的。图2显示我当前使用的JRE版本是1.5.0。(版本1.5.0是J2SE 5.0的内部版本号)

image
图2. 我已经配置好使用JRE 1.5.0的Java Plug-in

Listing 1给出了该applet的VersionDemo.java文件的源代码。这些代码在系统属性java.version 中设置了JRE 的版本。

Listing 1. VersionDetect.java
// VersionDetect.java

import java.awt.*;

public class VersionDetect extends java.applet.Applet
{
   public void paint (Graphics g)
   {
      int width = getSize ().width;
      int height = getSize ().height;

      g.setColor (Color.orange);
      g.fillRect (0, 0, width, height);

      String version = "JRE " + System.getProperty ("java.version");

      FontMetrics fm = g.getFontMetrics ();

      g.setColor (Color.black);
      g.drawString (version, (width-fm.stringWidth (version))/2, height/2);
   }
}


为了简洁,在这篇文章中我将不会给出运行这个或者其他applet的HTML。参见这篇文章中的source code 。

提示
Firefox只支持Java Plug-in 1.3.0_01和更高版本。

调用DOM

根据WWW 联合会 (W3C)所说,文件对象模块(DOM)是一个API,它针对“有效的HTML和合式的XML文档。它定义了文档的逻辑结构,访问和操作文档的方法。” Java Plug-in提供了两种方法来调用DOM:类netscape.javascript.JSObject和Common DOM API。

JSObject为Java applet 和Web 浏览器的JavaScript实现之间提供了接口,包含使用了DOM 的JavaScript 对象。这些对象的例子:Document, Link, 和 Window。我将不会深入JSObject,因为在我早期的文章"Talk with Me Java"中,我已经讨论了这个类。因此我专注于在一个applet中,通过Common DOM API来遍历DOM 。

在J2SE 版本1.4中已经介绍过Common DOM API,它是一个类和接口的集合,通过这些接口可以让applet遍历DOM实例。因为一个浏览器通过帧和窗口能够显示多个文档,所以会有许多DOM实例以备遍历。一般一个applet就遍历它自己的DOM实例—这个与文档相联系的DOM实例指定了这个applet。

访问DOM实例的起点就是静态方法getService(Object obj),该方法位于类com.sun.java.browser.dom.DOMService中。一般情况下,一个被唤醒applet的this指针会被作为一个参数传递给getService()。这个方法要么返回一个   DOMService对象(为这个applet和它的DOM实例之间提供接口),要么抛一个异常:
com.sun.java.browser.dom.DOMUnsupportedException (the DOM service is not available to the object) 或者 com.sun.java.browser.dom.DOMAccessException (a security violation has resulted)。例子:DOMService service = DOMService.getService (this);。

因为web浏览器提供了不同的DOM实现,所以访问一个DOM实例不是线程安全的,除非那个访问是发生在DOM access dispatch线程。为了确保线程安全性,DOMService提供了两个方法来保证访问只是发生在DOM access dispatch线程—invokeLater() 和 invokeAndWait()。

两种方法都用实现了接口com.sun.java.browser.dom.DOMAction的对象作为参数,来提供方法run()。invokeLater()在DOM dispatch线程中异步执行run(),invokeAndWait()在DOM dispatch线程中同步执行run()。

方法run()用实现了接口com.sun.java.browser.dom.DOMAccessor的对象作为其唯一参数,然后返回一个基本的Object引用。方法run()经常唤醒DOMAccessor的getDocument()方法,传递一个applet的指针做getDocument()的Object参数。作为回应,getDocument()会返回一个实现org.w3c.dom.Document接口的对象。那个对象中就包含了这个文档的信息。对于HTML文档而言,它会把Document向下转型为HTMLDocument(位于org.w3c.dom.html中),然后调用HTMLDocument的方法去获取这个文档的标题,域,applet集,和一些其他的。在调用属性方法后,run()返回一个包含文档信息(比如HTMLDocument的标题)的Object对象。那个Object随后又从invokeAndWait()和invokeLater()方法中返回。

为了梳理上面讨论的内容,我写了一个从一个HTML文档中提取标题的applet,然后把标题显示给用户。下面就是它的代码。
Listing 2. TitleExtract.java
// TitleExtract.java

import com.sun.java.browser.dom.*;

import java.applet.Applet;


import java.awt.*;

import org.w3c.dom.html.*;

public class TitleExtract extends Applet
{
   private String title = "unknown";

   public void init ()
   {
      try
      {
          DOMService service = DOMService.getService (this);
          title = (String) service.invokeAndWait (new DOMAction ()
                           {
                              public Object run (DOMAccessor accessor)
                              {
                                 HTMLDocument doc = (HTMLDocument)
                                    accessor.getDocument (TitleExtract.this);
                                 return doc.getTitle ();
                              }
                           });
      }
      catch (DOMUnsupportedException e)
      {
          System.out.println ("DOM not supported");
      }
      catch (DOMAccessException e)
      {
          System.out.println ("DOM cannot be accessed");
      }
   }

   public void paint (Graphics g)
   {
      int width = getSize ().width;
      int height = getSize ().height;

      g.setColor (Color.cyan);
      g.fillRect (0, 0, width, height);

      FontMetrics fm = g.getFontMetrics ();

      g.setColor (Color.black);
      g.drawString (title, (width-fm.stringWidth (title))/2, height/2);
   }
}


DOMAction的run()方法调用了HTMLDocument的getTitle()方法去获取HTML文档的标题。随后显示该标题。例如,当在TitleExtract.html(参见本文的source code)中遇到元素时,getTitle()返回“Extract the title”。图3中显示了Firefox中的结果。

image
图3。 显示一个文档的标题

注意
当从标签<applet> 中调用TitleExtract时,Firefox要求mayscript属性需要被给出。否则,由于Firefox的DOM实现依赖于JSObject,Java Plug-in会抛出各种异常。

Applet在Firefox session中的持久状态

Java Plug-in 5.0的文档提到许多有趣的课题。其中之一就是applet的持久性API,它可以让一个applet保存其状态以备在后来的相同的web浏览器session中使用。State被保存在由Java Plug-in控制的一个内部持久性存储数据结构中;一个session是指某个web浏览器被打开运行开始到这个浏览器被关闭结束。

在J2SE 1.4中介绍的applet持久性API ,由声明在接口java.applet.AppletContext中的三个方法构成:

·        void setStream(String key, InputStream stream) throws IOException 需要当前applet上下文的一个具体key和具体的stream作为参数。如果一个新的stream对应了当前的key,这个新stream将会取代那个旧的stream。如果新stream的size超出了内部size的限制,将会抛出一个异常IOException。
·        InputStream getStream(String key)返回与当前applet key相联系的InputStream。如果没有指向该key的stream就返回null。
·        Iterator<String> getStreamKeys()返回一个迭代器,它包括了指向当前applet中stream的所有key。
通过调用setStream()来保存状态。这个方法把一个key(它可以方便地标识一个输入流)和一个InputStream的引用存储到一个内部数据结构中去,比如一个HashMap。取出某状态可以通过相应的标识key调用getStream()。它会返回一个InputStream(如果这个key存在)以恢复到这个状态。

因为Java Plug-in5.0文档没有提供例子来指出怎样使用applet持久性API,所以我准备了一个例子。它给出了一个消息传送applet的两个实例,其中的一个使用applet持久性API发送消息给另一个。图4中,用户在左边实例的 Message To Send文本框中输入一个消息,然后点击该实例的Send按扭。然后用户点击右边实例的Receive按扭,这个消息就会在该实例的Message Received文本框中显示。

image
图4 .applet的持久性API使applet之间相互发送消息给对方。点击“最大化”

消息发送发生在下面代码的action listener中。
Listing 3. MessageTransfer.java
// MessageTransfer.java

import java.applet.*;


import java.awt.*;

import java.awt.event.*;

import java.io.*;

import javax.swing.*;

public class MessageTransfer extends JApplet implements ActionListener
{
   private TextField txtRecvMsg, txtSendMsg;

   public void init ()
   {
      // Build the applet's GUI.

      setLayout (new GridLayout (3, 1));

      JPanel pnl = new JPanel ();
      pnl.setLayout (new FlowLayout (FlowLayout.LEFT));

      pnl.add (new JLabel ("Message to send:"));

      txtSendMsg = new TextField (20);
      pnl.add (txtSendMsg);

      getContentPane ().add (pnl);

      pnl = new JPanel ();
      pnl.setLayout (new FlowLayout (FlowLayout.LEFT));

      pnl.add (new JLabel ("Message received:"));

      txtRecvMsg = new TextField (20);
      pnl.add (txtRecvMsg);

      getContentPane ().add (pnl);

      pnl = new JPanel ();
      pnl.setLayout (new FlowLayout (FlowLayout.LEFT));

      JButton btnSend = new JButton ("Send");
      btnSend.addActionListener (this);
      pnl.add (btnSend);

      JButton btnReceive = new JButton ("Receive");
      btnReceive.addActionListener (this);
      pnl.add (btnReceive);

      getContentPane ().add (pnl);
   }

   public void actionPerformed (ActionEvent e)
   {
      JButton btn = (JButton) e.getSource ();

      if (btn.getText ().equals ("Send"))
      {
          String text = txtSendMsg.getText ();

          try
          {
              // Output the String object to a byte array output stream.


              ByteArrayOutputStream baos = new ByteArrayOutputStream ();
              ObjectOutputStream oos = new ObjectOutputStream (baos);
              oos.writeObject (text);
              oos.close ();

              // Extract the String object from the byte array output stream
              // as an array of bytes.

              byte [] data = baos.toByteArray ();

              // Convert the array of bytes to a byte array input stream. When
              // the setStream() method is invoked, it caches the input stream
              // reference and key in the applet persistent store.

              InputStream is = new ByteArrayInputStream (data);
              getAppletContext ().setStream ("text", is);
          }
          catch (Exception e2)
          {
              System.out.println (e2.toString ());
          }
      }
      else
      {
          InputStream is = getAppletContext ().getStream ("text");

          if (is != null)
              try
              {
                  // Input the cached String object.

                  ObjectInputStream ois = new ObjectInputStream (is);
                  String text = (String) ois.readObject ();
                  txtRecvMsg.setText (text);
              }
              catch (Exception e2)
              {
                 System.out.println (e2.toString ());
              }
      }
   }
}


这个消息发送applet把消息持久化为一个string对象,通过把这个对象序列化到ByteArrayOutputStream,转化这个stream到一个byte数组,基于这个byte数组构建一个ByteArrayInputStream,然后通过这个stream和一个名为text的key调用方法setStream()。该applet用这个名为text的key调用getStream()取回这个消息,然后反序列化这个InputStream。

在Firefox中,被持久化后的消息对在不同窗口或面版上运行的applet都是可以被访问的。这种消息对不同session(也就是说,Firefox的不同实例)中运行的applet是不能被访问的,因为每个session只与它自己的Java Plug-in实例和内部持久性存储数据结构进行通信。

提示
出于安全考虑,使用不同codebase的applet不能访问对方的stream。

了解cookie

Web浏览器和web服务器经常发送小的数据包给对方进行交互。这些包,也就是大家知道的cookie,可以被用来跟踪用户的喜好,帮用户自动登录站点等。Java Plug-in结合web 浏览器可以让applet访问cookie。例如,Java Plug-in让签名applet去查看从web服务器发送到web浏览器的cookie。

Java Plug-in5.0文档中谈及对cookie的支持时,给出了几个与cookie交互的代码片段。因为你可能想在applet中测试这些代码片段,还有就是可能你不确定该怎样把它们转变成签名applet,所以下面我给出了一个用来查看cookie的签名applet。在讨论完这些重要的代码后,我将带你学习怎样建立和签名applet。最后,我们会在Firefox web浏览器中运行这个applet。
下面就是代码。

Listing 4. CookieDetect.java
// CookieDetect.java

import java.awt.BorderLayout;

import java.awt.event.*;

import java.net.*;

import java.util.*;

import javax.swing.*;

public class CookieDetect extends JApplet implements ActionListener
{
   private JTextArea txtaStatus;
   private JTextField txtURL;

   public void init ()
   {
      // Build the applet's GUI

      JPanel pnl = new JPanel ();

      pnl.add (new JLabel ("Enter URL:"));

      txtURL = new JTextField (20);
      txtURL.addActionListener (this);
            
      pnl.add (txtURL);


      getContentPane ().add (pnl, BorderLayout.NORTH);

      txtaStatus = new JTextArea (10, 40);

      getContentPane ().add (new JScrollPane (txtaStatus));
   }

   public void actionPerformed (ActionEvent e)
   {
      try
      {
          URL url = new URL (txtURL.getText ());
          URLConnection conn = url.openConnection ();

          conn.connect ();

          Map<String, List<String>> headers = conn.getHeaderFields ();
          List<String> values = headers.get ("Set-Cookie");

          if (values == null)
          {
              txtaStatus.setText ("No cookies detected\n");
              return;
          }

          txtaStatus.setText ("");
          for (Iterator iter = values.iterator (); iter.hasNext();)
               txtaStatus.setText (txtaStatus.getText () + iter.next () + "\n");

          txtaStatus.setText (txtaStatus.getText () + "\n");
      }
      catch (Exception e2)
      {
          System.out.println (e2);
      }
   }
}


CookieDetect.java生成的GUI主要由两个条目构成:一个接受URL的文本框,和一个显示cookie的文本域。无论何时用户按下Enter键和这个文本框获得了输入的光标,文本框的action listener的方法actionPerformed()都会被调用。

方法actionPerformed()首先用文本框中的URL建立一个URL对象。然后调用这个对象的openConnection()方法返回一个表示该applet和该URL相互连接的URLConnection对象。继续往下面看,URLConnection()的方法connect()建立这个连接,它的getHeaderFields()方法可以得到不会改变的一组HTTP头和相对应的值,Map的方法get()返回与头Set-Cookie相对应的值组成的List。一个循环列举出了该List中的值;每个值表示一个cookie,被陆续加入文本区域中。

假使CookieDetect.java存放在当前目录c:\applets\CookieDetect中,完成下面的操作,建立和签名这个查看cookie的applet:
·        编译 CookieDetect.java: javac CookieDetect.java.
·        把上步得到的CookieDetect.class替换成一个jar文件,jar cvf CookieDetect.jar CookieDetect.class。
·        在一个新keytore中创建一个新key:keytool -genkey -keystore ks -alias me。当弹出来后,输入testtest作为keystore的密码,你的姓和名,你所在行业(比如IT),你公司的名字,你所在城市名,所在州或省的名字,你的行业代码 ,不管你刚才输入的信息是否真实,当弹出窗口时选择Yes。当弹出窗口让你输入me的密码 时,单击Enter。这样可以让密码与keystore 中的密码(testtest)相同。所有这些信息都被放在文件ks中,这个文件需要我们自己签名的测试认证。
·        创建一个签名的测试认证:keytool -selfcert -alias me -keystore ks。当被弹出后,输入testtest作为keystore的密码。这个认证就被放进ks中了。Alias me (在前一步,这步,和下一步中)提醒你这个认证已被签名,仅仅用来被测试。换句话说,不要在公共站点上用这个测试认证来发布签名applet。
·        用这个测试认证来签名这个jar文件:jarsigner -keystore ks CookieDetect.jar me。当弹出后,输入testtest作为keystore的密码。这个工具更新该jar文件的META-INF目录以包含认证信息和CookieDetect.class的一个数字签名。
让我们运行这个applet。从本文附的代码中找到CookieDetect.html,然后放进目录c:\applets\CookieDetect下。该HTML文件的<applet>中包含一个archive属性来标识CookieDetect.jar文件。打开Firefox,然后输入该HTML文件的URL:
c:\applets\CookieDetect\CookieDetect.html。一段时间后,图5的安全对话框就会出现在你眼前。

image
Figure 5. 安全对话框让你有权信任这个签名的applet。

单击yes键响应该安全对话框。然后这个applet被显示。输入URL:http://javaworld.com,然后按下回车。如图6所示,网站JavaWorld 不会发送cookie。

image
Figure 6. 你不会从 JavaWorld 取得cookie

与JavaWorld 相比,网站JavaLobby会发送一个cookie。输入http://javalobby.org,图7中就会显示有这样一个cookie,id 是SESSIONID。

image
Figure 7.  JavaLobby 发送了一个简单的cookie

一些网站会发送出大量的cookie,比如像kasssamba。如图8所显示的,该站点发送了4个cookie到web浏览器。

image
Figure 8. Kasamba 发送了不少的cookie到web浏览器

我极力建议你继续去体会cookie的使用,把余下的三段代码(来源于Java Plug-in 5.0文档中对cookie支持的标题)也转换成签名applet。

小窍门
访问 http://www.cookiecentral.com/faq/ 可以学到更多关于cookie的内容。

理解 hood

许多人在让Firefox识别Java Plug-in时会遇到困难。说来说去,就是指applet不能运行。通过理解Firefox与Java Plug-in怎样进行交互,你能避开许多类似的麻烦。在后续部分,我会为你讲解Firefox如何探测Java Plug-in,JRE的 NP*.dll 插件文件,和一些被称为OJI的东西。

探测Java Plug-in
在前面你已经安装了一个简单的JRE(它包含了Java Plug-in),现在要安装Firefox。你可以运行那个浏览器,上网冲浪,打开那些使用了applet的网页,那些applet就会运行起来了。。不久后,你会思考Firefox是怎样找到Java Plug-in,让applet运行起来的。毕竟说来,Firefox只检索它自己的插件列表来查找插件,而JRE把它自己的Java Plug-in放在它自身的bin目录下。在这样的安排下,Firefox怎么可能检测到Java Plug-in呢?

当Firefox开始运行时,它的目录服务提供器就接到一个任务,在windows平台上的安装目录中去找adobe Acrobat, Apple Quicktime, Microsoft Windows Media Player, 和 Sun Java plug-in。Java Plug-in的安装目录一经找到,目录服务提供器将会传递以下信息给plugin.scan.SunJRE:用户的个人设置名称和该设置的值(要求的最低JRE版本)。更进一步,security.enable_java 这个用户设置必须存在,而且它的布尔值必须为true。

假如plugin.scan.SunJRE 和 security.enable_java存在,还假设security.enable_java的值是true,目录服务提供器会在windows的注册表中列出所有版本号作为HKEY_LOCAL_MACHINE\\Software\\JavaSoft\\Java Plug-in的子键。最新版本号识别出Firefox所使用的JRE/Java Plug-in,这个版本号必须要比plugin.scan.SunJRE的值要大或相等.版本号子键自身的JavaHome子键包含了被识别出的JRE根目录路径。目录服务提供器把\bin附加在这个目录后,这时Firefox就知道了Java Plug-in的安装路径了。有点糊涂了?我会用一个例子来拨开这一层雾。

我的Firefox浏览器给出我的plugin.scan.SunJRE值为1.3。它同时也指定security.enable_java值为真。在启动时,目录服务提供器扫描我的windows注册表;相关的设置如下:
HKEY_LOCAL_MACHINE
  Software
    JavaSoft
      Java Plug-in
        1.5.0
          JavaHome "C:\Program Files\Java\jre1.5.0"

目录服务提供器列举出所有版本号的子键,在Java Plug-in子键下面,那个子键所示的最高版本号就大于或等于1.3了。我仅有一个子键大于或等于1.3:1.5.0。因此,目录服务提供器含有子键值为1.5.0的JavaHome子键—C:\Program Files\Java\jre1.5.0—然后把\bin附加在这个值的后面。这就意味着Firefox会在目录c:\Program Files\Java\jre1.5.0\bin下去找Java Plug-in。

因为Firefox1.0的plugin.scan.SunJRE用户设置用1.3作为它的默认值,所以Java Plug-in版本低于1.3的不会被识别。这就是为什么Firefox只支持Java Plug-in 1.3.0_01和更高的版本。
NP*.dll文件

仔细查看你的JRE的 bin目录,你会发现不少文件名以NP开头,以.dll结尾的文件。例如,我的平台下就列出了下面这些文件:
NPJava11.dll
NPJava12.dll
NPJava13.dll
NPJava14.dll
NPJava32.dll
NPJPI150.dll
NPOJI610.dll

上面列出的文件是Netscape的插件文件。加上你可能在你的JRE的bin目录下发现的其他NP*.dll文件,和也应该被列出的若干个jpi*.dll文件,他们一起构成了Java Plug-in。每个NP*.dll文件有相同的大小,因为他们基本上都是做的同样的事情:它与jpi*.dll文件中的一个协同工作,下载虚拟机,让java环境运行起来。

每一个NP*.dll文件能识别一种或多种MIME(多用途网际邮件扩展协议)类型。当遇到某种MIME类型时,这种类型会告诉Firefox去装载一个相应的具体NP*.dll文件。例如,思考下面的<EMBED>标签:
<embed code="VersionDetect.class" width="200" height="200"
       pluginspage="."
       type="application/x-java-applet;version=1.1">


注意type属性的application/x-java-applet;version=1.1 MIME类型。当Firefox遇到这种MIME类型,它就会选择相应的NP*.dll文件。因为NPJava11.dll标记了那种MIME类型,NPJava11.dll会去装载——而不是其他的NP*.dll装载。NPJava11.dll与jpi*.dl文件一起让java环境运行。

当Firefox遇见<applet>标签时,它到底表示的是哪种MIME类型?我认为当Firefox 遇到<applet> 标签时,application/x-java-vm就是MIME类型:测试显示出只有拥有那个MIME类型的NPOJI610.dll会去装载。

什么是OJI?
你可能已经注意到在NPOJI610.dll中有OJI,想知道这三个字母代表什么。OJI表示Open JVM Integration ,这是个Mozilla project/API,它允许外部的JVM能够插入一个 Mozilla浏览器(就像Firefox这样)。除了没有被绑定在内部虚拟机上,这个浏览器也没有被绑定在sun指定的外部虚拟机上——浏览器能够通过其他途径与虚拟机进行交互,只要这些虚拟机支持OJI。

OJI有许多特性,包括允许用户通过web浏览器来显示java主控台。OJI也会更改一个applet的生命周期:一旦一个applet网页被打开,这个applet的init() 和 start()方法就会被调用。为了让你能看到这个过程,先编译Listing 5的 LifeCycle.java源代码,在Firefox下运行这个applet,打开java主空台,然后不停在网页之间进行切换。在你每次进入这个applet网页的时候,你将注意到对这个applet构造器的调用,它表明一个新的LifeCycle对象被生成了。

Listing 5. LifeCycle.java
// LifeCycle.java

public class LifeCycle extends java.applet.Applet
{
   public LifeCycle ()
   {
      System.out.println ("constructor called");
   }

   public void init ()
   {
      System.out.println ("init() called");
   }

   public void start ()
   {
      System.out.println ("start() called");
   }

   public void stop ()
   {
      System.out.println ("stop() called");
   }

   public void destroy ()
   {
      System.out.println ("destroy() called");
   }
}


总结
即使讲完上面所有的内容,我也仅仅是做了浅层次的讲解。其实还有很多东西我想写下来。可能只有在以后,我再写另一篇后续文章来完成了。或者你也可以写那篇文章。不管怎样,都让我们继续拓展我们对Sun的 Java Plug-in技术的理解吧。

关于作者
Jeff Friesen 是软件发展的自由撰稿人,同时也是C, C++, 和 Java技术的研究员。

资源列表
·        下载这篇文章中的代码:
http://www.javaworld.com/javaworld/jw-06-2005/plugin/jw-0627-plugin.zip
·        浏览Java Plug-in 5.0的文档:
http://java.sun.com/j2se/1.5.0/docs/guide/plugin/index.html
·        学习Mozilla.org的 nsPluginDirServiceProvider.cpp 目录服务提供器C++ 写的代码 :
http://lxr.mozilla.org/mozilla1.7/source/modules/plugin/base/src/nsPluginDirServiceProvider.cpp
·        查看 Mozilla.org的 OJI站点 :
http://www.mozilla.org/oji/
·        "Plug into Java with Java Plug-in," Jeff Friesen (JavaWorld, June 1999):
http://www.javaworld.com/javaworld/jw-06-1999/jw-06-plugin.html
·        查看 Sun的 Java Plug-in 主页:
http://java.sun.com/products/plugin/index.html
·        Jeff Friesen, "Talk with Me Java," (JavaWorld, June 2004):
http://www.javaworld.com/javaworld/jw-06-2004/jw-0621-talk.html
·        非官方的 Cookie FAQ:
http://www.cookiecentral.com/faq/
加载更多

专题访谈

合作站点
stat