wicketと格闘 mountポジション (イントラ用語集5)
かなり昔に考えていたイントラ用語集のネタが腐る前に掘り起こすことにします。
http://domain.name/context/servlet/path/info.ext
REST的にリソースを考えた上、本来のURIの不透明性よりもリソースのコンテントを示すほうが有用と
考えたところまででした。
Servlet処理はそれなりに進んでいたものの、画面デザインは自身にセンスを持ち合わせていないこともあり、
悩んでいたのですが、JSPでガリガリやるのは画面表示が確認できないし、タグを駆使してもどうしてもJSPは綺麗
に書けないと思ったので(個人的に好きになれない…)、Next Strutsを探す旅と言う意味も込めてイロイロと探って
みた結果、HTMLをそのまま使えるという(POHPと言うらしい)wicketにたどり着きました。
wicketの感想はまたの機会にするとして、wicketでのURLの扱いはかなりユニークに出来ているみたいでフレームワーク
でありながら、拡張も簡単に出来る工夫がしてあるようです。
今回の目的である、リソースを表すURLには
MixedParamUrlCodingStrategy クラスをマネして参考に作成してみました。
wicket歴も浅いので、いい加減なところもありますが、ツッコミがありましたらお願いします。
コンストラクタ
getDesignedParameterNamesメソッド
appendParametersメソッド Redirect After Postでリダイレクトされる時のURLの生成
ほとんどMixedParamUrlCodingStrategyのマネ。
Pageクラスに渡すPageParameter作成メソッド
内部メソッドのおまけ
http://domain.name/context/servlet/path/info.ext
REST的にリソースを考えた上、本来のURIの不透明性よりもリソースのコンテントを示すほうが有用と
考えたところまででした。
Servlet処理はそれなりに進んでいたものの、画面デザインは自身にセンスを持ち合わせていないこともあり、
悩んでいたのですが、JSPでガリガリやるのは画面表示が確認できないし、タグを駆使してもどうしてもJSPは綺麗
に書けないと思ったので(個人的に好きになれない…)、Next Strutsを探す旅と言う意味も込めてイロイロと探って
みた結果、HTMLをそのまま使えるという(POHPと言うらしい)wicketにたどり着きました。
wicketの感想はまたの機会にするとして、wicketでのURLの扱いはかなりユニークに出来ているみたいでフレームワーク
でありながら、拡張も簡単に出来る工夫がしてあるようです。
今回の目的である、リソースを表すURLには
- 拡張子がない時はhtmlとして扱う
- htmlを付けたURLでも同じように扱う
MixedParamUrlCodingStrategy クラスをマネして参考に作成してみました。
wicket歴も浅いので、いい加減なところもありますが、ツッコミがありましたらお願いします。
コンストラクタ
publicFileExtensionUrlCodingStrategy(String mountPath,
ClassbookmarkablePageClass, String pageMapName,
String[] parameterNames, String extension) {
super(mountPath, bookmarkablePageClass, pageMapName);
/* TODO 拡張子からMimeを確認する方法がバラバラ
* Resource#detectContentType参照
* 下記はgeronimo-activationライブラリの拡張したものを流用
*/
if (!FileTypeMap.getDefaultFileTypeMap().exist(extension))
throw new IllegalArgumentException("指定した拡張子はサポートされていません。: " + extension );
this.parameterNames = getDesignedParameterNames(parameterNames);
this.extension = extension;
}
getDesignedParameterNamesメソッド
private String[] getDesignedParameterNames(String[] parameterNames) {
boolean found = false;
for (int i = 0; i < parameterNames.length; i++) {
if ("format".equals(parameterNames[i])) {
found = true;
break;
}
}
return found ? parameterNames : (String[]) ArrayUtils.add(parameterNames, "format");
}
appendParametersメソッド Redirect After Postでリダイレクトされる時のURLの生成
ほとんどMixedParamUrlCodingStrategyのマネ。
@SuppressWarnings("unchecked")
@Override
protected void appendParameters(AppendingStringBuffer url, Map parameters) {
if (!url.endsWith("/"))
url.append("/");
Set parameterNamesToAdd = new HashSet(parameters.keySet());
/* Find index of last specified parameter */
boolean foundParameter = false;
int lastSpecifiedParameter = parameterNames.length;
while (lastSpecifiedParameter != 0 && !foundParameter)
foundParameter = parameters.containsKey(parameterNames[--lastSpecifiedParameter]);
if (foundParameter) {
for (int i = 0; i <= lastSpecifiedParameter; i++) {
String parameterName = parameterNames[i];
if ("format".equals(parameterName))
continue;
if (i != 0 && !url.endsWith("/"))
url.append("/");
final Object param = parameters.get(parameterName);
String value = param instanceof String[] ? ((String[])param)[0] : (String)param;
if (value == null)
value = "";
url.append(urlEncodePathComponent(value));
parameterNamesToAdd.remove(parameterName);
}
/* format未指定の場合のみURLに追加
* defaultはhtmlになるが、URLとして表現しない。
* http://server/context/pathinfo
*/
if (parameters.get("format") != null)
url.append(".").append(parameters.get("format"));
parameterNamesToAdd.remove("format");
}
if (!parameterNamesToAdd.isEmpty()) {
boolean first = true;
final Iterator iterator = parameterNamesToAdd.iterator();
while (iterator.hasNext()) {
url.append(first ? '?' : '&');
String parameterName = (String)iterator.next();
final Object param = parameters.get(parameterName);
String value = param instanceof String[] ? ((String[])param)[0] : (String)param;
url.append(urlEncodeQueryComponent(parameterName)).append("=").
append(urlEncodeQueryComponent(value));
first = false;
}
}
}
Pageクラスに渡すPageParameter作成メソッド
@SuppressWarnings("unchecked")
@Override
protected ValueMap decodeParameters(String urlFragment, Map urlParameters) {
PageParameters params = new PageParameters();
/* Add all url parameters */
params.putAll(urlParameters);
String urlPath = urlFragment;
if (urlPath.startsWith("/"))
urlPath = urlPath.substring(1);
if (urlPath.length() > 0) {
String[] pathParts = extensionSplit(urlPath);
if (pathParts.length > parameterNames.length) {
throw new IllegalArgumentException(
"Too many path parts, please provide sufficient number of path parameter names");
}
for (int i = 0; i < pathParts.length; i++)
params.put(parameterNames[i], urlDecodePathComponent(pathParts[i]));
} else {
/* "/"指定時にはディレクトリインデックス "index.html"をマッピングする。
* TODO 将来的にはweb.xml#welcom file listから取得出来るようにしたい。
*/
params.put(parameterNames[0], "index");
params.put(parameterNames[1], DEFAULT_EXTENSION);
}
return params;
}
内部メソッドのおまけ
private String[] extensionSplit(String urlPath) {
String[] elements = urlPath.split("/");
String target = null;
if (elements[elements.length -1].contains(".")) {
target = elements[elements.length -1];
String filename = StringUtils.substringBeforeLast(elements[elements.length -1], ".");
String ext = StringUtils.substringAfterLast(elements[elements.length -1], ".");
elements = (String[]) ArrayUtils.addAll(elements, new String[]{filename, ext});
} else {
elements = (String[]) ArrayUtils.add(elements, extension);
}
return target != null ? (String[]) ArrayUtils.removeElement(elements, target) : elements;
}
コメント