Thursday, February 7, 2013

Alfrescoのカスタム属性(とアスペクト名、タイプ名とか)を日本語化する

こんにちは。大谷です。
今回は「Alfrescoにカスタム属性を追加する - タイプとアスペクト -」に続く形で、カスタムモデル周りの日本語化(多言語化)について紹介したいと思います。基本的にはメッセージリソースの追加方法の説明だと思ってください。


プロパティ名とか変じゃない?


先ほどのリンク先の記事、特に画像を見た人は既にお気づきだと思いますが、追加したプロパティ名やアスペクト名がリソースIDみたいな文字列になっています。まあ頑張れば何を表しているか分からなくもないですが、あまりユーザフレンドリではありません。そこで、今回はこの表示をユーザが分かりやすい文字列に変えてみようと思います。つまり、表示ラベルを設定するようなものです。


まずは英語で表示できるようにしてみる


日本人であれば日本語で表示したいところですが、まずは英語にしてみましょう。日本語に関しては、設定時に一工夫必要なので(まあ大体想像つくと思いますが)、後ほど多言語化の方法と併せて説明することとします。

まずは、プロパティの表示名を設定するために、以下の2ファイルを作成します。custom-model-context.xmlは前回作成してあるので、<property name="labels">タグを追加して読み込むリソースファイル名を指定します。そして、指定したファイル名のリソースファイルを作成します。コンテンツモデル名やプロパティ名の":"を"_"に置き換える形で用い、title(表示名)やdescription(説明)の文言を設定します。

<alf_dir>/tomcat/shared/classes/alfresco/extension/custom-model-context.xml
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
    <!-- Registration of new models -->   
    <bean depends-on="dictionaryBootstrap" id="extension.dictionaryBootstrap" parent="dictionaryModelBootstrap">
        <property name="models">
            <list>
                <value>alfresco/extension/customModel.xml</value>
            </list>
        </property>
        <property name="labels">
            <list>
                <value>alfresco/messages/custom-model</value>
            </list>
        </property>
    </bean>
</beans>

<alf_dir>/tomcat/shared/classes/alfresco/messages/custom-model.properties
custom_customModel.property.custom_reviewer.title=Reviewer
custom_customModel.property.custom_reviewer.description=Reviewer's name
custom_customModel.property.custom_reviewDate.title=Reviewed Date
custom_customModel.property.custom_reviewDate.description=When this item reviewed

次に、アスペクトの表示名を設定するために、以下の2ファイルを作成します。読み込むリソースファイル名を指定するcustom-messages-context.xmlはweb-extension以下に配置します。タイプもこの方法で表示名を設定できます。リソースファイル内でtype.***=***のように設定するだけです。

<alf_dir>/tomcat/shared/classes/alfresco/web-extension/custom-messages-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
   <bean id="custom.resources" class="org.springframework.extensions.surf.util.ResourceBundleBootstrapComponent">
      <property name="resourceBundles">
         <list>
            <value>alfresco.messages.custom-share-messages</value>
         </list>
      </property>
   </bean>
</beans>

<alf_dir>/tomcat/shared/classes/alfresco/messages/custom-share-messages.properties
aspect.custom_reviewable=Reviewable

以上で設定完了です。Alfrescoサーバを再起動し、プロパティ名やアスペクト名が指定した文言になっていることが確認できると思います。先のエントリのスナップショットと比較すると変化が分かりやすいと思います。




日本語表示を追加してみよう


英語でうまく表示できたら、次は日本語表示に進みます。方法としては以下のように2通りの方法があります。
  1. 先ほど設定したリソースを日本語の文言に置き換える
  2. 先ほどのリソースファイルとは別に日本語用のリソースファイルを用意する
Alfrescoの場合、ブラウザの言語設定によって表示言語が自動的に変更されます。例えばブラウザの言語設定を英語に変更すると、Alfrescoの表示が英語になるはずです。ここで改めて先ほどの2つの方法を見てみると、2.の方法はこの言語切り替えに対応する方法ということになります。もちろんどちらの方法を選択するかは要件によりますが、ここでは2.の方法を紹介したいと思います。

手順は簡単、以下の2ファイルを追加で用意するだけです。追加するファイル名は、既存のリソースファイル名に_jaを付けたものになります。これだけで日本語フランス語のリソースだったら_fr、イタリア語だったら_it、英語だったら_enという感じです。英語のリソースファイルも用意してあげれば、日本語/英語の両方に対応した表示が完成です。何もついてない元のリソースファイルはデフォルトの表示名ということになります。

