コレクションを変換する
」
特定のサイクルの分野のリストの例を使用して、Caché+ Java + Flexバンドル全体のコレクションの変換を調べてみましょう。 コレクションの例として、リレーションシップ(Cachéクラス間のリレーションシップのタイプ)を検討します。これは、リレーションシップタイプのプロパティとして実装され、特定のタイプの整合性サポートを備えています。 Cachéの関係の詳細をご覧ください 。
Class IKIT.cCicl Extends %Persistent { … Relationship ListOfDisc As IKIT.cDiscipline [Cardinality = many, Inverse = Cicl]; … }
生成されたjavaプロジェクション(Java c-classesパッケージ)では、このプロパティはcachedb.jarライブラリのcom.intersys.classes.RelationshipObjectクラスのオブジェクトによって表されます。
public com.intersys.classes.RelationshipObject getListOfDisc() throws com.intersys.objects.CacheException { com.intersys.cache.Dataholder dh = mInternal.getProperty("ListOfDisc", true); com.intersys.cache.CacheObject cobj = dh.getCacheObject(); if (cobj == null) return null; return (com.intersys.classes.RelationshipObject)(cobj.newJavaInstance()); }
このクラスには標準のasListメソッドがあり、RelationshipObjectを取得してListを返します。これにより、将来のリストの操作が大幅に容易になります。
Mクラスはリスト(List listOfDisc)を使用するため、各cクラスオブジェクトをRelationshipObjectから対応するmクラスオブジェクトに変換する必要があります。 このアクションは、CacheTransformクラスで実行されます。
for (int i=0;i<cur.getListOfDisc().size();i++) { res.getListOfDisc(). add(TranformDi((cDiscipline)cur.getListOfDisc().asList().get(i))); } // cur – cCicl, res – mCicl
次に、GraniteDSのPOMファイルで指定されたパラメーターに従って、mクラスがflexモジュールに投影されます。 GraniteDSはデフォルトで、List型の投影(Java)にListCollectionView型(ActionScript)を使用します。 たとえば、生成されたmCiclBase ASクラスのリストの投影は次のようになります。
[Bindable] public class mCiclBase implements IExternalizable { … protected var _listOfDisc:ListCollectionView; … public function set listOfDisc (value: ListCollectionView):void { _listOfDisc = value; } public function get listOfDisc():ListCollectionView { return _listOfDisc; } … }
ActionScriptで直接作業をさらに簡素化するために、ListCollectionViewから派生したクラスであり、必要に応じてListCollectionViewとして簡単に変換できる標準のflexインターフェイスIlist(cur.listOfDisc = new ArrayCollection();)を実装するArrayCollectionクラスを使用しました。
逆変換も同じパターンに従います。 GraniteDSを介したASプロジェクションで発生する変更は、Java m-classesパッケージの対応するクラスでも実行されます。 コレクションオブジェクトのjava m-クラスからjava c-クラスへの変換は、Rev。プレフィックスを持つ関数のCacheTransformクラスで発生します。 この場合、Mクラスオブジェクトとアクション(上書きまたは作成)を行うRevTranformCi関数(mCicl cur、Integer act)で、オブジェクトをデータベースに書き込み、cクラスオブジェクトを返します。 この関数では、次のようにシート変換が行われます。
for (int i=0;i<cur.getListOfDisc().size();i++) { if(cur.getListOfDisc().get(i).getId()!=null) { res.getListOfDisc().add(RevTranformDi(cur.getListOfDisc().get(i),1)); } if(cur.getListOfDisc().get(i).getId()==null) { res.getListOfDisc().add(RevTranformDi(cur.getListOfDisc().get(i),2)); } }
その後、Cクラスオブジェクトで標準の_saveメソッドが呼び出されます。このオブジェクトは、Cachéデータベースにデータを格納し、ListタイプをCachécom.intersys.classes.RelationshipObjectの対応するタイプにキャストします。
コレクションですべてが明らかになったので、オブジェクトの追加と削除を示す例に移りましょう。
オブジェクトの追加と削除の例
カリキュラムの追加と削除の例を使用して、サービスインターフェイスの操作を検討してください。 「カリキュラム」オブジェクトは、mCurriculumクラスのASプロジェクションで最初に作成されます。 このオブジェクトの作成はクライアント側で実行され、サーバーに転送されてデータベースに保存されます。 これを行うには、オブジェクトを介してサーバーサービスインターフェイスを実装するaddOneCurrメソッドを呼び出します。
userService.addOneCurr(cur, k);
ここで、curはflexで作成されたmCurriculum投影クラスのオブジェクトであり、kはアクション(追加または編集)の選択を担当する変数です。
ここで、 GraniteDSはリクエストを非同期に送信し、関数の完了後に厳密に何らかのアクションを実行する必要がある場合、結果ハンドラ関数に直接配置する必要があることに注意する必要があります。 例:
userService.addOneCurr ( cur, k, function(e:TideResultEvent):void { Alert.show(" "); updateOneCur(curCurriculum.id); }, function (e:TideFaultEvent):void { Alert.show(e.fault.faultDetail); } );
この関数は、addOneCurr関数が正常に完了した後、厳密に「Add completed」というメッセージを表示します。
以下は、GraniteDSによって生成されたIUserServiceインターフェイスのActionScriptプロジェクションクラスのaddOneCurr関数のコードです。
public function addOneCurr(arg0:mCurriculum, arg1:Number, resultHandler:Object = null, faultHandler:Function = null):void { if (faultHandler != null) callProperty("addOneCurr", arg0, arg1, resultHandler, faultHandler); else if (resultHandler is Function || resultHandler is ITideResponder) callProperty("addOneCurr", arg0, arg1, resultHandler); else if (resultHandler == null) callProperty("addOneCurr", arg0, arg1); else throw new Error("Illegal argument to remote call (last argument should be Function or ITideResponder): " + resultHandler); }
IUserServiceインターフェイスを実装するソースJavaクラスUserServiceの同じ関数。
@Override public Boolean addOneCurr(mCurriculum cur,Integer k){ objT.RevTranformCu(cur,k); return true; }
この関数は、CacheTransformクラスのRevTranformCu(mCurriculum cur、Integer act)メソッドを呼び出します。このメソッドは、クラスmCurriculumのオブジェクトをクラスcCurriculumのオブジェクトに変換し、データベースに書き込むように設計されています。 さらに、addOneCurr関数「カスケード」により、処理中のカリキュラムのコレクションに含まれるオブジェクトが保存されます。
RevTranformCuメソッド。
/// public cCurriculum RevTranformCu(mCurriculum cur,Integer act) { try { cCurriculum res=null; if (act==1) { System.out.println("//MAS: TRY EDIT Curriculum: " + act.toString() + "\nID:" + cur.getId().toString()); res=(cCurriculum) cCurriculum._open(dbconnection, new Id(cur.getId())); } else { System.out.println("//MAS: TRY ADD Curriculum"); res=new cCurriculum(dbconnection); } res.setName(cur.getName()); // if(res.getListOfCicl()!=null) { res.getListOfCicl()._clear(); } if(cur.getListOfCicl()!=null) { for (int i=0;i<cur.getListOfCicl().size();i++) { cur.getListOfCicl().get(i).setCurriculum(cur.getId()); if(cur.getListOfCicl().get(i).getId()!=null) { res.getListOfCicl().add(RevTranformCi (cur.getListOfCicl().get(i),1)); } if(cur.getListOfCicl().get(i).getId()==null) { res.getListOfCicl().add(RevTranformCi (cur.getListOfCicl().get(i),2)); } } } // if(res.getListOfSemestr()!=null) { res.getListOfSemestr()._clear(); } if(cur.getListOfSemestr()!=null) { for (int i=0;i<cur.getListOfSemestr().size();i++) { cur.getListOfSemestr().get(i).setCurriculum(cur.getId()); if(cur.getListOfSemestr().get(i).getId()!=null) { res.getListOfSemestr().add(RevTranformSe (cur.getListOfSemestr().get(i),1)); } if(cur.getListOfSemestr().get(i).getId()==null) { res.getListOfSemestr().add(RevTranformSe (cur.getListOfSemestr().get(i),2)); } } } // if(res.getListOfLogs()!=null) { res.getListOfLogs()._clear(); } if(cur.getListOfLogs()!=null) { for (int i=0;i<cur.getListOfLogs().size();i++) { cur.getListOfLogs().get(i).setCurriculum(cur.getId()); if(cur.getListOfLogs().get(i).getId()!=null) { res.getListOfLogs().add(RevTranformLo (cur.getListOfLogs().get(i),1)); } if(cur.getListOfLogs().get(i).getId()==null) { res.getListOfLogs().add(RevTranformLo (cur.getListOfLogs().get(i),2)); } } } res._save(); return res; } catch (CacheException e) { e.printStackTrace(); return null; } }
例からわかるように、このメソッドは、学期、サイクル、およびログのリストからすべてのオブジェクトを、対応するメソッドRevTranformSe、RevTranformCi、RevTranformLoとともに順次保存します。 原則は同じままです。idが存在しない場合は新しいオブジェクトが作成され、そうでない場合は既存のオブジェクトが編集されます。
同様に、カリキュラムの削除が進みます。 削除するには、mCurriculum投影クラスオブジェクトのIDを取得して、サーバーに転送します。 IUserServiceインターフェイス関数のASプロジェクションのdelOneCurr関数がこれを担当します。
userService.delOneCurr ( curId, function (e:TideResultEvent):void { loadCur(0); }, function (e:TideFaultEvent):void { Alert.show(e.fault.faultDetail); } );
IUserServiceインターフェイスを実装するソースJavaクラスUserServiceの同じ関数。
@Override public void delOneCurr(Integer i) { objT.deleteOneCurr(i); }
delOneCurr関数は、データベースからcCurriculumクラスのオブジェクトを削除するように設計されたCacheTransformクラスのdeleteOneCurr(整数dd)メソッドを呼び出します。 さらに、この機能は、削除されたカリキュラムのシートに含まれるオブジェクトの削除をカスケードします。
メソッドdeleteOneCurr。
public void deleteOneCurr(Integer dd) { try { System.out.println("//MAS: TRY DELETE Curriculum"); cCurriculum cur; cur=(cCurriculum) cCurriculum._open(dbconnection, new Id(dd)); if(cur.getListOfCicl()!=null){ for(int i=0;i<cur.getListOfCicl().size();i++) { cCicl k=(cCicl)cur.getListOfCicl().asList().get(i); deleteOneCicl(Integer.parseInt(k.getId().toString())); } } if(cur.getListOfSemestr()!=null) { for(int i=0;i<cur.getListOfSemestr().size();i++) { cSemestr k = (cSemestr)cur.getListOfSemestr().asList().get(i); deleteOneSeme(Integer.parseInt(k.getId().toString())); } } if(cur.getListOfLogs()!=null) { for(int i=0;i<cur.getListOfLogs().size();i++) { cLogs k=(cLogs)cur.getListOfLogs().asList().get(i); deleteOneLog(Integer.parseInt(k.getId().toString())); } } cur._close(); cCurriculum._deleteId(dbconnection, new Id(dd)); System.out.println("//MAS: DELETE Complite"); } catch (CacheException e) { e.printStackTrace(); } }
例からわかるように、このメソッドは、対応するメソッドdeleteOneSeme、deleteOneCicl、deleteOneLogを使用して、学期、サイクル、およびログのリストからすべてのオブジェクトを順次削除します。
「生産」についての一言
CacheプロジェクションはOOPの原則を完全にサポートしているため、Cacheクラスでフィールドを追加したりタイプを変更したりすることは、Javaで直接対応する操作と同等です。
より具体的には、プロジェクションの使用とクラスの複製により、新しいフィールドを追加するとき、またはCacheのデータ型を変更するときに、プロジェクトを比較的簡単に変更できます。
このようなソリューションは維持が容易であり、満たす必要がある主な要件は、クラス、プロパティ、およびメソッドに名前を付けるときに表記法を遵守することです。
クラスの数が増えると、コードは正比例して増加します。Tranform関数を統合しようとすると、数倍小さくなります。
この段階で、変更を行うか新しいクラスを追加するときは、次のことを行う必要があります。
- 投影クラスを再生成し、既存のクラスを置き換えます(または新しいクラスを追加します)。
- mクラスに適切な変更を加えます(OOPの原則が実装されているため、このような変更は難しくありません)。
- コントローラーに変更を加えます(統合は回避できます)。
おわりに
提示された組み合わせと提案されたアプローチのすべての長所と短所を考慮すると、エージェント技術に向けたシステムのさらなる開発を考慮する価値があります。
JADEがプラットフォームとして選択されたため、システム全体のアーキテクチャの設計に多くの制限を課すことは当然です。 JADE自体はJavaで記述されており、仮想マシンで動作するクロスプラットフォームシステムであるため、開発されたMACのロジックもこの環境で構築されます。 JADEのメインユニット(要素)はエージェントであり、本質的にはJavaクラスのオブジェクトです。 このエージェントの機能のロジック全体もこのクラスに実装されています。 次のように、オブジェクト指向データベースに各エージェントの長期データストレージを実装すると便利です。 エージェント自体は、セマンティックネットワークとオントロジーに基づいた知的コンポーネントの存在を想定しています。 オントロジーは、保存されたデータであり、オブジェクト指向のアプローチを(いわば)継承します。 したがって、このシステムを実装するのに最も便利なデータベース管理システムはオブジェクト指向であり、Javaクラスを介してそれを操作する機能を提供します。 私たちの意見では、CachéDBMSはこのタスクの良い候補です。
この段階では、Caché-Javaバンドルがさらなる開発に十分な選択肢を提供するため、WebインターフェースとしてFlexテクノロジーを使用することの有効性を評価することは困難です。
提案されたアーキテクチャの短所には、Java mクラスパッケージでのJavaプロジェクションの複製と、Javaプロジェクションとmクラスクラスオブジェクトの同期を保証するCacheTransformクラスでの追加機能の実装が含まれます。 将来的には、CachéでJavaプロジェクションを生成するメカニズムを完成させることでこの問題を解決できます。これにより、Javaプロジェクションで使用される外部アプリケーションによって決定される追加の特異性を考慮することができます。 たとえば、プロジェクション生成の追加要件は別のxmlファイルに記述できます。これを使用して、生成メカニズムが正しいJavaプロジェクションを作成します。 その後、Javaプロジェクションのクラスを複製する必要がなくなります。
著者から
この記事を読んで興味を持ち、自分に役立つ何かを見つけていただければ幸いです。 もちろん、私たちはプロジェクトの作業を継続し(最適化の作業を含む)、今後このシリーズの記事が拡張される可能性があります。
現在、開発中のマルチエージェントシステムのモジュールの1つだけを検討しました。主な目標は、Caché+ Java + Flexバンドルに読者を慣れさせることでした。 同時に、エージェントを使用する問題を未解決のまま残しました。 したがって、このトピックに興味がある人のために、ネタバレの下でいくつかの説明に慣れることをお勧めします。
エージェントとマイクロエージェント
これらのプロジェクトコンポーネントは、システムの特定の要件に従って機能をさらに拡張するために必要です。 現時点では、Webアプリケーションのみがサーバー上のエージェントに接続され、その機能の多くが呼び出されます。 これは、提示されたプロジェクトがエージェントの視覚的モジュールの1つに過ぎないJADE環境でのエージェントの相互作用に基づくシステムの開発にさらに役立ちます。 実際、マイクロエージェントは、ユーザーのマルチエージェントシステムでの作業を容易にするための補助的なコンポーネントです。 各ユーザーには、システムの他のエージェントと対話するための独自のエージェントが提供されます。 ユーザーとエージェントが常に通信できるように、ユーザーのコンピューターにインストールされているマイクロエージェントが使用されます。 マイクロエージェントは、進行中のイベントとメインエージェントによって送信された受信メッセージについてユーザーに通知します。 また、クライアント(Webページを表示するブラウザー)でアプリケーションを起動し、ユーザーがエージェントと対話できるようにします。
Webサーバーの起動時にJADEプラットフォームで新しいコンテナとエージェントを起動する機能を示します。
カリキュラムの機能構築を担当するエージェントモジュールの1つを以下に示します。
ここで、Agentsは、アクティブなエージェントと現在のWebアプリケーションに関連付けられたエージェントに関するデータを格納するクラスオブジェクトです。
Webサーバーの起動時にJADEプラットフォームで新しいコンテナとエージェントを起動する機能を示します。
public boolean StartAgent() { String aName = "ZavKaf Agent - "; String aClass = "agents.ZavCafAgent"; rt= Runtime.instance(); p=new ProfileImpl(); p.setParameter("container-name","ZavKaf_Agent"); mainCont=rt.createAgentContainer(p); try { Object[] temp=new Object[1]; temp[0]=testSoul; ac=mainCont.createNewAgent(aName, aClass, temp); ac.start(); agSt=true; System.out.println("Agent Start"); return true; } catch (Exception ex) { testSoul.setA(null); System.out.println("Agents ERROR: " + ex); return false; } }
カリキュラムの機能構築を担当するエージェントモジュールの1つを以下に示します。
public mAlgRes doAlgorithm(List<mDiscipline> curL, mCurriculum curriclum, List<mControlForm> cf) { return Agents.getA().doAlg(curL,curriclum,cf); }
ここで、Agentsは、アクティブなエージェントと現在のWebアプリケーションに関連付けられたエージェントに関するデータを格納するクラスオブジェクトです。