deployJava.js をマニアックに読み解く 第一章

Java SE 6u10 の Java Plug-In や Java Deployment Toolkit の話が最近自分の中の流行りなので、今日は deployJava.js を読んでみようと思います。
deployJava.js を使用すると、Java Plug-in アプレットおよび Java Web Start アプリケーション用の Java プラットフォームを自動的にインストールすることができます。
deployJava.js はここから入手できます。


かなり長編ものになりそうなので、三回に分割します。
それでは、早速 deployJava.js を読んでいきましょう。
まずファイルの冒頭は1 - 45行目までコメントです。

  1| /*
  2|  * Copyright (c)  2008 Sun Microsystems, Inc.  All rights reserved.
  3|  *
  4|  * Redistribution and use in source and binary forms, with or without
  5|  * modification, are permitted provided that the following conditions
  6|  * are met:
  7|  *
  8|  *   - Redistributions of source code must retain the above copyright
  9|  *     notice, this list of conditions and the following disclaimer.
 10|  *
 11|  *   - Redistributions in binary form must reproduce the above copyright
 12|  *     notice, this list of conditions and the following disclaimer in the
 13|  *     documentation and/or other materials provided with the distribution.
 14|  *
 15|  *   - Neither the name of Sun Microsystems nor the names of its
 16|  *     contributors may be used to endorse or promote products derived
 17|  *     from this software without specific prior written permission.
 18|  *
 19|  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 20|  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 21|  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 22|  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 23|  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 24|  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 25|  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 26|  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 27|  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 28|  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 29|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 30|  */
 31|
 32| /*
 33|  * deployJava.js
 34|  *
 35|  * This file is part of the Deployment Toolkit.  It provides functions for web
 36|  * pages to detect the presence of a JRE, install the latest JRE, and easily run
 37|  * applets or Web Start programs.  Usage guide may be found at http://<TBD>/.
 38|  * 
 39|  * The "live" copy of this file may be found at 
 40|  * http://java.com/js/deployJava.js.  
 41|  * You are encouraged to link directly to the live copy of the file.
 42|  *
 43|  * @version @(#)deployJava.js	1.13 08/10/28
 44|  */