<alf_dir>/tomcat/shared/classes/alfresco/messages/custom-model_ja.properties
custom_customModel.property.custom_reviewer.title=\u30ec\u30d3\u30e5\u30a2
custom_customModel.property.custom_reviewer.description=\u30ec\u30d3\u30e5\u30fc\u8005\u540d
custom_customModel.property.custom_reviewDate.title=\u30ec\u30d3\u30e5\u30fc\u65e5
custom_customModel.property.custom_reviewDate.description=\u30ec\u30d3\u30e5\u30fc\u65e5

<alf_dir>/tomcat/shared/classes/alfresco/messages/custom-share-messages_ja.properties
aspect.custom_reviewable=\u30ec\u30d3\u30e5\u30fc\u53ef\u80fd

ここでのポイントは、日本語の文言がUnicodeエンコーディングされている点です。JDKに付属するnative2ascii等を利用してエンコーディングする必要があります。もしくは、自動的にエンコーディングしてくれるようなEclipseプラグインを使ってpropertiesファイルを編集するなどの方法があります。

では、Alfrescoサーバを再起動して再度プロパティ名やアスペクト名を確認してみましょう。無事日本語の文言に変わっているはずです。



 
今回はextensionフォルダ側とweb-extensionフォルダ側から計2つのリソースファイルを参照しましたが、役割分担としては、extensionフォルダ側から参照するリソースファイルではカスタムモデルに関するものを、web-extensionフォルダ側から参照するリソースファイルではShare UI上のメッセージに関するものを指定します。


今回の説明は以上になりますが、基本的なメッセージリソースの追加方法はお分かりいただけたかと思います。メッセージの追加が必要になった場合は是非参考にしてください。

Wednesday, January 30, 2013

Alfrescoにカスタム属性を追加する - タイプとアスペクト -

こんにちは。大谷です。
日当たりが悪いのか、うちの周りが寒いのかは分かりませんが、うちの庭には相変わらず1月14日の雪が解け残っています(1月30日現在)。今回は、そんな大谷家からAlfrescoのコンテンツにカスタム属性を追加する方法をお伝えしたいと思います。基本的にはAlfresco4.2での話ですが、コンテンツモデルの仕組み自体はAlfresco3系でもほぼ同じです(そうそう変わるもんじゃない!)。


属性って何?そもそもコンテンツって何?


コンテンツは直訳すると内容物という意味です(当たり前ですが)。なので、ファイルサーバのコンテンツはファイルであり、CMSのコンテンツはリッチテキスト(と画像などの各種メディアファイル)ということになります。では、Alfrescoを始めとするECM(企業向けコンテンツ管理)の世界ではどうかというと、この世界では「コンテンツ=ファイル実体+属性情報(メタデータ)」と定義されることが多いです。つまり、ファイル実体とそのファイルに付随する各種の情報がセットで管理されるということを意味します。

そうなると、管理すべき属性を予め定義しておきたくなると思います。例えば、そのコンテンツが契約書であれば、属性情報として契約書番号や顧客番号などを管理したいでしょうし、そのコンテンツがある製品の説明書であれば製品番号などを管理したいと思います(そもそもそのコンテンツが契約書なのか、説明書なのか、というコンテンツタイプ自体も管理したいと思います)。このように、ECM製品を利用しようとすると必ずと言っていいほど行われるのが、カスタム属性の追加というカスタマイズです。


カスタム属性を実現するための2つの方法 -タイプとアスペクト-


カスタム属性は、上記例よろしく「ある種類のコンテンツには属性Aと属性Bを、この種類のコンテンツには属性Cと属性Dを」というようにコンテンツ種別に応じて特定の属性セットを付与、管理するという要件が多いかと思います。これを実現するのがタイプになります。タイプは、事前に定義された属性セットを持つもので、Alfresco上のコンテンツを特定のタイプに指定すると、そのタイプに定義された属性が管理できるようになります。

一方で、コンテンツ種別によらず、コンテンツ種別をまたぐような形で管理したい属性もあると思います。例えば、バージョン管理を行うときのバージョン番号や、タグ付け/カテゴリ付けする際のタグやカテゴリなどです。もちろん全てのタイプにそれら利用可能性のある全ての属性セットを持たせることも可能ですが、 それはとても無駄が多いことだし、そもそも各タイプにとってみればそれらの属性は本質的には関係ない属性だったりします。

