/**
* Copyright (c) Codice Foundation
* <p>
* This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or any later version.
* <p>
* 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
* Lesser General Public License for more details. A copy of the GNU Lesser General Public License
* is distributed along with this program and can be found at
* <http://www.gnu.org/licenses/lgpl.html>.
*/
package ddf.compression.exi;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
import javax.ws.rs.core.HttpHeaders;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.cxf.helpers.CastUtils;
import org.apache.cxf.interceptor.MessageSenderInterceptor;
import org.apache.cxf.io.CachedOutputStream;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Interceptor that converts message content to exi-encoding if supporting by calling client.
*/
public class EXIOutInterceptor extends AbstractPhaseInterceptor<Message> {
private static final Logger LOGGER = LoggerFactory.getLogger(EXIOutInterceptor.class);
private static final String EXI_ACCEPT_ENCODING = "x-exi";
/**
* Creates a new Interceptor that handles converting server responses to exi-encoding.
*/
public EXIOutInterceptor() {
super(Phase.PREPARE_SEND);
addAfter(MessageSenderInterceptor.class.getName());
}
@Override
public void handleMessage(Message message) {
if (isRequestor(message)) {
//client sending request
LOGGER.trace("Not performing any EXI compression for initial request.");
} else {
//server sending back response
Message request = message.getExchange()
.getInMessage();
Map<String, List<String>> requestHeaders = CastUtils.cast((Map<?, ?>) request.get(
Message.PROTOCOL_HEADERS));
if (requestHeaders != null) {
String acceptEncodingHeader =
StringUtils.join(requestHeaders.get(HttpHeaders.ACCEPT_ENCODING), ",");
if (StringUtils.isNotBlank(acceptEncodingHeader) && acceptEncodingHeader.contains(
EXI_ACCEPT_ENCODING)) {
LOGGER.debug("Sending back response message using EXI-encoding.");
OutputStream os = message.getContent(OutputStream.class);
EXIOutputStream cached = new EXIOutputStream(os);
message.setContent(OutputStream.class, cached);
} else {
LOGGER.debug("EXI encoding not accepted by the client, skipping EXI encoding.");
}
} else {
LOGGER.debug(
"No request headers were found in the incoming request. Cannot encode to exi.");
}
}
}
/**
* OutputStream that caches data and on close will encode the data into an exi format and send it out on the outputstream
* provided in the constructor.
*/
private static class EXIOutputStream extends CachedOutputStream {
private OutputStream outStream;
/**
* Create a new Exi-based output stream.
*
* @param outStream Stream to write the exi-ecoded data to.
*/
public EXIOutputStream(OutputStream outStream) {
super();
this.outStream = outStream;
}
@Override
protected void doClose() throws IOException {
InputStream xmlStream = null;
try {
xmlStream = getInputStream();
EXIEncoder.encode(xmlStream, outStream);
} catch (Exception exp) {
LOGGER.debug(
"Encountered exception when trying to encode outgoing response into EXI. Sending back uncompressed response.",
exp);
resetOut(outStream, true);
} finally {
IOUtils.closeQuietly(xmlStream);
}
}
}
}