null Service Wrapper開発をLiferay7.4と7.1で比較してみた

はじめに

こんにちは、ヴァレリーです。

当記事では、Liferay7.4とLiferay7.1のサービスオーバーライド(サービスラッパー)の開発についてお伝えします。7.4の開発を主な内容としつつ、両方を比べた感想をお伝えできればと思います。

 

サービスラッパーとは?

Liferayサービスメソッドが呼び出される度に、実際に動作の実行をしてくれるのがサービスラッパーです。サービスラッパーにカスタムロジックを追加することで、Liferayの基幹コードに干渉せずに、サービスを安全に拡張することが可能になります。

使用する開発ツールはEclipse + Liferay IDEで、比較対象となるLiferayバージョンはliferay-dxp-7.4.13.u7とliferay-dxp-7.1.10.7-sp7です。

例として、ブログ記事を追加する時に呼び出されるaddEntryメソッドをServiceWrapperからオーバーライドします。シグネチャが異なるaddEntryメソッド複数ありました。UIでブログ追加の操作をした際に、その中のどれが呼び出されるか識別するために、 それぞれのメソッドにコンソールに出力させるコードを追加してみました。コードは以下をご参照ください。

 

サンプルコード

BlogLocalServiceOverride.java

package com.test.blog.override;

import com.liferay.blogs.model.BlogsEntry;
import com.liferay.blogs.service.BlogsEntryLocalServiceWrapper;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.service.ServiceContext;
import com.liferay.portal.kernel.service.ServiceWrapper;
import com.liferay.portal.kernel.servlet.taglib.ui.ImageSelector;

import java.util.Date;

import org.osgi.service.component.annotations.Component;

/**
 * @author tan.valerie
 */
@Component(
	immediate = true,
	property = {
	},
	service = ServiceWrapper.class
)
public class BlogLocalServiceOverride extends BlogsEntryLocalServiceWrapper {


	@Override
	public BlogsEntry addEntry(long userId, String title, String content, Date displayDate,
			ServiceContext serviceContext) throws PortalException {
		// TODO Auto-generated method stub
		System.out.println("inside addEntry1");
		return super.addEntry(userId, title, content, displayDate, serviceContext);
	}

	@Override
	public BlogsEntry addEntry(long userId, String title, String content, ServiceContext serviceContext)
			throws PortalException {
		
		System.out.println("inside addEntry2");
		// TODO Auto-generated method stub
		return super.addEntry(userId, title, content, serviceContext);
	}

	@Override
	public BlogsEntry addEntry(long userId, String title, String subtitle, String description, String content,
			Date displayDate, boolean allowPingbacks, boolean allowTrackbacks, String[] trackbacks,
			String coverImageCaption, ImageSelector coverImageImageSelector, ImageSelector smallImageImageSelector,
			ServiceContext serviceContext) throws PortalException {
		// TODO Auto-generated method stub
		System.out.println("inside addEntry3");
		return super.addEntry(userId, title, subtitle, description, content, displayDate, allowPingbacks, allowTrackbacks,
				trackbacks, coverImageCaption, coverImageImageSelector, smallImageImageSelector, serviceContext);
	}

	@Override
	public BlogsEntry addEntry(long userId, String title, String subtitle, String description, String content,
			int displayDateMonth, int displayDateDay, int displayDateYear, int displayDateHour, int displayDateMinute,
			boolean allowPingbacks, boolean allowTrackbacks, String[] trackbacks, String coverImageCaption,
			ImageSelector coverImageImageSelector, ImageSelector smallImageImageSelector, ServiceContext serviceContext)
			throws PortalException {
		// TODO Auto-generated method stub
		System.out.println("inside addEntry4");
		return super.addEntry(userId, title, subtitle, description, content, displayDateMonth, displayDateDay, displayDateYear,
				displayDateHour, displayDateMinute, allowPingbacks, allowTrackbacks, trackbacks, coverImageCaption,
				coverImageImageSelector, smallImageImageSelector, serviceContext);
	}

