AlfrescoをGoogleライクな検索に改良してみる

Alfrescoのキーワード検索は一見Googleライクなんだけど、微妙に違うところがあって思うように検索結果を絞り込めないという話が出てきました。Alfrescoのソースと睨めっこしていると改良できそうだったのでやってみました。

スペース区切りがOR検索になってしまう

Googleだと、単語をスペースで区切ることで検索結果を絞り込むことができます。ところがAlfrescoだと、デフォルトではOR検索になるみたいです。明確に下記のようにANDですよと伝えなきゃならない。

apple AND banana

または、プラス(+)でもOK。

+apple +banana

これは知らない人ははまるだろうなぁ。一般的にはANDな気がするけどなんでORなんだろ?
Alfrescoのフォーラムを漁ってみたけど同じように困っている人はなぜか見つからない。。。唯一、デフォルトがGoogleのようにANDだといいなという投稿が見つかったくらい。

で、デフォルトをANDにする方法ですが、一応切り替える仕組みは持っているようで、SearchParameters#setDefaultOperatorにANDを渡せば良い。ただ、これをANDにするだけだとまったく検索が引っかからなくなってしまう。内部で生成されるクエリの違いを調べていると、webscriptsのsearch.lib.jsでクエリ文字列を組み立てているのだが、そこで一部スペース区切りになっているところがあった。これまでORだったものが、デフォルトをANDにするとここもANDになってしまうので、結果全く引っかからなくなってしまっていたようだ。

というわけで、明示的にsearch.lib.jsにORを書いてやることで解決。作ったパッチはJIRAにも投稿しておきました。

http://issues.alfresco.com/jira/browse/ALF-6349

全角スペースが区切り文字としては認識されない

こちらもGoogleだと空気読んで全角スペースで区切って検索してくれるのですが、Alfrescoだと駄目。

全角スペースはLucene2.9で対応という話もあるのですが、Alfrescoで使われているLuceneは2.4.1と古い。試しに2.9にするとAPIが変わってて起動すらせず…

これは対応無理かなぁと思っていたけれども、Alfrescoのソースを見ると独自に検索文字列をANTLRでパースしている処理があり、そこで区切り文字列として全角スペース(\u3000)を追加するだけで対応可能でした。調べる時間は結構かかりましたが、修正自体は1行(とANTLRでクラスを再生成)。こちらも作成したパッチをJIRAに投稿しておきました。

http://issues.alfresco.com/jira/browse/ALF-6350


これでちょっとはGoogleライクに検索できるようになるかな。後はハイライト機能があればいいんですが、これはかなり対応が難しそうです。

Alfresco Share JAR ModulesによるDashletの作成方法

前回のエントリでは、Alfresco Share JAR Modulesで作成されたSite Tags Dashletを紹介しました。今回はこのDashletの作成方法について書いていきます。

前提

  • Maven2 or 3がインストールされていること

Alfresco Share JAR Modulesを作成するための、Maven用のテンプレートが用意されているのでこれを利用します。

プロジェクトの作成

  • コマンドプロンプトから下記のコマンドを実行します。コマンド中の、groupId、artifactId、versionは好みの値に変えてください。
mvn archetype:generate -DarchetypeGroupId=org.alfresco.maven -DarchetypeArtifactId=maven-alfresco-share-module-archetype -DarchetypeVersion=1.0.0-SNAPSHOT -DgroupId=com.mycompany -DartifactId=my-custom-share-module -Dversion=1.0-SNAPSHOT -DarchetypeRepository=http://maven.alfresco.com/nexus/content/repositories/snapshots -DinteractiveMode=false
  • これでAlfresco Share JAR Modulesのプロジェクトひな形が自動生成されます。下記の構成となっていて、実は、Site Tags Dashletのソースがサンプルとして含まれている。
my-custom-share-module
├─pom.xml
└─src
    └─main
        └─resources
            ├─alfresco
            │  └─site-webscripts
            │      └─org
            │          └─alfresco
            │              └─components
            │                  └─dashlets
            │                      ├─site-tags.get.config.xml
            │                      ├─site-tags.get.desc.xml
            │                      ├─site-tags.get.head.ftl
            │                      ├─site-tags.get.html.ftl
            │                      ├─site-tags.get.js
            │                      ├─site-tags.get.properties
            │                      └─site-tags.get_cy.properties
            └─META-INF
                └─components
                    └─dashlets
                        ├─images
                        │  └─refresh.png
                        ├─site-tags-min.js
                        ├─site-tags.css
                        └─site-tags.js

上記ファイルについて簡単に説明します。

