複数BaseURLからそれぞれテナントを解決する方法

ここでは、複数のBaseURLを持つシステムにおいて、BaseURL単位でテナントを解決する方法について説明します。

まず、複数のBaseURLを持つシステムの作成方法として、以下のいずれかを実装していること前提とします。

上記、CookBookを実装している場合、HTTP Header(x-com-base-url)には BaseURLが常に設定されます。

この x-com-base-url を用いたテナント解決の実装を行います。
なお、テナント解決の仕様については以下のリンクを参照してください。
https://document.intra-mart.jp/library/iap/public/setup/iap_setup_guide/texts/appendix/tenant_resolution/index.html

1.テナント解決用クラスを作成します。

このクラスは、プラグイン設定ファイル(後述)の BaseURL と TenantID を紐付けたパラメータを読み込みます。
また、すべての「テナントの環境情報」のベースURL 設定も読み込みます。

「テナントの環境情報」のベースURL
https://document.intra-mart.jp/library/iap/public/setup/iap_setup_guide/texts/tenant/setup_to_tenant_env.html


BaseURL からテナントを解決する優先順位は以下の通りです。
1、 テナント設定画面の BaseURL 設定
2、 プラグイン設定ファイル のパラメータ

【注意事項】
各設定を読み込むのは、このクラスが初期化されたタイミングとなるため、 各テナント設定画面の BaseURL を設定および変更した場合は、アプリケーションサーバの再起動が行われるまで反映されません。
また、分散環境の場合、全てのアプリケーションサーバの再起動が必要です。

com/example/HttpHeaderTenantIdResolver.java

package com.example;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.http.HttpServletRequest;

import jp.co.intra_mart.common.platform.log.Logger;
import jp.co.intra_mart.foundation.admin.tenant.TenantInfoManager;
import jp.co.intra_mart.foundation.admin.tenant.context.RequestBasedTenantIdResolver;
import jp.co.intra_mart.foundation.security.PropertyInitParamable;

public class HttpHeaderTenantIdResolver implements RequestBasedTenantIdResolver, PropertyInitParamable {

	private static final class LazyHolder {

		public static final Map<String, String> TENANT_STATIC_MAP = new ConcurrentHashMap<String, String>();
		public static Map<String, String> TENANT_MAP = new ConcurrentHashMap<String, String>();

	}

	private static final String BASE_URL_ATTR_KEY = "im_base_url";
	private static final String BASE_URL_HEADER_KEY = "x-com-base-url";
	private static final Logger LOGGER = Logger.getLogger(HttpHeaderTenantIdResolver.class);

	@Override
	public void init(final Map<String, String> params) {

		// プラグイン設定情報の読み込み
		LazyHolder.TENANT_STATIC_MAP.clear();
		LazyHolder.TENANT_STATIC_MAP.putAll(params);

		// BaseURLとテナント情報の読み込み
		load();

	}

	@Override
	public String getTenantId(final HttpServletRequest request) {

		if (request == null) {
			return null;
		}

		// 一致する情報が無い時は、null を返却することで、後続の RequestBasedTenantIdResolver に処理を委ねることができます。
		return LazyHolder.TENANT_MAP.get(request.getHeader(BASE_URL_HEADER_KEY));

	}

	/**
	 * BaseURLとテナント情報の読み込み
	 */
	private void load() {

		try {

			Map<String, String> newTenantMap = new ConcurrentHashMap<String, String>();

			// プラグイン設定よりテナント設定が優先とする処理
			newTenantMap.putAll(LazyHolder.TENANT_STATIC_MAP);
			newTenantMap.putAll(loadTenantInfo());

			// 作成された情報の置き換え。
			LazyHolder.TENANT_MAP = newTenantMap;

		} catch (Exception e) {
			LOGGER.error("Loading error.", e);
		}

	}

	/**
	 * テナント情報からテナントIDとBaseURLのMapを作成。
	 *
	 * @return テナントIDとBaseURLのMap
	 * @throws Exception テナント情報取得時にエラーが発生した場合にスローされます。
	 */
	private Map<String, String> loadTenantInfo() throws Exception {

		Map<String, String> newTenantMap = new ConcurrentHashMap<String, String>();

		TenantInfoManager manager = new TenantInfoManager();

		// 全テナント情報を取得し、BaseURLが設定されている場合は保管する。
		for (final String tenantId : manager.getTenantIds()) {
			final String baseUrl = manager.getTenantInfo(tenantId).getAttributes()
					.get(HttpHeaderTenantIdResolver.BASE_URL_ATTR_KEY);
			if (baseUrl != null && baseUrl.trim().length() > 0) {
				newTenantMap.put(baseUrl.trim(), tenantId);
			}
		}

		return newTenantMap;

	}

}

2 .プラグイン設定ファイルの作成します。

WEB-INF/plugin/com.example.http.header.tenant.resolver_1.0.0/plugin.xml を作成します。


<param-name> には BaseURL、<param-value> には紐付けたい TenantID を記述します。


なお、この設定の値は、各テナントの設定画面のBaseURLに記述がない場合のみ使われます。

plugin.xml

<?xml version="1.0" encoding="UTF-8"?>
<plugin>
	<extension point="jp.co.intra_mart.foundation.admin.tenant.context.tenant.resolvers">
		<tenant-id-resolvers
			id="com.example.http.header.tenant.resolver"
			version="1.0.0"
			rank="1">

			<tenant-id-resolver class="com.example.HttpHeaderTenantIdResolver">
				<init-param>
					<param-name>http://test1.sample.com/imart</param-name>
					<param-value>default</param-value>
				</init-param>
				<init-param>
					<param-name>http://test2.sample.com/imart</param-name>
					<param-value>default2</param-value>
				</init-param>
			</tenant-id-resolver>
		</tenant-id-resolvers>
	</extension>
</plugin>

これらの実装を行うことで、アクセスするBaseURL毎にテナントを解決することが可能です。