Upload page content

You can upload content for the page named below. If you change the page name, you can also upload content for another page. If the page name is empty, we derive the page name from the file name.

File to load page content from
Page name
Comment

Locked History Actions

java/jws

Java Web Start

以下では特にJava Web Startを使用してSWTアプリケーションを配布する際の問題について調査する。

SWTは動作対象とする各プラットフォームに応じて、必要となるjarファイルが異なる。 つまり、windows用のjarファイルとlinux用のjarファイルは違う。これはSWTに各プラットフォーム用のネイティブライブラリを含むからである。

SWTアプリケーションを配布する方法

How to deploy SWT Applications using Java Web Startに記述がある。要するに、

  • http://www.eclipse.org/swtで配布されている各プラットフォーム用のzipファイルを展開してその中のswt.jarファイルをswt-native-<ws>-<os>-<arch>.jarの形に名称変更する。

  • それらのjarファイルに署名する。
  • jnlpファイルを記述する。以下のように、同じWindowsであっても、アーキテクチャによって異なるものになる。

        <resources os="Windows" arch="x86">
                <nativelib href="swt-native-win32-windows-x86.jar" />
                <jar href="swt-win32-windows-x86.jar" />
        </resources>

        <resources os="Windows" arch="x86_64">
                <nativelib href="swt-native-win32-windows-x86_64.jar" />
                <jar href="swt-win32-windows-x86_64.jar" />
        </resources>

        <resources os="Windows" arch="amd64">
                <nativelib href="swt-native-win32-windows-amd64.jar" />
                <jar href="swt-win32-windows-x86_64.jar" />
        </resources>

しかし、SWTでのプラットフォームの切り分け方とJNLPでのそれとは異なるフォーマットになっている。つまり、SWTでは「<ws>-<os>-<arch>」となっているが、JNLLPでは「os="?" arch="?"」である。この対応表のようなものはどこにも見つからない。

<ws>-<os>-<arch>の意味

これはosgiのプラットフォームの定義方法らしい。wsは「window system」の略である。 eclipse側ではこの定義に従おうとしているが、そもそものjavaでは従っていない。そして、例えば実行中のjvm環境がこの定義に即すと何であるかが、SWT環境では検出できなくてはならないため、(基本的には)javaのSystem.getPropertyの値を変換している。これは、eclipse3.7の環境だと、org.eclipse.core.runtime.internal.adaptor.EclipseEnvironmentInfoで行われている。

