ここでは、Multi Site Manager の機能を拡張する方法について説明します。
- MSM Java API の主な構成要素について学習します。
- ロールアウト設定で使用できる、新しい同期アクションを作成します。
- サイトを作成ウィザードで「章」ステップを削除します。
- デフォルトの言語コードと国コードを変更します。
注意:
このページは、コンテンツの再利用:Multi Site Managerと併せて読んでください。
警告:
Multi Site Manager とその API は Web サイトのオーサリング時に使用するものなので、オーサー環境での使用のみを目的としています。
主要な MSM API オブジェクトは、次のような関係にあります(使用される用語も参照してください)。

-
Blueprint
Blueprint(ブループリント設定)は、ライブコピーのコンテンツ継承元となるページを指定します。 -
LiveRelationship
LiveRelationship は、ライブコピーブランチのリソースと、同等のソースまたはブループリントのリソースとの関連付け(関係)を指定します。
- この関係は、継承およびロールアウトの実現時に使用されます。
- LiveRelationship オブジェクトは、ロールアウト設定(RolloutConfig)、LiveCopy および関係に関連付けられた LiveStatus オブジェクトへのアクセス(参照)を可能にします。
- 例えば、/content/geometrixx にあるソースまたはブループリントから、/content/copy にライブコピーが作成されるとします。この場合、リソース /content/geometrixx/en/jcr:content と /content/copy/en/jcr:content が関係を形成します。
カスタム同期アクションを作成して、ロールアウト設定と併用します。インストール済みのアクションが特定のアプリケーション要件を満たさない場合に同期アクションを作成します。同期アクションを作成するには、次の 2 つのクラスを作成します。
- アクションを実行する com.day.cq.wcm.msm.api.LiveAction インターフェイスの実装。
- com.day.cq.wcm.msm.api.LiveActionFactory インターフェイスを実装し、LiveAction クラスのインスタンスを作成する OSGi コンポーネント。
LiveActionFactory は、指定された設定の LiveAction クラスのインスタンスを作成します。
- LiveAction クラスには次のメソッドが含まれます。
- getName:アクション名を返します。この名前は、ロールアウト設定などで、アクションを参照するために使用します。
- execute:アクションのタスクを実行します。
- LiveActionFactory クラスには次のメンバーが含まれます。
- LIVE_ACTION_NAME:関連付けられた LiveAction の名前を格納するフィールド。この名前は、LiveAction クラスの getName メソッドが返す値と一致する必要があります。
- createAction:LiveAction のインスタンスを作成します。オプションの Resource パラメーターを使用して、設定情報を提供できます。
- createsAction:関連付けられた LiveAction の名前を返します。
リポジトリ内の LiveAction 設定ノードを使用して、LiveAction インスタンスの実行時動作に影響を与える情報を保存します。LiveAction 設定を保存するリポジトリ内のノードは、実行時に LiveActionFactory オブジェクトに使用できます。そのため、設定ノードにプロパティを追加し、必要に応じて LiveActionFactory 実装内で使用することができます。
例えば、LiveAction にはブループリント作成者の名前を保存する必要があります。設定ノードのプロパティには、情報を保存するブループリントページのプロパティ名が含まれます。実行時、LiveAction は設定からプロパティ名を取得して、そのプロパティ値を取得します。
LiveActionFactory.createAction メソッドのパラメーターは、Resource オブジェクトです。この Resource オブジェクトは、ロールアウト設定内のこのライブアクションの cq:LiveSyncAction ノードを表します。詳しくはロールアウト設定の作成を参照してください。通常どおり、設定ノードを使用する場合は、ValueMap オブジェクトに適応させる必要があります。
public LiveAction createAction(Resource resource) throws WCMException { ValueMap config; if (resource == null || resource.adaptTo(ValueMap.class) == null) { config = new ValueMapDecorator(Collections.<String, Object>emptyMap()); } else { config = resource.adaptTo(ValueMap.class); } return new MyLiveAction(config, this); }
LiveAction オブジェクトの execute メソッドのパラメーターとして、以下のオブジェクトを指定します。
- ライブコピーのソースを表す Resource オブジェクト。
- ライブコピーのターゲットを表す Resource オブジェクト。
- ライブコピーの LiveRelationship オブジェクト。
- 値 autoSave は、LiveAction がリポジトリに対しておこなわれた変更を保存する必要があることを示します。
- 値 reset は、ロールアウトのリセットモードを示します。
これらのオブジェクトから、LiveCopy に関するすべての情報を取得できます。Resource オブジェクトを使用して、ResourceResolver オブジェクト、Session オブジェクトおよび Node オブジェクトも取得できます。これらのオブジェクトは、リポジトリコンテンツの操作に役立ちます。
以下のコードの先頭行で、source はソースページの Resource オブジェクトです。
ResourceResolver resolver = source.getResourceResolver(); Session session = resolver.adaptTo(javax.jcr.Session.class); Node sourcenode = source.adaptTo(javax.jcr.Node.class);
注意:
Resource 引数には、null、または NonExistingResource オブジェクトなどの Node オブジェクトに適応しない Resource オブジェクトを指定できます。
インストールされるロールアウト設定がアプリケーションの要件を満たさない場合は、ロールアウト設定を作成します。
- ロールアウト設定を作成します。
- ロールアウト設定に同期アクションを追加します。
ブループリントまたはライブコピーページでロールアウト設定を指定すると、新しいロールアウト設定が使用可能になります。
注意:
ロールアウトのカスタマイズのベストプラクティスも参照してください。
-
クラシック UI でツールコンソールを開きます(例:http://localhost:4502/miscadmin#/etc)。
注意:
タッチ操作向け UI では、レールエントリのツール/運営/設定を使用してクラシック UI のツールコンソールに移動できます。
-
ロールアウトの設定ダイアログで、「トリガーを同期」を選択して、ロールアウトを発生させるアクションを定義します。
ロールアウト設定は、/etc/msm/rolloutconfigs ノードの下に保存されます。タイプ cq:LiveSyncAction の子ノードを追加して、同期アクションをロールアウト設定に追加します。同期アクションノードの順序によって、アクションが実行される順序が決まります。
-
CRXDE Lite を開きます。例:http://localhost:4502/crx/de
-
「作成」をクリックして、「ノードを作成」をクリックします。次のノードプロパティを設定して、「OK」をクリックします。
- 名前:同期アクションのノード名。名前は、同期アクションの下の表の「アクション名」と同じである必要があります。例えば、contentCopy または workflow です。
- タイプ:cq:LiveSyncAction
この節の手順を実行して LiveActionFactory を作成し、ロールアウト設定で使用します。この手順では、Maven と Eclipse を使用して、LiveActionFactory を作成およびデプロイします。
- Maven プロジェクトを作成し、Eclipse に読み込みます。
- POM ファイルに依存関係を追加します。
- LiveActionFactory インターフェイスを実装し、OSGi バンドルをデプロイします。
- ロールアウト設定を作成します。
- ライブコピーを作成します。
GitHub のコード
このページのコードは GitHub にあります
- GitHub の experiencemanager-java-msmrollout プロジェクトを開きます
- プロジェクトを ZIP ファイルとしてダウンロードします
以下の手順では、adobe-public プロファイルを Maven 設定ファイルに追加している必要があります。
- adobe-public プロファイルについては、コンテンツパッケージ Maven プラグインの取得を参照してください。
- Maven 設定ファイルについては、Maven の設定リファレンスを参照してください。
-
<dependency> <groupId>com.day.cq.wcm</groupId> <artifactId>cq-msm-api</artifactId> <version>5.6.2</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.sling</groupId> <artifactId>org.apache.sling.api</artifactId> <version>2.4.3-R1488084</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.day.cq.wcm</groupId> <artifactId>cq-wcm-api</artifactId> <version>5.6.6</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.sling</groupId> <artifactId>org.apache.sling.commons.json</artifactId> <version>2.0.6</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.day.cq</groupId> <artifactId>cq-commons</artifactId> <version>5.6.4</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.sling</groupId> <artifactId>org.apache.sling.jcr.jcr-wrapper</artifactId> <version>2.0.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.day.cq</groupId> <artifactId>cq-commons</artifactId> <version>5.6.4</version> <scope>provided</scope> </dependency>
-
<dependency> <groupId>com.day.cq.wcm</groupId> <artifactId>cq-msm-api</artifactId> </dependency> <dependency> <groupId>org.apache.sling</groupId> <artifactId>org.apache.sling.api</artifactId> </dependency> <dependency> <groupId>com.day.cq.wcm</groupId> <artifactId>cq-wcm-api</artifactId> </dependency> <dependency> <groupId>org.apache.sling</groupId> <artifactId>org.apache.sling.commons.json</artifactId> </dependency> <dependency> <groupId>com.day.cq</groupId> <artifactId>cq-commons</artifactId> </dependency> <dependency> <groupId>org.apache.sling</groupId> <artifactId>org.apache.sling.jcr.jcr-wrapper</artifactId> </dependency> <dependency> <groupId>com.day.cq</groupId> <artifactId>cq-commons</artifactId> </dependency>
次の LiveActionFactory クラスは、ソースページとターゲットページに関するメッセージをログに記録し、ソースノードからターゲットノードに cq:lastModifiedBy プロパティをコピーする LiveAction を実装します。ライブアクション名は exampleLiveAction です。
-
package com.adobe.example.msm; import java.util.Collections; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Property; import org.apache.felix.scr.annotations.Service; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; import org.apache.sling.api.resource.ValueMap; import org.apache.sling.api.wrappers.ValueMapDecorator; import org.apache.sling.commons.json.io.JSONWriter; import org.apache.sling.commons.json.JSONException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.jcr.Node; import javax.jcr.RepositoryException; import javax.jcr.Session; import com.day.cq.wcm.msm.api.ActionConfig; import com.day.cq.wcm.msm.api.LiveAction; import com.day.cq.wcm.msm.api.LiveActionFactory; import com.day.cq.wcm.msm.api.LiveRelationship; import com.day.cq.wcm.api.WCMException; @Component(metatype = false) @Service public class ExampleLiveActionFactory implements LiveActionFactory<LiveAction> { @Property(value="exampleLiveAction") static final String actionname = LiveActionFactory.LIVE_ACTION_NAME; public LiveAction createAction(Resource config) { ValueMap configs; /* Adapt the config resource to a ValueMap */ if (config == null || config.adaptTo(ValueMap.class) == null) { configs = new ValueMapDecorator(Collections.<String, Object>emptyMap()); } else { configs = config.adaptTo(ValueMap.class); } return new ExampleLiveAction(actionname, configs); } public String createsAction() { return actionname; } /************* LiveAction ****************/ private static class ExampleLiveAction implements LiveAction { private String name; private ValueMap configs; private static final Logger log = LoggerFactory.getLogger(ExampleLiveAction.class); public ExampleLiveAction(String nm, ValueMap config){ name = nm; configs = config; } public void execute(Resource source, Resource target, LiveRelationship liverel, boolean autoSave, boolean isResetRollout) throws WCMException { String lastMod = null; log.info(" *** Executing ExampleLiveAction *** "); /* Determine if the LiveAction is configured to copy the cq:lastModifiedBy property */ if ((Boolean) configs.get("repLastModBy")){ /* get the source's cq:lastModifiedBy property */ if (source != null && source.adaptTo(Node.class) != null){ ValueMap sourcevm = source.adaptTo(ValueMap.class); lastMod = sourcevm.get(com.day.cq.wcm.api.NameConstants.PN_PAGE_LAST_MOD_BY, String.class); } /* set the target node's la-lastModifiedBy property */ Session session = null; if (target != null && target.adaptTo(Node.class) != null){ ResourceResolver resolver = target.getResourceResolver(); session = resolver.adaptTo(javax.jcr.Session.class); Node targetNode; try{ targetNode=target.adaptTo(javax.jcr.Node.class); targetNode.setProperty("la-lastModifiedBy", lastMod); log.info(" *** Target node lastModifiedBy property updated: {} ***",lastMod); }catch(Exception e){ log.error(e.getMessage()); } } if(autoSave){ try { session.save(); } catch (Exception e) { try { session.refresh(true); } catch (RepositoryException e1) { e1.printStackTrace(); } e.printStackTrace(); } } } } public String getName() { return name; } /************* Deprecated *************/ @Deprecated public void execute(ResourceResolver arg0, LiveRelationship arg1, ActionConfig arg2, boolean arg3) throws WCMException { } @Deprecated public void execute(ResourceResolver arg0, LiveRelationship arg1, ActionConfig arg2, boolean arg3, boolean arg4) throws WCMException { } @Deprecated public String getParameterName() { return null; } @Deprecated public String[] getPropertiesNames() { return null; } @Deprecated public int getRank() { return 0; } @Deprecated public String getTitle() { return null; } @Deprecated public void write(JSONWriter arg0) throws JSONException { } } }
-
mvn -PautoInstallPackage clean install
AEM の error.log ファイルに、バンドルが開始されたことが記録されます。
例えば、http://localhost:4502/system/console/status-slinglogs は次のようになります。
13.08.2013 14:34:55.450 *INFO* [OsgiInstallerImpl] com.adobe.example.msm.MyLiveActionFactory-bundle BundleEvent RESOLVED 13.08.2013 14:34:55.451 *INFO* [OsgiInstallerImpl] com.adobe.example.msm.MyLiveActionFactory-bundle BundleEvent STARTING 13.08.2013 14:34:55.451 *INFO* [OsgiInstallerImpl] com.adobe.example.msm.MyLiveActionFactory-bundle BundleEvent STARTED 13.08.2013 14:34:55.453 *INFO* [OsgiInstallerImpl] com.adobe.example.msm.MyLiveActionFactory-bundle Service [com.adobe.example.msm.ExampleLiveActionFactory,2188] ServiceEvent REGISTERED 13.08.2013 14:34:55.454 *INFO* [OsgiInstallerImpl] org.apache.sling.audit.osgi.installer Started bundle com.adobe.example.msm.MyLiveActionFactory-bundle [316]
作成した LiveActionFactory を使用する MSM ロールアウト設定を作成します。
- 次のプロパティと標準の手順を使用して、ロールアウト設定を作成および設定します。
- 作成:
- タイトル:ロールアウト設定例
- 名前: examplerolloutconfig
- RolloutConfig テンプレートを使用
- 編集:
- トリガーを同期:アクティベート時
- 作成:
ロールアウト設定を使用して、Geometrixx デモサイトの english/Products ブランチのライブコピーを作成します。
- ソース:/content/geometrixx/en/products
- ロールアウト設定:ロールアウト設定例
ソースブランチの Products(english)ページをアクティベートし、LiveAction クラスが生成するログメッセージを監視します。
16.08.2013 10:53:33.055 *INFO* [Thread-444535] com.adobe.example.msm.ExampleLiveActionFactory$ExampleLiveAction *** ExampleLiveAction has been executed.*** 16.08.2013 10:53:33.055 *INFO* [Thread-444535] com.adobe.example.msm.ExampleLiveActionFactory$ExampleLiveAction *** Target node lastModifiedBy property updated: admin ***
場合によっては、サイトを作成ウィザードで、「章」の選択は必要ありません(「言語」の選択は必要です)。デフォルトの Geometrixx ブループリントでこの手順を削除するには、以下の手順を実行します。
- CRXDE Lite で、ノード
/etc/blueprints/geometrixx/jcr:content/dialog/items/tabs/items/tab_chap を削除します。 - /libs/wcm/msm/templates/blueprint/defaults/livecopy_tab/items に移動して、新しいノードを作成します。
- Name = chapters; Type = cq:Widget.
- 以下のプロパティを新しいノードに追加します。
- Name =name; Type = String; Value = msm:chapterPages
- Name = value; Type = String; Value = all
- Name = xtype; Type = String; Value = hidden
AEM では、言語コードと国コードのデフォルトセットを使用します。
- デフォルトの言語コードは、ISO-639-1 で定義されている小文字 2 文字のコードです。
- デフォルトの国コードは、ISO 3166 で定義されている小文字または大文字 2 文字のコードです。
MSM は、保存されている言語コードと国コードのリストを使用して、ページの言語バージョン名に関連付けられている国名を判断します。必要に応じて、リストの次の要素を変更できます。
- 言語タイトル
- 国名
- (特に en、de などのコードの)言語に対するデフォルトの国
言語のリストは、/libs/wcm/core/resources/languages ノードの下に保存されています。各子ノードは、言語または言語-国を表します。
- ノード名は、言語コード(en または de など)や言語_国コード(en_us または de_ch など)です。
- ノードの language プロパティには、そのコードが表す言語の正式名称が格納されます。
- ノードの country プロパティには、そのコードが表す国の正式名称が格納されます。
- ノード名が言語コードのみ(en など)で構成されている場合、country プロパティは * で、追加の defaultCountry プロパティに使用する国を示す言語-国のコードが格納されます。

-
Web ブラウザーで CRXDE Lite を開きます。例:http://localhost:4502/crx/de
例えば、次の 2 つのページプロパティを追加する場合は、
- 連絡先電子メール:
- このプロパティは国(またはブランドなど)によって異なるので、ロールアウトする必要はありません。
- キービジュアルのスタイル:
- プロジェクトの要件としては、このプロパティは(通常は)すべての国(またはブランドなど)に共通なので、ロールアウトする必要があります。
次のことを保証する必要があります。
- 連絡先電子メール:
- このプロパティを、ロールアウトするプロパティから除外します。詳しくは、プロパティとノードタイプの同期からの除外を参照してください。
- このプロパティを、ロールアウトするプロパティから除外します。詳しくは、プロパティとノードタイプの同期からの除外を参照してください。
- キービジュアルのスタイル:
- 継承がキャンセルされている場合以外はタッチ操作向け UI でこのプロパティを編集できないようにし、さらに継承を回復できるようにします。継承を制御するには、関連付けの状態をトグル切り替えするチェーンリンクまたはチェーン解除リンクをクリックします。
ページプロパティをロールアウトの対象にするかどうか(したがって編集時に継承をキャンセルまたは復元するかどうか)は、次のダイアログプロパティで制御されます。
- cq-msm-lockable
- このプロパティは、タッチ操作向け UI ダイアログの項目に適用されます。
- ダイアログ内にチェーンリンクシンボルを作成します。
- 継承がキャンセルされている(チェーンリンクが解除されている)場合は、編集のみ可能です。
- タイプ:String
- 値:対象のプロパティ名を保持します(また、name プロパティの値と比較できます)。例として、
/libs/foundation/components/page/cq:dialog/content/items/tabs/items/basic/items/column/items/title/items/title を参照してください。
- このプロパティは、タッチ操作向け UI ダイアログの項目に適用されます。
cq-msm-lockable が定義されている場合は、次の方法でチェーンの解除またはクローズを MSM と連携できます。
- cq-msm-lockable の値が
- 相対指定の場合(例:myProperty または ./myProperty)
- プロパティを cq:propertyInheritanceCancelled に追加および削除します。
- ダイアログのロジックと異なり、MSM は深いプロパティ(./image/fileReference など)を操作しません。チェーンがオープンされている場合、ページのロールアウトは ./image/fileReference を上書きします。image ノードのロールアウトは、親ノードまで遡って cq:propertyInheritanceCancelled を確認しないからです。
- 絶対指定の場合(例:/image)
- チェーンを解除すると、cq:LiveSyncCancelled mixin が ./image に追加され、cq:isCancelledForChildren が true に設定されて、継承がキャンセルされます。
- チェーンを閉じると、継承が元に戻ります。
- 相対指定の場合(例:myProperty または ./myProperty)
注意:
継承を再度有効にしても、ライブコピーページのプロパティはソースのプロパティとは自動的には同期されません。必要な場合は、手動で同期をリクエストできます。