001/**
002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com).
003 * <p>
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * <p>
008 * http://www.apache.org/licenses/LICENSE-2.0
009 * <p>
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package io.jboot.web.render;
017
018import com.jfinal.kit.JsonKit;
019import com.jfinal.kit.Ret;
020import com.jfinal.render.Render;
021import com.jfinal.render.RenderException;
022import com.jfinal.render.RenderManager;
023import io.jboot.exception.JbootExceptionHolder;
024import io.jboot.utils.RequestUtil;
025import io.jboot.utils.StrUtil;
026import io.jboot.components.valid.ValidException;
027
028import java.io.PrintWriter;
029import java.util.List;
030
031/**
032 * JbootErrorRender.
033 */
034public class JbootErrorRender extends Render {
035
036    protected static final String htmlContentType = "text/html;charset=" + getEncoding();
037    protected static final String jsonContentType = "application/json;charset=" + getEncoding();
038
039    protected static final String poweredBy = "<center><a href='http://jboot.io' target='_blank'><b>Powered by Jboot</b></a></center>";
040
041    protected static final String html404 = "<html><head><title>404 Not Found</title></head><body bgcolor='white'><center><h1>404 Not Found</h1></center><hr>" + poweredBy + "</body></html>";
042    protected static final String html401 = "<html><head><title>401 Unauthorized</title></head><body bgcolor='white'><center><h1>401 Unauthorized</h1></center><hr>" + poweredBy + "</body></html>";
043    protected static final String html403 = "<html><head><title>403 Forbidden</title></head><body bgcolor='white'><center><h1>403 Forbidden</h1></center><hr>" + poweredBy + "</body></html>";
044
045    protected static final String html500_header = "<html><head><title>500 Internal Server Error</title></head>" +
046            "<body bgcolor='white'><center><h1>500 Internal Server Error</h1></center>" +
047            "<hr>";
048    protected static final String html400_header = "<html><head><title>400 Internal Server Error</title></head>" +
049            "<body bgcolor='white'><center><h1>400 Internal Server Error</h1></center>" +
050            "<hr>";
051
052    protected static final String html500_footer = "<hr>" + poweredBy + "</body></html>";
053
054
055    protected static final String json401 = JsonKit.toJson(Ret.fail().set("errorCode", 401).set("message", "401 Unauthorized"));
056    protected static final String json403 = JsonKit.toJson(Ret.fail().set("errorCode", 403).set("message", "403 Forbidden"));
057    protected static final String json404 = JsonKit.toJson(Ret.fail().set("errorCode", 404).set("message", "404 Not Found"));
058
059
060    protected int errorCode;
061    protected String message;
062    protected Throwable throwable;
063
064    public int getErrorCode() {
065        return errorCode;
066    }
067
068    public void setErrorCode(int errorCode) {
069        this.errorCode = errorCode;
070    }
071
072    public String getMessage() {
073        return message;
074    }
075
076    public void setMessage(String message) {
077        this.message = message;
078    }
079
080    public Throwable getThrowable() {
081        return throwable;
082    }
083
084    public void setThrowable(Throwable throwable) {
085        this.throwable = throwable;
086    }
087
088    public JbootErrorRender(int errorCode, String view) {
089        this.errorCode = errorCode;
090        this.view = view;
091    }
092
093    @Override
094    public void render() {
095        response.setStatus(getErrorCode());
096
097        //render with view
098        String view = getView();
099        if (view != null) {
100            RenderManager.me().getRenderFactory()
101                    .getRender(view)
102                    .setContext(request, response)
103                    .render();
104            return;
105        }
106
107        try {
108            boolean needRenderJson = RequestUtil.isJsonContentType(request) || RequestUtil.isAjaxRequest(request);
109            response.setContentType(needRenderJson ? jsonContentType : htmlContentType);
110            PrintWriter writer = response.getWriter();
111            writer.write(needRenderJson ? getErrorJson() : getErrorHtml());
112        } catch (Exception ex) {
113            throw new RenderException(ex);
114        }
115
116    }
117
118
119    public String getErrorHtml() {
120        int errorCode = getErrorCode();
121        if (throwable instanceof ValidException) {
122            return buildErrorInfo(html400_header);
123        } else if (errorCode == 404) {
124            return html404;
125        } else if (errorCode == 401) {
126            return html401;
127        } else if (errorCode == 403) {
128            return html403;
129        } else if (errorCode == 400) {
130            return buildErrorInfo(html400_header);
131        } else if (errorCode == 500) {
132            return buildErrorInfo(html500_header);
133        }
134        return "<html><head><title>" + errorCode + " Error</title></head><body bgcolor='white'><center><h1>" + errorCode + " Error</h1></center><hr>" + poweredBy + "</body></html>";
135    }
136
137
138    public String buildErrorInfo(String headerHtml) {
139        StringBuilder stringBuilder = new StringBuilder(headerHtml);
140
141        List<String> messages = JbootExceptionHolder.getMessages();
142        for (String message : messages) {
143            stringBuilder.append(message).append("<br />");
144        }
145
146        List<Throwable> throwables = JbootExceptionHolder.getThrowables();
147        for (Throwable throwable : throwables) {
148            stringBuilder.append(throwable.getClass().getName() + " : " + throwable.getMessage()).append("<br />");
149            StackTraceElement[] elems = throwable.getStackTrace();
150            for (StackTraceElement element : elems) {
151                stringBuilder.append("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at ")
152                        .append(element)
153                        .append("<br />");
154            }
155        }
156
157        return stringBuilder.append(html500_footer).toString();
158    }
159
160
161    public String getErrorJson() {
162        int errorCode = getErrorCode();
163        if (throwable instanceof ValidException || errorCode == 500 || errorCode == 400) {
164            return buildErrorJson();
165        } else if (errorCode == 404) {
166            return json404;
167        } else if (errorCode == 401) {
168            return json401;
169        } else if (errorCode == 403) {
170            return json403;
171        }
172        return JsonKit.toJson(Ret.fail().set("errorCode", errorCode).set("message", errorCode + " Error"));
173    }
174
175
176    public String buildErrorJson() {
177
178        Ret ret = Ret.fail().set("errorCode", getErrorCode()).set("message", getErrorCode() + " Internal Server Error");
179
180        StringBuilder errorMsgBuilder = new StringBuilder();
181        List<String> messages = JbootExceptionHolder.getMessages();
182        for (String message : messages) {
183            errorMsgBuilder.append(message);
184        }
185
186        ret.set("errorMessage", errorMsgBuilder.toString());
187
188        List<Throwable> throwables = JbootExceptionHolder.getThrowables();
189        if (throwables.size() > 0) {
190            Throwable throwable = throwables.get(0);
191            ret.set("throwable", throwable.getClass().getName() + ": " + throwable.getMessage());
192            ret.set("message", throwable.getMessage());
193        }
194
195        if (this.throwable != null) {
196            ret.set("throwable", this.throwable.getClass().getName() + ": " + this.throwable.getMessage());
197            ret.set("message", throwable.getMessage());
198
199            if (throwable instanceof ValidException) {
200                ret.set("errorMessage", ((ValidException) throwable).getReason());
201            }
202        }
203
204        if (StrUtil.isNotBlank(this.message)) {
205            ret.set("message", this.message);
206        }
207
208        return JsonKit.toJson(ret);
209    }
210}
211
212
213
214
215