それを解決するために、Alfrescoではアスペクトと呼ばれる機能を使います。アスペクトもタイプと同様に属性セットを定義するものですが、任意のコンテンツ(=任意のタイプのコンテンツ)に対して複数のアスペクトを動的に付け外し可能である点がタイプと異なります。例えば、バージョンを管理したい任意のコンテンツに対してのみバージョン管理アスペクトを付与し、タグ付けを行いたい任意のコンテンツに対してのみタグ付け可能アスペクトを付与する、というような感じです。この機能により、Alfrescoではコンテンツ管理において無駄な属性の増殖や属性セットの体系が複雑化していくという状況(通称:属性ヘル)を避けることができます。


じゃあどうやって定義するの?


カスタム属性を追加するためには、
  1. コンテンツモデルの定義
  2. UIの設定
が必要です。1.でタイプやアスペクトなどの属性セットを定義し、2.でその属性をShare UI上に表示するように設定します。

コンテンツモデルの定義


まず、以下のファイルを作成します。このフォルダには元々custom-model-context.xml.sampleというサンプルファイルがあるので、それをリネームするだけでもOKです。
このファイルは、読み込むコンテンツモデル定義ファイルを指示するものです(以下の例ではcustomModel.xmlを読み込む)。Alfrescoはクラスパス上の*-context.xmlというファイルを自動で読み込むため、この命名規則に従う限り異なる名前でも問題ありません。

<alf_dir>/tomcat/shared/classes/alfresco/extension/custom-model-context.xml
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
    <!-- Registration of new models -->   
    <bean depends-on="dictionaryBootstrap" id="extension.dictionaryBootstrap" parent="dictionaryModelBootstrap">
        <property name="models">
            <list>
                <value>alfresco/extension/customModel.xml</value>
            </list>
        </property>
    </bean>
</beans>

次に、以下のファイルを作成します(ファイル名は前述のファイル内で指定した名前にする必要がある)。このフォルダには元々customModel.xml.sampleというサンプルファイルがあるので、それをリネームして利用しても構いません。このファイルがタイプやアスペクトなどのコンテンツモデル定義の実体となりますが、今回はアスペクトを追加してみましょう。

<alf_dir>/tomcat/shared/classes/alfresco/extension/customModel.xml
<?xml version="1.0" encoding="UTF-8"?>

<!-- Custom Model -->

<!-- Note: This model is pre-configured to load at startup of the Repository.  So, all custom -->
<!--       types and aspects added here will automatically be registered -->

<model name="custom:customModel" xmlns="http://www.alfresco.org/model/dictionary/1.0">

   <!-- Optional meta-data about the model -->   
   <description>Custom Model</description>
   <author></author>
   <version>1.0</version>

   <imports>
      <!-- Import Alfresco Dictionary Definitions -->
      <import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d"/>
      <!-- Import Alfresco Content Domain Model Definitions -->
      <import uri="http://www.alfresco.org/model/content/1.0" prefix="cm"/>
   </imports>

   <!-- Introduction of new namespaces defined by this model -->
   <!-- NOTE: The following namespace custom.model should be changed to reflect your own namespace -->
   <namespaces>
      <namespace uri="custom.model" prefix="custom"/>
   </namespaces>
   
   <aspects>
      <aspect name="custom:reviewable">
         <title>Reviewable</title>
         <properties>
            <property name="custom:reviewer">
               <type>d:text</type>
               <mandatory>false</mandatory>
            </property>
            <property name="custom:reviewDate">
               <type>d:date</type>
               <mandatory>false</mandatory>
            </property>
         </properties>
      </aspect>
   </aspects>
</model>
ここではアスペクトcustom:reviewableが定義しています。テキスト型プロパティcustom:reviewerと日付型プロパティcustom:reviewDateを持ちます。コンテンツモデルの詳細はまた別の機会に説明したいと思いますが、基本的にはData Dictionary Guide - alfrescowikiにほとんどの情報がまとまっています。

UIの設定


次に、UIの設定を行います。UIの設定は以下のファイルで行います(もしshare-config-custom.xmlが存在しない場合は、同じフォルダにあるshare-config-custom.xml.sampleをコピー・リネームして上記ファイルを作成しておきます)。

<alf_dir>/tomcat/shared/classes/alfresco/web-extension/share-config-custom.xml

