I have some controller (ExampleController) that receives requests with content-type application/x-www-form-urlencoded.
I need to send all the request data to a different URL using POST request. The data needs to be in the same order as received it.
Problem is that the content does not match because request.getParameterMap() destroys the order of the data.
In ExampleController:
def method(){
String s = request.reader.text //this is empty, need a way to read this text
Map<String, String[]> vars = request.getParameterMap() //it's not good for me because the map is unordered map
//but it full of data
}
which does not work.
I need something like:
byte[] data = request.getRequestData()
wr.write(data)
btw i've tried:
InputStream = request.getInputStream()
byte [] bytes = inputStream.getBytes()
I've also tried
String s = request.reader.text
but the string is empty.
I think the main problem is that grails mechanism reads the input stream before the controller even starts and place the data in the parameters hashMap. is there a way to undo it?
Any help will be greatly appreciated
Try using request.reader.text instead.
def result = request.reader.text.split('&').inject([:]) { map, token ->
token.split('=').with { map[it[0]] = it[1] }
map
}
Related
I have a BDD automation framework setup with Selenium WebDriver and Cucumber with Java. I have configured Rest Assured and I am currently using one JSON payload which is stored in an external JSON file. I am directly reading this JSON file into byte array and then converting the same to String and sending the payload to a post request.
Till now, everything was static and hence, this was working without any issue. However, now the requirement is to send a couple of attributes with dynamic values everytime I make a post call. I know how to send a complete dynamic payload using POJOs but I am looking for a different solution where I can read the payload from the same JSON file and can send dynamic values for few required attributes. Please let me know if this is possible.
Attaching the code for reference.
File which reads the JSON file and sends the payload to post request
public class AddOrderAPIActions {
ConfigReader configReader = new ConfigReader();
Properties prop;
public AddOrderAPIActions() {
prop = configReader.init_prop();
}
//Setting up the API URI
public void setURI() {
String URI = prop.getProperty("apiURI");
RestAssured.baseURI = URI;
}
//Sending the request payload via POST method
public String sendRequestPayload() throws IOException {
//read data from local JSON file then store in byte array
byte[] b = Files.readAllBytes(Paths.get("./src/test/resources/data/addOrder.json"));
//convert byte array to string
String bdy = new String(b);
//input details with header and body
Response response = given().header("Content-type", "application/json").queryParam("api_key", prop.getProperty("apiKey")).body(bdy)
//adding post method
.when().post().then().log().all().extract().response();
JsonPath jp = response.jsonPath();
String shipmentNumber = jp.get("data.shipmentDetails[0].shipmentNumber");
System.out.println("Shipment Number is "+ shipmentNumber);
return shipmentNumber;
}
}
The JSON file with payload
[
{
"originDetails": {
"originCode": "Dynamic_Value",
"originStartTime": "",
"originEndTime": "",
"senderName": "Origin Name",
"senderContactNumber": "9999999999",
"senderAddress": "Bali, Indonesia",
"senderPincode": "201001",
"senderCity": "Delhi",
"senderCountry": "India"
},
]
Here, I want to send a dynamic value for "originCode" attribute and rest of the attributes should be sent as read from the JSON file.
Thanks in advance.
Updated code for assistance with as requested.
buffer.append("\n\nBe sure to activate your account, by ");
buffer.append("<a href=\"")
.append(url)
.append("activateAccount.do?clientId=")
.append(client.getId())
.append("&activationCode=")
.append(client.getActivationCode())
.append("&mat=").append(mobileApplicationType)
.append("\">");[enter image description here][1]
.append("clicking here")</a>;
Your problem doesn't lie in the StringBuilder, but in the fact, that you miss quotes around the link. (At least at the beginning)
And remember that you can chain the calls to StringBuilder.
buffer.append("<a href=\"")
.append(url)
.append("activateAccount.do?clientId=")
.append(client.getId())
.append("&activationCode=")
.append(client.getActivationCode())
.append("&mat=").append(mobileApplicationType)
.append("\">")
.append("clicking here")
.append("</a>");
And please don't concatenate String in the append call for StringBuilder!
On a side note, when you notice, that you are doing multiple things at the same time, try to extract some functions from it. For example, the concatenation of the URL could be a separate function.
public String getActivationHTML() {
var buffer = new StringBuilder();
buffer.append("\n\nBe sure to activate your account, by ");
buffer.append("<a href=\"")
.append(buildUrl(url, client, mobileApplicationType))
.append("\">")
.append("clicking here")
.append("</a>");
return buffer.toString();
}
private String buildUrl(String url, Client client, AppType mobileApplicationType) {
var buffer = new StringBuilder();
buffer.append(url)
.append("activateAccount.do?clientId=")
.append(client.getId())
.append("&activationCode=")
.append(client.getActivationCode())
.append("&mat=")
.append(mobileApplicationType);
return buffer.toString();
}
Consider I have a large amount of csv strings in database and I need to pass them to the client by his request.
A naive way to do this:
#RequestMapping(value = "/{user}/ejournal", method = RequestMethod.GET, produces = "text/csv")
public ResponseEntity<ByteArrayResource> getEJournal(#PathVariable Long userId) {
final byte[] documentBody = EJournal
.findByUser(userId)
.stream()
.collect(Collectors.joining("\n"))
.getBytes();
return new ResponseEntity(
new ByteArrayResource(documentBody),
HttpStatus.OK);
}
From the client side its straightforward (kotlin code example):
val inputStream = eJournalService.getJournal(userId)
inputStream.reader().forEachLine { line -> ... }
But I am forced to load the entire data to memory before pass it to the stream and obviously it is not efficient.
So I need somehow to bufferize it to read data with pagination using custom reader and send buffers to client. I thought to implement my own InputStream but InputStream#read() returns int instead of String and it is a bit complicated.
Any best practices to do this? I tried to search but there are only examples to pass a picture using stream which is already in memory, not with buffered pagination with sequential database queries after batch sends.
Thanks in advance.
From the documentation
The following are the supported return types:
[...]
void if the method handles the response itself (by writing the response content directly, declaring an argument of type ServletResponse / HttpServletResponse for that purpose)
[...]
A StreamingResponseBody can be returned to write to the response OutputStream asynchronously; also supported as the body within a ResponseEntity.
So you can just do
public StreamingResponseBody getEJournal(#PathVariable Long userId) {
return outputStream -> {
// write your lines to the outputStream here
};
}
You can also wrote to the stream synchronously by just having the HttpServletResponse as argument of your method, and write to its output stream.
I've created a custom command to retrieve multiple objects in the same request (in order to solve some performance issues), instead of using the folder method .getMessage(..) which in my case retrieved an ImapMessage object:
Argument args = new Argument();
args.writeString(Integer.toString(start) + ":" + Integer.toString(end));
args.writeString("BODY[]");
FetchResponse fetch;
BODY body;
MimeMessage mm;
ByteArrayInputStream is = null;
Response[] r = protocol.command("FETCH", args);
Response status = r[r.length-1];
if(status.isOK()) {
for (int i = 0; i < r.length - 1; i++) {
...
}
}
Currently I'm validating if the object is a ImapResponse like this:
if (r[i] instanceof IMAPResponse) {
IMAPResponse imr = (IMAPResponse)r[i];
My question is, how can I turn this response into an ImapMessage?
Thank you.
Are you trying to download the entire message content for multiple messages at once? Have you tried using IMAPFolder.FetchProfileItem.MESSAGE? That will cause Folder.fetch to download the entire message content, which you can then access using the Message objects.
I haven't succeeded yet to convert it into a IMAPMessage but I'm now able transform it into a MIME Message. It isn't perfect but I guess it will have to work for now:
FetchResponse fetch = (FetchResponse) r[i];
BODY body = (BODY) fetch.getItem(0);
ByteArrayInputStream is = body.getByteArrayInputStream();
MimeMessage mm = new MimeMessage(session, is);
Then, it can be used to get information like this:
String contentType = mm.getContentType();
Object contentObject = mm.getContent();
There are also other methods to get information like the sender, date, etc.
I'm trying to get an audio data from a AS library, from the documentation the function is like this:
protected function audioData():String
{
var ret:String="";
buffer.position = 0;
while (buffer.bytesAvailable > 0)
{
ret += buffer.readFloat().toString() + ";";
}
return ret;
}
In between my code and this library is another js that have this code:
audioData: function(){
return this.flashInterface().audioData().split(";");
},
From my code I access this like:
function getdata(){
var data = Recorder.audioData();
console.log("audioData: " + data);
}
However, I tried to output the returned value to Firebug, I get a very long comma-separated list of of floating point values, how can I get back the byte[] buffer? What I mean by buffer is similar to Java, since I will be accessing the buffer from Java via JSNI.
Here's the sample log output (actual log is very long):
-0.00030517578125,0.00006103515625,0.00115966796875,0.00146484375,-0.00091552734375,-0.000946044921875,-0.001983642578125,-0.003997802734375,-0.005126953125,-0.00360107421875,-0.0032958984375,-0.004119873046875,-0.00433349609375,-0.0023193359375,-0.0008544921875,-0.003448486328125,-0.00347900390625,-0.0054931640625,-0.0067138671875,-0.005279541015625,-0.006072998046875,
I can't re-compile the AS that creates the output, for now what I can do is to interface to the SWF component in javascript and accept its floating point and convert it back to byte array. There's just too many errors in my AS project in FDT 5 IDE that I already need to do the mockup of my application.
I really want to recompile the AS library to fit the need however right now I just want to use it as it is.
If you want to see the actual byte data in the byte array you can use the following :
protected function audioData():String
{
var ret:String="";
buffer.position = 0;
while (buffer.bytesAvailable > 0)
{
ret += buffer.readByte().toString();
}
return ret;
}
AFAIK the ByteArray class in as3 is already a byte array(as the name suggests :)) you can access it's data using the [] operator, as in byteArray[0] will give you the first byte.
You should be able to send the byte array to a url on your server with a post request with something like this:
var request:URLRequest = new URLRequest ("http://someurl");
var loader: URLLoader = new URLLoader();
request.contentType = "application/octet-stream";
request.method = URLRequestMethod.POST;
request.data = byteArray;
loader.load(_request);