src/main/resources/alfresco/site-webscripts 以下のファイル

サーバサイドで動作するコンポーネントです。

  • site-tags.get.config.xml
    • 設定ファイル。ここで設定した値をftlファイルから参照できる。Site Tags Dashletでは、タグの最大表示数を設定している。
  • site-tags.get.desc.xml
    • Dashletのエントリポイントとなるファイル。下記の内容となっていますが、重要なのはの値です。ここをsite-dashletとすることで、サイト単位のDashletになります。もし、user-dashletとすると、ユーザごとのダッシュボードに配置可能なDashletになります。dashletとすると両方に配置可能になります。は、この後で説明するsrc/main/resources/META-INF以下のディレクトリ構造と一致させます。
<webscript>
   <shortname>Tag Cloud</shortname>
   <description>Displays a cloud of all the tags defined in this site</description>
   <family>site-dashlet</family>
   <url>/components/dashlets/site-tags</url>
</webscript>
  • site-tags.get.head.ftl
    • このDashletの画面をレスポンスとして出力するFreeMakerのテンプレートです。headがファイル名についていますが、HTMLので返したい内容を定義すると埋め込んでくれます。なので、CSSJavaScriptの読み込みなどで使います。
  • site-tags.get.html.ftl
    • 同様にFreeMakerのテンプレートですが、こちらはHTMLの本文を定義します。つまり、Dashletで返したい内容を記述します。
  • site-tags.get.js
    • JavaScriptですが、ブラウザで動作する物ではありません。こちらはサーバサイドで動作する物。ここに、Dashletの画面表示の前に処理したいことを記述することになります。
    • Alfresco内での一般的な書き方としては、下記のようにmain関数を定義し、そのmain関数を実行するような形になっています。
const PREFERENCES_ROOT = "org.alfresco.share.dashlet";

function main()
{
   var s = new XML(config.script);
   model.maxItems = parseInt(s.maxitems, 10);

   …(省略)…

   model.preferences = preferences;
}

main();
    • 重要なポイントはmodel.preferences = preferences;の部分。model変数の任意のプロパティに値を設定することで、レスポンスを生成するテンプレートファイルに値を渡すことができます。
  • site-tags.get.properties、site-tags.get_cy.properties
    • メッセージファイルです。多言語対応には必要。日本語リソースが必要な場合は、site-tags.get_ja.propertiesというファイルで作成すればOK。
src/main/resources/META-INF 以下のファイル

ここに配置したファイルは、クライアントからアクセスされる静的なリソースファイル(JavaScriptCSS、画像ファイルなど)になる。

  • site-tags.css
    • CSSファイル。site-tags.get.head.ftlによりで読み込まれている。
  • site-tags.js/site-tags-min.js
    • JavaScriptのファイル。*-min.jsファイルは、YUI Compressorで圧縮したもの。
    • これもsite-tags.get.head.ftlによりで読み込まれているのですが、FreeMakerのマクロ機能でデバッグモード時は*-min.jsを自動的に読むようになっています。site-tags.get.head.ftlの中身を見ると分かりますが、scriptタグを使用せずに@scriptタグを使用しています。
<#include "../component.head.inc">
<!-- Tag cloud -->
<@link rel="stylesheet" type="text/css" href="${page.url.context}/res/components/dashlets/site-tags.css" />
<@script type="text/javascript" src="${page.url.context}/res/components/dashlets/site-tags.js"></@script>
    • この@付きがFreeMakerのマクロで、実体は<#include>でインクルードしているcomponent.head.incに定義されている。これはAlfrescoの本体に格納されている共通部品なので注意。下記のように、DEBUG変数の値で-min.jsに置換している。
<#--
   JavaScript minimisation via YUI Compressor
-->
<#macro script type src>
   <script type="${type}" src="${DEBUG?string(src, src?replace(".js", "-min.js"))}"></script>
</#macro>
    • 肝心のタグクラウドとしての処理、タグの一覧を取得するのはどこに実装されているかですが、実はこのsite-tags.jsで実装されている。つまり、Site Tags DashletはほぼクライアントサイドのJavaScriptで実装されています。タグの一覧はAlfrescoのREST APIを叩いて取得していて、それを画面に表示しているだけです。下記のコードでタグ一覧をJSONで取得し、画面に描画しています。
         // Make an AJAX request to the Tag Service REST API
         Alfresco.util.Ajax.jsonGet(
         {
            url: Alfresco.constants.PROXY_URI + "api/tagscopes/site/" + $combine(this.options.siteId, this.containerId, "tags"),
            successCallback:
            {
               fn: this.onTagsSuccess,
               scope: this
            },
            failureCallback:
            {
               fn: this.onTagsFailed,
               scope: this
            },
            scope: this,
            noReloadOnAuthFailure: true
         });

