Hatena::ブログ(Diary)

最遅メンヘル研究会

2011-03-15

import/includeを使おうとするとMalformedURLExceptionが出る件

StreamSource xsl = new StreamSource("hoge.xsl");

これだとエラーになって、

StreamSource xsl = new StreamSource(new File("hoge.xsl"));

だと、ちゃんとパスが解決できる。……

Xalanのエラーメッセージが不親切すぎてストレス半端ないのでプロセッサをSaxonに切り替える

System.setProperty("javax.xml.transform.TransformerFactory", "net.sf.saxon.TransformerFactoryImpl");

これだけで、おk。他のコードは共通でいい。

2011-03-01

PDFBoxメモ

この方法だと画像が取れない形式のPDFがあるっぽい。XObjectは全部取ってきて、PDXObjectImageインスタンスか、PDXObjectFormインスタンスで処理を分けてやるといい。

	public static void main(String[] args) throws IOException {
		String readFile = args[0];
		FileInputStream pdfStream = new FileInputStream(readFile);
		PDFParser pdfParser = new PDFParser(pdfStream);
		pdfParser.parse();

		int cnt = 0;
		PDDocument pdf = pdfParser.getPDDocument();
		for (Iterator<PDPage> i = pdf.getDocumentCatalog().getAllPages().iterator(); i.hasNext();) {
			Map<String, PDXObject> objs = i.next().getResources().getXObjects();
			for (Iterator<String> j = objs.keySet().iterator(); j.hasNext();) {
				PDXObject obj = objs.get(j.next());
				if (obj instanceof PDXObjectImage) {
					PDXObjectImage image = (PDXObjectImage) obj;
					image.write2file(String.valueOf(cnt));
					cnt++;
				} else if (obj instanceof PDXObjectForm) {
					PDXObjectForm form = (PDXObjectForm) obj;
					Map<String, PDXObjectImage> images = form.getResources().getImages();
					for (Iterator<String> k = images.keySet().iterator(); k.hasNext();) {
						PDXObjectImage image = images.get(k.next());
						image.write2file(String.valueOf(cnt));
						cnt++;
					}
				}
			}
		}
	}

2011-02-28

system32にファイルコピーするには

WSHで簡易インストーラ作る必要があったのだけれど、FileSystemObjectでfileCopyしようとすると、権限がないとか言われて困り果てたのだが、shell.exec("cmd.exe /C copy")は通ってくれたので、助かった。

2011-01-21

デフォルトのcatalina.policyを使うとexamplesでcatalina.logにwarningが出る

2011/01/21 10:50:26 org.apache.catalina.startup.HostConfig deployDirectory
INFO: Webアプリケーションディレクトリ examples を配備します
2011/01/21 10:50:26 org.apache.catalina.loader.WebappClassLoader findClass
WARNING: WebappClassLoader.findClassInternal(chat.ChatServlet) security exception: access denied (java.lang.RuntimePermission accessClassInPackage.org.apache.catalina)
java.security.AccessControlException: access denied (java.lang.RuntimePermission accessClassInPackage.org.apache.catalina)

logが汚れて邪魔なので、examplesにpermissionを付与する。

// ========== EXAMPLE CODE PERMISSIONS =======================================


// These permissions apply to example
grant codeBase "file:${catalina.home}/webapps/examples/WEB-INF/classes/-" {
        permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina";
        // permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.manager";
        // permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.manager.util";
};

2011-01-19

Tomcatで動かすWebアプリをプラグインで機能拡張可能にするためにやったこと

ここら辺を参考に。

プラグインのインターフェースを決める

とりあえず適当に決める。

priority付けてるのはプラグインが複数あったときに実行順を決めたかっただけ。

package com.example;

public interface FooPlugin {
	public int getPriority();
	public Bar execute(Bar bar);
}

プラグイン読み込み管理クラスをつくる

最初URLClassLoaderで試してたんだけど、うまくいかないので、RMIClassLoaderに変更。

package com.example;