	@Override
	public BlogsEntry addEntry(String externalReferenceCode, long userId, String title, String subtitle,
			String urlTitle, String description, String content, Date displayDate, boolean allowPingbacks,
			boolean allowTrackbacks, String[] trackbacks, String coverImageCaption,
			ImageSelector coverImageImageSelector, ImageSelector smallImageImageSelector, ServiceContext serviceContext)
			throws PortalException {
		// TODO Auto-generated method stub
		System.out.println("inside addEntry5");
		System.out.println("external reference code =" + externalReferenceCode);
		System.out.println("companyid=" + serviceContext.getCompanyId());
		System.out.println("command=" + serviceContext.getCommand());

		if(title.length()>20) {
			System.out.println("title too long, length = " + title.length());
			throw new PortalException("Please provide a shorter title name");
		}
		return super.addEntry(externalReferenceCode, userId, title, subtitle, urlTitle, description, content, displayDate,
				allowPingbacks, allowTrackbacks, trackbacks, coverImageCaption, coverImageImageSelector,
				smallImageImageSelector, serviceContext);
	}

	@Override
	public BlogsEntry addEntry(String externalReferenceCode, long userId, String title, String subtitle,
			String urlTitle, String description, String content, int displayDateMonth, int displayDateDay,
			int displayDateYear, int displayDateHour, int displayDateMinute, boolean allowPingbacks,
			boolean allowTrackbacks, String[] trackbacks, String coverImageCaption,
			ImageSelector coverImageImageSelector, ImageSelector smallImageImageSelector, ServiceContext serviceContext)
			throws PortalException {
		// TODO Auto-generated method stub
		System.out.println("month: " + displayDateMonth + "day: " + displayDateDay);
		System.out.println("companyid=" + serviceContext.getCompanyId());
		System.out.println("inside addEntry6");
		return super.addEntry(externalReferenceCode, userId, title, subtitle, urlTitle, description, content, displayDateMonth,
				displayDateDay, displayDateYear, displayDateHour, displayDateMinute, allowPingbacks, allowTrackbacks,
				trackbacks, coverImageCaption, coverImageImageSelector, smallImageImageSelector, serviceContext);
	}

	public BlogLocalServiceOverride() {
		super(null);
	}
	

}

実行結果を見ると、addEntry6とaddentry5が呼び出されていることが分りました。

なぜ二つあるのかについて、ソースコードのBlogsEntryLocalServiceImplを参考にしたら、ブログのdisplayDateがaddEntry6のメソッドで生成されてaddEntry5のパラメーターに取り込まれる模様です。

 

BlogsEntryLocalServiceImpl.java

    @Override
	public BlogsEntry addEntry(
			String externalReferenceCode, long userId, String title,
			String subtitle, String urlTitle, String description,
			String content, int displayDateMonth, int displayDateDay,
			int displayDateYear, int displayDateHour, int displayDateMinute,
			boolean allowPingbacks, boolean allowTrackbacks,
			String[] trackbacks, String coverImageCaption,
			ImageSelector coverImageImageSelector,
			ImageSelector smallImageImageSelector,
			ServiceContext serviceContext)
		throws PortalException {

		User user = _userLocalService.getUser(userId);

		Date displayDate = _portal.getDate(
			displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
			displayDateMinute, user.getTimeZone(),
			EntryDisplayDateException.class);

		return blogsEntryLocalService.addEntry(
			externalReferenceCode, userId, title, subtitle, urlTitle,
			description, content, displayDate, allowPingbacks, allowTrackbacks,
			trackbacks, coverImageCaption, coverImageImageSelector,
			smallImageImageSelector, serviceContext);
	}

 

