Issue #2928: Limit thriftsrv and textdbsrv streams.

Change-Id: I5f59d3ac39f7e776f88d65f3d015862968c3e178

Former-commit-id: 96bf7347434344901965bd4510d14edb9bdcd62a
This commit is contained in:
Richard Peter 2014-04-16 17:12:11 -05:00 committed by Gerrit Code Review
parent d8303c10ee
commit 861a7b0cd5
21 changed files with 761 additions and 36 deletions

View file

@ -57,6 +57,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
* Aug 18, 2013 #2097 dhladky Allowed extension by OGCJAXBManager
* Sep 30, 2013 2361 njensen Refactored for cleanliness
* Nov 14, 2013 2361 njensen Added lazy init option, improved unmarshal error message
* Apr 16, 2014 2928 rjpeter Updated marshalToStream to not close the stream.
* </pre>
*
* @author chammack
@ -372,13 +373,22 @@ public class JAXBManager {
*/
public void marshalToXmlFile(Object obj, String filePath,
boolean formattedOutput) throws SerializationException {
OutputStream os = null;
try {
marshalToStream(obj, new FileOutputStream(new File(filePath)),
formattedOutput);
os = new FileOutputStream(new File(filePath));
marshalToStream(obj, os, formattedOutput);
} catch (SerializationException e) {
throw e;
} catch (Exception e) {
throw new SerializationException(e);
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
// ignore
}
}
}
}
@ -419,13 +429,6 @@ public class JAXBManager {
if ((msh != null) && (marshallers.size() < QUEUE_SIZE)) {
marshallers.add(msh);
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
// ignore
}
}
}
}

View file

