Skip to content

Commit

Permalink
Merge branch 'release-5u18' into master
Browse files Browse the repository at this point in the history
# Conflicts:
#	pom.xml
  • Loading branch information
mseko committed Sep 28, 2020
2 parents 21b2433 + 83af2d9 commit 4d91025
Show file tree
Hide file tree
Showing 35 changed files with 1,793 additions and 4 deletions.
37 changes: 33 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>com.nablarch.integration</groupId>
<artifactId>nablarch-router-adaptor</artifactId>
<version>1.1.0</version>
<version>1.2.0</version>

<scm>
<connection>scm:git:git://github.com/nablarch/${project.artifactId}.git</connection>
Expand All @@ -16,15 +16,28 @@
<parent>
<groupId>com.nablarch</groupId>
<artifactId>nablarch-parent</artifactId>
<version>5u13</version>
<version>5u18</version>
</parent>

<profiles>
<profile>
<id>java9</id>
<id>java11</id>
<properties>
<junit.additionalArgLine>--add-modules java.activation</junit.additionalArgLine>
<jmockit.version>1.43</jmockit.version>
<junit.additionalArgLine>-javaagent:${settings.localRepository}/org/jmockit/jmockit/${jmockit.version}/jmockit-${jmockit.version}.jar</junit.additionalArgLine>
</properties>
<dependencies>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>javax.activation-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sun.activation</groupId>
<artifactId>javax.activation</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</profile>
</profiles>

Expand All @@ -42,12 +55,28 @@
<groupId>com.nablarch.framework</groupId>
<artifactId>nablarch-core</artifactId>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.nablarch.framework</groupId>
<artifactId>nablarch-fw-jaxrs</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.nablarch.integration</groupId>
<artifactId>nablarch-jersey-adaptor</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.jmockit</groupId>
Expand Down
39 changes: 39 additions & 0 deletions src/main/java/nablarch/integration/router/PathOptions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package nablarch.integration.router;

import net.unit8.http.router.Options;