以上から対象メソッドがaddEntry5と判定できたので、そこにカスタムコードを追加してみます。試しにブログのタイトルの長さに制限をかけ、タイトル長さが20文字超える場合にPortalExceptionの例外処理を起こします。あくまでも例なので、実案件では要件に合わせてロジックをなんでも追加できます。

 

    @Override
	public BlogsEntry addEntry(String externalReferenceCode, long userId, String title, String subtitle,
			String urlTitle, String description, String content, Date displayDate, boolean allowPingbacks,
			boolean allowTrackbacks, String[] trackbacks, String coverImageCaption,
			ImageSelector coverImageImageSelector, ImageSelector smallImageImageSelector, ServiceContext serviceContext)
			throws PortalException {
		// TODO Auto-generated method stub
		System.out.println("inside addEntry5");
		System.out.println("external reference code =" + externalReferenceCode);
		System.out.println("companyid=" + serviceContext.getCompanyId());
		System.out.println("command=" + serviceContext.getCommand());

		if(title.length()>20) {
			System.out.println("title too long, length = " + title.length());
			throw new PortalException("Please provide a shorter title name");
		}
		return super.addEntry(externalReferenceCode, userId, title, subtitle, urlTitle, description, content, displayDate,
				allowPingbacks, allowTrackbacks, trackbacks, coverImageCaption, coverImageImageSelector,
				smallImageImageSelector, serviceContext);
	}

 

 

7.1と異なる部分

拡張するブログサービスラッパークラスのインポートを行う際、7.1では、IDEの自動インポート機能が廃止パッケージのcom.liferay.blogs.kernel.service.BlogsEntryLocalServiceWrapperを取り込んでしまう可能性があるため、依存関係に気をつけなければいけません。

仮に、com.liferay.blogs.apiを依存関係に追加せずcom.liferay.portal.kernelのみを指定した場合、 kernelモジュールのBlogsEntryLocalServiceWrapperが使用されます。これでデプロイしてもエラーを起こさないので、気付きにくいかもしれません。

実行ロジックを含むBlogsEntryLocalServiceImplクラスのラッパーではないのでカスタムロジックを入れても反応はありませんでした。build.gradleファイルに正しいパッケージの入ったblogs.apiモジュールの依存関係を宣言したら、コードが反映されるようになりました。

    dependencies {
        compileOnly group: "com.liferay.portal", name: "com.liferay.portal.kernel"
        compileOnly group: "org.osgi", name: "org.osgi.service.component.annotations"
        compileOnly group: "com.liferay", name: "com.liferay.blogs.api"
        compileOnly group: "javax.portlet", name: "portlet-api", version: "3.0.0"
        compileOnly group: "javax.servlet", name: "javax.servlet-api", version: "3.0.1"
    }

 

一方で、7.4からは個別のモジュールの依存関係を指定することが必要でなくなりました。メインの依存関係を1つ宣言すれば良いです。

dependencies { compileOnly group: "com.liferay.portal", name: "release.dxp.api" }

DXP 7.4で必要とする「Liferayクラス」のパッケージのほとんどはこのdxp.apiの中に含まれているようです。jarファイルを確認したら、すでにblogs.apiのパッケージが入ってました。

 

試しに、手動でkernelのパッケージcom.liferay.blogs.kernel.service.BlogsEntryLocalServiceWrapperを取り込もうとしても、赤い波線が引かれます。廃止されたkernelパッケージはもう存在していないようで、間違われることもないでしょう。

 

7.1で起きた廃止パッケージのインポート事例を踏まえ、ラッパーからメソッドオーバーライドした時に正しいメソッドをコピーできているかどうかは、一応ソースコードも確認しておいたほうがいいと個人的に思います。

 

その他

7.4のメソッドパラメーターにexternalReferenceCodeが追加されてます。例えば、データベースのBlogsEntryテーブルを確認すれば、フィールドとして反映されているのがわかります。 これは、外部システムからの参照番号を保持するために利用でき、データ移行をサポートする追加機能だそうです。

 

以上、Liferayのサービスラッパー機能を7.1と7.4で比較した内容をお伝えしました。 7.4からは、ポータルの全てのAPIの利用はbuild.gradleにメイン依存関係を1つ宣言するだけで済むので、依存関係の管理がシンプルになったということがよくわかります。

RANKING
2021.1.08
2020.12.28
2020.12.01
2020.10.30
2020.12.18