package java4s;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
#Path("/vinay")
public class JsonFromRestful {
#POST
#Path("/{runID}/{tweetID}/{tweet : .*}")
#Produces(MediaType.TEXT_PLAIN)
public String sayPlainTextHello( #PathParam("runID") String rid,
#PathParam("tweetID") String tid,
#PathParam("tweet") String twt) throws IOException, InterruptedException {
StringBuffer resneel=new StringBuffer();
resneel.append(rid);
resneel.append(tid);
resneel.append(twt);
return return resneel.toString();
}
}
client test program
package neel;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.core.util.MultivaluedMapImpl;
/*
* excerpt of the maven dependencies
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.19</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.19</version>
</dependency>
*/
public class ClientTest {
public static void main(String[] args)
{
if(args.length != 4)
{
System.out.println("Incorrect parameters, usage:");
System.out.println("java -jar neelclienttest.jar run_id tweet_id tweet_to_annotate rest_api");
System.exit(1);
}
String runID = args[0];
String tweetID = args[1];
String tweet = args[2];
String uri = args[3];
try {
String annotations = annotate(uri, runID, tweetID, tweet);
System.out.println(annotations);
} catch (Exception e) {
e.printStackTrace();
}
}
public static String annotate(String uri, String runID, String tweetID, String tweet) throws Exception
{
Client client = Client.create();
WebResource webResource = client.resource(uri);
MultivaluedMap<String,String> params = new MultivaluedMapImpl();
params.add("RunID", runID);
params.add("TweetID", tweetID);
params.add("Tweet", tweet);
ClientResponse response = webResource.
accept(MediaType.TEXT_PLAIN_TYPE).
post(ClientResponse.class, params);
// check if status code != 200 OK
if ( response.getStatus() != 200 )
throw new Exception ("The REST interface has answered with an unexpected status code" + response.getStatus());
return response.getEntity(String.class);
}
}
here i am giving command line arguements runid tweetid tweet and the path is http://localhost/cen_neel/vinay/ but it is showing java.lang exception. we created a webservice and whatever i have given clienttest is for testing. i dont need any changes in clienttest. please help if there is any error in my program. i tested the same program with restclient plugin like below
http://localhost/cen_neel/vinay/r12/v23/Chennai and i am getting response back correctly.
Here post(ClientResponse.class, params);. you're trying to post the URI information into the body of the request. That's not where they belong. Actually, based on your resource method, there shouldn't be a body at all. You can simply pass an empty string.
Instead, how you should be building the request, is with .path() on the WebResource to append path segments
ClientResponse response = webResource
.path(runID)
.path(tweetID)
.path(tweet)
.accept(MediaType.TEXT_PLAIN_TYPE)
.post(ClientResponse.class, "");
It seems completely pointless though, the way you are doing it. Why not just pass the entire URI, like you are in the Rest Client.
Anyway, this is not really a good design overall. Here are some improvements I would make.
The actual tweet should not be in the URI. It should be posted in the body. To accept it in the body, simply don't annotate it with #PathParam for the tweet method parameter, and get rid of the path template {tweet : .*}. Then you can post(ClientReponse.class, tweet). You should also add #Consumes(MediaType.TEXT_PLAIN) to the resource method, and use type to create the request. i.e.
.accept(MediaType.TEXT_PLAIN_TYPE)
.type(MediaType.TEXT_PLAIN_TYPE)
.post(ClientResponse.class, tweet);
If you are trying to create a new tweet, the id, should not be in the template. The id should not exist yet. When the tweet is created, the server should notify the client with the newly created id of the tweet, with a Location header.
Related
I've successfully used the Micronaut HTTP Client with several different external services in the past. However, I'm really struggling with one external service. I think it might be related to the fact that the response from the external service does not contain a Content-Type header, but I'm not sure.
The client and response type are defined in the same groovy file.
package us.cloudcard.api.transact
import groovy.transform.ToString
import io.micronaut.http.HttpResponse
import io.micronaut.http.MediaType
import io.micronaut.http.annotation.Body
import io.micronaut.http.annotation.Post
import io.micronaut.http.annotation.Produces
import io.micronaut.http.client.annotation.Client
import javax.validation.constraints.NotNull
#Client('${transact.url}')
interface TransactAuthenticationClient {
#Post
#Produces(MediaType.TEXT_PLAIN)
HttpResponse<TransactAuthenticationResponse> authenticate(#NotNull #Body String token)
}
#ToString
class TransactAuthenticationResponse {
Boolean Expired
String InstitutionId
String UserName
String customCssUrl
String email
String role
}
I'm testing it with a simple controller that just calls the client and renders the response status and body.
package us.cloudcard.api
import grails.compiler.GrailsCompileStatic
import grails.converters.JSON
import grails.plugin.springsecurity.annotation.Secured
import io.micronaut.http.HttpResponse
import org.springframework.beans.factory.annotation.Autowired
import us.cloudcard.api.transact.TransactAuthenticationClient
import us.cloudcard.api.transact.TransactAuthenticationResponse
#GrailsCompileStatic
#Secured("permitAll")
class MyController {
static responseFormats = ['json', 'xml']
#Autowired
TransactAuthenticationClient transactAuthenticationClient
def show(String id) {
String goodToken = "5753D...REDACTED...647F"
HttpResponse response = transactAuthenticationClient.authenticate(goodToken)
TransactAuthenticationResponse authenticationResponse = response.body()
log.error("status: ${response.status()} body: $authenticationResponse")
render "status: ${response.status()} body: $authenticationResponse"
}
}
However, the result I get is
status: OK body: null
Making the same request in Postman results in the correct response
When I debug, I can inspect the HttpResponse object and see all the correct headers, so I know I'm making the request successfully. I just can't bind the response.
I tried changing the client to bind to a String
#Post
#Produces(MediaType.TEXT_PLAIN)
HttpResponse<String> authenticate(#NotNull #Body String token)
and I got the following response
status: OK body: PooledSlicedByteBuf(ridx: 0, widx: 176, cap: 176/176, unwrapped: PooledUnsafeDirectByteBuf(ridx: 484, widx: 484, cap: 513))
This was interesting because the widx: 176, cap: 176/176 perfectly matched the content length of the successful response.
I am really at a loss, so I would appreciate any help you can give.
Thanks in advance for your help!
TL;DR: The Micronaut HTTP Client is not designed to work for this API
The Micronaut HTTP Client cannot consume APIs that do not include a content-type header in the response. I talked with Jeff Scott Brown about this, and that's just how Micronaut is designed. If there's no content-type header in the response, the client won't know how to parse the response body.
Work-Around
package us.cloudcard.api.transact
import groovy.json.JsonSlurper
import groovy.transform.ToString
import org.apache.http.client.methods.CloseableHttpResponse
import org.apache.http.client.methods.HttpPost
import org.apache.http.entity.StringEntity
import org.apache.http.impl.client.CloseableHttpClient
import org.apache.http.impl.client.HttpClientBuilder
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component
#Component
class TransactAuthenticationClient {
#Value('${transact.url}')
String transactAuthenticationUrl
TransactAuthenticationResponse workaround2(String token) {
HttpPost post = new HttpPost(transactAuthenticationUrl)
post.addHeader("content-type", "text/plain")
post.setEntity(new StringEntity(token))
CloseableHttpClient client = HttpClientBuilder.create().build()
CloseableHttpResponse response = client.execute(post)
def bufferedReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()))
def json = bufferedReader.getText()
println "response: \n" + json
def resultMap = new JsonSlurper().parseText(json)
return new TransactAuthenticationResponse(resultMap)
}
}
#ToString(includeNames = true)
class TransactAuthenticationResponse {
Boolean Expired
String InstitutionId
String UserName
String customCssUrl
String email
String role
}
JUST FYI: Before I found the above workaround, I tried this and it also does not work.
TransactAuthenticationResponse thisAlsoDoesNotWork (String token) {
String baseUrl = "https://example.com"
HttpClient client = HttpClient.create(baseUrl.toURL())
HttpRequest request = HttpRequest.POST("/path/to/endpoint", token)
HttpResponse<String> resp = client.toBlocking().exchange(request, String)
String json = resp.body()
println "json: $json"
ObjectMapper objectMapper = new ObjectMapper()
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
TransactAuthenticationResponse response = objectMapper.readValue(json, TransactAuthenticationResponse)
return response
}
Having the same problem, this is the best solution I found so far:
import io.micronaut.core.convert.ConversionService;
import io.micronaut.core.convert.TypeConverter;
import io.netty.buffer.ByteBuf;
// (...)
ConversionService.SHARED.addConverter(ByteBuf.class, String.class, new TypeConverter<ByteBuf, String>() {
#Override
public Optional<String> convert(ByteBuf object, Class<String> targetType, ConversionContext context) {
return Optional.ofNullable(object).map(bb -> bb.toString(StandardCharsets.UTF_8));
}
});
HttpRequest<String> req = HttpRequest.POST("<url>", "<body>");
// res is instance of io.micronaut.http.client.netty.FullNettyClientHttpResponse which uses the shared conversion service as "last chance" to convert the response body
HttpResponse<String> res = httpClient.toBlocking().exchange(req);
String responseBody = res.getBody(String.class).get();
I am trying to parse raw mime message which sengrid post to a URL by inbound parse web hook settings. Previously i was listening for incoming mails from Mailserver through Imap and from java MimeMessage i was able to convert it to the String and vice versa. Please see below code how i used to convert from MimeMessage to String and vice versa in java.
private void convertMimeMessageToStringAndViceVersa(javax.mail.internet.MimeMessage message) {
ByteArrayOutputStream bStream = new ByteArrayOutputStream();
message.writeTo(bStream);
String rawMimeMessageString = new String(bStream.toByteArray(), StandardCharsets.UTF_8.name());
// Now from the above String to MimeMessage see below code
Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
ByteArrayInputStream bais = new ByteArrayInputStream(rawMimeMessageString.getBytes());
javax.mail.internet.MimeMessage convertedMimeMessage = new MimeMessage(session, bais);
}
So my question is, i cannot convert the string raw mail message which sendgrid is posting through inbound parse webhook to javax.mail.internet.MimeMessage type. Is there anyway.
Probably SendGrid Raw MimeMessage is broken, however you can try to use non-raw payload and convert this payload to whatever you want.
According to this article: https://varunsastrydevulapalli.medium.com/the-sendgrid-inbound-webhook-with-spring-dc7b5bae4e0c,
we can receive the Inbound Message using this spring controller:
#Controller
#RequestMapping(value = "/messaging")
public class InboundMessageController {
#Bean(name = "multipartResolver")
public CommonsMultipartResolver commonsMultipartResolver() {
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
commonsMultipartResolver.setDefaultEncoding("UTF-8");
commonsMultipartResolver.setMaxUploadSize(5000);
return commonsMultipartResolver;
}
#RequestMapping(value = "/inbound", method = {RequestMethod.POST, RequestMethod.HEAD}, consumes = MediaType.MULTIPART_FORM_DATA)
public #ResponseBody
void processInboundSendGridEmails(HttpServletRequest request,
HttpServletResponse response,
#RequestParam(required = false) MultipartFile file,
SendGridInbound sendGridInbound) {
System.out.println(sendGridInbound);
convertToMimeMessage(sendGridInbound);
}
}
public class SendGridInbound {
String headers;
String dkim;
String to;
String html;
String from;
String text;
String sender_ip;
String spam_report;
String envelope;
String attachments;
String subject;
String spam_score;
String attchmentInfo;
String charsets;
String spf;
//getter setters toString
}
Hope it could help.
The previous solution hasn't worked to me. But the following solution worked fine.
This code snippet reads the request through the class MimeMessage, to learn how to deal with that you can read this topic.
Here goes the solution:
package package_;
import org.apache.log4j.Logger;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
#RestController
#RequestMapping("/listener")
public class SendGridListener {
protected final Logger logger = Logger.getLogger(this.getClass());
#RequestMapping(
method = {RequestMethod.POST},
consumes = {MediaType.MULTIPART_FORM_DATA_VALUE}
)
public #ResponseBody void listen(HttpServletRequest request) throws MessagingException, IOException {
String email = request.getParameter("email");
Session s = Session.getInstance(new Properties());
InputStream is = new ByteArrayInputStream(email.getBytes());
MimeMessage message = new MimeMessage(s, is);
logger.info(message);
}
}
I have a maven java web application developed using Netbeans. I have figured out to run a parameter based Restful service successfully.
The URL contains three names in separated by slashes before providing the parameter.
http://localhost:8080/chims/api/data/list?name=district_list
Can I have a URL with less slashes like
http://localhost:8080/chims/data?name=district_list
This is the applicatoin config file.
package org.netbeans.rest.application.config;
import javax.ws.rs.core.Application;
#javax.ws.rs.ApplicationPath("api")
public class ApplicationConfig extends Application {
}
This is the service file.
package lk.gov.health.phsp.ws;
import java.util.List;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.Produces;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import lk.gov.health.phsp.bean.AreaApplicationController;
import lk.gov.health.phsp.entity.Area;
import lk.gov.health.phsp.enums.AreaType;
import org.json.JSONArray;
import org.json.JSONObject;
#Path("data")
#RequestScoped
public class ApiResource {
#Context
private UriInfo context;
#Inject
AreaApplicationController areaApplicationController;
/**
* Creates a new instance of GenericResource
*/
public ApiResource() {
}
#GET
#Path("list")
#Produces(MediaType.APPLICATION_JSON)
public String getJson(#QueryParam("name") String name) {
JSONObject jSONObjectOut;
if (name == null || name.trim().equals("")) {
jSONObjectOut = errorMessageInstruction();
} else {
switch (name) {
case "district_list":
jSONObjectOut = districtList();
break;
default:
jSONObjectOut = errorMessage();
}
}
String json = jSONObjectOut.toString();
return json;
}
private JSONObject districtList() {
JSONObject jSONObjectOut = new JSONObject();
JSONArray array = new JSONArray();
List<Area> ds = areaApplicationController.getAllAreas(AreaType.District);
for (Area a : ds) {
JSONObject ja = new JSONObject();
ja.put("district_id", a.getCode());
ja.put("district_name", a.getName());
array.put(ja);
}
jSONObjectOut.put("data", array);
jSONObjectOut.put("status", successMessage());
return jSONObjectOut;
}
private JSONObject successMessage() {
JSONObject jSONObjectOut = new JSONObject();
jSONObjectOut.put("code", 200);
jSONObjectOut.put("type", "success");
return jSONObjectOut;
}
private JSONObject errorMessage() {
JSONObject jSONObjectOut = new JSONObject();
jSONObjectOut.put("code", 400);
jSONObjectOut.put("type", "error");
jSONObjectOut.put("message", "Parameter name is not recognized.");
return jSONObjectOut;
}
private JSONObject errorMessageInstruction() {
JSONObject jSONObjectOut = new JSONObject();
jSONObjectOut.put("code", 400);
jSONObjectOut.put("type", "error");
jSONObjectOut.put("message", "You must provide a value for the parameter name.");
return jSONObjectOut;
}
}
I have not done any changes to the web.xml file. All the tutorials I went through did not give me a clear picture as to how and why I have to change it. Even without changing it, the web service works as expected.
How can I reduce the slashes in the URL?
The first thing you can do is remove the #Path("list"). A GET to /data will automatically go to the getJson method.
The next thing you can do is remove the api. You can do this by changing the "api" to "", "/", or "/*". All three will result in the same "/*". What happens when you do this is that Jersey will now take all requests that come to the server (and the same context). Any other servlets or static content will not be reachable.
To get around this, you can configure Jersey to run as a servlet filter instead of a servlet. Then configure it to forward unknown requests. See this post for how to configure this.
I am using JDK 1.5 with SAAJ [saaj-api-1.3.jar and saaj-impl-1.3.15.jar] and activation.jar
Now I have simple client below: On running this I am just getting the response just as ERROR tag nothing else, its very confusion, I thought there is something wrong with the webservice, so I have printed the SOAP_MESSAGE generated by SAAJ and using SOAP-UI sent the exact same message and it gave me the correct response, I even tried another webservice from
URL [http://www.actionscript.org/forums/showthread.php3?t=70742] and it seem to be working correctly. Please someone let me know I am totally lost here. Thanks in advance.
import java.io.IOException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.OutputKeys;
public class Test {
// Method for creating the SOAP Request
private static SOAPMessage createSOAPRequest() throws Exception {
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage soapMessage = messageFactory.createMessage();
SOAPPart soapPart = soapMessage.getSOAPPart();
// Construct SOAP Request Message:
// SOAP Envelope
SOAPEnvelope envelope = soapPart.getEnvelope();
envelope.addNamespaceDeclaration("sch", "http://www.cpscreen.com/schemas");
// SOAP Body
SOAPBody soapBody = envelope.getBody();
SOAPElement soapBodyElem = soapBody.addChildElement("CPLinkRequest","sch");
QName attributeName1 = new QName("account");
soapBodyElem.addAttribute(attributeName1, "NOTEST");
QName attributeName2 = new QName("userId");
soapBodyElem.addAttribute(attributeName2, "NONAME");
QName attributeName3 = new QName("password");
soapBodyElem.addAttribute(attributeName3, "NOPASSWORD");
SOAPElement soapBodyElem1 = soapBodyElem.addChildElement("Type", "sch");
soapBodyElem1.addTextNode("Report");
SOAPElement soapBodyElem2 = soapBodyElem.addChildElement("ProviderReferenceId", "sch");
soapBodyElem2.addTextNode("WPS-6472130");
soapMessage.saveChanges();
// Check the input
System.out.println("Request SOAP Message for Product web service");
soapMessage.writeTo(System.out);
System.out.println();
return soapMessage;
}
// Method for receiving the SOAP Response
private static void printSOAPResponse(SOAPMessage soapResponse) throws Exception {
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount","2");
Source sourceContent = soapResponse.getSOAPPart().getContent();
System.out.println("\nResponse SOAP Message from Product web service : ");
StreamResult result = new StreamResult(System.out);
transformer.transform(sourceContent, result);
}
// Starting point for SaajClient
public static void main(String args[]) {
try {
// Create SOAP Connection
SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
SOAPConnection soapConnection = soapConnectionFactory.createConnection();
// Sending SOAP Message to SOAP Server i.e, Product Catalog service
//String url = "http://www.webservicex.net/convertFrequency.asmx?WSDL";
java.net.URL endpoint = new URL("https://abc.xyz.com/pub/aaa/ws/backgroundCheck");
SOAPMessage soapResponse = soapConnection.call(createSOAPRequest(),endpoint);
// Processing the SOAP Response
printSOAPResponse(soapResponse);
//System.out.print("Response SOAP Message:");
//soapResponse.writeTo(System.out);
soapConnection.close();
} catch (Exception e) {
System.err.println("Error occurred while sending SOAP Request to Server");
e.printStackTrace();
}
}
}
Can you tell me please how to create http(s) request in jsoup with request method PUT or DELETE?
I came across this link:
https://github.com/jhy/jsoup/issues/158
but it is few years old, so hopefully there is some restful support implemented in that library.
As far as I can see HttpConnection object I can only use 'get' or 'post' request methods.
http://jsoup.org/apidocs/org/jsoup/helper/HttpConnection.html
http://jsoup.org/apidocs/org/jsoup/Connection.html
Jsoup doesn't support PUT nor DELETE methods. Since it is a parser, it doesn't need to support those operations. What you can do is use HttpURLConnection , which is the same that Jsoup uses underneath. With this you can use whatever method you want and in the end parse the result with jsoup (if you really need it).
Check this code :
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
public class Main {
public static void main(String[] args) {
try {
String rawData = "RAW_DATA_HERE";
String url = "URL_HERE";
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
//add reuqest header
con.setRequestMethod("METHOD_HERE"); //e.g POST
con.setRequestProperty("KEY_HERE", "VALUE_HERE"); //e.g key = Accept, value = application/json
con.setDoOutput(true);
OutputStreamWriter w = new OutputStreamWriter(con.getOutputStream(), "UTF-8");
w.write(rawData);
w.close();
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println("Response code : " + responseCode);
System.out.println(response.toString());
//Use Jsoup on response to parse it if it makes your work easier.
} catch(Exception e) {
e.printStackTrace();
}
}
}