package org.jboss.resteasy.plugins.server.vertx;
import io.vertx.core.http.HttpHeaders;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.HttpServerResponse;
import org.jboss.resteasy.plugins.server.vertx.i18n.Messages;
import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
import org.jboss.resteasy.spi.HttpResponse;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.NewCookie;
import javax.ws.rs.ext.RuntimeDelegate;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
public class VertxHttpResponse implements HttpResponse
{
private int status = 200;
private OutputStream os;
private MultivaluedMap<String, Object> outputHeaders;
final HttpServerResponse response;
private boolean committed;
private ResteasyProviderFactory providerFactory;
private final HttpMethod method;
public VertxHttpResponse(HttpServerResponse response, ResteasyProviderFactory providerFactory)
{
this(response, providerFactory, null);
}
public VertxHttpResponse(HttpServerResponse response, ResteasyProviderFactory providerFactory, HttpMethod method)
{
outputHeaders = new MultivaluedMapImpl<String, Object>();
this.method = method;
os = (method == null || !method.equals(HttpMethod.HEAD)) ? new ChunkOutputStream(this, 1000) : null;
this.response = response;
this.providerFactory = providerFactory;
}
@Override
public void setOutputStream(OutputStream os)
{
this.os = os;
}
@Override
public int getStatus()
{
return status;
}
@Override
public void setStatus(int status)
{
this.status = status;
}
@Override
public MultivaluedMap<String, Object> getOutputHeaders()
{
return outputHeaders;
}
@Override
public OutputStream getOutputStream() throws IOException
{
return os;
}
@Override
public void addNewCookie(NewCookie cookie)
{
outputHeaders.add(javax.ws.rs.core.HttpHeaders.SET_COOKIE, cookie);
}
@Override
public void sendError(int status) throws IOException
{
sendError(status, null);
}
@Override
public void sendError(int status, String message) throws IOException
{
if (committed)
{
throw new IllegalStateException();
}
response.setStatusCode(status);
if (message != null)
{
response.end(message);
} else
{
response.end();
}
committed = true;
}
@Override
public boolean isCommitted()
{
return committed;
}
@Override
public void reset()
{
if (committed)
{
throw new IllegalStateException(Messages.MESSAGES.alreadyCommitted());
}
outputHeaders.clear();
}
@SuppressWarnings({"rawtypes", "unchecked"})
public static void transformHeaders(VertxHttpResponse vertxResponse, HttpServerResponse response, ResteasyProviderFactory factory)
{
for (Map.Entry<String, List<Object>> entry : vertxResponse.getOutputHeaders().entrySet())
{
String key = entry.getKey();
for (Object value : entry.getValue())
{
RuntimeDelegate.HeaderDelegate delegate = factory.getHeaderDelegate(value.getClass());
if (delegate != null)
{
response.headers().add(key, delegate.toString(value));
} else
{
response.headers().set(key, value.toString());
}
}
}
}
public void prepareChunkStream()
{
committed = true;
response.setStatusCode(getStatus());
response.setChunked(true);
transformHeaders(this, response, providerFactory);
}
private void prepareEmptyResponse()
{
committed = true;
response.setStatusCode(getStatus());
transformHeaders(this, response, providerFactory);
response.headersEndHandler(h -> {
response.headers().remove(HttpHeaders.CONTENT_LENGTH);
response.headers().set(HttpHeaders.CONNECTION, HttpHeaders.KEEP_ALIVE);
});
}
public void finish() throws IOException
{
if (os != null) {
os.flush();
if (!isCommitted())
{
prepareChunkStream();
}
} else {
prepareEmptyResponse();
}
response.end();
}
}