Failed sending bytes array to JAX-WS web service on Axis - java

Hi I have made a small example to show my problem. Here is my web-service:
package service;
import javax.jws.WebMethod;
import javax.jws.WebService;
#WebService
public class BytesService {
#WebMethod
public String redirectString(String string){
return string+" - is what you sended";
}
#WebMethod
public byte[] redirectBytes(byte[] bytes) {
System.out.println("### redirectBytes");
System.out.println("### bytes lenght:" + bytes.length);
System.out.println("### message" + new String(bytes));
return bytes;
}
#WebMethod
public byte[] genBytes() {
byte[] bytes = "Hello".getBytes();
return bytes;
}
}
I pack it in jar file and store in "axis2-1.5.1/repository/servicejars" folder. Then I generate client Proxy using Eclipse for EE default utils. And use it in my code in the following way:
BytesService service = new BytesServiceProxy();
System.out.println("Redirect string");
System.out.println(service.redirectString("Hello"));
System.out.println("Redirect bytes");
byte[] param = { (byte)21, (byte)22, (byte)23 };
System.out.println(param.length);
param = service.redirectBytes(param);
System.out.println(param.length);
System.out.println("Gen bytes");
param = service.genBytes();
System.out.println(param.length);
And here is what my client prints:
Redirect string
Hello - is what you sended
Redirect bytes
3
0
Gen bytes
5
And on server I have:
### redirectBytes
### bytes lenght:0
### message
So byte array can normally be transfered from service, but is not accepted from the client. And it works fine with strings. Now I use Base64Encoder, but I dislike this solution.

I suspect the problem is in serializing the byte-array into an XML SOAP message. The XML tag in the originating SOAP message is possibly zero bytes. I'd recommend using the SOAP monitor to take a peek at the message being sent to your web service.
You may dislike the idea of encoding the byte-arry in transit, however, you need to consider it binary data. For example what if someone sent you a SOAP message encoded in something other than UTF-8? You'll want to avoid the possibility of the byte-array data changing (conversion between character sets) when the SOAP message is parsed.

Related

How to receive PDF from HTTP Post in Citrus and write it to a file?

I am developing a test for a service.
I make a first HTTP Post, send an xml file, and receive a PDF.
Then I make a second call with this PDF, and the service sends me back a .png file corresponding to this PDF.
But I get stuck at the first step when I have to retrieve the PDF file. I use the Citrus framework, and here is how I make my call and I receive the answer
runner.http(httpActionBuilder -> httpActionBuilder
.client(vdeClient)
.send()
.post(PDF_GEN_URI)
.contentType(MediaType.APPLICATION_XML_VALUE)
.payload(xml)
);
runner.http(httpActionBuilder -> httpActionBuilder
.client(vdeClient)
.receive()
.response(HttpStatus.OK)
.contentType(MediaType.APPLICATION_PDF_VALUE)
);
And then I access the payload of the answer (= The PDF)
Object pdfPayload = context.getMessageStore().getMessage("nameOfTheMessage").getPayload();
The payload seems to be correct, but when I convert it to a byte[] and write it to a new file, it is empty and does not contain what it should.
Is this a character encoding problem or something like that? Thanks
Here is how I do the conversion
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = null;
byte[] pdfBytes;
try {
out = new ObjectOutputStream(bos);
out.writeObject(pdfPayload);
out.flush();
pdfBytes = bos.toByteArray();
} finally {
try {
bos.close();
} catch (IOException ex) {
// ignore close exception
}
}
If you managed to get PDF file content as bytes than you don't need to use ObjectOutputStream. Just write your byte array as it is into a file named .pdf and you should be OK. As for downloading and uploading files though Http requests I actually wrote my own Http client that is very simple in use. My Http client doesn't provide all the width of functionality that other well known Http clients (such as Apache Http client or OK Http client) provide but the simplicity of use is the key. Here is a working example that download and saves excutable file as file named kubectl
public static void downloadFile() {
HttpClient httpClient = new HttpClient();
httpClient.setRequestHeader("Accept", "application/octet-stream");
httpClient.setConnectionUrl("https://dl.k8s.io/release/v1.20.0//bin/linux/amd64/kubectl");
ByteBuffer buffer = null;
try {
buffer = httpClient.sendHttpRequestForBinaryResponse(HttpClient.HttpMethod.GET);
System.out.println(httpClient.getLastResponseCode() + " " + httpClient.getLastResponseMessage());
} catch (IOException ioe) {
System.out.println(httpClient.getLastResponseCode() + " " + httpClient.getLastResponseMessage());
System.out.println(TextUtils.getStacktrace(ioe, "com.mgnt.stam."));
}
try {
Files.write(Paths.get("C:\\Michael\\work\\Installations\\Kubernetes\\kubectl"), buffer.array());
} catch (IOException e) {
System.out.println(TextUtils.getStacktrace(e, "com.mgnt.stam."));
}
}
Here is Javadoc for HttpClient class. In particular note methods sendHttpRequest and sendHttpRequestForBinaryResponse using those methods you can send textual or binary info as part of request body and get back textual or binary content. This Http client is part of MgntUtils library (written and maintained by me). You can get the library as Maven artifacts or on the Github (including source code and Javadoc). BTW class TextUtils used in my example is also part of MgntUtils library

