template parsing URL in java - java

I have a application that receive a message from SMPP server and forward the received message to users web services. all users have a URL in database like this:
http://www.example.com/get.php?from=${originator}&to=${destination}&data=${content}
http://www.example.com/submit?origin=${originator}&dst=${destination}&cnt=${content}
All of them have ${originator},${destination},${content} in their pattern. they may have other parameters in their URL or not. I use Jodd StringTemplateParser to replace above arguments after getting user URL from database:
private StringTemplateParser stp = new StringTemplateParser();
private final Map<String, String> args = new HashMap<>();
args.put("originator", msg.getOriginator());
args.put("destination", msg.getDestination());
args.put("content", msg.getContent());
String result = stp.parse(deliveryUrl, new MacroResolver() {
#Override
public String resolve(String macroName) {
return args.get(macroName);
}
});
Then I use apache http client to call user URL:
URL url = new URL(result);
int port = url.getPort();
uri = new URI(url.getProtocol(), null, url.getHost(), port == -1 ? 80 : port, url.getPath(), url.getQuery(), null);
DefaultHttpClient client = new DefaultHttpClient();
HttpGet request = null;
try {
request = new HttpGet(uri);
client.execute(request)
} catch (Exception ex) {
if (request != null) {
request.releaseConnection();
}
}
I tried to do some encoding because user may send any text containing characters like %$&. The problem is when content contains something like hello&x=2&c=3243 user only gets hello. URI class treats that as regular GET query parameter. Can anyone help?

You need to encode the parameter values when you are building your new URI.
You can encode the parameters using URLEncoder.encode(String).
So, in your MacroResolver, just return URLEncoder.encode(map.get(macroName)).

I think in your case you need to use HTTP default content char-set something like this for your code
request = new HttpGet(url+"?"+URLEncodedUtils.format(namevaluepair,
HTTP.DEFAULT_CONTENT_CHARSET));

Related

entity must be null for http method GET

I'm trying to consume an external api exposed a payment provider.
I user Jersey and javax.ws.rs for request, because I can easily send authent with Digest.
But when it comes to make the request, a GET with payload, Jersey returns
> IllegalStateException. Entity must be null for http method GET
CashTransactionResponse responseData = null;
//We connect to intouch server
String requestUrl = rootUrlTouchPay + agency.getAgencyCode() + "/" + IntouchMethodApis.TRANSACTION + "?loginAgent=" + agency.getLogin() + "&passwordAgent=" + agency.getPassword();
ClientConfig clientConfig = new ClientConfig();
//Open Digest authentication
HttpAuthenticationFeature feature = HttpAuthenticationFeature.digest(BASIC_LOGIN, BASIC_PWD);
clientConfig.register(feature);
clientConfig.register(JacksonFeature.class);
//Create new rest client
Client client = ClientBuilder.newClient(clientConfig);
clientConfig.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true);
//Set the url
WebTarget webTarget = client.target(requestUrl);
Invocation.Builder invocationBuilder = webTarget.request(javax.ws.rs.core.MediaType.APPLICATION_JSON);
logger.info("Initialisation of cashout service successful for cash");
// create request
Gson gson = new Gson();
String transactionString = gson.toJson(cashRequest);
Response response = null;
// start the response
if (cashRequest.getServiceCode().contains(TelecomEnum.WAVE.name().toUpperCase())) {
response = invocationBuilder.method("GET", Entity.entity(transactionString, javax.ws.rs.core.MediaType.APPLICATION_JSON));
} else {
response = invocationBuilder.put(Entity.entity(transactionString, javax.ws.rs.core.MediaType.APPLICATION_JSON));
}
Please how could i do to send my GET request with body ?
Thanks
I believe the problem is in
Client client = ClientBuilder.newClient(clientConfig);
clientConfig.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true);
The client copied the values from clientConfig and any further settings on clientConfig do not have any impact on the client.
Either switch the lines or set the ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION property on the client.
Instead of doing an invocationBuilder.method("GET", ...), use invocationBuilder.post(entity), as described here. This will allow you to POST your transaction String to the endpoint.

