DIVE INTO S2 .HACK : INCLUDE PART II+
Seasar2に慣れ親しむためにS2Containerをプチハックしてみる第2.5弾。 (^^;;;
- カスタムPathResolverを使って、S2Container間の依存関係(include)をDEPENDENCY-LOOKUPからDEPENDENCY-INJECTIONにしてみる。
- てゆうか、既存のdiconファイルの設定を変更することなく、一部のdiconファイルを差し替える。 (^^;;;
ResourceResolverを使用してやってみる予定だったのですが、PathResolverをいじらずに、前回とおなじようなことをするためには、XmlS2ContainerBuilderにも変更を加える必要があったので、前のPathResolver版に蛇の足を付けてお茶を濁す…
今回は、既存のdiconファイルを、さらに上位のdiconファイルでインクルードすることで、diconツリーの一部のdiconを差し替えてみたり…なんか、視点が、DEPENDENCY-LOOKUPとかINJECTIONとかじゃなくなってきたような…orz
-
- 想定する既存のdiconファイル群は、こんな感じです。*1
- ごく普通のdiconファイルたち。
■org/seasar/framework/container/factory/PathAliasResolverTest2.Node0a.dicon
component0
component1
component2
"Here is node0a container."
■org/seasar/framework/container/factory/PathAliasResolverTest2.Node1a.dicon
"Here is node1a container."
■org/seasar/framework/container/factory/PathAliasResolverTest2.Node2a.dicon
"Here is node2a container."
■org/seasar/framework/container/factory/PathAliasResolverTest2.Node2b.dicon
"Here is node2b container."
-
- で、これらの上位に位置させて、既存のdiconを差し替えるためのルートdiconファイルがこちら。
- 1目のincludeで、Node2aをNode2bに差し替えている。
■org/seasar/framework/container/factory/PathAliasResolverTest2.dicon
<include path="org/seasar/framework/container/factory/PathAliasResolverTest2.Node2a.dicon
=org/seasar/framework/container/factory/PathAliasResolverTest2.Node2b.dicon"/>
-
- テストコードは、こんな感じで。
■org/seasar/framework/container/factory/PathAliasResolverTest2.java
package org.seasar.framework.container.factory;import java.util.List;
import junit.framework.TestCase;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.util.ClassUtil;/**
* @author hidebsd
*/
public class PathAliasResolverTest2 extends TestCase {private static final String BASE = ClassUtil.getResourcePath(PathAliasResolverTest2.class).replaceAll("\\.class$", "");
private static final String S2CFG = BASE + ".Configuration.dicon";private static final String PATH0 = BASE + ".Node0a.dicon";
private static final String PATH1 = BASE + ".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) {
assertEquals("node" + i, "Here is node" + i + "a 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) {
String node = "node" + i + (i != 2 ? "a" : "b");
assertEquals("node" + i, "Here is " + node + " container.", list.get(i));
}
}
}
-
- で、S2コンテナカスタマイズ用diconはこんな感じで。PathResolverインターフェースを実装しているクラスがあると差し替えられるので、これでOK。
- ちなみに、s2container.dicon というファイル名でクラスパスのルートに置けば、明示的に S2ContainerFactory.configure(…) しなくても、自動的にそのファイルを読み込んで、S2コンテナがカスタマイズされます。
■org/seasar/framework/container/factory/PathAliasResolverTest2.Configuration.dicon
■org/seasar/framework/container/factory/PathAliasResolver.java
package org.seasar.framework.container.factory;import java.util.HashMap;
import java.util.Map;import org.seasar.framework.util.ClassUtil;
import org.seasar.framework.util.StringUtil;/**
* @author hidebsd
*/
public class PathAliasResolver implements PathResolver {private static final String TRIM = "[\\n\\r\\t ]*";
private static final String dummyConfigPath = ClassUtil.getResourcePath(
PathAliasResolver.class).replaceAll("\\.class$", "Dummy.dicon");private final Map aliasDefinitions = new HashMap();
private String delimiter = "=";
public PathAliasResolver() {
}public PathAliasResolver(String delimiter) {
this.delimiter = delimiter;
}public void setDelimiter(String delimiter) {
this.delimiter = delimiter;
}public String resolvePath(String context, String path) {
if (path == null) {
throw new IllegalStateException("Specified path was null.");
}
path = trimPath(path);
if (path.contains(delimiter)) {
path = registerPathAlias(path);
}
if (aliasDefinitions.containsKey(path)) {
path = resolvePath(path);
}
return path;
}private String trimPath(String path) {
path = path.replaceAll("^" + TRIM, "");
path = path.replaceAll(TRIM + "$", "");
path = path.replaceAll(TRIM + delimiter + TRIM, delimiter);
return path;
}private String registerPathAlias(String path) {
int pos = path.indexOf(delimiter);
String alias = path.substring(0, pos);
if (!aliasDefinitions.containsKey(alias)) {
path = path.substring(pos + delimiter.length());
path = (path.length() != 0 ? path : dummyConfigPath);
aliasDefinitions.put(alias, path);
}
return dummyConfigPath;
}private String resolvePath(String path) {
String resolvedPath = (String) aliasDefinitions.get(path);
if (resolvedPath == null) {
return path;
}
return resolvedPath;
}}
-
- それから、diconファイルパスの別名を登録する場合、返すパスがないのですが、なにかしらdiconファイルのパスを返す必要があったので、ダミーのdiconファイルを作成。
- これは、なんとかならないかなぁ…。やっぱりIncludeTagHandlerで対処するしかないかなぁ…、ま、実行に影響はないからいっか…。
■org/seasar/framework/container/factory/PathAliasResolverDummy.dicon
-
- では、テスト開始〜!
- RED RED RED RED RED RED GREEN!
- Y-A-T-T-A-A !!!
- さらなる深みを目指して、DIVE INTO S2 !
IT ARCHITECT SUMMIT 2006 SUMMER
「ITアーキテクト・サミット 2006 Summer」に行ってきました。場所は大手町。そういえば、20世紀最後の大晦日から21世紀の元旦にかけて、この近くで仕事してたなぁ…。
- 【SP-1】サービス指向アーキテクチャの実践 / マイクロソフト株式会社 成本 正史 氏
- 実際の事例に携わった経験を踏まえたお話は、説得力がありました。また、マイクロソフトっぽくなく (偏_見;;; 、ユーザ本位の姿勢がとても好印象でした。
- 金融業界を例にした、ケーパビリティのマッピング*1の説明は、分かりやすかったです。「ビジネスケーパビリティ=サービス」という考え方にもとづいて、いい感じの粒度で、サービスコンポーネントに設計ができれば、業務の規模に応じてそれらの組み合わせを変え、変化に強いビジネスアプリケーションの実現も夢ではないのかなぁと思いました。
- あと、「SOA設計ガイドライン」と「ポリシーのデザイン」はSOAの考え方を取り入れた開発を行おうとした際に、とても参考になりそうです。
- Windows Vista の画面、チラ見しました。ん〜やっぱ、これからは3Dですね♪
- 【IB-1】SOA開発を支える技術/製品、その最新動向を探る / 野村総合研究所 城田 真琴 氏
- 基本的にSOA弱者なので、大変ためになりました。BPMN*2が標準になりつつあるそうな…。
- ESB…分散、疎結合、標準技術 がキーポイントかぁ…なるほど。
- XMLアプライアンス…XML処理専用機で、負荷の高いXML処理を高速実行するもの?
- SCA*3とSDO*4は、様々なデータソースに対し、統一的なインターフェースを提供する仕組みのようです。でも、これって、コンセプト的にはADO*5と同じでは…と思ったのは私だけ? ODBC→JDBC、ADO→SDO ? … う〜ん、微妙 … ADOは個人的な浅い経験からすると、ODBCの焼き直し?みたいな印象があったのだけれど、果たしてSDOは…? ま、現在はWebサービスやSOAの考え方が広まってきている状況があるので、きちんとSOAっぽく利用されるでしょうね。
- オープンソースのBPMプロダクト*6、ESBプロダクト*7ってけっこうあるんですね。
- まとめ「ビジネスプロセス中心のモデル駆動型の開発はSOAアプリケーション開発の中心になる」に自分で赤線引いてました… ^^;
- 【IB-4】米国SOA最新事情 / 米国マサチューセッツ大学 鈴木 純一 氏
- (^^ サインもらいました♪ 快く書いて頂きありがとう御座いました。
- NASAなどにおける、衛星写真の加工/検索システムへのESB適用例をもとにお話されていました。
- コンポーネントをデプロイメント・ディスクリプタに基づいてフィルターアーキテクチャー構成でデプロイして、システムを実現するというESBのコンセプトが非常に分かりやすかったです。
- また、デプロイメント・ディスクリプタの記述量が多くなってくると、直接XMLを変更するのは困難になってくるということで、それに対する解決策として、UML拡張を使用して、視覚的にサービス定義やプロセス定義が出来るようにしているということでした。UMLのステレオタイプを使用して意味づけしたクラス図から、プロイメント・ディスクリプタを生成する方式で対応しているようです。これぞまさしく、仕様と実装の一体化では!
- 実装には、Mule ESB を使用しているそうです。
- サービスの数としては、けっこうな数になるそうです。
- 衛星からは、X線写真とか、ノイズ除去したものとか、様々な種類の画像が送られてくるそうです。
- 利用者の要望に応じて、検索された画像を、指定の加工処理を施したのちに届けるというシステムのようです。
- スケジューリングされたタスクによる処理と、ユーザイベントによる処理の両方に対応しているとのこと。
- SOAの特色としては、疎結合と処理の隠蔽 という点を強調されていました。
- アメリカの地方自治体が、高額なものを買う場合、専門の購買組織に申請する必要があるそうで、今はFAX+手作業というワークフローなのですが、エラー率45%(購買組織側の入力ミスとか) !! とのこと。 このワークフローを自動化するために、SOAベースのシステムを提案しているとのこと。購買組織はやる気満々なのだけれど、申請書などの共通化を図るために自治体の現状分析をしに行ったりした人の話だと、今のワークフロー(FAX申請)に、特に不満はないので、なかなか協力的になってくれないとのこと…。人間いずこも同じ?
- 感じたこと
- エピローグ
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
DIVE INTO S2 .HACK : INCLUDE PART I
Seasar2に慣れ親しむためにS2Containerのコードをプチハックしてみました。 v(^^)v
- S2Container間の依存関係(include)をDEPENDENCY-LOOKUPからDEPENDENCY-INJECTIONにしてみる。
-
- S2Containerは、1つのdiconファイル*1に対し、1つのS2Containerインスタンスが生成される仕組みになっています。そこで、コンポーネント群を機能ブロック毎に複数のdiconファイルに分けて使用する場合*2、includeタグを使って依存する子コンテナを関連付けるわけです。具体的には、依存するdiconファイルのパスを指定することで、関連付けを行います。しかし、この指定方法は、DEPENDENCY-LOOKUPスタイルなので、依存関係を外部からコントロールしようとすると、工夫が必要*3になります。そこで、なんかいい方法ないかなぁ〜と、悶悶と考えた結果“依存関係…依存関係…依存関係の解決…!…DI*4があるぢゃぁないか!”となったわけです。
- 現状の課題点は、依存関係が直接diconファイルのパスになっている点です。ここを別名にして、別名とパスのマッピングを別に定義する仕組みを作ってやればいいんじゃな〜い? … と、いうわけで、実験君のはじまりはじまり〜。
- diconファイルとしては、こんな感じの定義で動いたらいいかなぁ〜というのをまず書いてみました。includeタグの表記形式を拡張する方法*5で対応してます。
と書いた場合には、定義のみを行う。 と書いた場合には、別名を使ってincludeを行う。 と書いた場合には、今までと同様に、指定パスでincludeを行う。 - 同じ別名がincludeで複数定義されていた場合には、includeツリーをルートから辿る順序で、先勝ちのルールとする。
- Node0 ← Node1 ← Node2a という依存関係。
■ org/seasar/framework/container/factory/IncludeTagHandlerResolverNode0.dicon
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" "http://www.seasar.org/dtd/components24.dtd">
<!-- Alias definition section -->
<!-- Include section -->
<!-- Component section -->
component0
component1
component2
</component>
"Here is node0 container."
■ org/seasar/framework/container/factory/IncludeTagHandlerResolverNode1.dicon
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" "http://www.seasar.org/dtd/components24.dtd">
<!-- Include section -->
<!-- Component section -->
"Here is node1 container."
■ org/seasar/framework/container/factory/IncludeTagHandlerResolverNode2a.dicon
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" "http://www.seasar.org/dtd/components24.dtd">
<!-- Component section -->
"Here is node2a container."
■ org/seasar/framework/container/factory/IncludeTagHandlerResolverTest.java
package org.seasar.framework.container.factory;import java.util.List;
import junit.framework.TestCase;
import org.seasar.framework.container.S2Container;
public class IncludeTagHandlerResolverTest extends TestCase {
private static final String PATH = "org/seasar/framework/container/factory/IncludeTagHandlerResolverNode0.dicon";
public void setUp() {
IncludeTagHandler.clear();
}
public void testBasicSettings() throws Exception {
S2Container container = S2ContainerFactory.create(PATH);
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));
}
}
}
}
-
- じゃ、ハッキングしまぁ〜す。オレンジ色部分が追加コード。
■ org/seasar/framework/container/factory/IncludeTagHandler.java
/*
* Copyright 2004-2006 the Seasar Foundation and the Others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
package org.seasar.framework.container.factory;import java.util.HashMap;
import java.util.Map;import org.seasar.framework.container.S2Container;
import org.seasar.framework.env.Env;
import org.seasar.framework.util.StringUtil;
import org.seasar.framework.xml.TagHandlerContext;
import org.xml.sax.Attributes;/**
* @author higa
*
*/
public class IncludeTagHandler extends AbstractTagHandler {private static final long serialVersionUID = 7770349626071675269L;
/**
* @see org.seasar.framework.xml.sax.handler.TagHandler#start(org.seasar.framework.xml.sax.handler.TagHandlerContext,
* org.xml.sax.Attributes)
*/
public void start(TagHandlerContext context, Attributes attributes) {
String path = attributes.getValue("path");
if (path == null) {
throw new TagAttributeNotDefinedRuntimeException("include", "path");
}
S2Container container = (S2Container) context.peek();
String condition = attributes.getValue("condition");
if (!StringUtil.isEmpty(condition)) {
Map map = new HashMap();
map.put("ENV", Env.getValue());
Object o = createExpression(context, condition).evaluate(container,
map);
if (!(o instanceof Boolean)) {
throw new IllegalStateException("condition:" + condition);
}
if (!( (Boolean) o).booleanValue()) {
return;
}
}
path = resolveOrRegisterPath(path);
if (path == null) {
return; // Alias-path mapping was Registered
}
S2ContainerFactory.include(container, path);
}
private static final Map aliasNameDefinitions = new HashMap();public static void clear() {
aliasNameDefinitions.clear();
}
private String resolveOrRegisterPath(String path) {
if (!path.startsWith("@")) {
return path;
}
int nameSep = path.indexOf(':');
if (nameSep < 0) {
// Resolve path
String name = path.substring(1);
path = resolvePath(name);
} else if (nameSep == 1) {
// 'path' attibute value was specified like "@:....".
throw new IllegalStateException(
"Alias name of S2Container was empty.");
} else if (nameSep > 1) {
// Register alias-path mapping
String name = path.substring(1, nameSep);
path = path.substring(nameSep + 1);
registerPath(name, path);
path = null;
}
return path;
}private void registerPath(String name, String path) {
if (aliasNameDefinitions.get(name) != null) {
return;
}
aliasNameDefinitions.put(name, path);
}private String resolvePath(String name) {
String path = (String) aliasNameDefinitions.get(name);
if (path == null) {
throw new IllegalStateException("Alias name '" + name
+ "' was not defined.");
}
return path;
}
}
-
- んで、テスト! RED RED RED RED RED RED RED RED GREEN! いいんじゃなぁ〜い?
- こんどは、リーフノードのコンテナを交換してみます。
- Node0、Node1のdiconファイルには、全く手を加えず、Test1で依存関係を変更する方向で…。
- Test1 ← Node0 ← Node1 ← Node2b という依存関係。
- 切り替え用*8のルートのdiconファイルはこんな感じ。
■ org/seasar/framework/container/factory/IncludeTagHandlerResolverTest1.dicon
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" "http://www.seasar.org/dtd/components24.dtd">
<!-- Alias definition section -->
<!-- Include section -->
-
- そして、切り替えられるリーフノードのdiconファイルがこれ。〜aが〜bになってます。
■ org/seasar/framework/container/factory/IncludeTagHandlerResolverNode2b.dicon
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" "http://www.seasar.org/dtd/components24.dtd">
<!-- Component section -->
"Here is node2b container."
-
- そして、I'm Test-Driven*9 なので、またまたテストコードを書いてみます。先のテストコードに以下のコードを追加します。
private static final String PATH1 = "org/seasar/framework/container/factory/IncludeTagHandlerResolverTest1.dicon";
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));
}
}
}
-
- しょっしゃぁ!、DOテスト! RED RED RED RED RED GREEN! ふぅ。しばしのプログラマーズ・ハイ状態…*10
- 以上でハック完了であります。
- それから、このコードの課題としては、以下のようなところでしょうか…ま、プチハックということで。*11
- diconファイルの別名とパスをstaticなMapに持っているため、リロードの際には、中身をクリアしてあげる必要がある。
- 別名を定義する際の表記方法がイマイチ*12。includeタグに別の新規属性を追加した方が、きっと自然。
- IncludeTagHandlerに追加したコードは、別クラス(Innerクラスでもいいかも)にした方がいいだろうなぁ。
- スレッドセーフとか全く考慮してないです。
- まだまだ課題はありそうですが、とりあえず、YATTAA!!
あとがき
はじめは、MetaDefに別名とパスのマッピング情報を持たせようとしたのですが、includeタグの処理の時点では、S2Containerのrootとかchildrenが設定されていないようで、かなり試行錯誤+七転八倒したのですが、出来ませんでした…理解不足の可能性大…orz。結局…あれ?、Mapで別に持てばいいんじゃない?ということに気づき、この形になりました。*14 staticフィールではなくて、ルートのS2Containerのインスタンス変数とかに持てると、多少いいかなぁと思うのですが、私の今の実力では、これが限界でした orz. orz. orz. orz.
*1:ちなみにdiconファイル以外のリソースからS2Containerを構築する拡張性もあって、拡張子でコンテナビルダーの振舞いを制御出来るようになっています。
*2:業務アプリケーションなら普通はそうしますよね…^^;;;
*3:最近、この課題の解決策の1つとしてincludeタグに、condition属性が付きました v(^^)v これは便利ですね〜。けっこう待ち望んでいた人いるんじゃないかなぁ〜。
*4:Dependency Injection です念のため ^^;;
*5:初めは
*6:但し、気が向いたときに限る ^^;;
*7:当然、はじめに書いたコードにはバグがありました。IncludeTagHandler.clearが抜けてたり…
*8:というか上書き指定という感じかなぁ…Override?
*9:但し、気が向いたときに限る。っていうかクドイ!
*10:魂が抜け、画面を見つめてニヤニヤしている状態。他人に見られるととってもYABAI。
*11:はい、その通りです、自分の無力さに対する言い訳です。orz
*12:イマ3くらい?
*13:ちょっと「桃や」のキャラクターに似ていた、故・宮永好道さん[シャープ顧問]
*14:これに気づいたときにはかなり脱力しました。 orz
FOLLOWING ECLIPSE GMF
…つづき
- クイック・スタート
-
- /HEAD/org.eclipse.gmf/examplesを開いて、3っのorg.eclipse.gmf.examples.taipan.* modulesを選択してから、右クリックでチェックアウトを選択して下さい。もしあなたの使用しているGMFと依存プラグインが最新版でない場合には、そのバージョンに合った Tipan サンプルをチェックアウトできます。重要なのは、使用しているGMF SDKのバージョンと、Taipan サンプルのバージョンが合っていることです。古いバージョンの Taipan をチェックアウトするには、最新版をチェックアウトした後に、プロジェクトのところで、右クリックし、'Team | Switch to Another Branch or Version...' を選択し、それから、'Select the tag from the following list' を選んで、'Add Date...' ボタンを使って GMF 1.0 release (27 June 2006) を入力します。あとは Finish ボタンを押せば、指定したバージョンに設定されます。
- プラグイン開発・パースペクティブに切り替えて、org.eclipse.gmf.examples.taipan プロジェクトの models フォルダを開いてみましょう。それぞれのモデルを探してみましょう。特に taipan.gmfgraph と taipan.gmfmap モデルと、それらの要素の属性を探してみて下さい。
- このチュートリアルを進めていく間に、これらのモデルを見ることになりますが、とりあえず、設定が正しいかどうかを確認するために、ランタイム・ワークスペース(単に、'Eclpse Application' を実行した場合のデフォルト設定でOKです)で、実行したほうが良いでしょう。ランタイム・ワークスペースで、新しい空のプロジェクトを作り、そのプロジェクトの新規作成メニューの中の 'Example' を選択します。'New Example' ダイアログを開くと 'Taipan Diagram' が見つかるはずです。好きなファイル名を付けて、Finish ボタンをクリックして下さい。あなたが見たい、生成されたダイアグラム・エディタが開くでしょう。特に注目すべき点は…
これで、クイック・スタートは終わりです。さて次は、マインドマップ・モデリングのところで見てきた、それぞれのモデルについて、より詳細に見ていきます。
…つづけぇ〜
FOLLOWING ECLIPSE GMF
…つづいた
- セットアップ
- このチュートリアルは、GMF 1.0 を使用して書かれています。GMFをインストールする前に必要なプラグインについては、ビルドのページに書かれています。これらは、ダウンロードページ、もしくはアップデートマネージャーによりインストール可能です。
- GMFをはじめる一番簡単な方法は、たぶん、最新の Eclipse Platform 3.2 をインストールして、Callisto*1のアップデートサイトを使用することです。メニューの Help > Updates > Find and Install... Search for new features to install > Callisto Discovery Site にあります。それから、Models and Model Development カテゴリの Graphical Modeling Framework (Callist Edition) を選択し、GMFの依存プラグインが一緒にダウンロードされるように 'Select Required' ボタンをクリックして下さい。簡単でしょ?
…つづくか?
FOLLOWING ECLIPSE GMF
…つづき
-
- この図は、GMFベースの開発で使われる主なコンポーネントとモデルを示しています。GMFの核となる概念は、グラフィカル要素定義モデル*1です。このモデルはGEFベースのアプリケーションを実行した際に表示されるグラフィカルな要素に関連する情報を含んでいますが、表示や編集の対象であるドメインモデルへの直接的な関連は含みません。パレットやその他のメニュー、ツールバーなどのデザインには、オプションのツール定義モデルが使われます。
- グラフィカル要素やツール要素の定義は、複数のドメインで同じように動作することが求められます。例えば、UMLのクラス図には多くの要素がありますが、それらの基本的な外見や構造はどれもよく似ています。GMFの目標は、グラフィカル要素定義を複数のドメインで利用できるようにすることです。これは、グラフィカル要素とツール要素の定義と、指定されたドメインモデルを紐づける、マッピングモデルを別に定義することにより実現されます。
- 一度、適切なマッピングが定義されれば、GMFはアプリケーション生成フェーズで必要となるGMFジェネレーターモデル(実装の詳細なモデル)を供給します。ジェネレーターモデルにもとづいた編集用プラグインの製作では、最終的なモデル(ダイアグラム・ランタイムモデル*2または“表示”モデル*3 )を目指します。実行時に、ユーザが図を操作すると、表示モデルとドメインモデルが連動し、モデルの永続化と同期も行われます。ここで重要となるのは、実行環境が、EMFとGEFの機能に対して、サービスベースのアプローチをとるということです。そして、実行環境において、まだアプリケーションを生成していない状態で動作させることができるという点です。GMFの基礎はこれで終わりにして、今度は、特定ドメインのグラフィカルな編集画面の開発を通して、GMFの使い方を見ていきましょう。まず最初に、GMFと依存ライブラリをインストールする必要があります。
…つづくかも