22
33import static java .util .Objects .requireNonNull ;
44
5- import java .io .PrintWriter ;
6- import java .io .StringWriter ;
75import java .nio .charset .Charset ;
86import java .util .Arrays ;
97import java .util .Collections ;
3331import jooby .Request ;
3432import jooby .Response ;
3533import jooby .Route ;
36- import jooby .Viewable ;
34+ import jooby .Route . Err ;
3735
3836import org .slf4j .Logger ;
3937import org .slf4j .LoggerFactory ;
@@ -65,19 +63,23 @@ public class RouteHandler {
6563
6664 private MediaTypeProvider typeProvider ;
6765
66+ private Err err ;
67+
6868 @ Inject
6969 public RouteHandler (final Injector injector ,
7070 final BodyConverterSelector selector ,
7171 final Set <Request .Module > modules ,
7272 final Set <Route .Definition > routes ,
7373 final Charset defaultCharset ,
74- final Locale defaultLocale ) {
74+ final Locale defaultLocale ,
75+ final Route .Err err ) {
7576 this .rootInjector = requireNonNull (injector , "An injector is required." );
7677 this .selector = requireNonNull (selector , "A message converter selector is required." );
7778 this .modules = requireNonNull (modules , "Request modules are required." );
7879 this .routeDefs = requireNonNull (routes , "The routes are required." );
7980 this .charset = requireNonNull (defaultCharset , "A defaultCharset is required." );
8081 this .locale = requireNonNull (defaultLocale , "A defaultLocale is required." );
82+ this .err = requireNonNull (err , "An err handler is required." );
8183 this .typeProvider = injector .getInstance (MediaTypeProvider .class );
8284 }
8385
@@ -106,9 +108,9 @@ public void handle(final HttpServletRequest request, final HttpServletResponse r
106108
107109 final String path = verb + requestURI ;
108110
109- log .info ("handling: {}" , path );
111+ log .debug ("handling: {}" , path );
110112
111- log .info (" content-type: {}" , type );
113+ log .debug (" content-type: {}" , type );
112114
113115 Charset charset = Optional .ofNullable (request .getCharacterEncoding ())
114116 .map (Charset ::forName )
@@ -142,7 +144,8 @@ public void handle(final HttpServletRequest request, final HttpServletResponse r
142144 .next (reqFactory .apply (injector , notFound ), resFactory .apply (injector , notFound ));
143145
144146 } catch (Exception ex ) {
145- log .error ("handling of: " + path + " ends with error" , ex );
147+ log .debug ("execution of: " + path + " resulted in exception" , ex );
148+
146149 // reset response
147150 response .reset ();
148151
@@ -155,20 +158,15 @@ public void handle(final HttpServletRequest request, final HttpServletResponse r
155158 res .header ("Cache-Control" , NO_CACHE );
156159 res .status (status );
157160
158- // TODO: move me to an error handler feature
159- Map <String , Object > model = errorModel (req , ex , status );
160161 try {
161- res .format ()
162- .when (MediaType .html , () -> Viewable .of ("/status/" + status .value (), model ))
163- .when (MediaType .all , () -> model )
164- .send ();
162+ err .handle (req , res , ex );
165163 } catch (Exception ignored ) {
166- log .trace ("rendering of error failed, fallback to default error page" , ignored );
167- defaultErrorPage (req , res , status , model );
164+ log .debug ("rendering of error failed, fallback to default error page" , ignored );
165+ defaultErrorPage (req , res , err . err ( req , res , ex ) );
168166 }
169167 } finally {
170168 long end = System .currentTimeMillis ();
171- log .info (" status -> {} in {}ms" , response .getStatus (), end - start );
169+ log .debug (" status -> {} in {}ms" , response .getStatus (), end - start );
172170 }
173171 }
174172
@@ -283,8 +281,9 @@ public Request.Verb verb() {
283281 };
284282 }
285283
286- private void defaultErrorPage (final Request request , final Response response ,
287- final HttpStatus status , final Map <String , Object > model ) throws Exception {
284+ private void defaultErrorPage (final Request request , final Response res ,
285+ final Map <String , Object > model ) throws Exception {
286+ HttpStatus status = res .status ();
288287 StringBuilder html = new StringBuilder ("<!doctype html>" )
289288 .append ("<html>\n " )
290289 .append ("<head>\n " )
@@ -308,7 +307,7 @@ private void defaultErrorPage(final Request request, final Response response,
308307
309308 model .remove ("reason" );
310309
311- String [] stacktrace = (String []) model .remove ("stackTrace " );
310+ String [] stacktrace = (String []) model .remove ("stacktrace " );
312311
313312 for (Entry <String , Object > entry : model .entrySet ()) {
314313 Object value = entry .getValue ();
@@ -319,7 +318,7 @@ private void defaultErrorPage(final Request request, final Response response,
319318 }
320319
321320 if (stacktrace != null ) {
322- html .append ("<h2>stackTrace :</h2>\n " )
321+ html .append ("<h2>stack :</h2>\n " )
323322 .append ("<div class=\" trace\" >\n " );
324323
325324 Arrays .stream (stacktrace ).forEach (line -> {
@@ -340,45 +339,14 @@ private void defaultErrorPage(final Request request, final Response response,
340339 .append ("</body>\n " )
341340 .append ("</html>\n " );
342341
343- response .header ("Cache-Control" , NO_CACHE );
344- response .send (html , FallbackBodyConverter .TO_HTML );
345- }
346-
347- private Map <String , Object > errorModel (final Request request , final Exception ex ,
348- final HttpStatus status ) {
349- Map <String , Object > error = new LinkedHashMap <>();
350- String message = ex .getMessage ();
351- message = message == null ? status .reason () : message ;
352- error .put ("message" , message );
353- error .put ("stackTrace" , dump (ex ));
354- error .put ("status" , status .value ());
355- error .put ("reason" , status .reason ());
356- return error ;
357- }
358-
359- private static String [] dump (final Exception ex ) {
360- StringWriter writer = new StringWriter ();
361- ex .printStackTrace (new PrintWriter (writer ));
362- String [] stacktrace = writer .toString ().replace ("\r " , "" ).split ("\\ n" );
363- return stacktrace ;
342+ res .header ("Cache-Control" , NO_CACHE );
343+ res .send (html , FallbackBodyConverter .TO_HTML );
364344 }
365345
366346 private HttpStatus statusCode (final Exception ex ) {
367347 if (ex instanceof HttpException ) {
368348 return ((HttpException ) ex ).status ();
369349 }
370- // Class<?> type = ex.getClass();
371- // Status status = errorMap.get(type);
372- // while (status == null && type != Throwable.class) {
373- // type = type.getSuperclass();
374- // status = errorMap.get(type);
375- // }
376- // return status == null ? defaultStatusCode(ex) : status;
377- // TODO: finished me
378- return defaultStatusCode (ex );
379- }
380-
381- private HttpStatus defaultStatusCode (final Exception ex ) {
382350 if (ex instanceof IllegalArgumentException ) {
383351 return HttpStatus .BAD_REQUEST ;
384352 }
0 commit comments