eclipse3.6 RCPにバンドルされているcommonsなアレ。

  • org.apache.commons.codec.source_1.3.0.v20100518-1140.jar
  • org.apache.commons.codec_1.3.0.v20100106-1700.jar
  • org.apache.commons.codec_1.3.0.v20100518-1140.jar
  • org.apache.commons.el_1.0.0.v201004212143.jar
  • org.apache.commons.httpclient.source_3.1.0.v201005080502.jar
  • org.apache.commons.httpclient_3.1.0.v20080605-1935.jar
  • org.apache.commons.httpclient_3.1.0.v201005080502.jar
  • org.apache.commons.lang_2.3.0.v201005080501.jar
  • org.apache.commons.logging.source_1.0.4.v201005080501.jar
  • org.apache.commons.logging_1.0.4.v200904062259.jar
  • org.apache.commons.logging_1.0.4.v201005080501.jar

codecとhttpclientとloggingが、同じバージョンでリリース日付の違うものがさらっと入ってるとか、どういう事なの?

資格情報マネージャをマネージドコードから使用する。

正しいやり方がマジで分らない。誰か教えて下さい。
まず、前提条件として、既に読んでいるけれどもイマイチ意味が分らないと言うか、分った気がしない情報源等。

  1. Credentials Management
  2. ローカルストレージに保存するデータの暗号化 ― Windows の場合
  3. Windows XP および Windows Server 2003 での資格情報管理の使用方法
  4. Authentication Functions
    1. 説明がアッサリし過ぎててどうしたら良いか全然分らない…orz
  5. Credential Management with the .NET Framework 2.0
  6. Windows Data Protection
    1. ProtectedData クラス
続きを読む

ClojureのコードをMaven2でビルドする。

そこそこ頑張ってビルドしたので、成果をまとめておきますですだよ。
まずは、

を見てクダサシ。正直にビルドするだけなら、ここに記述されている内容を読めば特に問題ないです。

Clojureソースコードたる.cljファイルを配布物に含めるには。

clojure-maven-pluginにおけるClojureソースコードを配置するデフォルトの推奨ディレクトリは、
maven-resources-pluginの管理対象外なので、こんな感じに追記しる。

<build>
  <resources>
    <resource>
      <directory>src/main/clojure</directory>
    </resource>
  </resources>
〜以下省略〜
</build>

これで、.classが詰まってるjarファイルと、-sources.jarの中に、.cljファイルが含まれるます。

ユニットテストを、自分の好きなコンテキストで動かすには。

clojure-maven-pluginでは、testフェイズにおいて、clojure.testをブートストラップする為の、特別なスクリプトを自動生成して、そこからテストを動かします。
コードはここですね。

deftestの中で、必要なコンテキストを全て揃えて動かしているのであれば、それで特に問題ないのですけど、僕が書いていたテストコードは、ブートストラップコストが少々高めなモノを動かしていたので、出来れば、名前空間単位で生成した上で、束縛したいオブジェクトがあるました。


と、言うわけで、こんな感じの記述をpom.xmlにしる。
ポイントは、testScriptって所。
普通に使う分には、pom.xmlからの相対パスを書いておけば、特に問題無いのだけど、マルチプロジェクトに対応する為には、前の${basedir}ってのを付けておかないと、プラグインの中で、パスの処理をちゃんとやってくれないので、思いとおりに動かない事になるます。
resources-pluginとは、出来が違うって事であります。

<build>
  〜前省略〜
  <plugins>
    <plugin>
      <groupId>com.theoryinpractise</groupId>
      <artifactId>clojure-maven-plugin</artifactId>
      <version>1.3.2</version>
      <executions>
        <execution>
          <id>test-clojure</id>
          <phase>test</phase>
          <goals>
            <goal>test</goal>
          </goals>
          <configuration>
            <testScript>${basedir}/src/test/clojure/test.clj</testScript>
          </configuration>
        </execution>
      </executions>
    </plugin>
〜以下省略〜
</build>

ちなみに、test.cljの中はこんな感じ。

