JavaWebStartに挑む。
以前に、断念したJavaWebStartからのWebアプリケーション起動が、Winstoneを使う事によって、
超簡単に実現できる事が判明したので、久しぶりに頑張ってみる。
実装は、主にhudsonからパクってきました。
warファイルだけで、自身に含まれているwinstoneごと起動する為のMainクラス。
テンポラリファイルを作って、処理が終わったら、リソースを消そうと頑張っているますが、実は消えません。
public class Main { private static final String W = "winstone"; public static void main(String[] args) throws Exception { ClassLoader loader = Thread.currentThread().getContextClassLoader(); URL jar = loader.getResource(W + ".jar"); URLConnection uc = jar.openConnection(); uc.setDefaultUseCaches(false); if (uc instanceof JarURLConnection) { JarURLConnection jarcon = (JarURLConnection) uc; File me = new File(jarcon.getJarFile().getName()); final File tmpJar = File.createTempFile(W, ".jar"); copy(jar.openStream(), new FileOutputStream(tmpJar)); ClassLoader cl = new URLClassLoader(new URL[] { tmpJar .toURL() }); Class launcher = cl.loadClass("winstone.Launcher"); Method main = launcher.getMethod("main", new Class[] { java.lang.String[].class }); List<String> arguments = new ArrayList<String>(Arrays .<String> asList(args)); arguments.add(0, "--warfile=" + me.getAbsolutePath()); main.invoke(null, new Object[] { arguments .toArray(new String[arguments.size()]) }); Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { try { delete(new File(tmpJar.getParentFile(), W)); delete(new File(tmpJar.getParentFile(), W + ".tmp")); tmpJar.delete(); } catch (Exception e) { e.printStackTrace(); } } }); } else { System.err.println("I'm not jar file..."); } } private static void copy(InputStream in, OutputStream out) throws IOException { byte buf[] = new byte[8192]; int len; try { while (0 < (len = in.read(buf))) { out.write(buf, 0, len); } } finally { in.close(); out.close(); } } private static void delete(File file) throws IOException { if (file.isDirectory()) { File files[] = file.listFiles(); if (files != null) { for (int i = 0; i < files.length; i++) delete(files[i]); } } file.delete(); } }
次に、JavaWebStartで起動した時に、コンソールをリダイレクトする先となるSwingアプリ。
ログを出さずに、起動・停止ボタンを設置するのがイイかもしれないと思ったり。
public class JNLPMain { public static void main(String[] args) throws Exception { System.setSecurityManager(null); UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); (new MainDialog()).setVisible(true); Main.main(args); } static class MainDialog extends JFrame { private static final long serialVersionUID = 7528520198276440331L; public MainDialog() throws HeadlessException, IOException { super("Console"); JScrollPane pane = new JScrollPane(textArea); pane.setMinimumSize(new Dimension(800, 150)); pane.setPreferredSize(new Dimension(800, 150)); add(pane); setDefaultCloseOperation(3); setLocationByPlatform(true); PipedOutputStream out = new PipedOutputStream(); PrintStream pout = new PrintStream(out); System.setErr(pout); System.setOut(pout); final BufferedReader in = new BufferedReader(new InputStreamReader( new PipedInputStream(out))); (new Thread() { public void run() { do try { String line; while ((line = in.readLine()) == null) ; final String text = line; SwingUtilities.invokeLater(new Runnable() { public void run() { textArea.append(text + '\n'); scrollDown(); } }); } catch (IOException e) { throw new Error(e); } while (true); } }).start(); pack(); } private void scrollDown() { int pos = textArea.getDocument().getEndPosition().getOffset(); textArea.getCaret().setDot(pos); textArea.requestFocus(); } private final JTextArea textArea = new JTextArea(); } }
次に、サイトに配置するJNLPファイル。
ポイントは、ダウンロードされるjarファイルのURLと、
application-descで指定するJNLPMainクラス。
そこだけ、気を付ければ、大体まぁ、何となく動く感じ。
<!-- See http://java.sun.com/j2se/1.5.0/docs/guide/javaws/developersguide/syntax.html for the syntax --> <jnlp spec="1.0+"> <information> <title>JNLP Example</title> <vendor>JNLP project</vendor> <homepage href="http://www.seasar.org/"/> <offline-allowed/> </information> <security> <all-permissions/> </security> <resources> <j2se version="1.5+"/> <jar href="http://localhost:8082/test.jar"/> </resources> <application-desc main-class="org.seasar.jnlp.JNLPMain" /> </jnlp>
んで、配布するWebサーバが返すMimeTypeを追加するなり。
取りあえず、サーブレットコンテナ上で配布するなら、こんな感じ。
Servlet2.4な事に深い意味はあるません。テキトーに手元にあったweb.xmlをコピーして、中身を削除しただけだから。
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <mime-mapping> <extension>jnlp</extension> <mime-type>application/x-java-jnlp-file</mime-type> </mime-mapping> </web-app>
後は、さっきのMainとJNLPMainが入ってるwarファイルを作った上で、署名するです。
やり方は、このへん。
俺様証明書でも、動かすだけなら動かせますです。
もしかしたら、Maven2のGoalで、まとめて署名する事が出来るのかしらん…とか思ったり。