Java tutorial
/** * Copyright (C) 2011-2018 Red Hat, Inc. (https://github.com/Commonjava/indy) * * 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.commonjava.indy.bind.jaxrs.util; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.codec.digest.DigestUtils; import org.commonjava.indy.IndyWorkflowException; import org.commonjava.indy.model.core.StoreKey; import org.commonjava.indy.model.core.dto.CreationDTO; import org.commonjava.indy.model.util.HttpUtils; import org.commonjava.indy.util.ApplicationContent; import org.commonjava.indy.util.ApplicationHeader; import org.commonjava.indy.util.ApplicationStatus; import org.commonjava.indy.util.LocationUtils; import org.commonjava.indy.util.UriFormatter; import org.commonjava.maven.galley.model.Transfer; import org.commonjava.maven.galley.transport.htcli.model.HttpExchangeMetadata; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; import javax.ws.rs.core.Response.Status; import java.io.File; import java.io.PrintWriter; import java.io.StringWriter; import java.net.URI; import java.net.URISyntaxException; import java.util.List; import java.util.Map; import java.util.function.Consumer; import java.util.function.Supplier; public final class ResponseUtils { private final static Logger LOGGER = LoggerFactory.getLogger(ResponseUtils.class); private ResponseUtils() { } public static Response formatRedirect(final URI uri) throws URISyntaxException { return formatRedirect(uri, null); } public static Response formatRedirect(final URI uri, final Consumer<ResponseBuilder> builderModifier) throws URISyntaxException { ResponseBuilder builder = Response.status(Status.MOVED_PERMANENTLY).location(uri); if (builderModifier != null) { builderModifier.accept(builder); } return builder.build(); } public static Response formatCreatedResponse(final String baseUri, final UriFormatter uriFormatter, final String... params) throws URISyntaxException { return formatCreatedResponse(baseUri, uriFormatter, null, params); } public static Response formatCreatedResponse(final String baseUri, final UriFormatter uriFormatter, final Consumer<ResponseBuilder> builderModifier, final String... params) throws URISyntaxException { final URI location = new URI(uriFormatter.formatAbsolutePathTo(baseUri, params)); ResponseBuilder builder = Response.created(location); if (builderModifier != null) { builderModifier.accept(builder); } return builder.build(); } public static Response formatCreatedResponseWithJsonEntity(final URI location, final Object dto, final ObjectMapper objectMapper) { return formatCreatedResponseWithJsonEntity(location, dto, objectMapper, null); } public static Response formatCreatedResponseWithJsonEntity(final URI location, final Object dto, final ObjectMapper objectMapper, final Consumer<ResponseBuilder> builderModifier) { ResponseBuilder builder = null; if (dto == null) { builder = Response.noContent(); } else { try { builder = Response.created(location).entity(objectMapper.writeValueAsString(dto)) .type(ApplicationContent.application_json); } catch (final JsonProcessingException e) { return formatResponse(e, "Failed to serialize DTO to JSON: " + dto, builderModifier); } } if (builderModifier != null) { builderModifier.accept(builder); } return builder.build(); } public static Response formatCreatedResponse(final String baseUri, final CreationDTO dto) { return formatCreatedResponse(baseUri, dto, null); } public static Response formatCreatedResponse(final String baseUri, final CreationDTO dto, final Consumer<ResponseBuilder> builderModifer) { ResponseBuilder builder = Response.created(dto.getUri()).entity(dto.getJsonResponse()); if (builderModifer != null) { builderModifer.accept(builder); } return builder.build(); } public static Response formatOkResponseWithJsonEntity(final String json) { return formatOkResponseWithEntity(json, ApplicationContent.application_json, null); } public static Response formatOkResponseWithJsonEntity(final Object dto, final ObjectMapper objectMapper) { return formatOkResponseWithJsonEntity(dto, objectMapper, null); } public static Response formatOkResponseWithJsonEntity(final Object dto, final ObjectMapper objectMapper, final Consumer<ResponseBuilder> builderModifier) { if (dto == null) { return Response.noContent().build(); } try { ResponseBuilder builder = Response.ok(objectMapper.writeValueAsString(dto), ApplicationContent.application_json); if (builderModifier != null) { builderModifier.accept(builder); } return builder.build(); } catch (final JsonProcessingException e) { return formatResponse(e, "Failed to serialize DTO to JSON: " + dto, builderModifier); } } public static ResponseBuilder setInfoHeaders(final ResponseBuilder builder, final Transfer item, final StoreKey sk, final String path, final boolean includeContentLength, final String contentType, final HttpExchangeMetadata exchangeMetadata) throws IndyWorkflowException { Logger logger = LoggerFactory.getLogger(ResponseUtils.class); boolean lastModSet = false; boolean lenSet = false; boolean conTypeSet = false; if (exchangeMetadata != null) { for (final Map.Entry<String, List<String>> headerSet : exchangeMetadata.getResponseHeaders() .entrySet()) { final String key = headerSet.getKey(); if (ApplicationHeader.content_type.upperKey().equals(key)) { logger.debug("Marking {} as already set.", ApplicationHeader.content_type.upperKey()); conTypeSet = true; } else if (ApplicationHeader.last_modified.upperKey().equals(key)) { logger.debug("Marking {} as already set.", ApplicationHeader.last_modified.upperKey()); lastModSet = true; } else if (ApplicationHeader.content_length.upperKey().equals(key)) { logger.debug("Marking {} as already set.", ApplicationHeader.content_length.upperKey()); lenSet = true; if (!includeContentLength) { continue; } } for (final String value : headerSet.getValue()) { logger.debug("Setting header: '{}'= '{}'", key, value); builder.header(key, value); } } } if (item != null && item.exists()) { if (!lastModSet) { builder.header(ApplicationHeader.last_modified.key(), HttpUtils.formatDateHeader(item.lastModified())); } if (includeContentLength && !lenSet) { logger.debug("Adding Content-Length header: {}", item.length()); builder.header(ApplicationHeader.content_length.key(), item.length()); } if (!conTypeSet) { logger.debug("Adding Content-Type header: {}", contentType); builder.header(ApplicationHeader.content_type.key(), contentType); } // Indy origin contains the storeKey of the repository where the content came from builder.header(ApplicationHeader.indy_origin.key(), LocationUtils.getKey(item).toString()); } else { if (!lastModSet) { logger.debug("CANNOT SET: {}", ApplicationHeader.last_modified.key()); } if (includeContentLength && !lenSet) { logger.debug("CANNOT SET: {}", ApplicationHeader.content_length.key()); } } return builder; } public static ResponseBuilder setInfoHeaders(final ResponseBuilder builder, final File item, final boolean includeContentLength, final String contentType) throws IndyWorkflowException { // I don't think we want to use the result from upstream; it's often junk...we should retain control of this. builder.header(ApplicationHeader.content_type.key(), contentType); builder.header(ApplicationHeader.last_modified.key(), HttpUtils.formatDateHeader(item.lastModified())); if (includeContentLength) { builder.header(ApplicationHeader.content_length.key(), item.length()); } return builder; } public static Response formatResponseFromMetadata(final HttpExchangeMetadata metadata) { return formatResponseFromMetadata(metadata, null); } public static Response formatResponseFromMetadata(final HttpExchangeMetadata metadata, final Consumer<ResponseBuilder> builderModifier) { int code = metadata.getResponseStatusCode(); // 500-level error; use 502 response. Logger logger = LoggerFactory.getLogger(ResponseUtils.class); logger.info("Formatting response with code: {}", code); ResponseBuilder builder = null; if (code / 100 == 5) { builder = Response.status(502); } builder = Response.status(code); if (builderModifier != null) { builderModifier.accept(builder); } return builder.build(); } public static Response formatOkResponseWithEntity(final Object output, final String contentType, final Consumer<ResponseBuilder> builderModifier) { ResponseBuilder builder = Response.ok(output).type(contentType); if (builderModifier != null) { builderModifier.accept(builder); } return builder.build(); } public static Response formatOkResponseWithEntity(final Object output, final String contentType) { return formatOkResponseWithEntity(output, contentType, null); } public static Response formatBadRequestResponse(final String error, final Consumer<ResponseBuilder> builderModifier) { final String msg = "{\"error\": \"" + error + "\"}\n"; ResponseBuilder builder = Response.status(Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON).entity(msg); if (builderModifier != null) { builderModifier.accept(builder); } return builder.build(); } public static Response formatBadRequestResponse(final String error) { return formatBadRequestResponse(error, null); } public static Response formatResponse(final Throwable error, final Consumer<ResponseBuilder> builderModifier) { return formulateResponse(null, error, null, false, builderModifier); } public static Response formatResponse(final Throwable error) { return formulateResponse(null, error, null, false, null); } public static void throwError(final Throwable error, final Consumer<ResponseBuilder> builderModifier) { formulateResponse(null, error, null, true, builderModifier); } public static void throwError(final Throwable error) { formulateResponse(null, error, null, true, null); } public static Response formatResponse(final ApplicationStatus status, final Throwable error, final Consumer<ResponseBuilder> builderModifier) { return formulateResponse(status, error, null, false, builderModifier); } public static Response formatResponse(final ApplicationStatus status, final Throwable error) { return formulateResponse(status, error, null, false, null); } public static Response formatResponse(final ApplicationStatus status, final String message) { return formulateResponse(status, null, message, false, null); } public static void throwError(final ApplicationStatus status, final Throwable error, final Consumer<ResponseBuilder> builderModifier) { formulateResponse(status, error, null, true, builderModifier); } public static void throwError(final ApplicationStatus status, final Throwable error) { formulateResponse(status, error, null, true, null); } public static Response formatResponse(final Throwable error, final String message, final Consumer<ResponseBuilder> builderModifier) { return formulateResponse(null, error, message, false, builderModifier); } public static Response formatResponse(final Throwable error, final String message) { return formulateResponse(null, error, message, false, null); } public static void throwError(final Throwable error, final String message, final Consumer<ResponseBuilder> builderModifier) { formulateResponse(null, error, message, true, builderModifier); } public static void throwError(final Throwable error, final String message) { formulateResponse(null, error, message, true, null); } public static Response formatResponse(final ApplicationStatus status, final Throwable error, final String message, final Consumer<ResponseBuilder> builderModifier) { return formulateResponse(status, error, message, false, builderModifier); } public static Response formatResponse(final ApplicationStatus status, final Throwable error, final String message) { return formulateResponse(status, error, message, false, null); } public static void throwError(final ApplicationStatus status, final Throwable error, final String message, final Consumer<ResponseBuilder> builderModifier) { formulateResponse(status, error, message, true, builderModifier); } public static void throwError(final ApplicationStatus status, final Throwable error, final String message) { formulateResponse(status, error, message, true, null); } private static Response formulateResponse(final ApplicationStatus status, final Throwable error, final String message, final boolean throwIt, Consumer<ResponseBuilder> builderModifier) { final String id = generateErrorId(); final String msg = formatEntity(id, error, message).toString(); Status code = Status.INTERNAL_SERVER_ERROR; if (status != null) { code = Status.fromStatusCode(status.code()); LOGGER.debug("got error code from parameter: {}", code); } else if ((error instanceof IndyWorkflowException) && ((IndyWorkflowException) error).getStatus() > 0) { final int sc = ((IndyWorkflowException) error).getStatus(); LOGGER.debug("got error code from exception: {}", sc); code = Status.fromStatusCode(sc); } LOGGER.error("Sending error response: {} {}\n{}", code.getStatusCode(), code.getReasonPhrase(), msg); ResponseBuilder builder = Response.status(code).type(MediaType.TEXT_PLAIN).entity(msg); if (builderModifier != null) { builderModifier.accept(builder); } Response response = builder.build(); if (throwIt) { throw new WebApplicationException(error, response); } return response; } public static String generateErrorId() { return DigestUtils.sha256Hex(Thread.currentThread().getName()); //+ "@" + new SimpleDateFormat( "yyyy-MM-ddThhmmss.nnnZ" ).format( new Date() ); } public static CharSequence formatEntity(final Throwable error) { return formatEntity(generateErrorId(), error, null); } public static CharSequence formatEntity(final String id, final Throwable error) { return formatEntity(id, error, null); } public static CharSequence formatEntity(final Throwable error, final String message) { return formatEntity(generateErrorId(), error, message); } public static CharSequence formatEntity(final String id, final Throwable error, final String message) { final StringWriter sw = new StringWriter(); sw.append("Id: ").append(id).append("\n"); if (message != null) { sw.append("Message: ").append(message).append("\n"); } if (error != null) { sw.append(error.getMessage()); final Throwable cause = error.getCause(); if (cause != null) { sw.append("Error:\n\n"); cause.printStackTrace(new PrintWriter(sw)); } sw.write('\n'); } return sw.toString(); } public static ResponseBuilder markDeprecated(final ResponseBuilder rb, final String alt) { return rb.header(ApplicationHeader.deprecated.key(), alt); } }