import java.io.File;
import java.io.IOException;
import java.rmi.RMISecurityManager;
import java.rmi.server.RMIClassLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.logging.Logger;

public class FooPluginManager {
	private static final Logger logger = Logger.getLogger(FooPluginManager.class.getName());
	private ArrayList<FooPlugin> plugins = new ArrayList<FooPlugin>();

	public FooPluginManager(String pluginPath) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
		logger.info(pluginPath);
		if (System.getSecurityManager() == null) {
			System.setSecurityManager(new RMISecurityManager());
		}
		File dir = new File(pluginPath);
		String[] files = dir.list();
		for (int i = 0; i < files.length; i++) {
			if (files[i].toLowerCase().endsWith(".jar")) {
				File jarFile = new File(pluginPath + File.separator + files[i]);
				JarFile jar = new JarFile(jarFile);
				Manifest manifest = jar.getManifest();
				Attributes attribs = manifest.getMainAttributes();
				String className = attribs.getValue("Plugin-Class");
				if (className != null) {
					className = className.trim();
					Class<?> clazz = RMIClassLoader.loadClass(jarFile.toURL(), className);
					logger.info("load... " + className);
					Object obj = clazz.newInstance();
					plugins.add((FooPlugin) obj);
				}
			}
		}
	}

	public ArrayList<FooPlugin> sort() {
		Collections.sort(plugins, new Comparator<FooPlugin>() {
			public int compare(FooPlugin a, FooPlugin b) {
				if (a.getPriority() < b.getPriority()) return -1;
				if (a.getPriority() > b.getPriority()) return  1;
				return a.getClass().getCanonicalName().compareTo(b.getClass().getCanonicalName());
			}
		});
		for (Iterator<FooPlugin> iter = plugins.iterator(); iter.hasNext();) {
			logger.info("sort... " + iter.next().getClass().getCanonicalName());
		}
		return plugins;
	}
}

プラグインを書く

2個くらい書いてみる。

package com.example;

import com.example.Bar;
import com.example.FooPlugin;

public class FooPluginImpl1 implements FooPlugin {
	private static final int priority = 2;

	public int getPriority() {
		return priority;
	}

	public Bar execute(Bar bar) {
		return bar;
	}
}
package com.example;

import com.example.Bar;
import com.example.FooPlugin;

public class FooPluginImpl2 implements FooPlugin {
	private static final int priority = 1;

	public int getPriority() {
		return priority;
	}

	public Bar execute(Bar bar) {
		return bar;
	}
}

マニフェストを書いてjarファイルをつくる

EclipseのExport機能を使ってjarファイルをつくる。(任意のマニフェストを指定できる。)

p1.mf
Manifest-Version: 1.0
Plugin-Class: com.example.FooPluginImpl1
p2.mf
Manifest-Version: 1.0
Plugin-Class: com.example.FooPluginImpl2

つくった二つのjarファイルをどこか適当に配置する。

「C:\jakarta-tomcat-6.0\webapps\foo\WEB-INF\plugins」に置いた。

メインプログラム

とりあえず読み込んでソートだけしてみる。

		FooPluginManager pm = new FooPluginManager("C:\\jakarta-tomcat-6.0\\webapps\\foo\\WEB-INF\\plugins");
		ArrayList<FooPlugin> plugins = pm.sort();

jakarta-tomcat-6.0/conf/catalina.policyの変更

とりあえずゆるゆるで。

// ========== FOO CODE PERMISSIONS =======================================


// These permissions apply to foo
grant codeBase "file:${catalina.home}/webapps/foo/WEB-INF/classes/-" {
        permission java.security.AllPermission;
};

// These permissions apply to plugin
grant codeBase "file:${catalina.home}/webapps/foo/WEB-INF/plugins/-" {
        permission java.security.AllPermission;
};

Tomcat起動引数を追加