/*     */ package org.eclipse.core.runtime.internal.adaptor;
/*     */ 
/*     */ import java.io.PrintStream;
/*     */ import java.util.Locale;
/*     */ import java.util.NoSuchElementException;
/*     */ import java.util.StringTokenizer;
/*     */ import org.eclipse.osgi.framework.internal.core.FrameworkProperties;
/*     */ import org.eclipse.osgi.service.environment.EnvironmentInfo;
/*     */ import org.eclipse.osgi.util.NLS;
/*     */ 
/*     */ public class EclipseEnvironmentInfo
/*     */   implements EnvironmentInfo
/*     */ {
/*     */   private static EclipseEnvironmentInfo singleton;
/*     */   private static String nl;
/*     */   private static String os;
/*     */   private static String ws;
/*     */   private static String arch;
/*     */   private static volatile String[] allArgs;
/*     */   private static volatile String[] frameworkArgs;
/*     */   private static volatile String[] appArgs;
/*     */   private static final String INTERNAL_OS_SUNOS = "SunOS";
/*     */   private static final String INTERNAL_OS_LINUX = "Linux";
/*     */   private static final String INTERNAL_OS_MACOSX = "Mac OS";
/*     */   private static final String INTERNAL_OS_AIX = "AIX";
/*     */   private static final String INTERNAL_OS_HPUX = "HP-UX";
/*     */   private static final String INTERNAL_OS_QNX = "QNX";
/*     */   private static final String INTERNAL_OS_OS400 = "OS/400";
/*     */   private static final String INTERNAL_OS_OS390 = "OS/390";
/*     */   private static final String INTERNAL_OS_ZOS = "z/OS";
/*     */   private static final String INTERNAL_ARCH_I386 = "i386";
/*     */   private static final String INTERNAL_AMD64 = "amd64";
/*     */ 
/*     */   private EclipseEnvironmentInfo()
/*     */   {
/*  53 */     setupSystemContext();
/*     */   }
/*     */ 
/*     */   public static EclipseEnvironmentInfo getDefault() {
/*  57 */     if (singleton == null)
/*  58 */       singleton = new EclipseEnvironmentInfo();
/*  59 */     return singleton;
/*     */   }
/*     */ 
/*     */   public boolean inDevelopmentMode() {
/*  63 */     return (FrameworkProperties.getProperty("osgi.dev") != null);
/*     */   }
/*     */ 
/*     */   public boolean inDebugMode() {
/*  67 */     return (FrameworkProperties.getProperty("osgi.debug") != null);
/*     */   }
/*     */ 
/*     */   public String[] getCommandLineArgs() {
/*  71 */     return allArgs;
/*     */   }
/*     */ 
/*     */   public String[] getFrameworkArgs() {
/*  75 */     return frameworkArgs;
/*     */   }
/*     */ 
/*     */   public String[] getNonFrameworkArgs() {
/*  79 */     return appArgs;
/*     */   }
/*     */ 
/*     */   public String getOSArch() {
/*  83 */     return arch;
/*     */   }
/*     */ 
/*     */   public String getNL() {
/*  87 */     return nl;
/*     */   }
/*     */ 
/*     */   public String getOS() {
/*  91 */     return os;
/*     */   }
/*     */ 
/*     */   public String getWS() {
/*  95 */     return ws;
/*     */   }
/*     */ 
/*     */   private static void setupSystemContext()
/*     */   {
/* 108 */     nl = FrameworkProperties.getProperty("osgi.nl");
/* 109 */     if (nl != null) {
/* 110 */       StringTokenizer tokenizer = new StringTokenizer(nl, "_");
/* 111 */       int segments = tokenizer.countTokens();
/*     */       try {
/* 113 */         Locale userLocale = null;
/* 114 */         switch (segments)
/*     */         {
/*     */         case 1:
/* 117 */           userLocale = new Locale(tokenizer.nextToken(), "");
/* 118 */           break;
/*     */         case 2:
/* 120 */           userLocale = new Locale(tokenizer.nextToken(), tokenizer.nextToken());
/* 121 */           break;
/*     */         case 3:
/* 123 */           userLocale = new Locale(tokenizer.nextToken(), tokenizer.nextToken(), tokenizer.nextToken());
/* 124 */           break;
/*     */         default:
/* 127 */           System.err.println(NLS.bind(EclipseAdaptorMsg.error_badNL, nl));
/* 128 */           userLocale = Locale.getDefault();
/*     */         }
/*     */ 
/* 131 */         Locale.setDefault(userLocale);
/*     */ 
/* 133 */         FrameworkProperties.setProperty("osgi.nl.user", nl);
/*     */       }
/*     */       catch (NoSuchElementException localNoSuchElementException) {
/*     */       }
/*     */     }
/* 138 */     nl = Locale.getDefault().toString();
/* 139 */     FrameworkProperties.setProperty("osgi.nl", nl);
/*     */ 
/* 143 */     os = FrameworkProperties.getProperty("osgi.os");
/* 144 */     if (os == null) {
/* 145 */       os = guessOS(FrameworkProperties.getProperty("os.name"));
/* 146 */       FrameworkProperties.setProperty("osgi.os", os);
/*     */     }
/*     */ 
/* 151 */     ws = FrameworkProperties.getProperty("osgi.ws");
/* 152 */     if (ws == null) {
/* 153 */       ws = guessWS(os);
/* 154 */       FrameworkProperties.setProperty("osgi.ws", ws);
/*     */     }
/*     */ 
/* 159 */     arch = FrameworkProperties.getProperty("osgi.arch");
/* 160 */     if (arch == null) {
/* 161 */       String name = FrameworkProperties.getProperty("os.arch");
/*     */ 
/* 163 */       if (name.equalsIgnoreCase("i386")) {
/* 164 */         arch = "x86";
/*     */       }
/* 166 */       else if (name.equalsIgnoreCase("amd64"))
/* 167 */         arch = "x86_64";
/*     */       else
/* 169 */         arch = name;
/* 170 */       FrameworkProperties.setProperty("osgi.arch", arch);
/*     */     }
/*     */   }
/*     */ 
/*     */   public static void setAllArgs(String[] allArgs)
/*     */   {
/* 176 */     allArgs = allArgs;
/*     */   }
/*     */ 
/*     */   public static void setAppArgs(String[] appArgs)
/*     */   {
/* 181 */     appArgs = appArgs;
/*     */   }
/*     */ 
/*     */   public static void setFrameworkArgs(String[] frameworkArgs)
/*     */   {
/* 186 */     frameworkArgs = frameworkArgs;
/*     */   }
/*     */ 
/*     */   public static String guessWS(String osName)
/*     */   {
/* 191 */     if (osName.equals("win32"))
/* 192 */       return "win32";
/* 193 */     if (osName.equals("linux"))
/* 194 */       return "gtk";
/* 195 */     if (osName.equals("macosx"))
/* 196 */       return "cocoa";
/* 197 */     if (osName.equals("hpux"))
/* 198 */       return "motif";
/* 199 */     if (osName.equals("aix"))
/* 200 */       return "motif";
/* 201 */     if (osName.equals("solaris"))
/* 202 */       return "gtk";
/* 203 */     if (osName.equals("qnx"))
/* 204 */       return "photon";
/* 205 */     return "unknown";
/*     */   }
/*     */ 
/*     */   public static String guessOS(String osName)
/*     */   {
/* 211 */     if (osName.regionMatches(true, 0, "win32", 0, 3)) {
/* 212 */       return "win32";
/*     */     }
/* 214 */     if (osName.equalsIgnoreCase("SunOS"))
/* 215 */       return "solaris";
/* 216 */     if (osName.equalsIgnoreCase("Linux"))
/* 217 */       return "linux";
/* 218 */     if (osName.equalsIgnoreCase("QNX"))
/* 219 */       return "qnx";
/* 220 */     if (osName.equalsIgnoreCase("AIX"))
/* 221 */       return "aix";
/* 222 */     if (osName.equalsIgnoreCase("HP-UX"))
/* 223 */       return "hpux";
/* 224 */     if (osName.equalsIgnoreCase("OS/400"))
/* 225 */       return "os/400";
/* 226 */     if (osName.equalsIgnoreCase("OS/390"))
/* 227 */       return "os/390";
/* 228 */     if (osName.equalsIgnoreCase("z/OS")) {
/* 229 */       return "z/os";
/*     */     }
/* 231 */     if (osName.regionMatches(true, 0, "Mac OS", 0, "Mac OS".length()))
/* 232 */       return "macosx";
/* 233 */     return "unknown";
/*     */   }
/*     */ 
/*     */   public String getProperty(String key) {
/* 237 */     return FrameworkProperties.getProperty(key);
/*     */   }
/*     */ 
/*     */   public String setProperty(String key, String value) {
/* 241 */     return FrameworkProperties.setProperty(key, value);
/*     */   }
/*     */ }

