I have generated CXF client for a secured web service (file upload) and try to call it. I have following files in my generated folder
CarbonAppUploader(class)
CarbonAppUploaderPortType(Interface)
UploadApp(class).
.........
..........
Following is my client
public class MyTest {
public static void main(String[] args) throws IOException {
JaxWsProxyFactoryBean clientFactory = new JaxWsProxyFactoryBean();
clientFactory.setAddress( "https://localhost:8243/services/CarbonAppUploader.CarbonAppUploaderHttpsEndpoint/" );
clientFactory.setServiceClass( CarbonAppUploader.class );
clientFactory.setUsername("admin");
clientFactory.setPassword("admin");
UploadApp req = new UploadApp();
FileInputStream fileInputStream;
File file1 = new File("/home/malintha/support/....../AxisCApp-1.0.0.car");
byte[] bFile = new byte[(int) file1.length()];
//convert file into array of bytes
fileInputStream = new FileInputStream(file1);
fileInputStream.read(bFile);
fileInputStream.close();
//convert array of bytes into file
FileOutputStream fileOuputStream =
new FileOutputStream("/home/malintha/support/....../AxisCApp-1.0.0.car");
fileOuputStream.write(bFile);
fileOuputStream.close();
org.wso2.carbon.application.upload.xsd.ObjectFactory of=new org.wso2.carbon.application.upload.xsd.ObjectFactory();
UploadedFileItem file=new UploadedFileItem();
file.setFileName(of.createUploadedFileItemFileName("AxisCApp-1.0.0.car"));
file.setFileName(of.createUploadedFileItemFileType("CAR"));
file.setDataHandler(of.createUploadedFileItemDataHandler(bFile));
List<UploadedFileItem> flies=new ArrayList<UploadedFileItem>();
flies.add(0,file);
UploadApp myApp = new UploadApp();
myApp.fileItems=flies;
req.getFileItems().add( file );
CarbonAppUploaderPortType uploadSvc = (CarbonAppUploaderPortType) clientFactory.create();
uploadSvc.uploadApp( req );
}
}
when I run this class I got a exception as follows
INFO: Creating Service {http://upload.application.carbon.wso2.org/}CarbonAppUploaderService from class org.wso2.carbon.application.upload.CarbonAppUploader
Exception in thread "main" java.lang.IllegalArgumentException: org.wso2.carbon.application.upload.CarbonAppUploader is not an interface
at java.lang.reflect.Proxy.getProxyClass0(Proxy.java:470)
clientFactory.create(); method call cause this exception. How can I solve this ?
This is carbonAppUploader class
#WebServiceClient(name = "CarbonAppUploader",
wsdlLocation = "file:/home/malintha/software/axis2-bin/bin/src/org/CappUpload /src/main/resources/myService.wsdl",
targetNamespace = "http://upload.application.carbon.wso2.org")
public class CarbonAppUploader extends Service {
public final static URL WSDL_LOCATION;
public final static QName SERVICE = new QName("http://upload.application.carbon.wso2.org", "CarbonAppUploader");
public final static QName CarbonAppUploaderHttpsSoap12Endpoint = new QName("http://upload.application.carbon.wso2.org", "CarbonAppUploaderHttpsSoap12Endpoint");
public final static QName CarbonAppUploaderHttpsSoap11Endpoint = new QName("http://upload.application.carbon.wso2.org", "CarbonAppUploaderHttpsSoap11Endpoint");
public final static QName CarbonAppUploaderHttpsEndpoint = new QName("http://upload.application.carbon.wso2.org", "CarbonAppUploaderHttpsEndpoint");
static {
URL url = null;
try {
url = new URL("file:/home/malintha/software/axis2-bin/bin/src/org/CappUpload/src/main/resources/myService.wsdl");
} catch (MalformedURLException e) {
java.util.logging.Logger.getLogger(CarbonAppUploader.class.getName())
.log(java.util.logging.Level.INFO,
"Can not initialize the default wsdl from {0}", "file:/home/malintha/software/axis2-bin/bin/src/org/CappUpload/src/main/resources/myService.wsdl");
}
WSDL_LOCATION = url;
}
public CarbonAppUploader(URL wsdlLocation) {
super(wsdlLocation, SERVICE);
}
public CarbonAppUploader(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
public CarbonAppUploader() {
super(WSDL_LOCATION, SERVICE);
}
/**
*
* #return
* returns CarbonAppUploaderPortType
*/
#WebEndpoint(name = "CarbonAppUploaderHttpsSoap12Endpoint")
public CarbonAppUploaderPortType getCarbonAppUploaderHttpsSoap12Endpoint() {
return super.getPort(CarbonAppUploaderHttpsSoap12Endpoint, CarbonAppUploaderPortType.class);
}
/**
*
* #param features
* A list of {#link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the <code>features</code> parameter will have their default values.
* #return
* returns CarbonAppUploaderPortType
*/
#WebEndpoint(name = "CarbonAppUploaderHttpsSoap12Endpoint")
public CarbonAppUploaderPortType getCarbonAppUploaderHttpsSoap12Endpoint(WebServiceFeature... features) {
return super.getPort(CarbonAppUploaderHttpsSoap12Endpoint, CarbonAppUploaderPortType.class, features);
}
/**
*
* #return
* returns CarbonAppUploaderPortType
*/
#WebEndpoint(name = "CarbonAppUploaderHttpsSoap11Endpoint")
public CarbonAppUploaderPortType getCarbonAppUploaderHttpsSoap11Endpoint() {
return super.getPort(CarbonAppUploaderHttpsSoap11Endpoint, CarbonAppUploaderPortType.class);
}
/**
*
* #param features
* A list of {#link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the <code>features</code> parameter will have their default values.
* #return
* returns CarbonAppUploaderPortType
*/
#WebEndpoint(name = "CarbonAppUploaderHttpsSoap11Endpoint")
public CarbonAppUploaderPortType getCarbonAppUploaderHttpsSoap11Endpoint(WebServiceFeature... features) {
return super.getPort(CarbonAppUploaderHttpsSoap11Endpoint, CarbonAppUploaderPortType.class, features);
}
/**
*
* #return
* returns CarbonAppUploaderPortType
*/
#WebEndpoint(name = "CarbonAppUploaderHttpsEndpoint")
public CarbonAppUploaderPortType getCarbonAppUploaderHttpsEndpoint() {
return super.getPort(CarbonAppUploaderHttpsEndpoint, CarbonAppUploaderPortType.class);
}
/**
*
* #param features
* A list of {#link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the <code>features</code> parameter will have their default values.
* #return
* returns CarbonAppUploaderPortType
*/
#WebEndpoint(name = "CarbonAppUploaderHttpsEndpoint")
public CarbonAppUploaderPortType getCarbonAppUploaderHttpsEndpoint(WebServiceFeature... features) {
return super.getPort(CarbonAppUploaderHttpsEndpoint, CarbonAppUploaderPortType.class, features);
}
}
Related
Using as an example a following code from https://www.jitendrazaa.com/blog/java/snmp/create-snmp-client-in-java-using-snmp4j/ to monitor a network when I send OIDs to an empty IP or to a device without SNMP the program throws an exception.
I use a for loop to read IPs. I have tried to change the flow of execution in different ways without success.
the program falls in the getAsStrint method with java.lang.NullPointerException
public class SNMPManager {
Snmp snmp = null;
String address = null;
/**
* Constructor
*
* #param add
*/
public SNMPManager(String add) {
address = add;
}
public static void main(String[] args) throws IOException {
/**
* Port 161 is used for Read and Other operations
* Port 162 is used for the trap generation
*/
for (int i = 37; i < 40; i++) {
System.out.println("ip x.x.x." + i);
SNMPManager client = new SNMPManager("udp:192.168.1." + i + "/161");
//SNMPManager client = new SNMPManager("udp:192.168.1.37/161");
client.start();
/**
* OID - .1.3.6.1.2.1.1.1.0 => SysDec
* OID - .1.3.6.1.2.1.1.5.0 => SysName
* => MIB explorer will be usefull here, as discussed in previous article
*/
String sysDescr = client.getAsString(new OID(".1.3.6.1.2.1.1.5.0"));
System.out.println(".1.3.6.1.2.1.1.5.0" + " - SysName: " + sysDescr);
String sysDescr2 = client.getAsString(new OID(".1.3.6.1.2.1.1.1.0"));
System.out.println(".1.3.6.1.2.1.1.1.0" + " - SysDec: " + sysDescr2);
}
}
/**
* Start the Snmp session. If you forget the listen() method you will not
* get any answers because the communication is asynchronous
* and the listen() method listens for answers.
*
* #throws IOException
*/
private void start() throws IOException {
TransportMapping transport = new DefaultUdpTransportMapping();
snmp = new Snmp(transport);
// Do not forget this line!
transport.listen();
}
/**
* Method which takes a single OID and returns the response from the agent as a String.
*
* #param oid
* #return
* #throws IOException
*/
public String getAsString(OID oid) throws IOException {
ResponseEvent event = get(new OID[]{oid});
return event.getResponse().get(0).getVariable().toString();
}
/**
* This method is capable of handling multiple OIDs
*
* #param oids
* #return
* #throws IOException
*/
public ResponseEvent get(OID oids[]) throws IOException {
PDU pdu = new PDU();
for (OID oid : oids) {
pdu.add(new VariableBinding(oid));
}
pdu.setType(PDU.GET);
ResponseEvent event = snmp.send(pdu, getTarget(), null);
if (event != null) {
return event;
}
throw new RuntimeException("GET timed out");
}
/**
* This method returns a Target, which contains information about
* where the data should be fetched and how.
*
* #return
*/
private Target getTarget() {
Address targetAddress = GenericAddress.parse(address);
CommunityTarget target = new CommunityTarget();
target.setCommunity(new OctetString("public"));
target.setAddress(targetAddress);
target.setRetries(2);
target.setTimeout(1500);
target.setVersion(SnmpConstants.version2c);
return target;
}
make getAsString(OID oid) method like this
public String getAsString(OID oid) throws IOException {
ResponseEvent event = get(new OID[]{oid});
if(event.getResponse() != null){
return event.getResponse().get(0).getVariable().toString();
} else {
return "no target"
}
}
there are no target that is why null pointer exception
I have a RestController with Hystrix and Spring Cloud Stream channels:
#RestController
#RequestMapping(value = "/api/products")
#EnableBinding(ProductProcessor.class)
public class ProductUiController {
/*******
* LISTENERS
*******/
private List<Product> listenAllProducts;
private Product listenProduct;
/*******
* CHANNELS
*******/
#Autowired
#Qualifier(ProductProcessor.OUTPUT_DELETE)
private MessageChannel channel_delete;
#Autowired
#Qualifier(ProductProcessor.OUTPUT_CREATE)
private MessageChannel channel_create;
#Autowired
#Qualifier(ProductProcessor.OUTPUT_UPDATE)
private MessageChannel channel_update;
Logger logger = Logger.getLogger(ProductUiController.class);
#Autowired
RabbitTemplate rabbitTemplate;
#Autowired
RabbitAdmin rabbitAdmin;
#Autowired
private LoadBalancerClient loadBalancer;
/**
* returns all the products in the database
*
* #return
*/
#RequestMapping(method = RequestMethod.GET)
#HystrixCommand(fallbackMethod = "getAllProductsFallback")
public List<Product> getAllProducts() {
try {
ServiceInstance instance = loadBalancer.choose("product-service");
URI uri = instance.getUri();
URL obj = new URL(uri.toString() + "/products");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.getResponseCode();
} catch (MalformedURLException e) {
logger.error(e.getMessage());
} catch (IOException e) {
logger.error(e.getMessage());
}
return this.listenAllProducts;
}
/**
* Returns a specific product from product-service
*
* #param id
* #return
*/
#RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public Product getProduct(#PathVariable("id") Long id) {
try {
ServiceInstance instance = loadBalancer.choose("product-service");
URI uri = instance.getUri();
URL obj = new URL(uri.toString() + "/products/" + id);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
con.getResponseCode();
} catch (MalformedURLException e) {
logger.error(e.getMessage());
} catch (IOException e) {
logger.error(e.getMessage());
}
System.out.println("RETURNED PRODUCT = " + listenProduct);
return listenProduct;
}
#HystrixCommand(fallbackMethod = "addProductFallback")
#RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public Product addProduct(#RequestBody Product product) {
logger.info("SENT VIA OUTPUT_CREATE: " + product);
channel_create.send(MessageBuilder.withPayload(product).build());
return product;
}
#HystrixCommand(fallbackMethod = "removeProductFallback")
#RequestMapping(method = RequestMethod.DELETE)
public void removeProduct(#RequestParam("id") Long id) {
logger.info("SENT VIA OUTPUT_DELETE: " + id);
this.channel_delete.send(MessageBuilder.withPayload(id).build());
}
/**************************************/
/**********LISTENERS*******************/
/**************************************/
/**
* Receiver for all products
*
* #param products
*/
#StreamListener(ProductProcessor.INPUT_GETALL)
public void listenerGetAllProducts(List<Product> products) {
logger.info("RECEIVED FROM INPUT_GETALL: " + products);
listenAllProducts = products;
}
/**
* Receiver for product
*
* #param product
*/
#StreamListener(ProductProcessor.INPUT_GET)
public void listenerGetProduct(Product product) {
logger.info("RECEIVED FROM INPUT_GET: " + product);
listenProduct = product;
}
/**************************************/
/**********FALLBACK METHODS************/
/**************************************/
/**
* Fallback method for getAllProducts
*
* #return
*/
public List<Product> getAllProductsFallback(Throwable e) {
logger.info("getAllProductsFallback");
return listenAllProducts;
}
/**
* Fallback method for addProduct
*
* #param product
* #return
*/
Product addProductFallback(Product product) {
logger.info("addProductFallback");
return null;
}
/**
* Fallback method for delete
*
* #param id
*/
void removeProductFallback(Long id) {
logger.info("removeProductFallback");
}
}
In the implementation HystrixCommand makes a getDeclaredMethod to ProductUiController to find the fallback methods but #EnableBinding hides class methods from reflection, any clue of a workaround?
Solution: Moved #EnableBinding to main SpringBootApplication class.
Overview:
I am going to use RestTemplate to invoke a get request from external REST webservice.
My code is as follows:
#Slf4j
#Component("AccMemberDetailsApiControllerImpl")
public class AccMemberDetailsApiControllerImpl implements MemberDetailsApiController {
private static final String CONTENT_TYPE_HEADER_NAME = "Content-Type";
private static final String AUTHORIZATION_HEADER_NAME = "Authorization";
private static final String USERID_PARAMETER_NAME = "userId";
private static final String VEHICLEID_PARAMETER_NAME = "vehicleId";
private static final ObjectMapper mapper = new ObjectMapper();
/**
* This constant is used to check whether or not the response from ACC is an empty JSON string
*/
private static final String EMPTY_RESPONSE = "{}";
#Value("${com.blss.memberServices.provider.posServiceURL}")
private String accPosServiceURL;
#Autowired
private RestTemplate restTemplate;
#Autowired
private AccTokenUtility accTokenUtility;
#Autowired
private ResourceMessage resourceMessage;
void setAccTokenUtility(AccTokenUtility accTokenUtility) {
this.accTokenUtility = accTokenUtility;
}
void setResourceMessage(ResourceMessage resourceMessage) {
this.resourceMessage = resourceMessage;
}
/**
* #see MemberDetailsApiController#getMemberDetails(String, String)
*/
#Override
public MemberDetailsModel getMemberDetails(String storeId, String membershipIdentifier) {
/**
* Getting CAD token
*/
String token = accTokenUtility.getCadToken();
/**
* Preparing the request
*/
HttpHeaders headers = new HttpHeaders();
// headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.set(CONTENT_TYPE_HEADER_NAME, MediaType.APPLICATION_JSON_VALUE);
headers.set(AUTHORIZATION_HEADER_NAME, token);
HttpEntity<String> entity = new HttpEntity<>(headers);
/**
* Creating the dispatch URL by means of userId and vehicleId
*/
String dispatchURL = accPosServiceURL + "DispatchedEvent/{userId}/{vehicleId}";
/**
* Creating the URL variables and being valued by corresponding method parameters
*/
Map<String, String> parameters = new HashMap<>();
// parameters.put(USERID_PARAMETER_NAME, storeId);
parameters.put(USERID_PARAMETER_NAME, "mr2");
// parameters.put(VEHICLEID_PARAMETER_NAME, membershipIdentifier);
parameters.put(VEHICLEID_PARAMETER_NAME, "VEH1");
/**
* Calling the rest webservice and returning response with body of type {#link AccMemberDetails}
*/
ResponseEntity<String> response;
MemberDetailsModel memberDetailsModel = null;
AccMemberDetails accMemberDetails;
try {
response = restTemplate.exchange(dispatchURL, HttpMethod.GET, entity, String.class, parameters);
if (response == null || StringUtils.isBlank(response.getBody()) || EMPTY_RESPONSE.equals(response.getBody())) {
throw new ResourceNotFoundException(resourceMessage.getMessage(MEMBER_ERROR_NOT_FOUND, storeId, membershipIdentifier));
} else {
accMemberDetails = deserialize(response.getBody(), AccMemberDetails.class);
String accErrorMessage = accMemberDetails.getUserMessage();
if (!StringUtils.isBlank(accErrorMessage)) {
throw new InternalServerException(resourceMessage.getMessage(MEMBER_ERROR_MESSAGE_FROM_API, "ACC", accErrorMessage));
}
memberDetailsModel = convert(accMemberDetails);
}
} catch (RestClientException e) {
handleExceptions(e, storeId, membershipIdentifier);
}
return memberDetailsModel;
}
/**
* This method is responsible for deserializing string REST response into an object of type {#link AccMemberDetails}
*/
<T> T deserialize(final String response, final Class<T> responseClass) {
try {
return mapper.readValue(response, responseClass);
} catch (IOException e) {
throw new InternalServerException(resourceMessage.getMessage(MEMBER_ERROR_MAP_RESPONSE_OBJECT), e);
}
}
/**
* This method is responsible for converting an instance of type {#link AccMemberDetails} to an instance of type
* {#link MemberDetailsModel}
*
* #param accMemberDetails an instance of type {#link AccMemberDetails}
* #return an instance of type {#link MemberDetailsModel}
*/
MemberDetailsModel convert(AccMemberDetails accMemberDetails) {
MemberDetailsModel memberDetailsModel = new MemberDetailsModel();
memberDetailsModel.setEventId(accMemberDetails.getEventId());
memberDetailsModel.setMemberName(accMemberDetails.getMemberName());
memberDetailsModel.setMembershipNumber(accMemberDetails.getMembershipNumber());
memberDetailsModel.setMembershipLevel(accMemberDetails.getPricingLevel());
return memberDetailsModel;
}
/**
* This method is responsible for handling Exceptions may be thrown by ACC REST webservice
*
* #param e an instance of type {#link RestClientException}
* #param storeId an instance of type {#link String} and used in building exception messages
* #param membershipIdentifier an instance of type {#link String} and used in building exception messages
*/
private void handleExceptions(RestClientException e, String storeId, String membershipIdentifier) {
if (e instanceof HttpStatusCodeException) {
HttpStatusCodeException httpStatusCodeException = (HttpStatusCodeException) e;
HttpStatus httpStatusCode = httpStatusCodeException.getStatusCode();
if (404 == httpStatusCode.value()) {
throw new ResourceNotFoundException(resourceMessage.getMessage(MEMBER_ERROR_NOT_FOUND, storeId, membershipIdentifier), e);
} else if (500 == httpStatusCode.value()) {
throw new InternalServerException(resourceMessage.getMessage(MEMBER_SERVER_ERROR, "ACC"), e);
} else {
throw new InternalServerException(resourceMessage.getMessage(MEMBER_HTTP_STATUS_CODE_ERROR, "HttpStatusCodeException", "ACC"), e);
}
} else {
throw new InternalServerException(resourceMessage.getMessage(MEMBER_REST_CLIENT_ERROR, "RestClientException", "ACC"), e);
}
}
Problem
However I got UnhandledHttpStatusException after calling "restTemplate.exchange(dispatchURL, HttpMethod.GET, entity, String.class, parameters);" in the code snippet. the exception stack trace is as follows:
Caused by: org.springframework.web.client.UnknownHttpStatusCodeException: Unknown status code [443] null
at org.springframework.web.client.DefaultResponseErrorHandler.getHttpStatusCode(DefaultResponseErrorHandler.java:60)
at org.springframework.web.client.DefaultResponseErrorHandler.hasError(DefaultResponseErrorHandler.java:50)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:629)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:597)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:565)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:484)
at com.blss.retailServices.memberServices.controllers.impl.acc.AccMemberDetailsApiControllerImpl.getMemberDetails(AccMemberDetailsApiControllerImpl.java:110)
Now I would be grateful if anyone could suggest me a solution.
I called this webservice with curl by using "-v" in order to get more info in response. As a result, I got the same exception (443) from their side. So, It sounds like they should have a better exception handler to return meaningful exception messages.
How could I implement disposable MBean, one that doesn't prevent resource it is monitoring from being garbage collected?
Let say I wrote dummy statistic MBean but the class it is monitoring is not singleton in the system. I would like MBean to be automatically unregistered once resource is no longer in use.
Any ideas how to achieve that?
Any existing solutions?
Thanks.
Usage
registerWeakMBean("com.company:type=connection,name=" +
getClass().getSimpleName(), connectionStatMBeanImpl, ConnectionStatMBean.class);
Implementatin
package util;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.ref.WeakReference;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanServer;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.StandardMBean;
import org.apache.log4j.Logger;
import sun.management.Agent;
public class JmxUtils {
private static Logger log = Logger.getLogger(JmxUtils.class);
private static Map<Object, String> weakMBeans = new ConcurrentHashMap<Object, String>();
static {
verifyJmxAgentStarted();
}
private static final int getAvailablePort() throws IOException {
ServerSocket s = new ServerSocket(0);
int result = s.getLocalPort();
s.close();
return result;
}
/**
* #param objName
* domain:type=value[,name=value]
* #param implementation
* #param mbeanInterface
* #see ObjectName
* #see StandardMBean
*/
public static final <I> ObjectInstance registerMBean(String objName, I implementation, Class<I> mbeanInterface) {
int counter = 0;
String uniqueSuffix = "";
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
while (true) {
try {
final ObjectName name = new ObjectName(objName + uniqueSuffix);
final StandardMBean mbean = new StandardMBean(implementation, mbeanInterface);
return mbs.registerMBean(mbean, name);
} catch (final InstanceAlreadyExistsException e) {
uniqueSuffix = "" + ++counter;
} catch (final Exception e) {
throw new Error(e);
}
}
}
/**
* Weak MBean will not prevent resource it is monitoring from been garbage collected. MBean will be automatically unregistered.
*
* #param objName
* domain:type=value[,name=value]
* #param implementation
* #param mbeanInterface
* #see ObjectName
* #see StandardMBean
* #see WeakReference
*/
public static final <I> ObjectInstance registerWeakMBean(String objName, I implementation, Class<I> mbeanInterface) {
I proxy = DisposableWeakReference.newWeakReferenceProxy(new DisposableWeakReference<I>(implementation) {
#Override
public void dispose(Object disposable) {
unregisterMBean(weakMBeans.remove(disposable));
}
}, mbeanInterface);
ObjectInstance instance = registerMBean(objName, proxy, mbeanInterface);
weakMBeans.put(proxy, instance.getObjectName().getCanonicalName());
return instance;
}
public static <T> T newJmxClient(Class<T> clazz, String objectName, String serviceUrl) {
return createJmxClient(clazz, objectName, serviceUrl, null, null);
}
public static <T> T newJmxClient(Class<T> clazz, String objectName, String serviceUrl, final String user, final String pass) {
try {
JMXServiceURL jmxServiceUrl = new JMXServiceURL(serviceUrl);
Map<String, ?> env = user == null ? null : new HashMap<String, Object>() {{
put(JMXConnector.CREDENTIALS, new String[] {user, pass});
}};
JMXConnector jmxc = JMXConnectorFactory.connect(jmxServiceUrl, env);
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
ObjectName mbeanName = new ObjectName(objectName);
return JMX.newMBeanProxy(mbsc, mbeanName, clazz, true);
} catch (IOException | MalformedObjectNameException e) {
throw new RuntimeException("Can not create client for remote JMX " + serviceUrl, e);
}
}
/**
* #param objName
* #see ObjectName
*/
public static final void unregisterMBean(String objName) {
try {
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
final ObjectName name = new ObjectName(objName);
mbs.unregisterMBean(name);
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
private static final void verifyJmxAgentStarted() {
try {
String port = System.getProperty("com.sun.management.jmxremote.port");
if (port == null) {
port = String.valueOf(getAvailablePort());
System.setProperty("com.sun.management.jmxremote.port", port);
System.setProperty("com.sun.management.jmxremote.ssl", "false");
System.setProperty("com.sun.management.jmxremote.authenticate", "false");
Agent.startAgent();
}
log.info(InetAddress.getLocalHost().getCanonicalHostName() + ":" + port);
} catch (Exception e) {
throw new Error(e);
}
}
}
package util;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.WeakHashMap;
/**
* Disposable weak reference calls you back when referent has been disposed. You can also create proxy to the referent to emulate direct access.
*
* <pre>
* public class Example {
* public interface I {
* // interface referent is implementing to create a proxy
* }
*
* public static final class T implements I {
* public String toString() {
* return "blah";
* }
* }
*
* private WeakReference<T> wr;
* private I wrp;
* private List<Object> list = new LinkedList<Object>();
*
* private void testWeakRef() {
* T o = new T();
* wr = new DisposableWeakReference<T>(o) {
* public void dispose(Object disposable) {
* list.remove(disposable);
* }
* };
* list.add(wr);
* wrp = DisposableWeakReference.newWeakReferenceProxy(new DisposableWeakReference<I>(o) {
* public void dispose(Object disposable) {
* list.remove(disposable);
* Example.this.wrp = null;
* }
* }, I.class);
* list.add(wrp);
* }
*
* public static void main(final String[] args) throws Exception {
* Example exmple = new Example();
* exmple.testWeakRef(); // try to replace with exact implementation
*
* System.out.println("exmple.wr.get() " + exmple.wr.get()); // blah
* System.out.println("exmple.wrp " + exmple.wrp); // blah
* System.out.println("exmple.list.contains(exmple.wr) " + exmple.list.contains(exmple.wr)); // true
* System.out.println("exmple.list.contains(exmple.wrp) " + exmple.list.contains(exmple.wrp)); // true
* System.gc();
* Thread.sleep(10);
* System.out.println("exmple.wr.get() " + exmple.wr.get()); // null
* System.out.println("exmple.wrp " + exmple.wrp); // null or exception
* System.out.println("exmple.list.contains(exmple.wr) " + exmple.list.contains(exmple.wr)); // false
* System.out.println("exmple.list.contains(exmple.wrp) " + exmple.list.contains(exmple.wrp)); // false
* }
* }
*
* <pre>
*
* #param <T> weak reference referent type
* #author Mykhaylo Adamovych
*/
#SuppressWarnings({ "rawtypes" })
public abstract class DisposableWeakReference<T> extends WeakReference<T> {
public static class DisposedException extends RuntimeException {
private static final long serialVersionUID = -1176608195614694732L;
public DisposedException() {
super();
}
public DisposedException(String message) {
super(message);
}
public DisposedException(String message, Throwable cause) {
super(message, cause);
}
public DisposedException(Throwable cause) {
super(cause);
}
}
private static class ReferenceProxy<T> implements InvocationHandler {
private final DisposableWeakReference<T> reference;
public ReferenceProxy(DisposableWeakReference<T> reference) {
this.reference = reference;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("equals".equals(method.getName()))
return proxy == args[0];
else if ("hashCode".equals(method.getName()))
return hashCode();
T referent = reference.get();
if (referent == null)
throw new DisposedException("Referent has been disposed.");
return method.invoke(referent, args);
}
}
private static class WeakReferenceDisposerThread extends Thread {
WeakReferenceDisposerThread() {
super("Weak Reference Disposer");
}
#Override
public void run() {
while (true)
try {
DisposableWeakReference<?> reference = (DisposableWeakReference<?>) queue.remove();
Object disposable = reference.proxy;
if (disposable == null)
disposable = reference;
reference.dispose(disposable);
} catch (Throwable e) {
// ignore any exception while disposing
}
}
}
private static final ReferenceQueue queue = new ReferenceQueue();
static {
Thread disposer = new WeakReferenceDisposerThread();
disposer.setPriority(Thread.MAX_PRIORITY - 2);
disposer.setDaemon(true);
disposer.start();
}
/**
* You can use referent directly without {#link #get()}. Runtime exception will rise in case referent has been disposed by GC. You can use
* {#link #dispose(Object)} to deal with proxy also.
*
* #param reference
* disposable weak reference
* #param clazz
* referent interface class
* #param <T>
* referent type
* #param <I>
* referent interface to create a proxy
* #return referent proxy using weak reference
*/
public static <I> I newWeakReferenceProxy(DisposableWeakReference<I> reference, Class<I> clazz) {
I proxy = ReflectUtils.<I>newProxyInstance(new ReferenceProxy<I>(reference), clazz);
reference.proxy = proxy;
return proxy;
}
private Object proxy;
public DisposableWeakReference(T referent) {
super(referent, queue);
}
/**
* Remove this weak reference wrapper from whatever when referent has been garbage collected.
*
* #param disposable
* either this reference instance or proxy instance created by {#link #newWeakReferenceProxy(DisposableWeakReference, Class)}
* #see WeakHashMap
*/
public abstract void dispose(Object disposable);
}
I'm working on legacy code and need to make a patch.
The problem: an ancient application sends bad HTTP POST requests. One of the parameters is not URL encoded. I know that this parameter always comes last and I know it's name. I'm now trying to fix it on the server side which is running inside tomcat.
This parameter is not accessible via standard getParameter method of HttpServletRequest, since it's malformed. Method simply returns null. But when I manually read the whole body of request through ServletInputStream all the other parameters disappear. Looks like underlying classes can't parse contents of ServletInputStream since it's drained out.
So far I've managed to make a wrapper that reads all parameters from body and overrides all parameter access methods. But if any filter in the chain before mine will try to access any parameter, everything will break since ServletInputStream will be empty.
Can I somehow evade this problem? May be there's different approach?
To summarize, If I'll read raw request body in the filter, parameters will disappear from the request. If I read single parameter, ServletInputStream will become empty and manual processing will be impossible. Moreover, it's impossible to read malformed parameter via getParameter method.
Solution I've found:
It's not enough to just redefine parameter accessing methods. Several things must be done.
A filter is needed where request will be wrapped.
A custom HttpRequestWrapper is needed with all parameter access methods overridden. Request body should be parsed in constructor and stored as a field.
getInputStream and getReader methods should be redefined as well. They return values depend on the stored request body.
Custom class extending ServletInputStream is required since this one is abstract.
This 4 combined will allow you to use getParameter without interference with getInputStream and getReader methods.
Mind that manual request parameter parsing may get complicated with multipart requests. But that's another topic.
To clarify, I redefined parameter accessing methods because my request was damaged as stated in the question. You may not need that.
Rather than overriding methods, why don't you install a servlet filter which rewrites the request?
Jason Hunter has a pretty good article on filters.
I did a more complete wrapper that allows you to still access the content in the case Content-Type is application/x-www-form-urlencoded and you already called one of the getParameterXXX methods:
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.Principal;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletInputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* This class implements the Wrapper or Decorator pattern.<br/>
* Methods default to calling through to the wrapped request object,
* except the ones that read the request's content (parameters, stream or reader).
* <p>
* This class provides a buffered content reading that allows the methods
* {#link #getReader()}, {#link #getInputStream()} and any of the getParameterXXX to be called
* safely and repeatedly with the same results.
* <p>
* This class is intended to wrap relatively small HttpServletRequest instances.
*
* #author pgurov
*/
public class HttpServletRequestWrapper implements HttpServletRequest {
private class ServletInputStreamWrapper extends ServletInputStream {
private byte[] data;
private int idx = 0;
ServletInputStreamWrapper(byte[] data) {
if(data == null)
data = new byte[0];
this.data = data;
}
#Override
public int read() throws IOException {
if(idx == data.length)
return -1;
return data[idx++];
}
}
private HttpServletRequest req;
private byte[] contentData;
private HashMap<String, String[]> parameters;
public HttpServletRequestWrapper() {
//a trick for Groovy
throw new IllegalArgumentException("Please use HttpServletRequestWrapper(HttpServletRequest request) constructor!");
}
private HttpServletRequestWrapper(HttpServletRequest request, byte[] contentData, HashMap<String, String[]> parameters) {
req = request;
this.contentData = contentData;
this.parameters = parameters;
}
public HttpServletRequestWrapper(HttpServletRequest request) {
if(request == null)
throw new IllegalArgumentException("The HttpServletRequest is null!");
req = request;
}
/**
* Returns the wrapped HttpServletRequest.
* Using the getParameterXXX(), getInputStream() or getReader() methods may interfere
* with this class operation.
*
* #return
* The wrapped HttpServletRequest.
*/
public HttpServletRequest getRequest() {
try {
parseRequest();
} catch (IOException e) {
throw new IllegalStateException("Cannot parse the request!", e);
}
return new HttpServletRequestWrapper(req, contentData, parameters);
}
/**
* This method is safe to use multiple times.
* Changing the returned array will not interfere with this class operation.
*
* #return
* The cloned content data.
*/
public byte[] getContentData() {
return contentData.clone();
}
/**
* This method is safe to use multiple times.
* Changing the returned map or the array of any of the map's values will not
* interfere with this class operation.
*
* #return
* The clonned parameters map.
*/
public HashMap<String, String[]> getParameters() {
HashMap<String, String[]> map = new HashMap<String, String[]>(parameters.size() * 2);
for(String key : parameters.keySet()) {
map.put(key, parameters.get(key).clone());
}
return map;
}
private void parseRequest() throws IOException {
if(contentData != null)
return; //already parsed
byte[] data = new byte[req.getContentLength()];
int len = 0, totalLen = 0;
InputStream is = req.getInputStream();
while(totalLen < data.length) {
totalLen += (len = is.read(data, totalLen, data.length - totalLen));
if(len < 1)
throw new IOException("Cannot read more than " + totalLen + (totalLen == 1 ? " byte!" : " bytes!"));
}
contentData = data;
String enc = req.getCharacterEncoding();
if(enc == null)
enc = "UTF-8";
String s = new String(data, enc), name, value;
StringTokenizer st = new StringTokenizer(s, "&");
int i;
HashMap<String, LinkedList<String>> mapA = new HashMap<String, LinkedList<String>>(data.length * 2);
LinkedList<String> list;
boolean decode = req.getContentType() != null && req.getContentType().equals("application/x-www-form-urlencoded");
while(st.hasMoreTokens()) {
s = st.nextToken();
i = s.indexOf("=");
if(i > 0 && s.length() > i + 1) {
name = s.substring(0, i);
value = s.substring(i+1);
if(decode) {
try {
name = URLDecoder.decode(name, "UTF-8");
} catch(Exception e) {}
try {
value = URLDecoder.decode(value, "UTF-8");
} catch(Exception e) {}
}
list = mapA.get(name);
if(list == null) {
list = new LinkedList<String>();
mapA.put(name, list);
}
list.add(value);
}
}
HashMap<String, String[]> map = new HashMap<String, String[]>(mapA.size() * 2);
for(String key : mapA.keySet()) {
list = mapA.get(key);
map.put(key, list.toArray(new String[list.size()]));
}
parameters = map;
}
/**
* This method is safe to call multiple times.
* Calling it will not interfere with getParameterXXX() or getReader().
* Every time a new ServletInputStream is returned that reads data from the begining.
*
* #return
* A new ServletInputStream.
*/
public ServletInputStream getInputStream() throws IOException {
parseRequest();
return new ServletInputStreamWrapper(contentData);
}
/**
* This method is safe to call multiple times.
* Calling it will not interfere with getParameterXXX() or getInputStream().
* Every time a new BufferedReader is returned that reads data from the begining.
*
* #return
* A new BufferedReader with the wrapped request's character encoding (or UTF-8 if null).
*/
public BufferedReader getReader() throws IOException {
parseRequest();
String enc = req.getCharacterEncoding();
if(enc == null)
enc = "UTF-8";
return new BufferedReader(new InputStreamReader(new ByteArrayInputStream(contentData), enc));
}
/**
* This method is safe to execute multiple times.
*
* #see javax.servlet.ServletRequest#getParameter(java.lang.String)
*/
public String getParameter(String name) {
try {
parseRequest();
} catch (IOException e) {
throw new IllegalStateException("Cannot parse the request!", e);
}
String[] values = parameters.get(name);
if(values == null || values.length == 0)
return null;
return values[0];
}
/**
* This method is safe.
*
* #see {#link #getParameters()}
* #see javax.servlet.ServletRequest#getParameterMap()
*/
#SuppressWarnings("unchecked")
public Map getParameterMap() {
try {
parseRequest();
} catch (IOException e) {
throw new IllegalStateException("Cannot parse the request!", e);
}
return getParameters();
}
/**
* This method is safe to execute multiple times.
*
* #see javax.servlet.ServletRequest#getParameterNames()
*/
#SuppressWarnings("unchecked")
public Enumeration getParameterNames() {
try {
parseRequest();
} catch (IOException e) {
throw new IllegalStateException("Cannot parse the request!", e);
}
return new Enumeration<String>() {
private String[] arr = getParameters().keySet().toArray(new String[0]);
private int idx = 0;
public boolean hasMoreElements() {
return idx < arr.length;
}
public String nextElement() {
return arr[idx++];
}
};
}
/**
* This method is safe to execute multiple times.
* Changing the returned array will not interfere with this class operation.
*
* #see javax.servlet.ServletRequest#getParameterValues(java.lang.String)
*/
public String[] getParameterValues(String name) {
try {
parseRequest();
} catch (IOException e) {
throw new IllegalStateException("Cannot parse the request!", e);
}
String[] arr = parameters.get(name);
if(arr == null)
return null;
return arr.clone();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getAuthType()
*/
public String getAuthType() {
return req.getAuthType();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getContextPath()
*/
public String getContextPath() {
return req.getContextPath();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getCookies()
*/
public Cookie[] getCookies() {
return req.getCookies();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getDateHeader(java.lang.String)
*/
public long getDateHeader(String name) {
return req.getDateHeader(name);
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getHeader(java.lang.String)
*/
public String getHeader(String name) {
return req.getHeader(name);
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getHeaderNames()
*/
#SuppressWarnings("unchecked")
public Enumeration getHeaderNames() {
return req.getHeaderNames();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getHeaders(java.lang.String)
*/
#SuppressWarnings("unchecked")
public Enumeration getHeaders(String name) {
return req.getHeaders(name);
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getIntHeader(java.lang.String)
*/
public int getIntHeader(String name) {
return req.getIntHeader(name);
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getMethod()
*/
public String getMethod() {
return req.getMethod();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getPathInfo()
*/
public String getPathInfo() {
return req.getPathInfo();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getPathTranslated()
*/
public String getPathTranslated() {
return req.getPathTranslated();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getQueryString()
*/
public String getQueryString() {
return req.getQueryString();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getRemoteUser()
*/
public String getRemoteUser() {
return req.getRemoteUser();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getRequestURI()
*/
public String getRequestURI() {
return req.getRequestURI();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getRequestURL()
*/
public StringBuffer getRequestURL() {
return req.getRequestURL();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getRequestedSessionId()
*/
public String getRequestedSessionId() {
return req.getRequestedSessionId();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getServletPath()
*/
public String getServletPath() {
return req.getServletPath();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getSession()
*/
public HttpSession getSession() {
return req.getSession();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getSession(boolean)
*/
public HttpSession getSession(boolean create) {
return req.getSession(create);
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getUserPrincipal()
*/
public Principal getUserPrincipal() {
return req.getUserPrincipal();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromCookie()
*/
public boolean isRequestedSessionIdFromCookie() {
return req.isRequestedSessionIdFromCookie();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromURL()
*/
public boolean isRequestedSessionIdFromURL() {
return req.isRequestedSessionIdFromURL();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromUrl()
*/
#SuppressWarnings("deprecation")
public boolean isRequestedSessionIdFromUrl() {
return req.isRequestedSessionIdFromUrl();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#isRequestedSessionIdValid()
*/
public boolean isRequestedSessionIdValid() {
return req.isRequestedSessionIdValid();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#isUserInRole(java.lang.String)
*/
public boolean isUserInRole(String role) {
return req.isUserInRole(role);
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getAttribute(java.lang.String)
*/
public Object getAttribute(String name) {
return req.getAttribute(name);
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getAttributeNames()
*/
#SuppressWarnings("unchecked")
public Enumeration getAttributeNames() {
return req.getAttributeNames();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getCharacterEncoding()
*/
public String getCharacterEncoding() {
return req.getCharacterEncoding();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getContentLength()
*/
public int getContentLength() {
return req.getContentLength();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getContentType()
*/
public String getContentType() {
return req.getContentType();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getLocalAddr()
*/
public String getLocalAddr() {
return req.getLocalAddr();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getLocalName()
*/
public String getLocalName() {
return req.getLocalName();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getLocalPort()
*/
public int getLocalPort() {
return req.getLocalPort();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getLocale()
*/
public Locale getLocale() {
return req.getLocale();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getLocales()
*/
#SuppressWarnings("unchecked")
public Enumeration getLocales() {
return req.getLocales();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getProtocol()
*/
public String getProtocol() {
return req.getProtocol();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getRealPath(java.lang.String)
*/
#SuppressWarnings("deprecation")
public String getRealPath(String path) {
return req.getRealPath(path);
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getRemoteAddr()
*/
public String getRemoteAddr() {
return req.getRemoteAddr();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getRemoteHost()
*/
public String getRemoteHost() {
return req.getRemoteHost();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getRemotePort()
*/
public int getRemotePort() {
return req.getRemotePort();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getRequestDispatcher(java.lang.String)
*/
public RequestDispatcher getRequestDispatcher(String path) {
return req.getRequestDispatcher(path);
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getScheme()
*/
public String getScheme() {
return req.getScheme();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getServerName()
*/
public String getServerName() {
return req.getServerName();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getServerPort()
*/
public int getServerPort() {
return req.getServerPort();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#isSecure()
*/
public boolean isSecure() {
return req.isSecure();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#removeAttribute(java.lang.String)
*/
public void removeAttribute(String name) {
req.removeAttribute(name);
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#setAttribute(java.lang.String, java.lang.Object)
*/
public void setAttribute(String name, Object value) {
req.setAttribute(name, value);
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#setCharacterEncoding(java.lang.String)
*/
public void setCharacterEncoding(String env)
throws UnsupportedEncodingException {
req.setCharacterEncoding(env);
}
}
I wanted to post this as a comment, but I do not have enough rep. Your solution is insufficient in that ServletInputStreamWrapper will return negative integers. For instance, mock a request with input encoding UTF-16, either big or little endian. The input may start with the Byte Order Mark indicating endianess, and when testing my statement please construct the mock request content to do so. http://en.wikipedia.org/wiki/Byte_order_mark#UTF-16 Either of these BOMs contains a 0xFF byte. Since java has no unsigned byte, this 0xFF is returned as a -1. To work around this, just change the read function like so
public int read() throws IOException {
if (index == data.length) {
return -1;
}
return data[index++] & 0xff;
}
I somewhat like your solution because it works well with Spring. At first I tried to eliminate some of the delegation code you wrote by extending from HttpServletRequestWrapper. However, Spring does something interesting: when it encounters a request of type ServletRequestWrapper it unwraps it, calling getRequest(). Problem being that my getRequest() method, as copied from your code, returns a new class that extends from HttpServletRequestWrapper... rinse and repeat infinitely. So it's sad to say, chalk up a win for not using interfaces!
You could write your own Servlet Filter and hopefully ensure that it appears first in the chain. Then wrap the ServletRequest object in something that will handle the re-writing where needed. Have a look at the Programming Customized Requests and Responses section of http://java.sun.com/products/servlet/Filters.html
------ Update ------
I must be missing something. You say you can read the request body and read the parameters yourself. Couldn't you then ensure your filter is first, wrap the ServletRequest object, read, process and store the parameters, pass your request object up the chain and offer the parameters you stored instead of the original ones?