このファイルに以下の設定を追加します。サンプルファイルをリネームして使う場合は、既に同じconfigセクションが定義されている場合もありますので、その場合はそのセクションに以下の設定を追記してください。
<alfresco-config>
   <config evaluator="node-type" condition="cm:content">
      <forms>
         <form>
            <field-visibility>
               <show id="custom:reviewer" />
               <show id="custom:reviewDate" />
            </field-visibility>
         </form>
      </forms>
   </config>
   <config evaluator="string-compare" condition="DocumentLibrary">
      <aspects>
         <visible>
            <aspect name="custom:reviewable" />
         </visible>
      </aspects>
   </config>
</alfresco-config>
この設定によって、コンテンツのプロパティ表示/編集画面にcustom:reviewableの2プロパティが表示され、アスペクトリストにcustom:reviewableが追加されてアスペクト管理やルールで利用できるようになります。


ためしてみよう!


では、早速カスタム属性を使ってみましょう。まずはAlfrescoを再起動します。これらの設定ファイルをいじった後は再起動が必要になります。

まずは、適当なファイルをアップロードし、コンテンツ詳細画面のアクションメニューから「アスペクト管理」をクリックします。すると以下の画面が表示され、custom:reviewableアスペクトを使えるようになっているのでこれを選択します(表示されない場合は設定に問題があるはずです。alfrescoのログを見てみてください)。


 「変更を反映」をクリックすると、custom:reviewerプロパティとcustom:reviewDateプロパティが利用可能になります。ためしに「プロパティを編集」をクリックして値を入力すると、プロパティ一覧画面にもその値が表示されます(設定が間違ってるとプロパティが表示されません)。



手動じゃちょっと…


さすがに毎回手動でアスペクト付け外しやタイプ変更をするというのは実用的ではないので、実際に使う場合には、Java APIやJavaScript APIを使ってプログラマティックに行ったり、ルール機能を使ってコンテンツ追加時に自動的に行ったりします。ルール機能の使い方は「Alfresco4の使い方 - 基礎編(2) - ルール機能を使ってみよう!」に詳しいですが、例えば以下のような設定を行うと、特定のフォルダ以下に投入されたコンテンツに自動でアスペクトを付与することができます。


今回はタイプとアスペクトを使ったカスタム属性の追加方法について説明しました。今回言及できなかった、プロパティで指定できるデータ型や制約に関することや、プロパティ名の日本語化などの話題は折を見て書いていこうかと思います。


(2013/02/10 追記) 「Alfrescoのカスタム属性(とアスペクト名、タイプ名とか)を日本語化する」を公開しました。

Alfresco4の使い方 - 基礎編(2) - ルール機能を使ってみよう!

こんにちは!大谷です。

今回は、Alfrescoを特徴づける機能の1つであるルール機能について紹介したいと思います。


ルール機能って何?


ルール機能をざっくり一言で表すと、コンテンツの追加・更新・削除をトリガに処理を自動実行する、機能ということになります。例えば、コンテンツ追加時にメールを送信したり、オフィス文書が追加されたらPDF化したりすることが、簡単な設定のみで実現できます。


どういう設定ができるの?


では、実際にはどのような設定ができるのかを見てみましょう。

フォルダに対して設定する

ルールはフォルダに対して設定します。1つのフォルダに複数のルールを設定することも可能で、ル適用するルールの順序も指定できます。
ルールが設定されているフォルダには一律のルールが適用されます。サブフォルダにもルールを適用するか否かは、設定するルールごとに設定可能です。

アクション実行の条件を指定可能

アクション実行の条件と、その条件評価のタイミングを指定することができます。タイミングはアイテム(コンテンツもしくはフォルダ)作成/受入時、アイテム更新時、アイテム削除/流出時から選択可能です(複数選択も可)。アクション実行条件は、当該アイテムについて以下のような条件を複数組み合わせることが可能です。
  • すべてのアイテム
  • 作成日、変更日
  • 作成者、変更者
  • MIMEタイプ
  • エンコーディング
  • 名前
  • タグ、カテゴリ
  • コンテンツタイプ
  • アスペクト
  • プロパティ

実行するアクションを指定可能

実行するアクションを指定することができます。デフォルトでは以下のようなアクションが用意されており、簡単な設定だけで処理を追加することができます。複数のアクションを設定することもできます。
  • アイテムのコピー、移動
  • コンテンツのチェックイン、チェックアウト
  • カテゴリの付与
  • アスペクトの追加、削除
  • 簡易ワークフローの開始
  • Eメールの送信
  • コンテンツの別形式への変換
  • メタデータ抽出
  • ACP形式でのコンテンツインポート
  • コンテンツタイプの変更
  • スクリプトの実行
