/* * Copyright 2015 Petr Bouda * * 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. */ package org.joyrest.exception.processor; import java.util.List; import java.util.Map; import java.util.Optional; import org.joyrest.context.ApplicationContext; import org.joyrest.exception.handler.InternalExceptionHandler; import org.joyrest.model.http.MediaType; import org.joyrest.model.request.InternalRequest; import org.joyrest.model.response.InternalResponse; import org.joyrest.transform.Writer; import static org.joyrest.exception.type.RestException.internalServerErrorSupplier; import static org.joyrest.model.http.HeaderName.CONTENT_TYPE; import static java.util.Objects.isNull; import static java.util.Objects.nonNull; public class ExceptionProcessorImpl implements ExceptionProcessor { private final Map<Class<? extends Exception>, InternalExceptionHandler> handlers; public ExceptionProcessorImpl(ApplicationContext config) { this.handlers = config.getExceptionHandlers(); } @Override public <T extends Exception> InternalResponse<Object> process(final T ex, final InternalRequest<Object> req, final InternalResponse<Object> resp) throws Exception{ Class<? extends Exception> clazz = ex.getClass(); InternalExceptionHandler handler = handlers.get(clazz); if (isNull(handler)) { handler = getHandlerFromParent(clazz).orElseThrow(() -> ex); } handler.execute(req, resp, ex); writeEntity(handler, req, resp); return resp; } private void writeEntity(InternalExceptionHandler handler, InternalRequest<?> request, InternalResponse<?> response) { if (response.getEntity().isPresent()) { Writer writer = null; if (nonNull(request.getMatchedAccept())) { Optional<Writer> optWriter = handler.getWriter(request.getMatchedAccept()); if (optWriter.isPresent()) { writer = optWriter.get(); } } if (isNull(writer)) { writer = chooseWriter(handler, request); } response.header(CONTENT_TYPE, writer.getMediaType().get()); writer.writeTo(response, request); response.setEntityWritten(true); } } private Writer chooseWriter(InternalExceptionHandler handler, InternalRequest<?> request) { List<MediaType> acceptMediaTypes = request.getAccept(); return acceptMediaTypes.stream() .filter(accept -> handler.getWriter(accept).isPresent()) .findFirst() .flatMap(handler::getWriter) .orElseThrow(internalServerErrorSupplier( String.format("No writer registered for Accept%s and Exception Response-Type[%s]", acceptMediaTypes, handler.getExceptionClass()))); } private Optional<InternalExceptionHandler> getHandlerFromParent(Class<? extends Exception> clazz) { if (clazz == Exception.class) { return Optional.empty(); } Class<?> superClazz = clazz.getSuperclass(); while (superClazz != Exception.class) { InternalExceptionHandler handler = handlers.get(superClazz); if (nonNull(handler)) { return Optional.of(handler); } superClazz = superClazz.getSuperclass(); } return Optional.empty(); } }