コメントではこのプログラムの著作権に関する条件と、このスクリプトの機能の簡単な説明が書かれています。
詳細は省略します。

 46| var deployJava = {
 47|     debug: null,
 48| 
 49|     myInterval: null,
 50|     preInstallJREList: null,
 51|     returnPage: null,
 52|     brand: null,
 53|     locale: null,
 54|     installType: null,
 55|     
 56|     EAInstallEnabled: false,
 57|     EarlyAccessURL: null,
 58|     
 59|     // GetJava page
 60|     getJavaURL: 'http://java.sun.com/webapps/getjava/BrowserRedirect?host=java.com',
 61|     
 62|     // Apple redirect page
 63|     appleRedirectPage: 'http://www.apple.com/support/downloads/',
 64| 
 65|     // mime-type of the DeployToolkit plugin object
 66|     mimeType: 'application/npruntime-scriptable-plugin;DeploymentToolkit',
 67| 
 68|     // location of the Java Web Start launch button graphic
 69|     launchButtonPNG: 'http://java.sun.com/products/jfc/tsc/articles/swing2d/webstart.png',

46 - 71行目です。
46行目の変数宣言で deployJava がグローバル名前空間に定義されます。
以下では、この変数が参照するオブジェクトのプロパティが続きますが、ここも詳細は省略し、各プロパティについては以降のコードを追いながら、その意味や用途などを明らかにしていこうと思います。

 72|     /**
 73|      * Returns an array of currently-installed JRE version strings.  
 74|      * Version strings are of the form #.#[.#[_#]], with the function returning
 75|      * as much version information as it can determine, from just family 
 76|      * versions ("1.4.2", "1.5") through the full version ("1.5.0_06").
 77|      *
 78|      * Detection is done on a best-effort basis.  Under some circumstances 
 79|      * only the highest installed JRE version will be detected, and 
 80|      * JREs older than 1.4.2 will not always be detected.
 81|      */
 82|     getJREs: function() {
 83|         var list = new Array();
 84|         if (deployJava.isPluginInstalled()) {
 85|             var plugin =  deployJava.getPlugin();
 86|             for (var i = 0; i < plugin.jvms.getLength(); i++) {
 87|                 list[i] = plugin.jvms.get(i).version;
 88|             }
 89|         } else {
 90|             var browser = deployJava.getBrowser();
 91|         
 92|             if (browser == 'MSIE') {
 93|                 if (deployJava.testUsingActiveX('1.8.0')) {
 94|                     list[0] = '1.8.0';
 95|                 } else if (deployJava.testUsingActiveX('1.7.0')) {
 96|                     list[0] = '1.7.0';
 97|                 } else if (deployJava.testUsingActiveX('1.6.0')) {
 98|                     list[0] = '1.6.0';
 99|                 } else if (deployJava.testUsingActiveX('1.5.0')) {
100|                     list[0] = '1.5.0';
101|                 } else if (deployJava.testUsingActiveX('1.4.2')) {
102|                     list[0] = '1.4.2';
103|                 } else if (deployJava.testForMSVM()) {
104|                     list[0] = '1.1';
105|                 }
106|             }
107|             else if (browser == 'Netscape Family') {
108|                 if (deployJava.testUsingMimeTypes('1.8')) {
109|                     list[0] = '1.8.0';
110|                 } else if (deployJava.testUsingMimeTypes('1.7')) {
111|                     list[0] = '1.7.0';
112|                 } else if (deployJava.testUsingMimeTypes('1.6')) {
113|                     list[0] = '1.6.0';
114|                 } else if (deployJava.testUsingMimeTypes('1.5')) {
115|                     list[0] = '1.5.0';
116|                 } else if (deployJava.testUsingMimeTypes('1.4.2')) {
117|                     list[0] = '1.4.2';
118|                 }
119|             } else if (browser == 'Safari') {
120|                 if (deployJava.testUsingPluginsArray('1.8.0')) {
121|                     list[0] = '1.8.0';
122|                 } else if (deployJava.testUsingPluginsArray('1.7.0')) {
123|                     list[0] = '1.7.0';
124|                 } else if (deployJava.testUsingPluginsArray('1.6.0')) {
125|                     list[0] = '1.6.0';
126|                 } else if (deployJava.testUsingPluginsArray('1.5.0')) {
127|                     list[0] = '1.5.0';
128|                 } else if (deployJava.testUsingPluginsArray('1.4.2')) {
129|                     list[0] = '1.4.2';
130|                 }
131|             }
132|         }
133|             
134|         if (deployJava.debug) {
135|             for (var i = 0; i < list.length; ++i) {
136|                 alert('We claim to have detected Java SE ' + list[i]);
137|             }
138|         }
139|     
140|         return list;
141|     },

getJREs() メソッドです。
コメントには・・・
現在のブラウザで使用可能な JRE のバージョンの文字列を取得し、結果を配列でリターンする。
的なことが書かれています


84 - 88行目では Deployment Toolkit のプラグインがインストール済みである場合に、そのプラグインから使用可能な JRE のバージョンを取得します。
90 - 131行目の else ブロックの中は Deployment Toolkit がインストールされていない場合です。
90行目の getBrowser() メソッドは現在のブラウザを文字列で取得します。


92 - 106行目はブラウザが IE の場合です。
93 - 102行目では testUsingActiveX() メソッドで、バージョン1.8.0から順に1.4.2まで ActiveXObject を使って、インストールされている JRE をチェックし、見つかれば結果の配列の先頭にバージョンを格納します。
103 - 104行目は、1.8.0から1.4.2までのバージョンが見つからなかった場合に、マイクロソフトVM をチェックし、見つかれば結果の配列の先頭に"1.1"を格納します。


107 - 118行目はブラウザが Firefox など Mozilla の場合です。
108 - 117行目では testUsingMimeTypes() メソッドで、バージョン1.8.0から順に1.4.2まで ブラウザが処理可能な MIME タイプを調べて、インストールされている JRE をチェックしています。


119 - 131行目はブラウザが Safari の場合です。
120 - 129行目では testUsingPluginsArray() メソッドで、バージョン1.8.0から順に1.4.2まで ブラウザにインストールされているプラグインを調べて、JRE をチェックしています。


134 - 138行目は debug プロパティを見て、デバッグ中の場合に、配列の内容を確認します。
140行目で結果の配列をリターンします。


因みに、新しい Java Plug-In が現在サポートしているのは Windows XPVista 上の IE 6/7 それから XP Vista Solaris Linux 上の FF3 だけらしいので、Safari では動作しないようです。

143|     /**
144|      * Triggers a JRE installation.  The exact effect of triggering an 
145|      * installation varies based on platform, browser, and if the 
146|      * Deployment Toolkit plugin is installed.
147|      *
148|      * The requestVersion string is of the form #[.#[.#[_#]]][+|*], 
149|      * which includes strings such as "1.4", "1.5.0*", and "1.6.0_02+".  
150|      * A star (*) means "any version starting within this family" and 
151|      * a plus (+) means "any version greater or equal to this".  
152|      * "1.5.0*" * matches 1.5.0_06 but not 1.6.0_01, whereas 
153|      * "1.5.0+" matches both.
154|      *
155|      * If the Deployment Toolkit plugin is not present, this will just call 
156|      * deployJava.installLatestJRE(). 
157|      */
158|     installJRE: function(requestVersion) {
159|         var ret = false;
160|         if (deployJava.isPluginInstalled()) {
161|             if (deployJava.getPlugin().installJRE(requestVersion)) {
162|                 deployJava.refresh();
163|                 if (deployJava.returnPage != null) {
164|                     document.location = deployJava.returnPage;
165|                 }
166|                 return true;
167|             } else {
168|                 return false;
169|             }
170|         } else {
171|             return deployJava.installLatestJRE();
172|         }
173|     },

続いて installJRE() メソッドです。
コメントには・・・
JRE のインストールを実行する。
Deployment Toolkit のプラグインがインストールされているかどうか、また使用しているブラウザやプラットフォームによって、この処理の正確な結果は変わる。
引数 requestVersion は、必要な JRE のバージョンを "1.4", "1.5.0*", "1.6.0_02+" のような形式の文字列で指定する。
バージョン番号の末尾に "*" を付けると、特定のバージョン番号で始まる製品ファミリが選択される。
バージョン番号の末尾に "+" を付けると、特定のバージョン以降の製品が全て選択される。
Deployment Toolkit プラグインがインストールされていない場合は、installLatestJRE() メソッドを単に呼び出すだけ。
という風に書かれています。


160行目は isPluginInstalled() メソッドで Deployment Toolkit プラグインがインストール済みかどうかを調べています。
161 - 169行目は Deployment Toolkit プラグインがインストールされている場合の処理です。
161行目では、そのプラグインが提供している installJRE() メソッドを呼び出して、引数 requestVersion で指定したバージョンの JRE をインストールします。
162行目は refresh() メソッドを呼び出して、今インストールした JRE を利用できるようにしています。


163 - 165行目は、returnPage プロパティが null でないならば、それを document.location にセットして、ページを読み込みます。
returnPage プロパティは、プラグインのインストールページから戻ってくる為の URL を記憶しておく変数です。


166行目で true をリータンします。true は JRE のインストールが正常に完了したことを意味します。
168行目は、JRE のインストールが失敗した場合に false をリータンします。


171行目は、Deployment Toolkit プラグインがインストールされていない場合に installLatestJRE() を呼び出します。
ところで159行目の変数 ret は宣言したまま使われていませんね。

176|     /**
177|      * Triggers a JRE installation.  The exact effect of triggering an 
178|      * installation varies based on platform, browser, and if the 
179|      * Deployment Toolkit plugin is installed.
180|      *
181|      * In the simplest case, the browser window will be redirected to the 
182|      * java.com JRE installation page, and (if possible) a redirect back to 
183|      * the current URL upon successful installation.  The return redirect is 
184|      * not always possible, as the JRE installation may require the browser to 
185|      * be restarted.
186|      *
187|      * In the best case (when the Deployment Toolkit plugin is present), this
188|      * function will immediately cause a progress dialog to be displayed 
189|      * as the JRE is downloaded and installed.
190|      */
191|     installLatestJRE: function() {
192|         if (deployJava.isPluginInstalled()) {
193|             if (deployJava.getPlugin().installLatestJRE()) {
194|                 deployJava.refresh();
195|                 if (deployJava.returnPage != null) {
196|                     document.location = deployJava.returnPage;
197|                 }
198|                 return true;
199|             } else {
200|                 return false;
201|             }
202|         } else {
203|             var browser = deployJava.getBrowser();
204|             var platform = navigator.platform.toLowerCase();
205|             if ((deployJava.EAInstallEnabled == 'true') && 
206|                 (platform.indexOf('win') != -1) && 
207|                 (deployJava.EarlyAccessURL != null)) {
208| 
209|                 deployJava.preInstallJREList = deployJava.getJREs();
210|                 if (deployJava.returnPage != null) {
211|                     deployJava.myInterval = 
212|                         setInterval("deployJava.poll()", 3000);
213|                 }
214| 
215|                 location.href = deployJava.EarlyAccessURL;
216| 
217|                 // we have to return false although there may be an install
218|                 // in progress now, when complete it may go to return page
219|                 return false;
220|             } else {
221|                 if (browser == 'MSIE') {
222|                     return deployJava.IEInstall();
223|                 } else if ((browser == 'Netscape Family') && 
224|                            (platform.indexOf('win32') != -1)) {
225|                     return deployJava.FFInstall();
226|                 } else {
227|                     location.href = deployJava.getJavaURL + 
228|                         ((deployJava.returnPage != null) ?
229|                         ('&returnPage=' + deployJava.returnPage) : '') + 
230|                         ((deployJava.locale != null) ?
231|                         ('&locale=' + deployJava.locale) : '') +
232|                         ((deployJava.brand != null) ? 
233|                          ('&brand=' + deployJava.brand) : '');
234|                 }
235|                 // we have to return false although there may be an install
236|                 // in progress now, when complete it may go to return page
237|                 return false;
238|             }
239|         }
240|     },

installLatestJRE() メソッドです。
コメントには・・・
最もシンプルなケースでは、java.com の JRE インストールページへ遷移し、インストールが成功したら(可能であれば)、現在の URL に戻って来る。
ブラウザの再起動を要求されることがある為、現在の URL に戻れない場合もある。
Deployment Toolkit プラグインが既に存在していれば、JRE がダウンロードされインストールしている間、ダイアログで状況を表示する。
というように書かれています。


192 - 201行目は installJRE() メソッドで読んだ内容と同様なので省略します。
異なる点は、193行目でプラグインの installLatestJRE() メソッドを呼び出して、最新の JRE をインストールしようとしていることです。


203 - 238行目は Deployment Toolkit プラグインがインストールされていない場合の処理です。
203行目で getBrowser() メソッドを呼び出して現在のブラウザを文字列で取得します。
204行目で現在のプラットフォームを示す文字列を読み出しています。


205 - 219行目は、Windows 環境でアーリーアクセス版の JRE をインストールする場合の処理です。
205 - 207行目の EAInstallEnabled プロパティはアーリーアクセス版を使用するかどうかを表す変数で、EarlyAccessURL プロパティはアーリーアクセス版のURLです。
両プロパティの値は deployJava.js の外側から与えられることを想定しています。


209行目は getJREs() メソッドを呼び出してインストール済み JRE のバージョン配列を preInstallJREList プロパティにセットしています。
210 - 213行目は、returnPage プロパティが null でない場合に3秒毎に poll() メソッドが呼び出されるようにしています。
poll() は後で詳細を見ますが、JRE のインストールが完了したかをチェックして、完了していれば returnPage プロパティが保持する URL をブラウザに読み込ませるメソッドです。
215行目は EarlyAccessURL プロパティの値を location.href にセットしています。
EarlyAccessURL プロパティの値は、JRE の(インストーラーの)バイナリ自体の URL であることを想定しています。
つまり EarlyAccessURL プロパティの URL が正しければ、ダウンロードのダイアログが表示されます。
これをうっかりダウンロードページの URL などに設定してしまうと、そのページへ移動してしまうことになり、記憶しておいた returnPage プロパティの URL へ戻れなくなってしまうので注意が必要です。

EarlyAccessURL プロパティの URL の例:

'http://example/xxx/jre-xxx-beta-xxx-xxx-x-xxx.exe';


219行目で false をリターンします。


221 - 222行目ではブラウザが IE の場合に、IEInstall() メソッドを呼び出して JRE のインストールページへ移動します。
223 - 225行目ではブラウザが Firefox (現時点の公表では、Netscape ファミリーの中で Firefox のみ)の場合に、FFInstall() メソッドを呼び出しています。
223 - 225行目ではそれら以外のブラウザの場合ですが、現時点ではサポートされていません。


237行目で false をリターンします。

243|     /**
244|      * Ensures that an appropriate JRE is installed and then runs an applet.
245|      * minimumVersion is of the form #[.#[.#[_#]]], and is the minimum 
246|      * JRE version necessary to run this applet.  minimumVersion is optional, 
247|      * defaulting to the value "1.1" (which matches any JRE).  
248|      * If an equal or greater JRE is detected, runApplet() will call 
249|      * writeAppletTag(attributes, parameters) to output the applet tag, 
250|      * otherwise it will call installJRE(minimumVersion + '+').
251|      *
252|      * After installJRE() is called, the script will attempt to detect that the 
253|      * JRE installation has completed and begin running the applet, but there
254|      * are circumstances (such as when the JRE installation requires a browser
255|      * restart) when this cannot be fulfilled.
256|      *
257|      * As with writeAppletTag(), this function should only be called prior to 
258|      * the web page being completely rendered.  Note that version wildcards 
259|      * (star (*) and plus (+)) are not supported, and including them in the 
260|      * minimumVersion will result in an error message.
261|      */
262|     runApplet: function(attributes, parameters, minimumVersion) {
263|         if (minimumVersion == 'undefined' || minimumVersion == null) {
264|             minimumVersion = '1.1';
265|         }
266| 
267|         var regex = "^(\\d+)(?:\\.(\\d+)(?:\\.(\\d+)(?:_(\\d+))?)?)?$";
268| 
269|         var matchData = minimumVersion.match(regex);
270| 
271|         if (deployJava.returnPage == null) {
272|             // if there is an install, come back here and run the applet
273|             deployJava.returnPage = document.location;
274|         }
275| 
276|         if (matchData != null) {
277|             var browser = deployJava.getBrowser();
278|             if ((browser != '?') && (browser != 'Safari')) {
279|                 if (deployJava.versionCheck(minimumVersion + '+')) {
280|                     deployJava.writeAppletTag(attributes, parameters);
281|                 } else if (deployJava.installJRE(minimumVersion + '+')) {
282|                     // after successfull install we need to refresh page to pick
283|                     // pick up new plugin
284|                     deployJava.refresh();
285|                     location.href = document.location;
286|                     deployJava.writeAppletTag(attributes, parameters);
287|                 }
288|             } else {
289|                 // for unknown or Safari - just try to show applet
290|                 deployJava.writeAppletTag(attributes, parameters);
291|             }
292|         } else {
293|             if (deployJava.debug) {
294|                 alert('Invalid minimumVersion argument to runApplet():' + 
295|                       minimumVersion);
296|             }
297|         }
298|     },

runApplet() メソッドです。
コメントには・・・
適切な JRE がインストールされてから Applet を実行するように保証する。
引数 minimumVersion は Applet の実行に必要な最小(最古)のバージョンで、省略すると "1.1" がデフォルトで使用される。
必要な JRE が見つかれば writeAppletTag() メソッドを呼び出して applet タグを書き出すが、見つからなければ installJRE() メソッドを minimumVersion + '+' を引数として呼び出す。
installJRE() メソッドを呼び出した後は、JRE のインストール完了を検出し、Applet の実行を試みるが、JRE インストール時にブラウザの再起動が求められるなど、状況によっては実行できないことがある。
writeAppletTag() メソッドと同様に、このメソッドもページが完全に描画される前にだけ、呼ぶようにすべきである。
ワイルドカードを使用したバージョンはサポートしないことに注意すること。それらを引数 minimumVersion に含む場合、エラーメッセージで終了する。
というように書かれています。


263 - 265行目では引数 minimumVersion が指定されていない場合に、デフォルトの "1.1" を設定しています。
267行目は指定されたバージョンの書式をチェックする為の、正規表現を作成します。
269行目では引数 minimumVersion が正規表現に合致するかをチェックします。


271 - 274行目では returnPage プロパティが null の場合に、インストールしても後でまた現在のページに戻って Applet を実行できるように、現在のページの URL を returnPage プロパティにセットしています。


276 - 291行目は、引数 minimumVersion が正規表現に合致した場合の処理です。
277行目で getBrowser() メソッドを呼び出します。
278 - 287行目は、ブラウザが Safari でなく且つ不明なブラウザでない場合の処理です。
279 - 280行目では versionCheck() メソッドを呼び出して、引数 minimumVersion 以上のバージョンの JRE が利用できるを調べ、利用可能ならば writeAppletTag() メソッドを呼び出して applet タグを書き出します。


281 - 287行目は versionCheck() メソッドでチェックした結果、必要なバージョンの JRE が利用できない場合の処理です。
281行目で installJRE() メソッドを呼び出して必要な JRE をインストールしようとしています。
インストールが成功したら284行目で refresh() メソッドを呼び出して新しいプラグインを有効にします。
285行目では現在のページを再読み込みしようとしています。
286行目で writeAppletTag() メソッドを呼び出して applet タグを書き出します。


288 - 291行目は現在のブラウザが Safari か不明なブラウザの場合の処理ですが、とりあえず writeAppletTag() メソッドを呼び出して実行を試みています。


292 - 297行目は引数 minimumVersion が正規表現に合致しなかった場合に、エラーメッセージを表示しています。バージョンにワイルドカードが含まれているような場合はここでエラーメッセージが表示されます。

301|     /**
302|      * Outputs an applet tag with the specified attributes and parameters, where
303|      * both attributes and parameters are associative arrays.  Each key/value 
304|      * pair in attributes becomes an attribute of the applet tag itself, while
305|      * key/value pairs in parameters become <PARAM> tags.  No version checking 
306|      * or other special behaviors are performed; the tag is simply written to 
307|      * the page using document.writeln().
308|      *
309|      * As document.writeln() is generally only safe to use while the page is 
310|      * being rendered, you should never call this function after the page 
311|      * has been completed.
312|      */
313|     writeAppletTag: function(attributes, parameters) {
314|         var s = '<' + 'applet ';
315|         for (var attribute in attributes) {
316|             s += (' ' + attribute + '="' + attributes[attribute] + '"');
317|         }
318|         s += '>';
319|         document.write(s);
320|     
321|         if (parameters != 'undefined' && parameters != null) {
322|             var codebaseParam = false;
323|             for (var parameter in parameters) {
324|                 if (parameter == 'codebase_lookup') {
325|                     codebaseParam = true;
326|                 }
327|                 s = '<param name="' + parameter + '" value="' + 
328|                     parameters[parameter] + '">';
329|                 document.write(s);
330|             }
331|             if (!codebaseParam) {
332|               document.write('<param name="codebase_lookup" value="false">');
333|             }
334|         }
335|         document.write('<' + '/' + 'applet' + '>');
336|     },

writeAppletTag() メソッドです。
コメントには・・・
引数の attributes と parameters は共に連想配列で、これらを用いて apllet タグを書き出す。
attributes のキーと値はそれぞれ applet タグの属性になり、parameters のキーと値は、(applet タグの子要素の) タグになる。
バージョンチェックや、その他の特別な処理はせず、単純に document.writeln() を使って書かれる。
document.writeln() は通常、ページの描画中にのみ使用するのが安全であり、描画が完了した後は、このメソッドを決して呼び出すべきない。
というように書かれています。


314 - 319行目では、引数 attributes の内容を for/in ループでタグの属性名と値のペアの文字列として組み立て、applet タグの開始タグを書き出しています。
attributes には通常、Jar ファイル名 (archive) や、Applet クラスの名前 (code) や縦横のサイズ (width/height) などを含めます。


321 - 334行目では、引数 parameters が指定されてい場合に、for/in ループで param タグの文字列を組み立てて書き出しています。
name 属性が codebase_lookup の param タグは、applet の実行に必要なクラスやその他のリソースを、コードベースから検索するかどうかを設定します。
Applet と一緒の Jar ファイルにその他のリソースも同梱し、その Jar から検索させるのが一般的みたいです。
このあたりは Jar のサイズやトラフィックなどから効率性を考慮に入れて検討するべきだと思います。


第一章はこれで終わります。
以降は第二章に続きます。