このうち、スクリプトの実行はとても強力で、自前で用意したスクリプトを使って任意の処理を実行させることができます。これについては別の機会に説明したいと思います。

同期実行・非同期実行を選択可能

時間のかかる処理やリアルタイムで行う必要のない処理を非同期的に実行するよう設定することができます。


どうやって設定するの?


では、実際の設定手順を見ていきましょう。

1. ルールを設定するフォルダのアクションメニューから「ルールの管理」をクリックする。



2. 1件目のルールの場合は「ルールの作成」、2件目以降は「新規のルール」をクリックする。






3. 名前、タイミング、条件、実行アクションを指定し、オプションを適宜指定する。



4. 「作成」をクリックする。

以上でルールの設定は完了です。複数のルールが設定されている場合はドラッグ&ドロップで順序を変更することができます。



設定が終わったら、実際に動作を確認してみましょう。上記スナップショットのように設定すると、Wordファイルがアップロードされた時のみPDFに変換して宛先のフォルダにコピーされるはずです。(PDF変換処理にはOpenOfficeもしくはLibreOfficeが利用されます。インストーラインストールの場合は自動的に連携設定が行われますが、手動インストールの場合は連携のための設定が必要になります)


前述のとおり他にもたくさんのアクションや条件設定ができるので、是非いろいろと試してみてください。なお、スクリプトの実行については次の機会に紹介する予定です。

(2013/01/30 追記) 「Alfresco4の使い方 - 応用編(1) - ルールでスクリプトを実行する」を公開しました。

Wednesday, January 23, 2013

Wikivoyage Offline: Travel guide for Android


I just released Wikivoyage Offline, an Android application that contains guide books for 27,000 destinations.

Instead of carrying a heavy guidebook that shouts "I am a tourist", just use your phone!

Content is downloaded to the phone's SD card, so you can use it offline (useful in case of no Internet or expensive roaming).
The whole world is a 80MB download.

Content is updated every two weeks, from Wikivoyage, the "Wikipedia for tourism information", which graduated from beta last week.

The app is free and open source.

Alfresco4の使い方 - 応用編(1) - ルールでスクリプトを実行する

こんにちは。大谷です。

今回は、ルール機能を使って自動的に任意の処理をキックする方法を紹介したいと思います。ルール機能については以前の記事「Alfresco4の使い方 - 基礎編(2) - ルール機能を使ってみよう!」で紹介していますので、設定方法などはこちらを見てください。


スクリプトの準備


まずはスクリプトを準備し、所定の場所にアップロードします。ここではAlfrescoにデフォルトでついているスクリプトを使います。

1. adminでログインし、画面上部の「リポジトリ」をクリックする。



2. 「リポジトリ」->「データディクショナリ」->「スクリプト」に移動する。



3. backup.js.sampleをこのフォルダにコピーし、プロパティを編集して名前をbackup.jsに変更する。



以上でスクリプトの準備が完了です。もちろん自作のカスタムスクリプトをこのフォルダに登録することもできます。JavaScriptで記述し、ファイル名が*.jsとなっている必要があります。カスタムスクリプト作成の際には、このフォルダにあらかじめ登録されているサンプルスクリプトや、AlfrescoのJavaScript APIリファレンスを参考にしてみてください。


ルールの設定


続いて、スクリプト実行のルールを指定します。詳しくは以前のエントリを参考にしてもらうとして、今回のポイントは、実行アクションを「スクリプトを実行する」に設定し、実行スクリプトとして先ほど格納したスクリプトを指定するということです。



今回の例では、ルールを設定したフォルダにアップロードしたファイルが自動的にBackupフォルダにバックアップされるようになるので、実際に確認してみてください。


まとめ


この仕組みを利用すれば、ファイルの追加や更新をトリガとして独自のビジネスロジックをキックすることができるので、是非試してみてください。
AlfrescoのJavaScript APIを使えばJava APIには敵わないものの、それなりの処理を記述することができるので、てっとり早くAlfresco上にビジネスロジックを実装することができます。

Wednesday, January 9, 2013

Alfresco4の使い方 - 基礎編(1) - コンテンツ管理を始めよう!

こんにちは。大谷です。
本年もどうぞよろしくお願いします。