Send JSON body in HTTP GET request in java/spring boot

I need to send a GET request with a json body in java/spring boot. I'm aware of the advice against it, however I have to do it this was for a couple of reasons:
1. The 3rd party API I'm using only allows GET requests, so POST is not an option.
2. I need to pass an extremely large parameter in the body (a comma separated list of about 8-10k characters) so tacking query params onto the url is not an option either.
I've tried a few different things:
apache HttpClient from here: Send content body with HTTP GET Request in Java. This gave some error straight from the API itself about a bad key.
URIComponentsBuilder from here: Spring RestTemplate GET with parameters. This just tacked the params onto the url, which as I explained before is not an option.
restTemplate.exchange. This seemed the most straightforward, but the object wouldn't pass: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html#exchange-java.lang.String-org.springframework.http.HttpMethod-org.springframework.http.HttpEntity-java.lang.Class-java.util.Map-
as well as probably another thing or two that I've forgotten about.
Here is what I'm talking about in Postman. I need to be able to pass both of the parameters given here. It works fine if run through Postman, but I can't figure it out in Java/Spring Boot.
Here is a code snippet from the restTemplate.exchange attempt:
public String makeMMSICall(String uri, List<String> MMSIBatchList, HashMap<String, String> headersList) {
ResponseEntity<String> result = null;
try {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
for (String key : headersList.keySet()) {
headers.add(key, headersList.get(key));
}
Map<String, String> params = new HashMap<String, String>();
params.put("mmsi", String.join(",", MMSIBatchList));
params.put("limit", mmsiBatchSize);
HttpEntity<?> entity = new HttpEntity<>(headers);
result = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class, params);
System.out.println(result.getBody());
} catch (RestClientException e) {
LOGGER.error("Exception in makeGetHTTPCall :" + e.getMessage());
throw e;
} catch (Exception e) {
LOGGER.error("Exception in makeGetHTTPCall :" + e.getMessage());
throw e;
}
return result.getBody();
}
Thanks for helping!
You can try java.net.HttpUrlConnection, it works for me but indeed I normally use a POST
HttpURLConnection connection = null;
BufferedReader reader = null;
String payload = "body";
try {
URL url = new URL("url endpoint");
if (url.getProtocol().equalsIgnoreCase("https")) {
connection = (HttpsURLConnection) url.openConnection();
} else {
connection = (HttpURLConnection) url.openConnection();
}
// Set connection properties
connection.setRequestMethod(method); // get or post
connection.setReadTimeout(3 * 1000);
connection.setDoOutput(true);
connection.setUseCaches(false);
if (payload != null) {
OutputStream os = connection.getOutputStream();
os.write(payload.getBytes(StandardCharsets.UTF_8));
os.flush();
os.close();
}
int responseCode = connection.getResponseCode();
}
There's no way of implementing it via RestTemplate, even with .exchange method. It'll simply not send the request body for GET calls even if we pass the entity within the function parameters.(Tested via interceptor logs)
You can use the Apache client to solve this issue/request (whatever you'd like to call it). The code you need is something along following lines.
private static class HttpGetWithBody extends HttpEntityEnclosingRequestBase {
JSONObject requestBody;
public HttpGetWithBody(URI uri, JSONObject requestBody) throws UnsupportedEncodingException {
this.setURI(uri);
StringEntity stringEntity = new StringEntity(requestBody.toString());
super.setEntity(stringEntity);
this.requestBody = requestBody;
}
#Override
public String getMethod() {
return "GET";
}
}
private JSONObject executeGetRequestWithBody(String host, Object entity) throws ClientProtocolException, IOException {
CloseableHttpClient httpClient = HttpClients.createDefault();
try{
JSONObject requestBody = new JSONObject(entity);
URL url = new URL(host);
HttpRequest request = new HttpGetWithBody(url.toURI(), requestBody);
request.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
request.addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
HttpResponse response;
if(url.getPort() != 0) response = httpClient.execute(new HttpHost(url.getHost(), url.getPort()), request);
else response = httpClient.execute(new HttpHost(url.getHost()), request);
if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
JSONObject res = new JSONObject(EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8));
httpClient.close();
return res;
}
}catch (Exception e){
log.error("Error occurred in executeGetRequestWithBody. Error: ", e.getStackTrace());
}
httpClient.close();
return null;
}
If you inspect even Apache client library doesn't support passing the body natively(checked via code implementation of HttpGet method), since contextually request body for a GET request is not a good and obvious practice.
Try creating a new custom RequestFactory.
Similar to
get request with body

