src.main.java.com.mgnt.utils.WebUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of MgntUtils Show documentation
Show all versions of MgntUtils Show documentation
Set of various Utils: stacktrace noise filter, String to/from unicode sequence converter, simple Http client JSON parser/serializer,
Silent String parsing to Integer and other numeric types, Parsing String to time intervals with support for time unit suffixes,
JSON parser that provides serialization/deserialization of classes to JSON, Version comparator and Version ranges operations,
Self-throttling binary reader from Http request, File reader, A utility that automatically initiates a Factory with instances of all
classes that implement user provided interface. An infrastructure for writing Scheduled Task classes where time
interval for task execution is provided in humanly readable format (such as "9h" for 9 hours)
package com.mgnt.utils;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/*
* This class is commented out because deep-common project does not have "Java EE" packages in its classpath. It only
* contains Java SE. As a result class javax.servlet.http.HttpServletRequest can not be resolved. This is the only
* problem with this class. If Java EE extention will be added to the classpath this class may be uncommented and
* used.
*/
/**
* This class provides various web related utilities
*
* @author Michael Gantman
*/
public class WebUtils {
//Default buffer size - 8K
public static final int DEFAULT_BUFFER_SIZE = 8192;
/*
* This variable holds the maximum number of subsequent failures allowed. If we attempt to read from the source
* and the number of read bytes returns as 0 yet no error was reported we will try to read again. but we don't
* want to get stuck in the infinite loop if this situation keeps reoccuring. So we want to set upper limit
* for the number of subsequent failures, after which we will give up and report an error.
*/
public static final int MAX_SUBSEQUENT_FAILURES_LIMIT = 10;
/**
* This method reads the content of HTTPServletRequest as binary (raw) info without any modifications. I.e.
* just as it was received.
*
* @param request HTTPServletRequest to be read
* @return byte array that contains unmodified binary info read from request or null if no info was read
* @throws IOException if any problems occurred.
*/
public static byte[] readRequestContentAsByteArray(HttpServletRequest request) throws IOException {
List resultCollector = null;
boolean unknownLength = true;
try (InputStream reader = request.getInputStream()) {
int length = request.getContentLength();
switch (length) {
case -1: {
length = DEFAULT_BUFFER_SIZE;
break;
}
case 0: {
/*
* Request has no content. It's not expected to occur, but just in case
*/
return null;
}
default: {
unknownLength = false;
}
}
if (unknownLength) {
resultCollector = new ArrayList(length);
}
int totalNumberOfReadBytes = 0;
byte[] byteBuffer = new byte[length];
int numberOfReadBytes = totalNumberOfReadBytes = reader.read(byteBuffer);
if (numberOfReadBytes < 0) {
return null;
}
if (!unknownLength && totalNumberOfReadBytes == length) {
return byteBuffer;
}
if (unknownLength) {
for (int i = 0; i < numberOfReadBytes; i++) {
resultCollector.add(byteBuffer[i]);
}
}
/*
* If the original content length was unknown or if we did not read yet all the info then read until the end
*/
int numberOfsubsequentFailures = 0;
do {
if (!unknownLength) {
numberOfReadBytes = reader.read(byteBuffer, totalNumberOfReadBytes, length - totalNumberOfReadBytes);
} else {
numberOfReadBytes = reader.read(byteBuffer);
}
if (numberOfReadBytes > 0) {
/*
* This is the main or expected branch. It occurs if the reading from the source was successful
*/
if (numberOfsubsequentFailures > 0) {
/*
* We have read some bytes successfully. So if before this iteration there was some number
* of subsequent failures we just broke that sequence with current success. So we can reset
* the number of subsequent failures to 0
*/
numberOfsubsequentFailures = 0;
}
if (unknownLength) {
for (int i = 0; i < numberOfReadBytes; i++) {
resultCollector.add(byteBuffer[i]);
}
}
totalNumberOfReadBytes += numberOfReadBytes;
} else {
/*
* This branch occurs If we attempt to read from the source and the number of read bytes returns as 0
* yet no error was reported we will try to read again. But we don't want to get stuck in the infinite
* loop if this situation keeps reoccuring. So we want to set upper limit for the number of subsequent
* failures uninterrupted by any successful read, after which we will give up and report an error.
*/
if (++numberOfsubsequentFailures >= MAX_SUBSEQUENT_FAILURES_LIMIT) {
/*
* We reached the maximum number of subsequent failures. So we give up and report a reading error
*/
throw new IOException("The reading from the source could not be completed due to unknown error");
} else {
/*
* If we just read 0 bytes don't immediately read again. Make a small pause in order not to
* exhaust processor resources and to let the source some time to give us something to read
*/
TimeUtils.sleepFor(1L, TimeUnit.MILLISECONDS);
}
}
} while (numberOfReadBytes >= 0);
if (!unknownLength && totalNumberOfReadBytes < length) {
throw new IOException("The length of info read is less the declared content length");
}
if (unknownLength) {
byteBuffer = new byte[resultCollector.size()];
for (int i = 0; i < resultCollector.size(); i++) {
byteBuffer[i] = resultCollector.get(i);
}
}
return byteBuffer;
} catch (IOException ioe) {
throw ioe;
} catch (Exception e) {
throw new IOException("Unexpected error occurred", e);
}
}
}