今回は、Alfresco4の基本的な使い方について紹介させていただこうと思います。Alfrescoを使ってみようと考えている方の多くはコンテンツ管理を目的とされていると思いますので、ここではリポジトリもしくはサイトのドキュメントライブラリについて基本的な機能を見ていくことにしましょう(本記事ではAlfresco 4.2.cを利用しています)。

なお、リポジトリやサイトについては、Alfresco 4.0の使い方 - 準備編(2) - リポジトリとサイトの準備をしようで詳しく説明していますので必要に応じて確認してみてください。


ファイル/フォルダ操作


まずは基本的なファイル/フォルダ操作について見てみましょう。Alfrescoにおけるコンテンツ管理は一般的なファイルサーバ等と同様に、階層構造を持つフォルダとそのフォルダに配置されるファイルからなります。

フォルダのブラウズは画面左のフォルダツリーもしくは画面右の一覧画面のフォルダをクリックすることで行い、フォルダの追加は「新規フォルダ」から行います。



ファイルの追加方法は2通りあります。1つ目は「アップロード」から行う方法で、複数のファイルを一括アップロードすることができます。2つ目はPC上のファイルをブラウザにドラッグ&ドロップする方法で、こちらも複数のファイルを一括でアップロードすることができますが、一部対応していないブラウザ(Internet Explorer 9等、HTML5に完全対応していないもの)があるので注意が必要です。
※ Firefox, Chrome等ではD&Dできます。また、IE10(Release Preview版で確認)でもD&Dできました)



また、ファイル/フォルダのアクションメニューから、ダウンロードやコピー、移動、削除、更新(新規バージョンのアップロード)などを行うことができます。フォルダの場合は「Zip形式でダウンロード」というアクションが表示され、フォルダ内のファイル/フォルダを一括ダウンロードすることができます。
※ Windowsクライアントで「Zip形式でダウンロード」を行うと、MBCSのファイル名が文字化けしてしまう問題があるようです(Macではうまくいきます)

さらに、ファイルのサムネイルもしくはファイル名をクリックすると、コンテンツの詳細情報が表示されます。この画面ではファイルのプレビューやプロパティ情報の確認などを行えます。



タグ機能/カテゴリ機能


いわゆるフォークソノミ、タクソノミに対応する機能です。両者ともコンテンツの分類を行うためのものですが、タグ機能はユーザが自由な文言をタグとしてコンテンツに付与するもの、カテゴリ機能は管理者があらかじめ設定した階層化されたカテゴリをコンテンツに付与するものです。

タグ付けは、コンテンツ一覧画面もしくはプロパティ編集画面から行います。コンテンツ一覧画面ではタグをインライン編集することができます(以下のスナップショット)。
タグ付けを行うと、画面左側のタグ欄に非同期的に反映され、付けられているタグとその件数が表示されます。このタグをクリックすると、当該のタグが付与されたコンテンツの一覧が表示されます。もちろん、検索時にはタグも検索対象となります。



カテゴリは、デフォルトの状態では利用することができません。カテゴリを利用するためにはコンテンツに「分類対象」アスペクトを付与する必要があります。自動的にアスペクトを付与する一番簡単な方法はルール機能を用いる方法です。以下でその手順を説明します。

1. カテゴリを付与するコンテンツをアップロードするルートのフォルダで「ルールの管理」をクリックする。


2. 「ルールの作成」をクリックする。


3. 以下のように設定して「作成」をクリックする。


以上で、コンテンツ追加時に「分類対象」アスペクトを自動的に付与し、カテゴリを利用可能にする設定は完了です。さっそくこのフォルダにコンテンツを追加してみてください。一覧画面にカテゴリが表示され、プロパティ編集画面でカテゴリが編集できるようになっているはずです。





画面左側のカテゴリ欄でカテゴリを選択すると、そのカテゴリが付与されたコンテンツの一覧が表示されます。フォルダ階層とは異なる、カテゴリ階層のビューを使ってコンテンツにアクセスすることができます。もちろん複数のカテゴリが付与されたコンテンツは、カテゴリ階層の複数の場所に表示されます。



お気に入り、いいね、コメント…


その他、ブックマーク的に利用できる「お気に入り」や、ソーシャル的な要素である「いいね!」や「コメント」などもあります。

「お気に入り」 をクリックするとコンテンツに星マークが表示され、画面左の「お気に入り」やダッシュボードにお気に入りコンテンツの一覧を表示することができます。解除する場合は星マークを再度クリックしてください。

「いいね!」はいわゆる巷のWebサービスのlikeと同様の機能で、「いいね!」をクリックするだけです。Alfrescoではこの「いいね!」 の数が人気順のソートに反映されます(以下のスナップショット)。