Programmatically generate and retrieve BIRT Report from Web-Viewer

I've installed BIRT Web-Viewer on my server and am able to build the report with this URL:
http://hostname:port/birt/run?__report=test.rptdesign
Now I need to programmatically call this URL from my Java Code and retrieve the result as stream or file.
Is there any API for the Web-Viewer?
If not, could I just call the URL like this and extract the PDF?:
HttpClient httpClient = HttpClients.createDefault();
HttpGet postRequest = new HttpPost("http://hostname:port/birt/run");
List<NameValuePair> formData = new ArrayList<>();
formData.add(new BasicNameValuePair("__report", "test.rptdesign"));
HttpEntity entity = new UrlEncodedFormEntity(formData);
HttpResponse response = httpClient.execute(postRequest);
I found out, if I use the __format parameter with the value pdf, the response to the request is the PDF content, which is exactly what I wanted.
The standard response is a HTML, which will be returned with a second request. I'm pretty sure that response has to be retrieved with sessions.
Edit:
As requested I will post my request code. I modified it a bit, because I used some custom classes to hold configuration and the report.
public InputStream getReport() throws Exception {
StringBuilder urlBuilder = new StringBuilder()
.append("http://example.com:9080/contextRoot/run")
.append("?__report=ReportDesign.rptdesign&__format=pdf");
if (reportParameters != null) {
for (Map.Entry<String, String> parameter : reportParameters.entrySet()) {
String key = StringEscapeUtils.escapeHtml(parameter.getKey());
String value = StringEscapeUtils.escapeHtml(parameter.getValue());
urlBuilder.append('&')
.append(key);
.append('=');
.append(value);
}
}
URL requestUrl = new URL(burlBuilder.toString());
HttpURLConnection connection = (HttpURLConnection) requestUrl.openConnection();
connection.setRequestMethod("GET");
connection.setDoInput(true);
connection.connect();
return connection.getInputStream();
}
I also had another method write the used data as XML to the file system before I called requestUrl.openConnection(), but I think this is only necessary if you use very dynamic data like I did.

Embedding a File Attachment in JSON Object

Is it possible to embed a file attachment in a JSON Object. I have a HTML Form, which has several text field inputs and a file attachment. I want to send a JSON Object wrapping all these form data (including the file attachment) to the server.
Are there any particular libraries in Java available to do that? Can you give possible solution for this.
Thanks
If you want to send the actual data of the file, you'd probably want to encode it as a base64 string and send that in your JSON - see fiddle for example of encoding it in javascript:
http://jsfiddle.net/eliseosoto/JHQnk/
Then you could do the opposite on your server-side using whatever language and/or libraries are appropriate.
Use MultipartEntity, someone else posted a similar question: How to send file in JSON on android?
You could also consider saving the files on the server and sending a path/url to the file location where the other server can access them.
public String SendToServer(String aUrl,File Filename)
{
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(filename);
try
{
MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
entity.addPart("file", new FileBody(Filename));
entity.addPart("video-title", new StringBody("Video"));
entity.addPart("video-type", new StringBody("1"));
httpPost.setEntity(entity);
HttpContext context = new BasicHttpContext();
// Bind custom cookie store to the local context
context.setAttribute(ClientContext.COOKIE_STORE, Globals.sessionCookie);
HttpResponse response = httpClient.execute(httpPost, context);
HttpEntity resEntity = response.getEntity();
String Response = "";
if (response != null)
{
Response = EntityUtils.toString(resEntity);
}
return Response;
}
catch (IOException e)
{
e.printStackTrace();
}
return "Exception";
}

