DIVE INTO S2 .HACK : INCLUDE PART II
Seasar2に慣れ親しむためにS2Containerのコードをプチハックしてみる第2弾。 v(^^)v
- カスタムPathResolverを使って、S2Container間の依存関係(include)をDEPENDENCY-LOOKUPからDEPENDENCY-INJECTIONにしてみる。
koichikさんのアドバイスをもとに、PathResolverインターフェースを実装した AliasAwarePathResolverクラス を作ってから、デフォルトのPathResolverを差し替えることで、できちゃいました。これぞまさしく OPEN-CLOSED PRINCIPLE !!!
-
- テスト用のdiconファイルの構成は前回と同じで、こんな感じです。*1
■org/seasar/framework/container/factory/AliasAwarePathResolverTestNode0.dicon
component0
component1
component2
"Here is node0 container."
■org/seasar/framework/container/factory/AliasAwarePathResolverTestNode1.dicon
"Here is node1 container."
■org/seasar/framework/container/factory/AliasAwarePathResolverTestNode2a.dicon
"Here is node2a container."
■org/seasar/framework/container/factory/AliasAwarePathResolverTestNode2b.dicon
"Here is node2b container."
■org/seasar/framework/container/factory/AliasAwarePathResolverTest.java
package org.seasar.framework.container.factory;import java.util.List;
import junit.framework.TestCase;
import org.seasar.framework.container.S2Container;
/**
* @author hidebsd
*/
public class AliasAwarePathResolverTest extends TestCase {private static final String []S2CFG = "org/seasar/framework/container/factory/AliasAwarePathResolverConfiguration.dicon"[];
private static final String PATH0 = "org/seasar/framework/container/factory/AliasAwarePathResolverTestNode0.dicon";
private static final String PATH1 = "org/seasar/framework/container/factory/AliasAwarePathResolverTest1.dicon";
public void setUp() {
[]S2ContainerFactory.configure(S2CFG)[];
}public void testDefaultSettings() throws Exception {
S2Container container = S2ContainerFactory.create(PATH0);
container.init();
List list = (List) container.getComponent("collection");
for (int i = 0; i < list.size(); ++i) {
if (i == 2) {
assertEquals("node" + i, "Here is node" + i + "a container.",
list.get(i));
} else {
assertEquals("node" + i, "Here is node" + i + " container.",
list.get(i));
}
}
}public void testOverrideSettings() throws Exception {
S2Container container = S2ContainerFactory.create(PATH1);
container.init();
List list = (List) container.getComponent("collection");
for (int i = 0; i < list.size(); ++i) {
if (i == 2) {
assertEquals("node" + i, "Here is node" + i + "b container.",
list.get(i));
} else {
assertEquals("node" + i, "Here is node" + i + " container.",
list.get(i));
}
}
}
}
-
- で、入れ替えるクラスを作りました。今回は、PathResolverインターフェースを実装したAliasAwarePathResolverなるクラスを作成。中身は前回のIncludeTagHandlerに追加した処理とほぼ同じ。
■org/seasar/framework/container/factory/AliasAwarePathResolver.java
package org.seasar.framework.container.factory;import java.util.HashMap;
import java.util.Map;import org.seasar.framework.util.ClassUtil;
/**
* @author hidebsd
*/
public class AliasAwarePathResolver implements PathResolver {private Map aliasDefinitions = new HashMap();
private String prefix = "@";
private String delimiter = ":";
/**
*AliasAwarePathResolver
を構築します。
*/
public AliasAwarePathResolver() {
}/**
* プリフィックスとセパレータを指定して、AliasAwarePathResolver
を構築します。
*
* @param prefix
* 別名を示すプリフィックス
* @param delimiter
* 別名とパスを区切るセパレータ
*/
public AliasAwarePathResolver(String prefix, String delimiter) {
this.prefix = prefix;
this.delimiter = delimiter;
}/**
* パスとその別名が指定された場合には、これを登録し、パスまたは別名が指定された場合には、適切なパスを返します。
*
* @param context
* コンテキスト
* @param path
* パス
* @see org.seasar.framework.container.factory.PathResolver#resolvePath(java.lang.String,
* java.lang.String)
*/
public String resolvePath(String context, String path) {if (!path.startsWith(prefix)) {
return path;
}
int nameSep = path.indexOf(delimiter);
if (nameSep < 0) {
// Resolve path
String name = path.substring(prefix.length());
path = resolvePath(name);
} else if (nameSep > 1) {
// Register alias-path mapping
String name = path.substring(prefix.length(), nameSep);
path = path.substring(nameSep + delimiter.length());
registerPath(name, path);
path = []ClassUtil.getResourcePath(getClass()).replaceAll("\\.class$", "Dummy.dicon")[];
} else {
// 'path' attibute value was specified like "@:....".
throw new IllegalStateException(
"Alias name of S2Container was empty.");
}
return path;
}private void registerPath(String name, String path) {
if (aliasDefinitions.get(name) != null) {
return;
}
aliasDefinitions.put(name, path);
}private String resolvePath(String name) {
String path = (String) aliasDefinitions.get(name);
if (path == null) {
throw new IllegalStateException("Alias name '" + name
+ "' was not defined.");
}
return path;
}
}
-
- で、S2Containerの挙動制御用diconはこんな感じで。PathResolverインターフェースを実装しているクラスがあると差し替えられるので、これでOK。
■org/seasar/framework/container/factory/AliasAwarePathResolverConfiguration.dicon
■org/seasar/framework/container/factory/AliasAwarePathResolverDummy.dicon