また、コンテンツ一覧画面の「コメント」もしくは、コンテンツ詳細画面の「コメントの追加」をクリックしてコメントを追加します。コンテンツ詳細画面でコメントを確認することができ、コンテンツに関するちょっとしたディスカッションなどに利用できます。


他にもあるけど…


他にもたくさんの機能がありますが、まずは基本的な機能を見てみました。また折を見てAlfrescoに備わる強力な機能を紹介していきたいと思いますので引き続きよろしくお願いします。

Wednesday, December 19, 2012

.NETからAlfresco API につなぐ(その1)

こんにちは、杉本です。

いつもはこっちで書いてますが、勉強会の報告なのでこちらで書かせてもらいます。こちらでははじめまして。

ぼくは普段 .NET さんとお仕事をしているので、最近 Alfresco をぜんぜん触っていないのですが、今回は Alfresco とちょっと連携するようなコードを書いてみることにしました。

Alfresco は文書管理を行うための巨大な仕組みで、内部には RDB をつかっているわけですが、 API を通すことで Alfresco そのものを文書データベース、として扱うのも良いよね、と思っています。「文書管理の仕組み」を導入するとなるとなんだか大袈裟な気がしますが、別システムでファイルを保存するストアを文書管理 DB にする、というような視点で別システムのサブシステムとして見ることもできるんじゃないでしょうか。

AlfrescoのAPIといえば、普通は WebScript API を使いますね。ところが今回はあえてのSOAPで繋いでみます。


ちなみに、 Alfresco の Wiki をみると、Web Services という項目のところには、

Please note that this API has been superceded by CMIS (specifically, the CMIS SOAP binding). It's use is no longer recommended.

とあって、Web Service はもう使われなくなっていくことが書かれています(そもそも SOAP が……)

ただ、今回はちょっと簡単に実験したかったので、すでに消滅しつつある SOAP でやってみることにしました。続編として他のアクセス方法でもやっていきたいと思います。

環境としては手もとにあるものをそのままつかったので、Visual Studio 2012 で、.NET Framework 4.5 の環境下でやっています。たいしたことはしてないので、おそらく2010、4.0 の組み合わせでもいけると思います。

.NET では通信フレームワークとして WCF というのがあります。今回SOAPでお気軽にやってしまったのにはこれがあって、Web Service だと WDSL が型情報を持っているので戻ってくるオブジェクトのクラスを自動生成してくれるんですよね。 JSON からクラスを推測してくれるライブラリもあるにはありますが、標準で出来る以上たいへんお手軽なので、今回はWeb Serviceをつかって実験したのでした。

さて、WDSLの場所はこれです。

http://<servername:PORT>/alfresco/api/<サービス名>Service?wsdl
サービス名には Repository とか Content とかが入ります。

まずおもむろに Visual Studio 2012 で新規ソリューションとプロジェクトを作成して、「サービス参照の追加」を行います。

サービス参照追加画面がでるので、 URL を指定して、「探索」するとサービスのところにサービス一覧が出るので、それを選択、 OK をおせば完了です。簡単だ!(名前空間は適当に)


つづいて、 WCF で通信する際の設定です。app.config右クリックから[WCF構成の編集]を選べば UI で設定できます(app.configを直接編集しても良いです)昔はこんなのなかったんじゃなかったかなあ。便利だなあ。

[エンドポイント]でサービスを選択、[全般]タブ、項目 Binding が basicHttpBinding (デフォルトのまま)であることを確認します。

[バインド]でサービスを選択[セキュリティ]タブ、[(全般)]の下の項目 mode を TransportWithMessageCredential にセットします。

[MessageSecurityプロパティ]の下の項目 MessageClientCredentialType を UserName にセットします。

AuthenticationService はセキュリティ設定不要、 HTTP で接続します。
それ以外はセキュリティ設定が必要、HTTPSで接続します。

app.configは

    
        
            
                
                
                  
                    
                  
                
              
                
                  
                
              
            
        
        
            
            
            
        
    

こんな感じになりました。

次にコードを書いていきますが、今回はローカルに立てたサーバに繋ぐので SSL とかの処理をバイパスすることにします。


        private bool OnRemoteCertificateValidationCallback(Object sender, X509Certificate certificate, X509Chain chain,  SslPolicyErrors sslPolicyErrors) {
            return true; 
        }

