各位好,很久沒更新了,今天來談談Java Applet的一個
特別的應用方式。以前Java Applet並沒有太多可供討論的地方,
因為之前applet的執行受到瀏覽器的jvm的限制,基本上只能秀一些
簡單的圖形介面,很難有更多的功能,加上applet本身的安全性限制,
都綁住了applet的能力。然而,在java plugin開始推出之後,一方面
可以使用最新的jvm,一方面有一個較好的安全認證機制,讓擁有電子簽名
的applet可以在使用者的同意下存取更多的資源。如此一來,applet可以發揮
更大的公用。
我們先簡單的提一下applet的簽章機制。如果要做正式的產品,我們
必須向中立的機構付費先取得電子簽章,如果只是測試用途,我們可以使用jdk
內建的keytool來產生電子簽章。經過電子簽章的applet,在執行的時候,會顯示
出一個詢問視窗,詢問使用者是否願意信任這個電子簽章,如果使用者信任的話,
這個applet以及從這個applet產生的執行緒會被當成安全的本地端程式,擁有很大
的執行權限。不論透過任何方式取得電子簽章,我們都可以先利用jar這個工具把
applet的class檔案封裝起來,然後利用jdk內建的jarsigner工具來對這個jar檔案
做簽章的動作。
理論上,簽章過的applet一但獲得使用者的信任,即使要寫入本地的檔案系統
都沒有問題。不過我們想做更多的變化,把applet拿來當作類似ActiveX control那樣
,配合script language來使用。我們看看這個範例程式:
========================================================
========================================================
假設writeToLocalFileSystem()這個函式會寫入使用者的檔案系統。很可惜的是,
這個做法會失敗。雖然applet被使用者信任了,但是這個script並不會被使用者信任,因此
從這個script呼叫appletObj.writeToLocalFileSystem()的這個動作處在不被信任的執行緒中,
所以會被攔截下來。解決的辦法很簡單,因為writeToLocalFileSystem()這個函式是被不信任
的執行緒所呼叫的,我們只能讓他做很簡單的動作,我們可以讓他來設定applet裡面的某個變數
資料。然後,因為applet本身是被信任的,我們可以從applet內部產生一個受信任的執行緒,
讓這個執行緒監視前述的變數資料,然後來執行寫入檔案系統的動作就可以了。詳細的做法請參考
下列程式:
========================================================
package appletTest;
import java.applet.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import java.io.*;
import java.util.*;
public class testApplet extends Applet implements Runnable
{
private int value=0;
private int counter=0;
private Vector fileLoadingQueue=null;
private Hashtable fileLoadingTable=null;
private boolean running=true;
public testApplet()
{
fileLoadingQueue=new Vector();
fileLoadingTable=new Hashtable();
}
public int getValue(){return value;}
public void setValue(int value){this.value=value;}
public void stop()
{
running=false;
super.stop();
}
public void start()
{
new Thread(this).start();
}
public Element testObject(String filename)
{
try{
DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
DocumentBuilder db=dbf.newDocumentBuilder();
return db.parse(new java.io.File(filename)).getDocumentElement();
}catch(Exception e){return null;}
}
public helperObject getHelperObject()
{
return new helperObject();
}
public synchronized String testDom(String fileName)
{
String id=""+counter;
counter++;
LoadingEntry entry=new LoadingEntry();
entry.fileName=fileName;
entry.id=id;
fileLoadingQueue.add(entry);
notifyAll();
while(fileLoadingTable.get(id)==null)
{
try{
wait();
}catch(Exception e){}
}
Document dom=(Document)(fileLoadingTable.get(id));
fileLoadingTable.remove(id);
return dom.getDocumentElement().getNodeName();
}
public void run()
{
while(running)
{
try{
synchronized(this)
{
if(fileLoadingQueue.size()==0)
{
wait();
continue;
}
LoadingEntry entry=(LoadingEntry)(fileLoadingQueue.remove(0));
String fileName=entry.fileName;
DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
DocumentBuilder db=dbf.newDocumentBuilder();
Document dom=db.parse(new java.io.File(fileName));
fileLoadingTable.put(entry.id,dom);
FileOutputStream fileOutput=new FileOutputStream("c:\\test.dat");
PrintStream output=new PrintStream(fileOutput);
output.println("test.");
output.close();
notifyAll();
}
}
catch(SecurityException e1){throw e1;}
catch(Exception e){}
}
}
}
class LoadingEntry
{
public String fileName=null;
public String id=null;
public boolean equals(Object obj)
{
if(!(obj instanceof LoadingEntry) || id==null)
return false;
LoadingEntry entry=(LoadingEntry)obj;
if(entry.id==null)
return false;
return id.equals(entry.id);
}
public int hashCode()
{
int i1=0;
int i2=0;
if(fileName!=null)
i1=fileName.hashCode();
if(id!=null)
i2=id.hashCode();
return (i1+i2)%47;
}
}
========================================================