(require 'org.t2framework.lucy.clojure.test-lucy-config)
(use 'org.t2framework.lucy.clojure.lucy-config) 
(use 'clojure.test)
(import 
    (org.t2framework.lucy.clojure ClojureLucyConfiguration) 
    (org.t2framework.lucy 
      Lucy
      LucyBootstrap
    )
)
(when-not *compile-files*
  (let [results (atom [])]
    (let [report-orig report]
      (binding [report (fn [x] (report-orig x)
                         (swap! results conj (:type x)))]
        (binding [org.t2framework.lucy.clojure.lucy-config/lucy 
          (LucyBootstrap/init (ClojureLucyConfiguration.))]
            (try
              (run-tests 'org.t2framework.lucy.clojure.test-lucy-config)
            (finally (LucyBootstrap/destroy))) 
        )
    (shutdown-agents)
    (System/exit (if (empty? (filter {:fail :error} @results)) 0 -1))))))

.cljファイルをREPLでロードする分には動くのに、.classファイルを出力しようとすると出る謎のエラー対策

まぁ、コードとしても、そこそこ変な事をやっていて、Javaenumをあるルールに乗っとって、マクロでdefするみたいな。

(defmacro defvalues [values namer]
  `(do
    ~@(map 
      (fn [%] 
        `(def ~(symbol ((eval namer) %)) ~%)
      )
      (eval values))))
(defvalues (AutoInject/values) #(. #^AutoInject % getName))

ちなみに、ここで登場するAutoInjectってのは、こんなenumでつ。


こいつは普通に動かしてる分には特に問題なく動くのだけど、.classファイルを出力するべくコンパイラを起動すると謎のスタックトレースが出力されてコケてしまうのです。

Caused by: java.lang.RuntimeException: Can't embed object in code, maybe print-dup not defined: property
        at clojure.lang.Compiler$FnExpr.emitValue(Compiler.java:3379)
        at clojure.lang.Compiler$FnExpr.emitConstants(Compiler.java:3417)
        at clojure.lang.Compiler.compile(Compiler.java:5123)
        at clojure.lang.RT.compile(RT.java:358)
        at clojure.lang.RT.load(RT.java:397)
        at clojure.lang.RT.load(RT.java:371)
        at clojure.core$load__6449$fn__6458.invoke(core.clj:4171)
        at clojure.core$load__6449.doInvoke(core.clj:4170)
        at clojure.lang.RestFn.invoke(RestFn.java:413)
        at clojure.core$load_one__6379.invoke(core.clj:4007)
        at clojure.core$load_lib__6400.doInvoke(core.clj:4044)
        at clojure.lang.RestFn.applyTo(RestFn.java:147)
        at clojure.core$apply__4370.invoke(core.clj:438)
        at clojure.core$load_libs__6417.doInvoke(core.clj:4070)
        at clojure.lang.RestFn.applyTo(RestFn.java:142)
        at clojure.core$apply__4370.invoke(core.clj:440)
        at clojure.core$use__6443.doInvoke(core.clj:4148)
        at clojure.lang.RestFn.invoke(RestFn.java:413)
        at org.t2framework.lucy.clojure.aspect$loading__6309__auto____1.invoke(aspect.clj:1)
        at clojure.lang.AFn.applyToHelper(AFn.java:171)
        at clojure.lang.AFn.applyTo(AFn.java:164)
        at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:2775)

print-dupなる何かがアレで、ソレ…らしい。さっぱり分かりませんが、要は、何か直列化したいらしい。
と言うわけで、こんなコードを足します。
処理としては、print-methodなる別なマルチメソッドにディスパッチしているだけ。

(defmethod print-dup AutoInject [o w] (print-method (. #^AutoInject o (getName)) w))

print-dupは、clojure.coreと言う名前空間にに定義されているマルチメソッドなのだけど、具体的なファイルとしては、core_print.cljに入っております。


これで、期待した動作になるのだけど、何故これでOKなのかは、実は良くわかりませぬ。
誰か教えて下さい。

getEnclosingなんちゃら。

LoggingAPIを使っている皆様におかれましては、ガード節をキチンと記述しておりますでしょうか?


こういうやつですね。

if(LOG.isDebugEnabled()) {
  LOG.debug("hogehoge");
}

毎回記述するのが面倒な上に、コードの見栄えがあまりよろしくありません。
ガード節を書かないと、実行時におかれましては、
最終的にはどこにも出力されない巨大な文字列が、
不思議空間に浮かんでは消え、浮かんでは消えるなどしているかもしれません。


というワケで、コンパイラにガード節を記述して貰えば良いんじゃね?的な事を考えてみた。

  public static void main(String[] args) throws Exception {
    assert debug(new a() {
      public boolean b() {
        // assert する為の真偽値を演算しる。
        return true;
      }
    }, "hoge");
  }
  public static boolean debug(a a, String msg) {
    Class<?> aclazz = a.getClass();
    Class<?> clazz = aclazz.getEnclosingClass();
    Method m = aclazz.getEnclosingMethod();
    System.out.printf("%s - %s [%s]\n", clazz, m, msg);
    return a.b();
  }
  public interface a {
    boolean b();
  }

ここで登場するのが、getEnclosingなんちゃら。
StackTraceElement的な何かを作らなくても、呼出し元が分かるんだーぜーとか。


コードの綺麗さがどうこうって話は無かった事に…orz


いや、Javaクロージャが採用されれば、きっともっと綺麗にかける様になるさ!

ClassLoader#setPackageAssertionStatusがウゴゲ。

こんなクラスを用意しるます。

public class Hoge {
  public void fuga(String s) {
    assert s != null : "s must not be null";
    System.out.println(s);
  }
}

ポイントは、全く同じクラスを、二つのパッケージに配置する事。

  • aaa.bbb.ccc
    • SystemClassLoaderでロードする。
  • zzz.zzz
    • 俺様URLClassLoaderでロードする。

の二つ。


つまり、こんな感じのコード。

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

import aa.bb.cc.Hoge;

public class Main {
  public static void main(String[] args) throws Exception {
    Hoge h = new Hoge();
    h.fuga("s");
    h.fuga(null);

    URLClassLoader cl = new URLClassLoader(new URL[] { new File("classes")
        .toURI().toURL() });
    cl.setPackageAssertionStatus("zzz", true);
    Class<?> clazz = cl.loadClass("zzz.zzz.Hoge");
    Object o = clazz.newInstance();
    Method m = o.getClass().getMethod("fuga", String.class);
    m.invoke(o, "aaa");
    m.invoke(o, new Object[] { null });
  }
}

これを、-ea でassert構文を有効化せずJVMを起動しる。

s
null
aaa
Exception in thread "main" java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at Main.main(Main.java:26)
Caused by: java.lang.AssertionError: s must not be null
	at zzz.zzz.Hoge.fuga(Hoge.java:6)
	... 5 more

おおう!ファンタスティック!
JVMの-eaオプションは、まぁ、何というかビックリする位扱い辛い*1ので、
オレオレClassLoaderを提供する皆様におかれましては、
その実行を制御する為の設定ファイル内において、
assertモードをハンドリング出来る様にしてはうかがか?


例えば、こんな感じ?

<config assert="enable">
<component assert="enable" class="aaa.bbb.ccc.Hoge" />
</config>

アプリケーションコードのアサートと、
フレームワークのアサートのスイッチを、
JVMの起動オプションじゃ無しに、
設定ファイル的な何かでスイッチ出来たりすると、何か幸せかもぞ。


ちなむと、java.lang.ClassLoader には、こんな感じでメソッドが並んでいる。

  • clearAssertionStatus()
  • setClassAssertionStatus(String className, boolean enabled)
  • setDefaultAssertionStatus(boolean enabled)
  • setPackageAssertionStatus(String packageName, boolean enabled)

尚、このassertionStatusは、Classのロードじスタティックイニシャライザで、
Class#desiredAssertionStatus() を呼出してstaticメンバに抱えてしまうので、
一度ロードされたクラスの状態を変更する事は出来ませぬ。

Cloudera Desktop をUbuntu 8.0.4(hardy) 32bit に入れてみたよ。

噂のCloudera Desktop を、インストールしてみた。


インストールマニュアル通りにやれば、まぁ、大体出来る感じ。

続きを読む