デフォルトだとcatalina.policyは使われず、JRElib/security/java.policyが使われる。-securityオプションを付けるとcatalina.policyを使うようになるとTomcatのドキュメントにあったんだけど、実際に試すとそんなコマンドはないとか言われて困り果てたところ、RE: Simple Security Manager how to ? というのを見つけた。

Configure -> [Java] タブ -> Java Options

-Djava.security.manager
-Djava.security.policy=C:\jakarta-tomcat-6.0\conf\catalina.policy

おわり

ログで動作確認。

2011/01/19 10:54:17 com.example.FooPluginManager <init>
INFO: C:\jakarta-tomcat-6.0\webapps\foo\WEB-INF\plugins
2011/01/19 10:54:17 com.example.FooPluginManager <init>
INFO: load... com.example.FooPluginImpl1
2011/01/19 10:54:17 com.example.FooPluginManager <init>
INFO: load... com.example.FooPluginImpl2
2011/01/19 10:54:17 com.example.FooPluginManager sort
INFO: sort... com.example.FooPluginImpl2
2011/01/19 10:54:17 com.example.FooPluginManager sort
INFO: sort... com.example.FooPluginImpl1

そのほか読んだリソース

2011-01-16

放置していたtumblrを再動させつつあるので、やっつけbookmarklet書いた。

選択範囲からそれっぽい引用HTMLを生成

javascript:(function(d,t,s,r,f){t.appendChild(d.createTextNode(['<blockquote%20title="'+document.title+'"%20cite="'+location.href+'"><dl>','<dt>'+f(s.shift())+'</dt>',(s.length>0?'<dd><pre>'+s.map(function(v){v=f(v);v=v.replace(r,'<a%20href="$1;">$1;</a>');return%20v}).join('\n')+'</pre></dd>\n':'')+'</dl></blockquote>'].join('\n')));with(t.style){position='fixed';bottom=left=0;zIndex=999;width='90%';height='9em'}d.body.appendChild(t);t.addEventListener('blur',function(){this.parentNode.removeChild(this)},false);t.select()})(document,document.createElement('textarea'),getSelection().toString().split(/\n/).filter(function(v)v),/(https?:\/\/[\-_.!~*\'()\w;\/?:\@&=+\$,%#]+)/g,function(s)s.replace(/^\s+|\s+$/,''))

cite属性値からanchor要素を生成

昔からあるやつです。僕はFirefoxを使っていて、CSSの擬似要素でcontent:attr(cite)とかされてても嬉しくないので。

javascript:(function(d,q){Array.prototype.slice.apply(q('blockquote,q')).forEach(function(b){b.appendChild(d.createTextNode(b.cite))})})(document,function(q)document.querySelectorAll(q))

2010-10-14

ENTITY使ってますか

全国のXMLerの皆さん、ENTITY使ってますか。DTDをそらで書ける皆さんなら当然使ってますよね。たとえば、Androidの設定ファイルなんかでも、

main.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE LinearLayout [
	<!ENTITY padding '10dp'>
	<!ENTITY view.text '
		<TextView
			android:text="copy"
			android:layout_width="fill_parent"
			android:layout_height="wrap_content"
			android:padding="&padding;" />
	'>
]>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent">

	<ListView android:id="@+id/list_view_select"
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:padding="&padding;" />

	<Spinner
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:padding="&padding;" />

	<RatingBar
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:padding="&padding;" />

	<EditText
		android:hint="コメント"
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:padding="&padding;" />

	&view.text;
	&view.text;
	&view.text;
	&view.text;

</LinearLayout>

paddingの共通値に使ってみたり、Viewを複製してみたり、

strings.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE resources [
    <!ENTITY serv 'http://localhost/'>
]>
<resources>
    <string name="app_name">Layout</string>
    <string name="url_hoge">&serv;hoge</string>
    <string name="url_piyo">&serv;piyo</string>
    <string name="url_fuga">&serv;fuga</string>
    <string name="text_view_camera">カメラ</string>
    <string name="text_view_camera_role">カメラロール</string>
</resources>

文字列の共通部分とかにも! 簡単でしょ?