How to send special characters from javascript at frontend to java at backend?

I have a rest web service whose url is
http://localhost/rest/authenticate?username=username&password=pa+ssw1&rd%
In password parameter have 3 special character.
+ character read as white space
& character remove the all characters. for example - my password like this "passw&rd" and it will read like this "passw"
% character does not read the proper password, its read the null value.
my API like this ...
#Path("/authenticate")
public class AuthenticateService {
private ILiteWebServiceFacade liteWebServiceFacade = ServiceLocator.locateService(ILiteWebServiceFacade.class);
#POST
#Produces(MediaType.APPLICATION_JSON)
public Response authenticate(#FormParam("username") String username,
#FormParam("password") String password)
throws RestException {
AuthenticateResponse res = new AuthenticateResponse();
try {
res = liteWebServiceFacade.mobAuthenticate(username, password);
} catch (RestApplicationException e) {
res.setError(e.getErrorMessage().getErrorCode(), e.getErrorMessage().getErrorMessageKey());
}
return Response.ok(res).build();
}
}
Can you please suggest me how to read all these special character?
Fist of all, don't send passwords in the URL -- it's just really bad security as the query parameters can get logged in Apache or NGINX logs and are often exposed along the way.
Secondly, if you're using HTTP, understand that certain characters need to be escaped.
%2B +
%20 {space}
%26 &
You will have to make sure your code is actually decoding the strings, but depending on your framework it may do that automatically (Spring does, for example) or you may have to add a quick callout to decode.
If you change the behavior of the URI Encoding, you change the HTTP spec, and it's going to make it hard for anyone consuming your API to understand what's going on -- especially if you grab ampersands because any URI encoding will be broken for your API.
See the RFC: Uniform Resource Identifier (URI): Generic Syntax https://www.rfc-editor.org/rfc/rfc3986
Firstly, I recommend you not to send sensitive data like username and password in url. You should send it in request body.
A simple way to do that is Base64 encode on frontend in javascript and decode at backend in java.
FrontEnd: All chrome version, Firefox 1.0 and above, Internet Explorer 10 and above
var string = 'pa+ssw1&rd%';
// Encode the String
var encodedString = btoa(string);
console.log(encodedString); // Outputs: cGErc3N3MSZyZCU=
// Decode the String
var decodedString = atob(encodedString);
console.log(decodedString); // Outputs: pa+ssw1&rd%
Backend:
For Java 8 and above:
import java.util.Base64;
byte[] decoded = Base64.getDecoder().decode(password);
decodedpassword = new String(decoded, "utf-8");
For < Java 8
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.StringUtils;
public String decode1(String s) {
return StringUtils.newStringUtf8(Base64.decodeBase64(s));
}
public String decode2(String s) {
return new String(Base64.decodeBase64(s), "utf-8");
}
Maven / sbt repo: commons-codec, commons-codec, 1.8.

gRPC-java - Compilation of a .proto file

I have compiled my .proto file using the protobuf compiler and received a selection of Java files. I received a proto.java file and a .java file for each item in the .proto file, including the message type and each RPC call e.g. publicKeyRequest.java and Quote.java as the RPC and request parameter type.
Is this all the files that are needed as I still cannot seem to to get any simple response back from the server?
I want to generate a request for the PublicKeyRequest RPC call. I generated the request object, but I do not know how to actually send it via the channel.
This is the full .proto file:
syntax = "proto3";
option java_multiple_files = true;
option java_package = "io.grpc.decryptiondevice";
option java_outer_classname = "DecryptionDeviceProto";
package decryptiondevice;
service DecryptionDevice {
// Decryption Request RPC
//
// Request contains ciphertext and proof
// Returns the plaintext record
rpc DecryptRecord(DecryptionRequest) returns (Record) {}
// Get Signed Root Tree Hash RPC
//
// Caller provides a nonce
// Returns a signed RTH and nonce
rpc GetRootTreeHash(RootTreeHashRequest) returns (RootTreeHash) {}
// Get Public key RPC
//
// Returns a Remote attestation report containing the public key as user data
rpc GetPublicKey(PublicKeyRequest) returns (Quote) {}
}
// Decryption Request
// - Byte array containing ciphertext
// - Proofs represented as JSON trees
message DecryptionRequest {
bytes ciphertext = 1;
string proofOfPresence = 2;
string proofOfExtension = 3;
}
// A plaintext record
message Record {
bytes plaintext = 1;
}
// RTH request contains
// - A random nonce
message RootTreeHashRequest {
bytes nonce = 1;
}
// Root Tree Hash
// Random nonce used as message ID
// Signature over rth and nonce
message RootTreeHash {
bytes rth = 1;
bytes nonce = 2;
bytes sig = 3;
}
// Public key request message
message PublicKeyRequest {
bytes nonce = 1;
}
// Attestation Quote, containing the public key
message Quote {
string quote = 1; //some format.. to be defined later
//PEM formatted key
bytes RSA_EncryptionKey = 2;
bytes RSA_VerificationKey = 3;
}
And this is the code I am attempting to run on the client side:
public static void main(String[] args) {
DeviceClient client = new DeviceClient("localhost", 50051);
MannagedChanel channel = ManagedChannelBuilder.forAddress("localhost", 50051).usePlaintext(true);
ByteString nonce = ByteString.copyFromUtf8("someRandomString");
PublicKeyRequest keyRequest = PublicKeyRequest.newBuilder().setNonce(nonce).build();
// Here I want to send this to the server
ByteString response = DecryptionDeviceProto.getKey(keyRequest, channel);//this line is not even close to being valid, but this is the sort thing I wish to achieve
Sys.out.println(response);
}
Apologies if this is very wrong, I am new to gRPC.
A few points about this system:
A client and server has already been written in Go which has been tested and works with this same .proto file.
I am attempting to rewrite the client in Java to communicate with the same server.
There are two sets of files that need to be generated: Java Protobuf and Java gRPC. To my knowledge, for all languages except Go, these are two separate generation steps (that can be combined into one protoc invocation, but they are conceptually separate).
It seems you are generating the Java Protobuf code, but not the Java gRPC code. You need to use the protoc-gen-grpc-java plugin to protoc. If you are using Maven or Gradle, read grpc-java's README. If you are running protoc manually, you can download a pre-built binary from Maven Central and see an answer to a similar question.

Convert JMS BytesMessage to String in java and use the same bytesmessage in another process

My code is listening to an IBM MQ. Receives JMS BytesMessage, converts it to string in the receiver class and pass on the same JMS BytesMessage to another processor class. Processor class again converts it into String. Both receiver class and processor class use the same code like below to get the string from BytesMessage. I am getting the right string in the Receiver class but when trying to get the string from the BytesMessage in Processor class its returning empty string. Please advise what has to be done in addition to preserve the JMS BytesMessage so that it gets converted to String in the Processor class as well.
Code that sends message to processor:
String strMessage = null;
strMessage = getStringFromMessage(Message message)
process(message)
Code used for String Conversion:
if (message instanceof BytesMessage){
BytesMessage byteMessage = (BytesMessage) message;
byte[] byteData = null;
byteData = new byte[(int) byteMessage.getBodyLength()];
byteMessage.readBytes(byteData);
stringMessage = new String(byteData);
}
I found the solution. I added the below code after reading the message for the first time
byteMessage.reset()
This has reset the cursor position to the beginning and hence i am able to read it in the processor. So my final code in the receiver will look like below
if (message instanceof BytesMessage){
BytesMessage byteMessage = (BytesMessage) message;
byte[] byteData = null;
byteData = new byte[(int) byteMessage.getBodyLength()];
byteMessage.readBytes(byteData);
byteMessage.reset();
stringMessage = new String(byteData);
}
The reason to read it again is the i started reading it in the receiver to perform some recovery functionality. I wanted to implement that without touching the framework. Initial framework is to read the message only in the processor.
The answer from #Shankar Anand will work but, I would like to refactor the code to accommodate what it exactly needs to do
public String readIbmMqMessageAsString(BytesMessage message) throws JMSException, UnsupportedEncodingException {
message.reset(); //Puts the message body in read-only mode and repositions the stream of bytes to the beginning
int msgLength = ((int) message.getBodyLength());
byte[] msgBytes = new byte[msgLength];
message.readBytes(msgBytes, msgLength);
String encoding = message.getStringProperty(JMS_IBM_CHARACTER_SET);
return new String(msgBytes, encoding).trim();
}
Before reading the message, we need to reposition the stream of bytes to the beginning. Hence the message.reset() should happen before the actual reading of the message.
Then we can read the message and put it in the bytes array
When we create the String from the bytes, It's better to provide the encoding character set which character set is used in convert message to bye
We may not need the extra trailing spaces. In that case, you can trim it as well.
I throw the exceptions to the parent method to handle

java decoding base64 String

I realise this is probably more of a general java question, but since it's running in Notes\ Domino environment, thought I'd check that community first.
Summary:
I don't seem to be able to decode the string: dABlAHMAdAA= using lotus.domino.axis.encoding.Base64 or sun.misc.BASE64Decoder
I know the original text is: test
I confirmed by decoding at http://www5.rptea.com/base64/ it appears it is UTF-16.
As simple test, using either of below:
String s_base64 = "dABlAHMAdAA=";
byte[] byte_base64 = null;
String s_decoded = "";
byte_base64 = new sun.misc.BASE64Decoder().decodeBuffer(s_base64);
s_decoded = new String(byte_base64, "UTF-16");
System.out.println("Test1: " + s_decoded);
byte_base64 = lotus.domino.axis.encoding.Base64.decode(s_base64);
s_decoded = new String(byte_base64, "UTF-16");
System.out.println("Test2: " + s_decoded);
System.out.println("========= FINISH.");
I get the output:
Test1: ????
Test2: ????
If I create String as UTF-8
s_decoded = new String(byte_base64, "UTF-8");
it outputs:
t
no error is thrown, but it doesn't complete the code, doesn't get to the "FINISH".
Detail
I'm accessing an asmx web service, in the SOAP response, some nodes contain base64 encoded data. At this point in time, there is no way to get the service changed, so I am having to XPath and decode myself. Encoded data is either text or html. If I pass the encoded data thru http://www5.rptea.com/base64/ and select UTF-16, it decodes correctly, so I must be doing something incorrectly.
As side note, I encoded "test":
s_base64 = lotus.domino.axis.encoding.Base64.encode(s_text.getBytes());
System.out.println("test1 encodes to: " + s_base64);
s_base64 = new sun.misc.BASE64Encoder().encode(s_text.getBytes());
System.out.println("test2 encodes to: " + s_base64);
they both encode to:
dGVzdA==
...which if you then feed into 2 decoders above, as expected, decodes correctly.
If I go to site above, and encode "test" as UTF-16, I get: dABlAHMAdAA= so that confirms that data is in UTF-16.
It's like the data is genuine base64 data, but the decoder doesn't recognise it as such. I'm slightly stumped at the moment.
Any pointers or comments would be gratefully received.
The string has been encoded in UTF-16LE (little-endian), where the least significant byte is stored first. Java defaults to big-endian. You need to use:
s_decoded = new String(byte_base64, "UTF-16LE");
i have used your sample "dABlAHMAdAA=" on my base64 decode online tool and it seems like you are missing the Apache base64 jar files
Click the link below.
http://www.hosting4free.info/Base64Decode/Base64-Decode.jsp
The code behind the website is
import org.apache.commons.codec.binary.Base64;
public class base64decode
{
public static void main(String[] args) throws UnsupportedEncodingException
{
byte[] decoded = Base64.decodeBase64("YWJjZGVmZw==".getBytes());
System.out.println(new String(decoded) + "\n");
}
}

Categories

Resources