FrameworkProperties.getPropertyは基本的にSystem.getPropertyと同じと考えてよいようだ。

JNLPのosとarchとlocale

JNLPのresources属性であるosとarchは上記のosgi定義とは全く無関係である。 このため、基本的には対応しようとするプラットフォームごとにos,archを調べて指定する必要がある。 これは基本的には、System.getProperty()に"os.name", "os.arch"を指定した値と思われる。

ただし、注意すべき点としては、os,arch,localeとして指定される文字列は、空白で区切って複数指定することがでkりう。 このため、os="Windows Linux"と記述すると、「Windows XP」「Windows 7」「Linux」などに一致する。 正確に「Windows 7」に一致させるためには、「Windows\ 7」と指定しなければならない。

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7014170を参照のこと。

JNLPファイル内のJARリソースが単一の証明書によって署名されていません(resources in JNLP are not signed by same certificate)

ひどいことに、例えばSWTアプリをJWSによって配布しようとすると、このエラーが発生することがある。これは以下の二つの条件が揃ったときに発生する。

  • 既に署名済のjarファイルに自分の署名を行った。
    javaアクティベーションのactivation.jar、JavaMailのmail.jar、最近のeclipseのライブラリ(core,jfaceなど)はすべて署名がされている。そのまま署名すると、以前の署名は保持されたままた署名してしまうため、複数の署名が存在することになる。

  • JREのバージョンが古い。
    以前のJREでは、このエラーメッセージ通り、JNLPファイルから参照されるjarファイルはすべて単一の署名でなければならなかった。しかし、最近の少なくともJRE6u27では複数の署名があっても受け入れるように修正されている(しかし、この修正についてのドキュメントは見つからないので、単なるバグかも)。

jarを再署名する

http://www.jot.fm/issues/issue_2008_05/column2/index.html

ようするに、jarをほぐして、署名を削除し、再度jarを構成し、最後にjarsignerで署名するという方法。

その他のオプション

既に署名されているものをextensionとしてロードする方法もあるようだ(動作は未確認)。

http://download.oracle.com/javase/1,5.0/docs/guide/javaws/developersguide/faq.html#213