こんなコードを書き、
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(OnRemoteCertificateValidationCallback);
こんな風に呼べばOKです。

今回はリポジトリサービス、コンテンツサービスを使ってリポジトリやコンテンツにアクセスしてみました。コードを全部載せてしまいます。


using System;
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Windows;
using AuthenticationService = WpfApplication1.Alfresco.AuthenticationService;
using ContentService = WpfApplication1.Alfresco.ContentService;
using RepositoryService = WpfApplication1.Alresco.RepositoryService;

namespace WpfApplication1 {
    public partial class App : Application {
        private void Application_Startup(object sender, StartupEventArgs e) {
            ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(OnRemoteCertificateValidationCallback);

            var authClient = new AuthenticationService.AuthenticationServiceSoapPortClient();
            var ticket = authClient.startSession("takuma.sugimoto", "takuma");


            var repoClient = new RepositoryService.RepositoryServiceSoapPortClient();
            repoClient.ClientCredentials.UserName.UserName = ticket.username;
            repoClient.ClientCredentials.UserName.Password = ticket.ticket;
            var store = repoClient.getStores().FirstOrDefault(p => p.address == "SpacesStore");
            var query = new RepositoryService.Query() {
                statement = "ID:\"workspace://SpacesStore/3763112e-e36f-44de-9992-ab122350bc21\"",
                language = "lucene",
            };
            var result = repoClient.query(new RepositoryService.QueryConfiguration(), store, query, true);
            var resultNode = result.resultSet.rows.FirstOrDefault();
            var path = resultNode.columns.FirstOrDefault(p => p.name == "{http://www.alfresco.org/model/content/1.0}path").value;
            var name = resultNode.columns.FirstOrDefault(p => p.name == "{http://www.alfresco.org/model/content/1.0}name").value;

            var contentClient = new ContentService.ContentServiceSoapPortClient();
            contentClient.ClientCredentials.UserName.UserName = ticket.username;
            contentClient.ClientCredentials.UserName.Password = ticket.ticket;
            var reference = new ContentService.Reference(){
                store =  new ContentService.Store(){scheme = "workspace",address ="SpacesStore"},
                uuid = resultNode.node.id,
            };
            var predicate = new ContentService.Predicate() {Items = new ContentService.Reference[] { reference }};
            var contents = contentClient.read(predicate, "{http://www.alfresco.org/model/content/1.0}content");
            
            var content = contents.FirstOrDefault();
            var url = content.url + "?ticket=" + ticket.ticket;
            
            var req = WebRequest.Create(url);
            using (var rsp = req.GetResponse()) {
                var stm = rsp.GetResponseStream();
                if (stm != null) {
                    using (stm)
                    using (var reader = new StreamReader(stm))
                    using (var writer = File.OpenWrite(@"D:\Users\takuma.sugimoto\Desktop\temp\" + name)) {
                        var count = 0;
                        var buffer = new byte[4096];
                        do {
                            count = stm.Read(buffer, 0, buffer.Length);
                            writer.Write(buffer, 0, count);
                        } while (count != 0);

                    }
                }

            }
        }

        private bool OnRemoteCertificateValidationCallback(Object sender, X509Certificate certificate, X509Chain chain,  SslPolicyErrors sslPolicyErrors) {
            return true; 
        }
    }
}

ID を直接していしてダウンロードしているというサンプルのためのサンプルコードと言った内容ですが、ご容赦ください。ここにポイントがいくつかあります。

  • WCF で自動生成した場合、サービスごとに型が出来てしまうので、おなじリポジトリを指すクラスが別のものになってしまう。
  • ファイル実体のダウンロード用 Web Service はないので、認証済みのトークンをダウンロード URL につけたURLを直にたたいてダウンロードしてくる

こんなところです。最初の問題は自分で型を作ることも出来るのでそれで解決しますが、それをやるのであれば Web Service でやりはじめた意味があまりないので、自分で型クラスを作るのは次回以降、Web Scriptの API と連携するところで試すことにしましょう。

後者も WebScript であれば専用の API があるようです。ただ、このダウンロード URL を直に叩くというやり方も簡単ではあるので、やりかたとして頭に入れておくと良さそうです。

ハイ、そんなわけで、わざわざフェードアウトしつつある技術を使って Alfresco にアクセスしてみました。技術自体は古くてもかなり簡単にアクセスできるように作られていることが分かってもらえたかと思います。今回はここまで。(いつになるかわかりませんが)次回は Web Script の API と CMIS の API で接続することを試してみたいと思います。