/**
* パスと、それに割り当てられている {@link Options} のセット。
*
* @author Tanaka Tomoyuki
*/
public class PathOptions {
private final String path;
private final Options options;

/**
* コンストラクタ。
* @param path パス
* @param options パスに割り当てられた設定
*/
public PathOptions(String path, Options options) {
this.path = path;
this.options = options;
}

/**
* パスを取得する。
* @return パス
*/
public String getPath() {
return path;
}

/**
* 設定を取得する
* @return 設定
*/
public Options getOptions() {
return options;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package nablarch.integration.router;

import java.util.List;

/**
* ログに出力するために {@link PathOptions} をフォーマットする機能を提供するインターフェース。
*
* @author Tanaka Tomoyuki
*/
public interface PathOptionsFormatter {

/**
* {@link PathOptions} のリストをログ出力用にフォーマットする。
* @param pathOptionsList フォーマット対象の {@link PathOptions} のリスト
* @return フォーマット結果
*/
String format(List<PathOptions> pathOptionsList);
}
17 changes: 17 additions & 0 deletions src/main/java/nablarch/integration/router/PathOptionsProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package nablarch.integration.router;

import java.util.List;

/**
* ルーティング定義を収集する機能を提供するインターフェース。
*
* @author Tanaka Tomoyuki
*/
public interface PathOptionsProvider {

/**
* ルーティング定義を収集する。
* @return ルーティング定義のリスト
*/
List<PathOptions> provide();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package nablarch.integration.router;

import nablarch.core.log.Logger;
import nablarch.core.log.LoggerManager;
import nablarch.core.repository.initialization.Initializable;
import nablarch.fw.ExecutionContext;
import nablarch.fw.web.HttpErrorResponse;
import nablarch.fw.web.HttpRequest;
import nablarch.fw.web.HttpResponse;
import nablarch.fw.web.handler.RoutingHandlerSupport;
import nablarch.fw.web.servlet.ServletExecutionContext;
import net.unit8.http.router.ARStringUtil;
import net.unit8.http.router.Options;
import net.unit8.http.router.RouteSet;
import net.unit8.http.router.RoutingException;

import java.util.List;
import java.util.Map;

/**
* {@link PathOptionsProvider} から取得したルーティング定義をベースにActionメソッドを特定するハンドラ。
*
* @author Tanaka Tomoyuki
*/
public class PathOptionsProviderRoutesMapping extends RoutingHandlerSupport implements Initializable {
private static final Logger LOGGER = LoggerManager.get(PathOptionsProviderRoutesMapping.class);

private final RouteSet routeSet = new RouteSet();
private String baseUri = "";
private PathOptionsProvider pathOptionsProvider;
private PathOptionsFormatter pathOptionsFormatter = new SimplePathOptionsFormatter();

@Override
protected Class<?> getHandlerClass(HttpRequest request, ExecutionContext executionContext) throws ClassNotFoundException {
try {
String path = getPath(request, executionContext);
Options options = routeSet.recognizePath(path, request.getMethod());

executionContext.setMethodBinder(methodBinderFactory.create((String) options.get("action")));

Options params = options.except("controller", "action");
for (Map.Entry<String, Object> option : params.entrySet()) {
if (option.getValue() != null) {
request.setParam(option.getKey(), option.getValue().toString());
}
}

return Thread.currentThread().getContextClassLoader().loadClass((String) options.get("controller"));
} catch (RoutingException e) {
throw new HttpErrorResponse(HttpResponse.Status.NOT_FOUND.getStatusCode(), e);
}
}

private String getPath(HttpRequest request, ExecutionContext executionContext) {
String path;
if (executionContext instanceof ServletExecutionContext) {
path = ((ServletExecutionContext) executionContext).getHttpRequest().getRequestPath();
} else {
path = request.getRequestPath();
}
String normalized = ARStringUtil.removeStart(path, getBaseUri());
return normalized.startsWith("/") ? normalized : "/" + normalized;
}

@Override
public void initialize() {
if (pathOptionsProvider == null) {
throw new IllegalStateException("pathOptionsProvider is not set.");
}

List<PathOptions> pathOptionsList = pathOptionsProvider.provide();

for (PathOptions pathOptions : pathOptionsList) {
routeSet.addRoute(pathOptions.getPath() , pathOptions.getOptions());
}

if (methodBinderFactory == null) {
setMethodBinderFactory(new RoutesMethodBinderFactory());
}

if (LOGGER.isDebugEnabled()) {
LOGGER.logDebug(pathOptionsFormatter.format(pathOptionsList));
}
}

/**
* ベースURIを取得する。
* @return ベースURI
*/
public String getBaseUri() {
return baseUri;
}

/**
* ベースURIを設定する。
* @param baseUri ベースURI
*/
public void setBaseUri(String baseUri) {
this.baseUri = baseUri;
}

/**
* {@link PathOptionsProvider} を設定する。
* @param pathOptionsProvider {@link PathOptionsProvider}
*/
public void setPathOptionsProvider(PathOptionsProvider pathOptionsProvider) {
this.pathOptionsProvider = pathOptionsProvider;
}

/**
* {@link PathOptionsFormatter} を設定する。
* @param pathOptionsFormatter {@link PathOptionsFormatter}
*/
public void setPathOptionsFormatter(PathOptionsFormatter pathOptionsFormatter) {
this.pathOptionsFormatter = pathOptionsFormatter;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package nablarch.integration.router;

import nablarch.core.util.StringUtil;
import net.unit8.http.router.Options;

import java.util.ArrayList;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

/**
* {@link PathOptions} を単純な形式でフォーマットする機能を提供するクラス。
* <p>
* このフォーマッタは、まず {@link PathOptions} のリストを {@code path} とHTTPメソッド({@code options.conditions.method})の昇順でソートする。<br>
* そして、それぞれの {@link PathOptions} を {@code "<options.conditions.method> <path> => <options.controller>#<options.action>"}
* という書式でフォーマットし、改行コード({@code System.getProperty("line.separator")})で連結したものをフォーマット結果として返す。<br>
* </p>
*
* @author Tanaka Tomoyuki
*/
public class SimplePathOptionsFormatter implements PathOptionsFormatter {

@Override
public String format(List<PathOptions> pathOptionsList) {
SortedMap<String, PathOptions> sortedByPathAndHttpMethod = new TreeMap<String, PathOptions>();

for (PathOptions pathOptions : pathOptionsList) {
Options condition = (Options)pathOptions.getOptions().get("conditions");
sortedByPathAndHttpMethod.put(pathOptions.getPath() + " " + condition.get("method"), pathOptions);
}

List<String> logStringList = new ArrayList<String>(pathOptionsList.size());
for (PathOptions pathOptions : sortedByPathAndHttpMethod.values()) {
logStringList.add(format(pathOptions));
}

return StringUtil.join(System.getProperty("line.separator"), logStringList);
}

private String format(PathOptions pathOptions) {
Options options = pathOptions.getOptions();
Options conditions = (Options) options.get("conditions");
return String.format("%s %s => %s#%s", conditions.get("method"), pathOptions.getPath(), options.get("controller"), options.get("action"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package nablarch.integration.router.jaxrs;

import nablarch.integration.router.PathOptionsProvider;
import nablarch.integration.router.PathOptions;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
* {@link javax.ws.rs.Path} アノテーションが設定されたクラスを探索してルーティング定義を収集するクラス。
*
* @author Tanaka Tomoyuki
*/
public class JaxRsPathOptionsProvider implements PathOptionsProvider {
private static final Comparator<PathOptions> ORDER_BY_PATH_ASC = new Comparator<PathOptions>() {
@Override
public int compare(PathOptions left, PathOptions right) {
return left.getPath().compareTo(right.getPath());
}
};

private String basePackage;
private String applicationPath;

@Override
public List<PathOptions> provide() {
if (applicationPath == null) {
throw new IllegalStateException("applicationPath is not set.");
}
if (basePackage == null) {
throw new IllegalStateException("basePackage is not set.");
}

JaxRsResourceFinder resourceFinder = new JaxRsResourceFinder();
JaxRsRouterConverter pathStringParser = new JaxRsRouterConverter(applicationPath);

List<PathOptions> pathOptionsList = new ArrayList<PathOptions>();

for (JaxRsResource jaxRsResource : resourceFinder.find(basePackage)) {
pathOptionsList.addAll(pathStringParser.parse(jaxRsResource));
}

/*
* http-request-router はルーティング定義のリストを順番に調べて、
* 最初にマッチした定義を使用するようになっている。
*
* したがって、以下のような順番でルーティング定義がリストに入っていると、
* "/foo" へのリクエストが "/foo/(:param)" の定義とマッチしてしまう。
*
* 1. "/foo/(:param)"
* 2. "/foo"
*
* これを回避するため、定義のリストをパスの昇順でソートしている。
*/
Collections.sort(pathOptionsList, ORDER_BY_PATH_ASC);

return pathOptionsList;
}

/**
* 検索ルートとなるパッケージを設定する。
* @param basePackage 検索ルートとなるパッケージ
*/
public void setBasePackage(String basePackage) {
this.basePackage = basePackage;
}

/**
* アプリケーションパスを設定する。
* @param applicationPath アプリケーションパス
*/
public void setApplicationPath(String applicationPath) {
this.applicationPath = applicationPath;
}
}
Loading

0 comments on commit 4d91025

Please sign in to comment.