How do I upload a document to SharePoint with Java?

I'm creating some big files (DB exports) with Java and I need to put them somewhere on our SharePoint server. Right now, I'm doing this with IE but I'd like to automate this step, too.
I searched the web and I found some hints to use SOAP but I don't really see to the ground of all this, yet. Can someone provide me with some sample code or a recipe what I need to do?
Please note: the SharePoint server asks for NT domain authentication. I can't even login with Firefox :(
EDIT
How do I convert the scary URL in IE into a WebDAV path?
Is there a WebDAV "explorer" which I can use before I ruin the production system with my code? I tried "DAV Explorer 0.91" from http://www.davexplorer.org/ but that can't connect (probably because of NT domain auth).
In addition to Sacha's suggestions, you can use the SharePoint SOAP web services. Each SharePoint site exposes a bunch of web services via the path http://<Site>/_vti_bin/.
In your case, you probably want the Lists web service (http://<Site>/_vti_bin/Lists.asmx). You can grab the WSDL from http://<Site>/_vti_bin/Lists.asmx?WSDL. The WSS 3.0 SDK has details on how to use the web service (you'll probably want to use the UpdateListItems and AddAttachment methods).
All that said, Sacha's first option (mapping a document library to a drive) is probably the easiest way assuming you can get around the NTLM issues.
If you're using Windows you can simply navigate to a UNC path for a document library. For example, if the browser URL for your document library is:
http://<Site>/Foo/BarDocs/Forms/AllItems.aspx
you can simply type the corresponding UNC path in the Windows Explorer address bar:
\\<Site>\Foo\BarDocs
and then drag and drop files to this location. If you'd like you can map this location to a drive letter using Windows Explorer or the SUBST.EXE command-line utility.
Okay ... after several hours of work and biting myself through the "documentation" MicroSoft provides and all the hints randomly spread over the 'net, I've managed to write some sample code to browse the content of a SharePoint server: Navigating SharePoint Folders With Axis2.
Next stop: Uploading something.
An other solution is to use HTTP PUT method to send a file directly to the Sharepoint.
For that you can use Apache HTTP Client:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.2.3</version>
</dependency>
And to permit NTLMv2 authentication you need JCIF library.
<dependency>
<groupId>jcifs</groupId>
<artifactId>jcifs</artifactId>
<version>1.3.17</version>
</dependency>
First we need to write a wrapper to permit Apache HTTP Client to use JCIF for NTLMv2 support :
public final class JCIFSEngine implements NTLMEngine {
private static final int TYPE_1_FLAGS =
NtlmFlags.NTLMSSP_NEGOTIATE_56
| NtlmFlags.NTLMSSP_NEGOTIATE_128
| NtlmFlags.NTLMSSP_NEGOTIATE_NTLM2
| NtlmFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN
| NtlmFlags.NTLMSSP_REQUEST_TARGET;
#Override
public String generateType1Msg(final String domain, final String workstation)
throws NTLMEngineException {
final Type1Message type1Message = new Type1Message(TYPE_1_FLAGS, domain, workstation);
return Base64.encode(type1Message.toByteArray());
}
#Override
public String generateType3Msg(final String username, final String password,
final String domain, final String workstation, final String challenge)
throws NTLMEngineException {
Type2Message type2Message;
try {
type2Message = new Type2Message(Base64.decode(challenge));
} catch (final IOException exception) {
throw new NTLMEngineException("Invalid NTLM type 2 message", exception);
}
final int type2Flags = type2Message.getFlags();
final int type3Flags = type2Flags
& (0xffffffff ^ (NtlmFlags.NTLMSSP_TARGET_TYPE_DOMAIN | NtlmFlags.NTLMSSP_TARGET_TYPE_SERVER));
final Type3Message type3Message = new Type3Message(type2Message, password, domain,
username, workstation, type3Flags);
return Base64.encode(type3Message.toByteArray());
}
}
Reference
The main code to execute HTTP PUT with authentication:
try {
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
DefaultHttpClient httpclient = new DefaultHttpClient(params);
//Register JCIF NTLMv2 to manage ntlm auth.
httpclient.getAuthSchemes().register("ntlm", new AuthSchemeFactory() {
#Override
public AuthScheme newInstance(HttpParams hp) {
return new NTLMScheme(new JCIFSEngine());
}
});
//Provide login/password
httpclient.getCredentialsProvider().setCredentials(
AuthScope.ANY,
new NTCredentials([LOGIN], [PASSWORD], "", [DOMAIN]));
//Create HTTP PUT Request
HttpPut request = new HttpPut("http://[server]/[site]/[folder]/[fileName]");
request.setEntity(new FileEntity([File]));
return httpclient.execute(request);
} catch (IOException ex) {
//...
}
I can think of different options:
Mapping the Document library to a file drive and just save the file like any other file in the file system.
Using HTTP WebDAV protocol.
...and for the NTLM authentication part:
http://www.luigidragone.com/networking/ntlm.html
I think my approach might help you.
Initially i have created sharepoint account and followed the procedure in this link (http://www.ktskumar.com/2017/01/access-sharepoint-online-using-postman/) to get needed credentials for REST API's. once i got the credentials all i needed was the following dependency and code:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5</version>
</dependency>
Since i used OAUTH2 authentication, the code to get access token helps for other CRUD operations.
/* OAuth2 authentication to get access token */
public String getSharePointAccessToken() throws ClientProtocolException, IOException
{
/* Initializing variables */
String grant_type = RcConstants.GRANT_TYPE;
String client_id = RcConstants.CLIENT_ID;
String client_secret = RcConstants.CLIENT_SECRET;
String resource = RcConstants.RESOURCE;
String url = RcConstants.OAUTH_URL + RcConstants.URL_PARAMETER + "/tokens/OAuth/2";
/*
* NOTE: RcConstants.OAUTH_URL =
* https://accounts.accesscontrol.windows.net/ RcConstants.URL_PARAMETER
* = Bearer Realm from
* (http://www.ktskumar.com/2017/01/access-sharepoint-online-using-
* postman/) Figure 6.
*/
/* Building URL */
HttpClient client = HttpClientBuilder.create().build();
HttpPost post = new HttpPost(url);
post.setHeader("Content-Type", "application/x-www-form-urlencoded");
/* Adding URL Parameters */
List<NameValuePair> urlParameters = new ArrayList<NameValuePair>();
urlParameters.add(new BasicNameValuePair("grant_type", grant_type));
urlParameters.add(new BasicNameValuePair("client_id", client_id));
urlParameters.add(new BasicNameValuePair("client_secret", client_secret));
urlParameters.add(new BasicNameValuePair("resource", resource));
post.setEntity(new UrlEncodedFormEntity(urlParameters));
/* Executing the post request */
HttpResponse response = client.execute(post);
logger.debug("Response Code : " + response.getStatusLine().getStatusCode());
String json_string = EntityUtils.toString(response.getEntity());
JSONObject temp1 = new JSONObject(json_string);
if (temp1 != null)
{
/* Returning access token */
return temp1.get("access_token").toString();
}
return RcConstants.OAUTH_FAIL_MESSAGE;
}
Once we get access token we can upload using following method:
public String putRecordInSharePoint(File file) throws ClientProtocolException, IOException
{
/* Token variable declaration */
String token = getSharePointAccessToken();
/* Null or fail check */
if (!token.equalsIgnoreCase(RcConstants.OAUTH_FAIL_MESSAGE))
{
/* Upload path and file name declaration */
String Url_parameter = "Add(url='" + file.getName() + "',overwrite=true)";
String url = RcConstants.UPLOAD_FOLDER_URL + Url_parameter;
/*
* NOTE: RcConstants.UPLOAD_FOLDER_URL =
* https://<your_domain>.sharepoint.com/_api/web/
* GetFolderByServerRelativeUrl('/Shared%20Documents/<FolderName>')/
* Files/
*/
/* Building URL */
HttpClient client = HttpClientBuilder.create().build();
HttpPost post = new HttpPost(url);
post.setHeader("Authorization", "Bearer " + token);
post.setHeader("accept", "application/json;odata=verbose");
/* Declaring File Entity */
post.setEntity(new FileEntity(file));
/* Executing the post request */
HttpResponse response = client.execute(post);
logger.debug("Response Code : " + response.getStatusLine().getStatusCode());
if (response.getStatusLine().getStatusCode() == HttpStatus.OK.value()|| response.getStatusLine().getStatusCode() == HttpStatus.ACCEPTED.value())
{
/* Returning Success Message */
return RcConstants.UPLOAD_SUCCESS_MESSAGE;
}
else
{
/* Returning Failure Message */
return RcConstants.UPLOAD_FAIL_MESSAGE;
}
}
return token;
}
I managed to up and download files to sharepoint with this code, using the integrated Windows identification, maybe it helps.
public class HttpClient {
HttpClient() { }
public static void download(final String source, final File resultingFile) {
CloseableHttpClient client = WinHttpClients.createSystem();
HttpGet httpRequest = new HttpGet(source);
CloseableHttpResponse httpResponse = null;
try {
httpResponse = client.execute(httpRequest);
HttpEntity entity = httpResponse.getEntity();
if(httpResponse.getStatusLine() != null && httpResponse.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
LOGGER.warn(httpResponse.getStatusLine());
}else {
LOGGER.debug(httpResponse.getStatusLine());
FileUtils.touch(resultingFile);
InputStream is = entity.getContent();
File outFile = new File(resultingFile.getAbsolutePath());
FileOutputStream fos = new FileOutputStream(outFile);
int inByte;
while ((inByte = is.read()) != -1) {
fos.write(inByte);
}
is.close();
fos.close();
client.close();
}
} catch (ClientProtocolException e) {
LOGGER.warn(e);
} catch (UnsupportedOperationException e) {
LOGGER.warn(e);
} catch (IOException e) {
LOGGER.warn(e);
}
}
public static void upload(final File source, final String destination) {
CloseableHttpClient httpclient = WinHttpClients.createSystem();
HttpPut httpRequest = new HttpPut(destination);
httpRequest.setEntity(new FileEntity(new File(source.getPath())));
CloseableHttpResponse httpResponse = null;
try {
httpResponse = httpclient.execute(httpRequest);
EntityUtils.consume(httpResponse.getEntity());
if (httpResponse.getStatusLine() != null && httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_CREATED) {
LOGGER.debug(httpResponse.getStatusLine());
LOGGER.info("Upload of " + source.getName() + " via HTTP-Client succeeded.");
} else if (httpResponse.getStatusLine() != null && httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
LOGGER.debug(httpResponse.getStatusLine());
}else {
LOGGER.warn("Uploading " + source.getName() + " failed.");
LOGGER.warn(httpResponse.getStatusLine().getStatusCode() + ": " + httpResponse.getStatusLine().getReasonPhrase());
}
} catch (IOException e) {
LOGGER.warn(e);
LOGGER.warn(e.getMessage());
}
return;
}
}
WinHttpClients:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient-win</artifactId>
<version>4.4</version>
</dependency>
Path:
org.apache.http.impl.client.WinHttpClients
Description:
Factory methods for CloseableHttpClient instances configured to use integrated Windows authentication by default.

Categories