Java tutorial
/************************************************************************* * Copyright 2009-2013 Eucalyptus Systems, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta * CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need * additional information or have any questions. ************************************************************************/ package com.eucalyptus.objectstorage.pipeline; import java.nio.charset.Charset; import org.apache.log4j.Logger; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpResponseStatus; import org.jboss.netty.handler.codec.http.HttpVersion; import com.eucalyptus.context.Context; import com.eucalyptus.context.Contexts; import com.eucalyptus.http.MappingHttpRequest; import com.eucalyptus.http.MappingHttpResponse; import com.eucalyptus.objectstorage.exceptions.ObjectStorageException; import com.eucalyptus.objectstorage.exceptions.s3.InvalidAccessKeyIdException; import com.eucalyptus.objectstorage.exceptions.s3.SignatureDoesNotMatchException; import com.eucalyptus.objectstorage.msgs.ObjectStorageErrorMessageType; import com.eucalyptus.ws.WebServicesException; import com.google.common.base.Strings; import com.google.common.util.concurrent.Runnables; public class ObjectStorageRESTExceptionHandler extends SimpleChannelUpstreamHandler { private static final Logger LOG = Logger.getLogger(ObjectStorageRESTExceptionHandler.class); private static final String CODE_UNKNOWN = "UNKNOWN"; private static final Charset UTF_8 = Charset.forName("UTF-8"); @Override public void exceptionCaught(final ChannelHandlerContext ctx, final ExceptionEvent e) throws Exception { final Channel ch = e.getChannel(); Throwable cause = e.getCause(); if (cause.getCause() != null) { // wrapped exception cause = cause.getCause(); } // Get the request ID from the context and clear the context. If you cant log an exception and move on String requestId = null; HttpVersion httpVersion = HttpVersion.HTTP_1_0; Runnable cleanup = Runnables.doNothing(); try { if (ch != null) { Context context = Contexts.lookup(ch); requestId = context.getCorrelationId(); MappingHttpRequest request = context.getHttpRequest(); httpVersion = request != null ? request.getProtocolVersion() : httpVersion; cleanup = () -> Contexts.clear(context); } } catch (Exception ex) { LOG.trace("Error getting request ID or clearing context", ex); } // Populate the error response fields final HttpResponseStatus status; final String code; final String resource; if (cause instanceof ObjectStorageException) { ObjectStorageException walrusEx = (ObjectStorageException) cause; status = walrusEx.getStatus(); code = walrusEx.getCode(); resource = walrusEx.getResource(); } else if (cause instanceof WebServicesException) { WebServicesException webEx = (WebServicesException) cause; status = webEx.getStatus(); code = CODE_UNKNOWN; resource = null; } else { status = HttpResponseStatus.INTERNAL_SERVER_ERROR; code = CODE_UNKNOWN; resource = null; } final ObjectStorageErrorMessageType errorResponse = new ObjectStorageErrorMessageType(); errorResponse.setResource(Strings.nullToEmpty(resource)); errorResponse.setMessage(Strings.nullToEmpty(cause.getMessage())); errorResponse.setCode(Strings.nullToEmpty(code)); errorResponse.setRequestId(Strings.nullToEmpty(requestId)); errorResponse.setStatus(status); if (cause instanceof InvalidAccessKeyIdException) { errorResponse.setAccessKeyId(((InvalidAccessKeyIdException) cause).getAccessKeyId()); errorResponse.setResource(null); } if (cause instanceof SignatureDoesNotMatchException) { SignatureDoesNotMatchException ex = (SignatureDoesNotMatchException) cause; errorResponse.setAccessKeyId(ex.getAccessKeyId()); errorResponse.setResource(null); errorResponse.setStringToSign(Strings.nullToEmpty(ex.getStringToSign())); errorResponse.setSignatureProvided(Strings.nullToEmpty(ex.getSignatureProvided())); if (ex.getStringToSign() != null) errorResponse.setStringToSignBytes(stringToByteString(ex.getStringToSign())); errorResponse.setCanonicalRequest(Strings.nullToEmpty(ex.getCanonicalRequest())); if (ex.getCanonicalRequest() != null) errorResponse.setCanonicalRequestBytes(stringToByteString(ex.getCanonicalRequest())); } if (ctx.getChannel().isConnected()) { final MappingHttpResponse response = new MappingHttpResponse(httpVersion); response.setStatus(status); response.setMessage(errorResponse); response.setCorrelationId(requestId); errorResponse.setCorrelationId(requestId); final ChannelFuture writeFuture = Channels.future(ctx.getChannel()); writeFuture.addListener(ChannelFutureListener.CLOSE); response.setHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE); Channels.write(ctx, writeFuture, response); cleanup.run(); } else { ctx.sendDownstream(e); } } private static String stringToByteString(String in) { StringBuilder sb = new StringBuilder(); byte[] b = in.getBytes(UTF_8); for (int i = 0; i < b.length; i++) sb.append(b[i]).append(" "); sb.deleteCharAt(sb.length() - 1); return sb.toString(); } }