日本語タグに対応してみる

前回のエントリでちょっと書いたとおり、日本語のタグを作ってしまうと、Site Tags Dashletからのリンク遷移で失敗してしまうという問題があります。これを修正してみます。

原因は何か?

日本語のタグを作ると、Site Tags Dashletからのリンク遷移を行うとタグ名が文字化けしています。タグ名はURLパラメータとして渡しているので、URLエンコードに問題がありそうです。

site-tags.js:325を見ると、タグ名はencodeURIComponentを使用してエンコードしています。

            case "documentLibrary":
               uri += '/documentlibrary#filter=tag|' + encodeURIComponent(tag.name);
               break;

一方、タグに対応したドキュメント一覧の表示画面では、share.war/components/documentlibrary/documentlist.jsで処理されています。これをみると、タグ名をDL_fnDecodeBookmarkedFilter関数でデコードしているのですが、window.unescapeを使って元にもどしている。encodeURIComponentとunescapeでは文字コードが異なるので、ここで化けてしまっていました*1

         var fnDecodeBookmarkedFilter = function DL_fnDecodeBookmarkedFilter(strFilter)
         {
            var filters = strFilter.split("|"),
               filterObj =
               {
                  filterId: window.unescape(filters[0] || ""),
                  filterData: window.unescape(filters[1] || "")
               };
            
            filterObj.filterOwner = Alfresco.util.FilterManager.getOwner(filterObj.filterId);
            return filterObj;
         };

なので、修正方法としては、site-tags.js:326のエンコード方式を変えてあげればよい。下記のように、encodeURIComponent関数をwindow.escape関数に変えてあげる。

            case "documentLibrary":
               uri += '/documentlibrary#filter=tag|' + window.escape(tag.name);
               break;

作成したDashletをビルドする

作成されたプロジェクトをビルドするには、Mavenの下記コマンドを実行します。ビルドが成功すると、target/my-custom-share-module-1.0-SNAPSHOT.jarができています。

mvn install

作成したDashletをデプロイする

前回のエントリと同様に、ビルドしたJARをAlfrescoの下記に配置します。また、catalina.propertiesのshared.loaderの設定も忘れずに!

/opt/alfresco-3.4.b/tomcat/shared/lib

Alfrescoを起動している場合は、再起動します。これでDashletが使えるようになる。

まとめ

  • Dashletの開発では、Mavenを使えば簡単にプロジェクトの作成→ビルドが行える環境が整います。
  • Dashletの開発において、Java言語は必要ありません。HTML、CSSJavaScript、FreeMakerによるテンプレートファイルがメインです。ShareはWeb2.0スタイルと言っているだけあって、クライアントサイドのJavaScriptでごりごり開発するのが基本的な形のようです。その時標準で使えるライブラリとしてはYUIとなります。
  • また、AlfrescoではREST APIが豊富に用意されています。JSONを返してくれるので、クライアントサイド(またはサーバサイド)のJavaScriptからアクセスし、結果を加工して画面表示するようなアーキテクチャになります。

*1:documentlist.jsではwindow.unescapeをなぜ利用しているかというと、YUIのHistoryManagerをこいつは使っていて、HistoryManager自身もwindow.escape/unescapeで利用しているためと思われる。

Alfresco Shareでタグクラウドを実現する

前回のエントリでAlfrescoのカスタマイズ方法の一つとして、「Alfresco Share JAR Modules」があると書きました。「Alfresco Share JAR Modules」はShareのDashletやPageの拡張しかできませんが、JARを配置するだけという非常にお手軽な導入方法となっています。

今回はこのカスタマイズ方法で作成された、タグクラウドを表示するDashletを紹介します。このDashletはWill Abson on Alfresco » Site Tags Dashletで公開されています。

Site Tags Dashletのインストール

/opt/alfresco-3.4.b/tomcat/shared/lib
  • catalina.propertiesのshared.loaderを下記のように編集する(これを行わないとJARがロードされない)