@ -50,7 +50,7 @@ import com.raytheon.uf.common.util.ServiceLoaderUtil;
* Aug 06, 2013 2228 njensen More efficient transformFromThrift(Class, byte[])
* Aug 13, 2013 2169 bkowal Unzip any gzipped data before applying thrift transformations
* Oct 01, 2013 2163 njensen Updated calls to JAXBManager
*
* Apr 16, 2014 2928 rjpeter Added jaxbMarshalToStream.
* </pre>
*
* @author chammack
@ -176,6 +176,26 @@ public final class SerializationUtil {
}
/**
* Convert an instance of a class to an XML representation and write XML to
* a stream. Uses JAXB.
*
* @param obj
* Object to be marshaled
* @param filePath
* Path to the output file
* @throws SerializationException
*/
public static void jaxbMarshalToStream(Object obj, OutputStream os)
throws SerializationException {
try {
getJaxbManager().marshalToStream(obj, os);
} catch (JAXBException e) {
throw new SerializationException(e);
}
}
/**
* Instantiates an object from the XML representation in a File. Uses JAXB.
*

View file

@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Utility Plug-in
Bundle-SymbolicName: com.raytheon.uf.common.util
Bundle-Version: 1.12.1174.qualifier
Bundle-Version: 1.14.0
Bundle-Vendor: RAYTHEON
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Require-Bundle: org.apache.commons.beanutils;bundle-version="1.8.3",
@ -18,4 +18,5 @@ Export-Package: com.raytheon.uf.common.util,
com.raytheon.uf.common.util.header,
com.raytheon.uf.common.util.mapping,
com.raytheon.uf.common.util.registry,
com.raytheon.uf.common.util.session
com.raytheon.uf.common.util.session,
com.raytheon.uf.common.util.stream

View file

@ -39,12 +39,15 @@ package com.raytheon.uf.common.util;
*/
public class SizeUtil {
private static final int BYTES_PER = 1024;
private static final String[] REP_PREFIX = new String[] { "B", "kB", "MB",
"GB", "TB", "PB", "EB", "ZB", "YB" };
public static final long BYTES_PER_KB = BYTES_PER;
public static final long BYTES_PER_MB = BYTES_PER_KB * BYTES_PER;
/**
* Transforms a number of bytes to a pretty string based on the total number
* of bytes, e.g. B, kB, MB, or GB as fitting. For example: 1000 -> 1000B,
@ -65,7 +68,7 @@ public class SizeUtil {
}
int reps = 0;
while (n > BYTES_PER && reps < REP_PREFIX.length - 1) {
while ((n > BYTES_PER) && (reps < (REP_PREFIX.length - 1))) {
reps++;
n /= BYTES_PER;
}

View file

@ -0,0 +1,175 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.util.stream;
import java.io.IOException;
import java.io.InputStream;
/**
* Stream that counts the number of bytes that have been read.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 15, 2014 2928 rjpeter Initial creation
*
* </pre>
*
* @author rjpeter
* @version 1.0
*/
public class CountingInputStream extends InputStream {
/**
* Stream to get data from.
*/
protected final InputStream wrappedStream;
/**
* Number of bytes that have been read.
*/
protected long bytesRead = 0;
/**
* Wraps the passed {@code InputStream} counting the bytes that are read
* from it.
*
* @param inputStream
*/
public CountingInputStream(InputStream inputStream) {
this.wrappedStream = inputStream;
}
/*
* (non-Javadoc)
*
* @see java.io.InputStream#read(byte[])
*/
@Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
/*
* (non-Javadoc)
*
* @see java.io.InputStream#read(byte[], int, int)
*/
@Override
public int read(byte[] b, int off, int len) throws IOException {
int rval = wrappedStream.read(b, off, len);
increaseBytesRead(rval);
return rval;
}
/*
* (non-Javadoc)
*
* @see java.io.InputStream#skip(long)
*/
@Override
public long skip(long n) throws IOException {
return wrappedStream.skip(n);
}
/*
* (non-Javadoc)
*
* @see java.io.InputStream#available()
*/
@Override
public int available() throws IOException {
return wrappedStream.available();
}
/**
* Closes the underlying stream. Nothing in this stream needs to be closed
* as long as the wrappedStream is closed.
*/
@Override
public void close() throws IOException {
wrappedStream.close();
}
/*
* (non-Javadoc)
*
* @see java.io.InputStream#mark(int)
*/
@Override
public synchronized void mark(int readlimit) {
wrappedStream.mark(readlimit);
}
/*
* (non-Javadoc)
*
* @see java.io.InputStream#reset()
*/
@Override
public synchronized void reset() throws IOException {
wrappedStream.reset();
}
/*
* (non-Javadoc)
*
* @see java.io.InputStream#markSupported()
*/
@Override
public boolean markSupported() {
return wrappedStream.markSupported();
}
/*
* (non-Javadoc)
*
* @see java.io.InputStream#read()
*/
@Override
public int read() throws IOException {
int rval = wrappedStream.read();
increaseBytesRead(1);
return rval;
}
/**
* Method that updates the internal count of the number of bytes read. Also
* useful extension point for special handling based on amount of bytes
* read.
*
* @param bytesRead
* @throws IOException
*/
public void increaseBytesRead(int bytesRead) throws IOException {
this.bytesRead += bytesRead;
}
/**
* Returns the bytes read so far.
*
* @return
*/
public long getBytesRead() {
return bytesRead;
}
}

View file

@ -0,0 +1,133 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.util.stream;
import java.io.IOException;
import java.io.OutputStream;
/**
* Stream that counts the number of bytes that have been written.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 15, 2014 2928 rjpeter Initial creation
*
* </pre>
*
* @author rjpeter
* @version 1.0
*/
public class CountingOutputStream extends OutputStream {
/**
* Stream to write data to.
*/
protected final OutputStream wrappedStream;
/**
* Number of bytes that have been written.
*/
protected long bytesWritten = 0;
/**
* Wraps the passed {@code OutputStream} counting the bytes that are written
* to it.
*
* @param outputStream
*/
public CountingOutputStream(OutputStream outputStream) {
this.wrappedStream = outputStream;
}
/*
* (non-Javadoc)
*
* @see java.io.OutputStream#write(byte[])
*/
@Override
public void write(byte[] b) throws IOException {
this.write(b, 0, b.length);
}
/*
* (non-Javadoc)
*
* @see java.io.OutputStream#write(byte[], int, int)
*/
@Override
public void write(byte[] b, int off, int len) throws IOException {
wrappedStream.write(b, off, len);
increaseBytesWritten(len);
}
/*
* (non-Javadoc)
*
* @see java.io.OutputStream#flush()
*/
@Override
public void flush() throws IOException {
wrappedStream.flush();
}
/**
* Closes the underlying stream. Nothing in this stream needs to be closed
* as long as the wrappedStream is closed.
*/
@Override
public void close() throws IOException {
wrappedStream.close();
}
/*
* (non-Javadoc)
*
* @see java.io.OutputStream#write(int)
*/
@Override
public void write(int b) throws IOException {
wrappedStream.write(b);
increaseBytesWritten(1);
}
/**
* Method that updates the internal count of the number of bytes written.
* Also useful extension point for special handling based on amount of bytes
* written.
*
* @param bytesRead
* @throws IOException
*/
public void increaseBytesWritten(int bytesWritten) throws IOException {
this.bytesWritten += bytesWritten;
}
/**
* Returns the bytes written so far.
*
* @return
*/
public long getBytesWritten() {
return bytesWritten;
}
}

View file

@ -0,0 +1,81 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.util.stream;
import java.io.IOException;
import java.io.InputStream;
import com.raytheon.uf.common.util.SizeUtil;
/**
* Stream that limits the number of bytes that can be read. If limit is reached
* an IOException is thrown. This does not preclude more bytes being read from
* the stream.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 15, 2014 2928 rjpeter Initial creation
*
* </pre>
*
* @author rjpeter
* @version 1.0
*/
public class LimitingInputStream extends CountingInputStream {
/**
* Maximum number of bytes that can be read from the wrapped stream before
* errors are thrown on read.
*/
protected final long maxBytes;
/**
* Wraps the given {@code InputStream} and will throw IOException once the
* specified number of bytes have been read from the stream.
*
* @param inputStream
* @param maxBytes
*/
public LimitingInputStream(InputStream inputStream, long maxBytes) {
super(inputStream);
this.maxBytes = maxBytes;
}
/**
* Tracks number of bytes read from wrapped stream. An IOException will be
* thrown if number of bytes read exceeds {@code maxBytes}.
*
* @param bytesRead
* @throws IOException
*/
@Override
public void increaseBytesRead(int bytesRead) throws IOException {
super.increaseBytesRead(bytesRead);
long curBytes = getBytesRead();
if (curBytes > maxBytes) {
throw new IOException("Maximum number of bytes ["
+ SizeUtil.prettyByteSize(maxBytes)
+ "] has been exceeded by stream");
}
}
}

View file

@ -0,0 +1,81 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.util.stream;
import java.io.IOException;
import java.io.OutputStream;
import com.raytheon.uf.common.util.SizeUtil;
/**
* Stream that limits the number of bytes that can be written. If limit is
* reached an IOException is thrown. This does not preclude more bytes from
* being written to the stream.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 15, 2014 2928 rjpeter Initial creation
*
* </pre>
*
* @author rjpeter
* @version 1.0
*/
public class LimitingOutputStream extends CountingOutputStream {
/**
* Maximum number of bytes that can be written to the wrapped stream before
* errors are thrown on write.
*/
protected final long maxBytes;
/**
* Wraps the given {@code OutputStream} and will throw IOException once the
* specified number of bytes have been written to the stream.
*
* @param inputStream
* @param maxBytes
*/
public LimitingOutputStream(OutputStream outputStream, long maxBytes) {
super(outputStream);
this.maxBytes = maxBytes;
}
/**
* Tracks number of bytes written to wrapped stream. An IOException will be
* thrown if number of bytes written exceeds {@code maxBytes}.
*
* @param bytesWritten
* @throws IOException
*/
@Override
public void increaseBytesWritten(int bytesWritten) throws IOException {
super.increaseBytesWritten(bytesWritten);
long curBytes = getBytesWritten();
if (curBytes > maxBytes) {
throw new IOException("Maximum number of bytes ["
+ SizeUtil.prettyByteSize(maxBytes)
+ "] has been exceeded by stream");
}
}
}

View file

@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Auth Plug-in
Bundle-SymbolicName: com.raytheon.uf.edex.auth
Bundle-Version: 1.12.1174.qualifier
Bundle-Version: 1.14.0
Bundle-Vendor: RAYTHEON
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Require-Bundle: com.raytheon.uf.common.serialization;bundle-version="1.11.31",
@ -10,7 +10,8 @@ Require-Bundle: com.raytheon.uf.common.serialization;bundle-version="1.11.31",
com.raytheon.uf.common.auth;bundle-version="1.0.0",
com.raytheon.edex.common;bundle-version="1.11.31",
com.raytheon.uf.common.status;bundle-version="1.11.31",
com.raytheon.uf.common.comm;bundle-version="1.12.1174"
com.raytheon.uf.common.comm;bundle-version="1.12.1174",
com.raytheon.uf.common.util
Export-Package: com.raytheon.uf.edex.auth,
com.raytheon.uf.edex.auth.authentication,
com.raytheon.uf.edex.auth.req,

View file

@ -2,4 +2,5 @@ source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.,\
res/
res/,\
resources/

View file

@ -9,6 +9,7 @@
<bean id="routeWrapper" class="com.raytheon.uf.edex.auth.RemoteRequestRouteWrapper">
<property name="server" ref="serializeServer" />
<property name="byteLimitInMB" value="${thriftService.byteLimitInMB}" />
</bean>
</beans>

View file

@ -0,0 +1,4 @@
# byte limit for input and output streams to the thrift service.
# After specified number of bytes, the stream is rejected to
# prevent jvm OutOfMemory as the client is doing something wrong.
thriftService.byteLimitInMB=100

View file

@ -19,7 +19,10 @@
**/
package com.raytheon.uf.edex.auth;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import com.raytheon.uf.common.auth.AuthException;
import com.raytheon.uf.common.auth.resp.AuthServerErrorResponse;
@ -31,7 +34,10 @@ import com.raytheon.uf.common.serialization.comm.RequestWrapper;
import com.raytheon.uf.common.serialization.comm.response.ServerErrorResponse;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.util.ByteArrayOutputStreamPool;
import com.raytheon.uf.common.util.SizeUtil;
import com.raytheon.uf.common.util.stream.LimitingInputStream;
import com.raytheon.uf.common.util.stream.LimitingOutputStream;
/**
* Wrapper for camel route so Serialization exceptions can be caught and
@ -48,6 +54,7 @@ import com.raytheon.uf.common.util.SizeUtil;
* reduce garbage objected generated by
* camel doing the auto conversion.
* Feb 06, 2014 2672 bsteffen Return error when Stream is not consumed.
* Apr 15, 2014 2928 rjpeter Limit data streams read in and written out.
* </pre>
*
* @author mschenke
@ -55,20 +62,31 @@ import com.raytheon.uf.common.util.SizeUtil;
*/
public class RemoteRequestRouteWrapper {
private static final IUFStatusHandler thriftSrvLogger = UFStatus
.getNamedHandler("ThriftSrvRequestLogger");
private RemoteRequestServer server;
private int byteLimitInMB;
public byte[] executeThrift(InputStream data) {
/*
* This stream does not need to be closed, Camel will handle closing of
* data
*/
InputStream inputStream = null;
OutputStream outStream = null;
try {
long startTime = System.currentTimeMillis();
inputStream = new LimitingInputStream(data, byteLimitInMB
* SizeUtil.BYTES_PER_MB);
Object obj = SerializationUtil.transformFromThrift(Object.class,
data);
int remaining = data.available();
inputStream);
int remaining = inputStream.available();
if (remaining == 1) {
int tail = data.read();
int tail = inputStream.read();
/*
* When http proxies are being used there is a single null
* character at the end of the message, no need to panic.
@ -89,7 +107,14 @@ public class RemoteRequestRouteWrapper {
request = (IServerRequest) obj;
}
Object rvalObj = server.handleThriftRequest(request);
byte[] rval = SerializationUtil.transformToThrift(rvalObj);
ByteArrayOutputStream baos = ByteArrayOutputStreamPool
.getInstance().getStream();
outStream = new LimitingOutputStream(baos, byteLimitInMB
* SizeUtil.BYTES_PER_MB);
SerializationUtil.transformToThriftUsingStream(rvalObj, outStream);
byte[] rval = baos.toByteArray();
long endTime = System.currentTimeMillis();
StringBuilder sb = new StringBuilder(300);
sb.append("Handled ").append(obj.toString()).append(" in ")
@ -119,6 +144,21 @@ public class RemoteRequestRouteWrapper {
"Failed to serialize throwable to client", e);
return new byte[] {};
}
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
// ignore
}
}
if (outStream != null) {
try {
outStream.close();
} catch (IOException e) {
// ignore
}
}
}
}
@ -130,4 +170,11 @@ public class RemoteRequestRouteWrapper {
this.server = server;
}
public int getByteLimitInMB() {
return byteLimitInMB;
}
public void setByteLimitInMB(int byteLimitInMB) {
this.byteLimitInMB = byteLimitInMB;
}
}

View file

@ -1,7 +1,11 @@
#Thu Mar 26 10:32:57 CDT 2009
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.6
org.eclipse.jdt.core.compiler.source=1.7

View file

@ -161,7 +161,7 @@ public class Main {
m.invoke(null, new Object[0]);
}
System.exit(0);
} catch (ClassNotFoundException e) {
} catch (ClassNotFoundException | LinkageError e) {
logger.error("Could not load class", e);
if (cl != null) {
StringBuilder msg = new StringBuilder(1000);

View file

@ -28,6 +28,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -75,6 +76,10 @@ public class Executor {
public static void start() throws Exception {
final long t0 = System.currentTimeMillis();
Thread.currentThread().setName("EDEXMain");
System.setProperty("System.status", "Starting");
final AtomicBoolean shutdownContexts = new AtomicBoolean(false);
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
@ -87,7 +92,12 @@ public class Executor {
.append("\n* EDEX ESB is shutting down *")
.append("\n**************************************************");
logger.info(msg.toString());
ctxMgr.stopContexts();
if (shutdownContexts.get()) {
ctxMgr.stopContexts();
} else {
logger.info("Contexts never started, skipping context shutdown");
}
long t2 = System.currentTimeMillis();
msg.setLength(0);
msg.append("\n**************************************************");
@ -102,9 +112,6 @@ public class Executor {
}
});
Thread.currentThread().setName("EDEXMain");
System.setProperty("System.status", "Starting");
List<String> xmlFiles = new ArrayList<String>();
List<File> propertiesFiles = new ArrayList<File>();
@ -166,6 +173,8 @@ public class Executor {
ContextManager ctxMgr = (ContextManager) context
.getBean("contextManager");
shutdownContexts.set(true);
// start final routes
ctxMgr.startContexts();

View file

@ -10,7 +10,8 @@ Require-Bundle: com.raytheon.edex.common,
org.apache.commons.lang,
com.raytheon.uf.edex.decodertools;bundle-version="1.0.0",
com.raytheon.uf.common.dataplugin.text,
com.raytheon.uf.common.site;bundle-version="1.12.1152"
com.raytheon.uf.common.site;bundle-version="1.12.1152",
com.raytheon.uf.common.status
Export-Package: com.raytheon.uf.edex.services,
com.raytheon.uf.edex.services.textdbimpl,
com.raytheon.uf.edex.services.textdbsrv

View file

@ -2,4 +2,5 @@ source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.,\
res/
res/,\
resources/

View file

@ -3,6 +3,11 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<bean id="textDbSrvWrapper" class = "com.raytheon.uf.edex.textdbsrv.TextDBSrvWrapper">
<property name="textdbSrv" ref="textdbsrv"/>
<property name="byteLimitInMB" value="${textdbsrv.byteLimitInMB}"/>
</bean>
<camelContext id="textdbsrv-request-camel" xmlns="http://camel.apache.org/schema/spring" errorHandlerRef="errorHandler">
<endpoint id="textdbsrvXml_from"
@ -10,9 +15,7 @@
<route id="textdbsrvXml">
<from uri="ref:textdbsrvXml_from" />
<bean ref="serializationUtil" method="unmarshalFromXml" />
<bean ref="textdbsrv" method="processMessage" />
<bean ref="serializationUtil" method="marshalToXml" />
<bean ref="textDbSrvWrapper" method="executeTextDBMessage" />
</route>
</camelContext>
</beans>

View file

@ -0,0 +1,4 @@
# byte limit for input and output streams to the textdb srv.
# After specified number of bytes, the stream is rejected to
# prevent jvm OutOfMemory as the client is doing something wrong.
textdbsrv.byteLimitInMB=10

View file

@ -0,0 +1,152 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
*/
package com.raytheon.uf.edex.textdbsrv;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import com.raytheon.uf.common.message.Message;
import com.raytheon.uf.common.serialization.SerializationUtil;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.util.ByteArrayOutputStreamPool;
import com.raytheon.uf.common.util.SizeUtil;
import com.raytheon.uf.common.util.stream.LimitingInputStream;
import com.raytheon.uf.common.util.stream.LimitingOutputStream;
import com.raytheon.uf.edex.services.TextDBSrv;
import com.raytheon.uf.edex.services.textdbimpl.CommandExecutor;
/**
* Thin wrapper around TextDBSrv to handle marshalling/unmarshalling and
* limiting of the byte stream.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 15, 2014 2928 rjpeter Initial creation.
*
* </pre>
*
* @author rjpeter
* @version 1.0
*/
public class TextDBSrvWrapper {
private final IUFStatusHandler statusHandler = UFStatus
.getHandler(TextDBSrvWrapper.class);
/**
* The limit of bytes that we are able to read in without erroring off.
*/
private long byteLimitInMB;
/**
* TextDbSrv implementation to use.
*/
private TextDBSrv textdbSrv;
/**
* Unmarshalls the input stream as xml data and sends to textdbsrv for
* processing.
*
* @param is
* @return
*/
public byte[] executeTextDBMessage(InputStream xmlDataStream) {
/*
* This stream does not need to be closed, Camel will handle closing of
* data
*/
InputStream inputStream = null;
Message rval;
try {
inputStream = new LimitingInputStream(xmlDataStream, byteLimitInMB
* SizeUtil.BYTES_PER_MB);
Message message = SerializationUtil.jaxbUnmarshalFromInputStream(
Message.class, inputStream);
rval = textdbSrv.processMessage(message);
} catch (Throwable e) {
statusHandler
.error("Error occured processing textDbSrv message", e);
rval = CommandExecutor
.createErrorMessage("Error occurred during processing: "
+ e.getLocalizedMessage());
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
// ignore
}
}
}
OutputStream outStream = null;
int tries = 0;
while (tries < 2) {
try {
ByteArrayOutputStream baos = ByteArrayOutputStreamPool
.getInstance().getStream();
outStream = new LimitingOutputStream(baos, byteLimitInMB
* SizeUtil.BYTES_PER_MB);
SerializationUtil.jaxbMarshalToStream(rval, outStream);
return baos.toByteArray();
} catch (Exception e) {
statusHandler.error("Error occured marshalling response", e);
tries++;
rval = CommandExecutor
.createErrorMessage("Error occurred during processing: "
+ e.getLocalizedMessage());
} finally {
if (outStream != null) {
try {
outStream.close();
} catch (IOException e) {
// ignore
}
}
}
}
return null;
}
public long getByteLimitInMB() {
return byteLimitInMB;
}
public void setByteLimitInMB(long byteLimitInMB) {
this.byteLimitInMB = byteLimitInMB;
}
public TextDBSrv getTextdbSrv() {
return textdbSrv;
}
public void setTextdbSrv(TextDBSrv textdbSrv) {
this.textdbSrv = textdbSrv;
}
}