package act.util;
/*-
* #%L
* ACT Framework
* %%
* Copyright (C) 2014 - 2017 ActFramework
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import act.Act;
import act.app.ActionContext;
import act.view.Template;
import act.view.ViewManager;
import com.alibaba.fastjson.JSON;
import org.osgl.$;
import org.osgl.http.H;
import org.osgl.mvc.ErrorPageRenderer;
import org.osgl.mvc.MvcConfig;
import org.osgl.mvc.result.ErrorResult;
import org.osgl.util.S;
import java.util.HashMap;
import java.util.Map;
import static org.osgl.http.H.Format.CSV;
import static org.osgl.http.H.Format.HTML;
import static org.osgl.http.H.Format.XML;
public class ActErrorPageRender extends ErrorPageRenderer {
public static final String ARG_ERROR = "_error";
private volatile Boolean i18n;
private Map<String, $.Var<Template>> templateCache = new HashMap<>();
@Override
protected String renderTemplate(ErrorResult error, H.Format format) {
ActionContext context = ActionContext.current();
if (null == context) {
return null;
}
Integer errorCode = error.errorCode();
int statusCode = error.statusCode();
fixRequestAcceptFormat(context);
Template t = getTemplate(statusCode, context);
if (null == t) {
String errorMsg = error.getMessage();
if (null == errorMsg) {
errorMsg = MvcConfig.errorMessage(error.status());
}
if (i18n()) {
String translated = context.i18n(true, errorMsg);
if (translated == errorMsg) {
translated = context.i18n(true, MvcConfig.class, errorMsg);
}
errorMsg = translated;
}
H.Format accept = context.accept();
if (H.Format.JSON == accept) {
return jsonContent(error, errorCode, errorMsg);
} else if (HTML == accept) {
String header = S.concat("HTTP/1.1 ", Integer.toString(statusCode), " ", errorMsg);
return S.concat("<!DOCTYPE html><html><head><meta charset='utf-8'><title>"
, header
, "</title></head><body><h1>"
, header, "</h1></body></html>");
} else if (H.Format.XML == accept) {
S.Buffer sb = context.strBuf();
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><error>");
if (null != errorCode) {
sb.append("<code>").append(errorCode).append("</code");
}
sb.append("<message>").append(errorMsg).append("</message></error>");
return sb.toString();
} else if (CSV == accept) {
if (null == errorCode) {
return S.concat("message\n", errorMsg);
} else {
return S.concat("code,message\n", Integer.toString(errorCode), ",", errorMsg);
}
} else if (H.Format.TXT == accept) {
return null == errorCode ? errorMsg : S.concat(Integer.toString(errorCode), " ", errorMsg);
} else {
// Unknown accept format
return "";
}
}
if (HTML == context.accept()) {
String header = S.concat("HTTP/1.1 ", Integer.toString(statusCode), " ", MvcConfig.errorMessage(error.status()));
context.renderArg("header", header);
}
context.renderArg(ARG_ERROR, error);
return t.render(context);
}
private void fixRequestAcceptFormat(ActionContext context) {
H.Request req = context.req();
if (null != req && !isAcceptGoodForErrorPage(req.accept())) {
req.accept(H.Format.HTML);
}
}
private boolean isAcceptGoodForErrorPage(H.Format fmt) {
return (null == fmt ||
HTML == fmt
|| CSV == fmt
|| H.Format.JSON == fmt
|| XML == fmt);
}
private String jsonContent(ErrorResult error, Integer errorCode, String errorMsg) {
Object payload = error.attachment();
if (null != payload) {
return JSON.toJSONString(payload);
}
if (null == errorCode) {
return S.concat("{\"message\":\"", errorMsg, "\"}");
} else {
return S.concat("{\"code\":", S.string(errorCode), ",\"message\":\"", errorMsg, "\"}");
}
}
private String templatePath(int code, ActionContext context) {
ErrorTemplatePathResolver resolver = context.config().errorTemplatePathResolver();
if (null == resolver) {
resolver = new ErrorTemplatePathResolver.DefaultErrorTemplatePathResolver();
}
return resolver.resolve(code, context.accept());
}
private Template getTemplate(int statusCode, ActionContext context) {
H.Format format = context.accept();
String key = statusCode + "" + format;
$.Var<Template> templateBag = templateCache.get(key);
if (null == templateBag) {
ViewManager vm = Act.viewManager();
if (null == vm) {
// unit testing
return null;
}
context.templatePath(templatePath(statusCode, context));
Template t = vm.load(context);
if (null == t) {
// try default one
if (Act.isDev()) {
context.templatePath("/error/dev/errorPage." + context.accept().name());
} else {
context.templatePath("/error/errorPage." + context.accept().name());
}
t = vm.load(context);
}
templateBag = $.var(t);
templateCache.put(key, templateBag);
}
return templateBag.get();
}
private boolean i18n() {
if (null == i18n) {
synchronized (this) {
if (null == i18n) {
i18n = Act.appConfig().i18nEnabled();
}
}
}
return i18n;
}
}