shared.loader=/opt/alfresco-3.4.b/tomcat/shared/classes,/opt/alfresco-3.4.b/tomcat/shared/lib/*.jar
  • Alfrescoを再起動

以上で導入は終わり。catalina.propertiesは1度設定すればいいので、実質JARの配置だけです。

これでDashboardのカスタマイズ画面に行くと、Site Tags Dashletが追加されています。配置するとこんな感じでタグクラウドが表示されます。
http://blogs.alfresco.com/wp/wabson/files/2009/11/site-tags-dashlet-150x150.png

なお、このタグクラウドですが、日本語のタグを作ってしまうと、Site Tags Dashletからのリンク遷移で失敗してしまうという問題があります。次回、Alfresco Share JAR Modulesの説明もしつつ修正方法に付いて解説したいと思います。

Alfrescoのカスタマイズ方法について覚え書き

AlfrescoのWikiやForumをうろうろして徐々にカスタマイズについて分かってきたので、備忘録として書いていこうと思います。

カスタマイズ方法は大きく2つの方法に分かれます。

  1. 設定のみ
    • 設定だけでもある程度はカスタマイズが可能です。
    • 代表的なものは、コンテンツモデルの拡張です。例えば、属性を増やすとか。
  2. モジュールを作成
    • 設定だけでは対応できない場合は、プログラミングが必要となります。ビューだけのカスタマイズであれば、テンプレートファイルやJavaScriptの作成のみでできます。サーバサイドで処理が必要な場合も、web-scriptというJavaScriptを使ってロジックを記述する仕組みあるので、JavaScriptオンリーで対応できるかも。Javaで開発することももちろんできる。
    • Alfrescoではプラグインのような機構を用意してくれていますが、過去の経緯からか色々やり方があるっぽい。自分もまだ整理できていないですが、
      • AMP(Alfresco Module Package)による拡張
        • AMPファイルを作成し、専用のツールでWARに組み込む。
      • Alfresco Share JAR Modules (カスタムダッシュレット、ページのみ。Alfresco 3.3から対応)
      • Mavenプラグインを使ってalfresco.war/share.warを作成。
        • Alfresco Repository Extensions (alfresco/extension Spring based WAR builds)
        • Alfresco Share WAR Extensions (alfresco/web-extension Spring customization WAR builds)

一番シンプルなのは、Alfresco Share JAR Modulesですね。作成したJARを1個を配置するだけ。他はWARをマージするのでビルドに結構時間がかかります。

最近Alfrescoを触っています

最近、オープンソースECM製品であるAlfrescoを触っています。(ECMはコンテンツ管理システムのことです。詳しくは下記ページなどを参照)

ECMとは「Enterprise Content Management(企業向けコンテンツ管理システム)」の略で、そのまま解釈すれば「企業内のコンテンツの管理精度を向上させる仕組み」ということになります。

ではここでいう「コンテンツ」とは何でしょうか。ECMの世界でコンテンツというと「非定型のデータのすべて」という定義が一般的です。基幹システムのデータベースに格納されているような定型的なデータではなく、WordやExcelなどのフォーマットで企業内に蓄積されている情報のすべてがECMの対象となり得ます。

http://thinkit.co.jp/free/article/0708/11/1/

使ってみると中々おもしろいです。かなり拡張性を考えて作られている。やろうと思えば色々できそうな感じです。

日本語の書籍としては↓が出ていますね。

オープンソース徹底活用 Alfrescoによるドキュメント管理入門

オープンソース徹底活用 Alfrescoによるドキュメント管理入門


ただしこちらは素のAlfrescoの使い方中心なのが残念。実際に使おうとすると、カスタマイズしたくなると思うんですけどねー。カスタマイズしようとするこの本では情報が足りない。

そんなときに参考になるのは、本家のWikiサイトです。英語ですが、拡張方法については結構かかれてます。なお、トップからうまく知りたい情報へたどりつきにくいので、ググった方が速いかも?フォーラムも参考になります。同じように悩んでいる人が質問していて、解答が付いている可能性があります。こちらもググった方が速いでしょう。

ちなみにですが、現在のAlfrescoでは、2種類のUIが用意されています。

  • Alfresco Explorer
    • こちらが昔からある方。JSFベース。個人的な印象だけど、アイコンがちっちゃすぎてクリックが難しい(苦笑)。
  • Share
    • こちらは比較的新しいUI。Spring Surf(Sprint MVC)ベースという日本では中々見かけないアーキテクチャ
    • Web2.0コンセプトのなんたらかんたらと書かれているくらいあって、結構リッチなUIです。今使うならShareかな?
    • ただし、Alfresco Explorerでしかできない操作もあるので要注意(カテゴリの定義とか)。エンドユーザはShare使って、管理者はAlfresco Explorerも使うというやり方になるのかも。

日本語での情報(特にカスタマイズとか)がまだあまりなさそうなので、今後書いていきたいと思います。