Rally Changeset request returning null - spring

I am attempting to automate some stuff in my Rally environment. Just as of a few days ago I have having this problem that I cannot seem to fix when I attempt to a valid rest exchange with Rally for information about some Changesets. This is run using Tomcat and simply listens from another server we have.
Here is some of the code and some logs:
String changesetRef defect.getAsJsonObject().get("Changesets").getAsJsonObject().get("_ref")
.toString();
try {
ResponseEntity<QueryResultWrapper> changeSetsRequest = caller.callRestfulAPIForRally(
changesetRef.substring(1, changesetRef.length() - 1), httpmethod,
new ParameterizedTypeReference<QueryResultWrapper>() {
});
// The Auth key is received from a file
public <T> ResponseEntity<T> callRestfulAPIForRally(String url, HttpMethod method, ParameterizedTypeReference<T> paramRef) {
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", RallyAuthKey);
headers.add("Content-Type", "application/json");
headers.add("Accepts", "application/json");
return callRestfulAPI(url, headers, method, paramRef);
}
private <T> ResponseEntity<T> callRestfulAPI(String url, HttpHeaders headers, HttpMethod method, ParameterizedTypeReference<T> paramRef) {
RestTemplate restTemplate = new RestTemplate();
SimpleClientHttpRequestFactory simpleFactory = new SimpleClientHttpRequestFactory();
//Set timeout on connection to 20 seconds
simpleFactory.setConnectTimeout(20*1000);
restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(simpleFactory));
ResponseEntity<T> result = restTemplate.exchange(url, method, new HttpEntity<String>(headers), paramRef);
logger.info("Result: " + result.toString());
logger.info("Result body: " + result.getBody());
return result;
}
These loggers return the following when this is run:
INFO - Result: <200
OK,com.mycompany.webservice.core.jenkins.QueryResultWrapper#33eb30ec,{Date=[Thu, 07 Jul 2016 22:08:41 GMT], Content-Type=[application/json; charset=utf-8], Transfer-Encoding=[chunked], Connection=[keep-alive], Set-Cookie=[__cfduid=dc0b3ebf63634c86250efdedf10fd4ead1467929321; expires=Fri, 07-Jul-17 22:08:41 GMT; path=/; domain=.rallydev.com; HttpOnly, JSESSIONID=qs-app-111wgnt86c424tz1hwu48m187shg.qs-app-11;Path=/;Secure;HttpOnly, ZSESSIONID=CONFIDENTIAL;Path=/;Domain=rally1.rallydev.com;Secure;HttpOnly, SUBBUCKETID=0;Path=/;Domain=rally1.rallydev.com;Secure;HttpOnly, SERVERID=CONFIDENTIAL; path=/], Strict-Transport-Security=[max-age=31536000 ; includeSubDomains], X-XSS-Protection=[1; mode=block], RallyRequestID=[qs-app-111wgnt86c424tz1hwu48m187shg.qs-app-1128098501], Expires=[Thu, 01 Jan 1970 00:00:00 GMT], ETag=[W/"028b6add6cf4389520d5bdb5163a9a21c"], Vary=[Accept-Encoding], P3P=[CP="NON DSP COR CURa PSAa PSDa OUR NOR BUS PUR COM NAV STA"], Cache-Control=[private,max-age=0,must-revalidate], Server=[cloudflare-nginx], CF-RAY=[2bee9dd3697809b2-ORD]}>
2016-07-07 17:08:41,361 RestCallHelper
INFO - Result body:com.mycompany.webservice.core.jenkins.QueryResultWrapper#33eb30ec
Here is the structure for the request and how I have it set up... Spring should autopopulate all of theses values.
QueryResultWrapper
--> QueryResult
--> Results[]
--> Changes
-->_ref
When this executes it says it has made a GET request that, when I copy and past it into the browser, contains a valid Json like this:
{"QueryResult": {"_rallyAPIMajor": "2", "_rallyAPIMinor": "0", "Errors": [], "Warnings": [], "TotalResultCount": 1, "StartIndex": 1, "PageSize": 20, "Results": [{"_rallyAPIMajor": "2", "_rallyAPIMinor": "0", "_ref": "STUFF IS IN HERE", "_refObjectUUID": "9b96f131-f7a3-4615-b699-f793677836ba", "_objectVersion": "2", "_refObjectName": "Automate-web:057c595a52d0b39233bc4796d69cb09fb329d007", "CreationDate": "2016-07-07T18:45:31.240Z", "_CreatedAt": "today at 1:45 pm", "ObjectID": 58917491560, "ObjectUUID": "9b96f131-f7a3-4615-b699-f793677836ba", "VersionId": "2", "Subscription": {STUFF IS IN HERE}, "Workspace": {STUFF IS IN HERE }, "Artifacts": {STUFF IS IN HERE}, "Author": {STUFF IS IN HERE}, "Branch": null, "Builds": {STUFF IS IN HERE}, "Changes": {STUFF IS IN HERE}, "CommitTimestamp": "2016-07-07T18:44:16.000Z", "Message": "DE3333. Check for an agent on the agent lookup.", "Name": "CONFIDENTIAL", "Revision": "057c595a52d0b39233bc4796d69cb09fb329d007", "SCMRepository": {STUFF IS IN HERE}, "Uri": "STUFF IS IN HERE", "_type": "Changeset"}]}}
Now why does QueryResult return null?

It happens that the Spring integration of Jackson doesn't seem to like how the QueryResultWrapper looks and was not able to assign that variable anything. This is the following changes I made to no use Jackson.
public <T> T callRestfulAPIForRallyObjectMapper(String url, HttpMethod method, T obj) throws JsonParseException, JsonMappingException, IOException {
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", RallyAuthKey);
headers.add("Content-Type", "application/json");
headers.add("Accepts", "application/json");
return callRestfulAPIObjectMapper(url, headers, method, obj);
}
private <T> T callRestfulAPIObjectMapper(String url, HttpHeaders headers, HttpMethod method, T obj) throws JsonParseException, JsonMappingException, IOException {
RestTemplate restTemplate = new RestTemplate();
SimpleClientHttpRequestFactory simpleFactory = new SimpleClientHttpRequestFactory();
//Set timeout on connection to 20 seconds
simpleFactory.setConnectTimeout(20*1000);
restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(simpleFactory));
ResponseEntity<String> result = restTemplate.exchange(url, method, new HttpEntity<String>(headers), new ParameterizedTypeReference<String>(){});
ObjectMapper mapper = new ObjectMapper();
#SuppressWarnings("unchecked")
T wrapper = (T) mapper.readValue(result.getBody(), obj.getClass());
return wrapper;
}
This is the changes I made in the code that calls the methods.
QueryResultWrapper changeSetsRequest = caller.callRestfulAPIForRallyObjectMapper(
changesetRef.substring(1, changesetRef.length() - 1), httpmethod,
new QueryResultWrapper());
QueryResult qr = changeSetsRequest.getQueryResult();

Related

Spring boot RestTemplate upload file to SharePoint online but file is corrupted

There is a RestController and I try to upload a MultiPartFile to SharePointOnline using, the SharePoint REST API I'm also using proxy due to corporate restrictions.
#Override
public ResponseEntity uploadFile(MultipartFile file) throws ApiException, IOException {
RestTemplate restTemplate = createBasicRestTemplate();
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("file",file.getResource());
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> uploadBodyEntity = new HttpEntity<>(body, header);
ResponseEntity<String> response = restTemplate.exchange(BASE_URL, HttpMethod.POST,
uploadBodyEntity, String.class);
return response;
}
public RestTemplate createBasicRestTemplate() {
RestTemplate restTemplate = new RestTemplateBuilder(new ProxyCustomizer()).build();
return restTemplate;
}
#Override
public void customize(RestTemplate restTemplate) {
HttpHost proxy = new HttpHost(PROXY_HOST, PROXY_PORT);
HttpClient httpClient = HttpClientBuilder.create()
.setRoutePlanner(new DefaultProxyRoutePlanner(proxy) {
#Override
public HttpHost determineProxy(HttpHost target, HttpRequest request, HttpContext context) throws HttpException {
return super.determineProxy(target, request, context);
}
})
.build();
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
}
The file upload is success, but it's cannot be opened. For example if upload a txt it will looks like this:
--raF_ORlUJptia2_av7ppLBeeMcGf5BUr
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plain
Content-Length: 159
--38dc5323d6b92b5c14c33fade0178306
Content-Disposition: form-data; name="file"; filename="test.txt"
blablalblalalal
--38dc5323d6b92b5c14c33fade0178306--
--raF_ORlUJptia2_av7ppLBeeMcGf5BUr--
If I upload an xlsx it's simply just not open, it shows 'File Format and Extension Don't Match' error.
I try to convert the MultiPartFile to simple File with this method:
public File convertFile(MultipartFile file) {
File convFile = new File(file.getOriginalFilename());
try {
convFile.createNewFile();
FileOutputStream fos = new FileOutputStream(convFile);
fos.write(file.getBytes());
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
return convFile;
}
and change the controller to:
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("file",convertFile(file));
But the same thing happens.
How can I upload file with RestTemplate?
This is a sample request to the SharePoint REST API and based on documentation the endpoint should receive a array buffer
POST https://{site_url}/_api/web/GetFolderByServerRelativeUrl('/Folder Name')/Files/add(url='a.txt',overwrite=true)
Authorization: "Bearer " + accessToken
Content-Length: {length of request body as integer}
X-RequestDigest: "{form_digest_value}"
"Contents of file"
This is what i can see in the https log: http log
Solution was to remove MultiValueMap and replace with:
HttpEntity<byte[]> entity = new HttpEntity<>(file.getBytes(), spoHelperService.createAuthHeader(authToken));
ResponseEntity<SpoUploadResponse> response = restTemplate.exchange(uploadFileUrl, HttpMethod.POST,
entity, SpoUploadResponse.class);

Why sending a request to controller using Postman runs fine but using RestTemplate throws 500 Internal Server Error?

Context
I have two controllers: /testParams and /callTestParams
Controller /testParams receives an object of type Example and I can call this controller from Postman without any problem.
Controller /callTestParams calls /testParams internally using RestTemplate but the response is a 500 Internal Server Error. I supose that the implementation of /callTestParams is equivalent to the call maded by Postman.
Here is the code:
#RequestMapping(value = "/testParams",
method = RequestMethod.POST, produces = "application/json", consumes = "application/json")
public ResponseEntity<Object> testParams(
#RequestBody Example credentials
) {
JSONObject params = new JSONObject( credentials );
System.out.println( params.get("clientId") + " from JSONObject");
System.out.println( credentials.getClientId() + " from GraphCredentials");
return new ResponseEntity<>(credentials,HttpStatus.OK);
}
#RequestMapping(value = "/callTestParams",
method = RequestMethod.POST, produces = "application/json", consumes = "application/json")
public ResponseEntity<Object> callTestParams() {
String url = "http://localhost:8080/GraphClient/testParams";
HttpHeaders headers = new HttpHeaders();
headers.set( HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE );
JSONObject params = new JSONObject();
params.put("clientId", "value1" );
RestTemplate restTemplate = new RestTemplate();
HttpEntity<?> entity = new HttpEntity<>(params,headers);
HttpEntity<Object> response = restTemplate.exchange(
url,
HttpMethod.POST,
entity,
Object.class
);
return new ResponseEntity<>(response.getBody(), HttpStatus.OK);
}
This is the response from Postman for /testParams
Headers:
(Content-Type,application/json)
Request Body:
JSON (appplication/json)
{"clientId":"value1"}
Response:
{
"clientId": "value1",
"clientSecret": null,
"tenantId": null,
"scope": null,
"grantType": null,
"microsoftLoginBaseURL": "https://login.microsoftonline.com/"
}
This is the response from Postman for /callTestParams
{
"timestamp": "2022-01-09T03:39:06.878+0000",
"status": 500,
"error": "Internal Server Error",
"message": "500 Internal Server Error",
"path": "/GraphClient/callTestParams"
}
This is the error in the console>
Forwarding to error page from request [/testParams] due to exception [JSONObject["clientId"] not found.]: org.json.JSONException: JSONObject["clientId"] not found.
In the parameter of the body of the HttpEntity constructor you need to pass params as String
HttpEntity<?> entity = new HttpEntity<>(params.toString(),headers);

Getting null body in response from feign client, even though a direct request is returning an entity

I have this Feign Client in my spring boot application :
#Component
#FeignClient(value = "apiKeyManager", url = "http://localhost:8081/", configuration = FileUploadConfiguration.class)
public interface ApiKeyClient {
#RequestMapping(method = RequestMethod.POST, value = "/api/public/getAppName", consumes = "application/json", produces = "application/json")
ResponseEntity getAppName(#RequestBody AppNameRequestDto appNameRequestDto);
}
And I have this code in my service, which calls it :
AppNameRequestDto request = new AppNameRequestDto(apiKey);
ResponseEntity verification = apiKeyClient.getAppName(request);
return verification;
The actual endpoint being called by the feign client looks like this :
#PostMapping(value = "getAppName", consumes = "application/json", produces = "application/json")
public ResponseEntity getAppName(#RequestBody AppNameRequestDto appNameRequestDto){
try {
return new ResponseEntity(apiKeyManagementService.getAppName(appNameRequestDto.getApiKey()), HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity("Failed to locate application by API_KEY : " + appNameRequestDto.getApiKey(), HttpStatus.NOT_FOUND);
}
}
When I run this code - I get this response :
{
"headers": {
<REMOVED FOR BREVITY>
},
"body": null,
"statusCode": "OK",
"statusCodeValue": 200
}
But when I make the call to the underlying API directly, I get the response I am expecting - an entity with an accompanies 200 status :
{
"applicationName": "MyNewFileUploadServiceApplication6"
}

Spring Boot Inject Rest Template to Login Filter

in default, my Login Filter output like this :
"role": "ROLE_ABC",
"succeed": "Success!",
"id": 123,
"username": "111222333",
"token": "xxxxx"
now i want to inject the output of rest tempalte, the output of rest template like this one :
{
"ResponseHeader": {
"ErrorCode": "0",
"ErrorDescription": "Success",
"TrxId": "123"
},
"UserInfo": {
"UserId": "111222333",
"FullName": ""
}
}
now i want to inject the output of rest template to my default login filter.
this is my code, im confuse how i can send the Request Body of rest template inside Login Filter
#Autowired
RestTemplate restTemplate;
#Override
protected void successfulAuthentication(final HttpServletRequest req, final HttpServletResponse res, final FilterChain chain,
final Authentication auth) throws IOException, ServletException {
logger.info("successfulAuthentication");
logger.info(auth);
Set<String> roles = AuthorityUtils.authorityListToSet(auth.getAuthorities());
String hasil=roles.toString().replace("[","").replace("]", "");
AuthenticationService.addToken(res, auth.getName());
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/json");
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add("Authorization", "Basic uYycjhow9iJOFOJj=");
HttpEntity<vwCredentials> entity = new HttpEntity<vwCredentials>(product,headers);
->variable "product" is request body,
i confuse where should i put this code "#RequestBody vwCredentials product"
ResponseEntity<vwJWTLDAP> respon = restTemplate.exchange(
"http://123/LDAP/", HttpMethod.POST, entity, vwJWTLDAP.class);
HashMap<String, Object> map = new HashMap<>();
String email = auth.getName();
User user = repository.findByEmail(email);
map.put("id", user.getId());
map.put("username", auth.getName());
map.put("role", hasil);
//map.put("LDAP", respon); -> I WANT TO CALL LIKE THIS WAY
map.put("token", AuthenticationService.addToken(auth.getName()));
map.put("succeed", "Success !");
String authString = new Gson().toJson(map);
PrintWriter out = res.getWriter();
res.setContentType("application/json");
res.setCharacterEncoding("UTF-8");
out.print(authString);
out.flush();
}
}
how can i call like this way. //map.put("LDAP", respon); -> I WANT TO CALL LIKE THIS WAY
lass.
You would go about this using the getBody() method. This method is inherited from the class HttpEntity.
That being said, a way to get it would be map.put("LDAP", respon.getBody());

Upgrading to Spring 5 broke RestTemplate MultipartFile upload

I upgraded from Spring 4.3.16 to Spring 5.0.7. When trying to upload a file using the restTemplate I started to get a "400 - Bad Request". After messing around the only difference in behavior I noticed was removing requestEntity from the exchange call and the error (bad request) goes away, however it fails because the file is not present to be uploaded.
Any help would be greatly appreciated!
The client:
public <T> ResponseEntity<T> uploadMultipartFile(String requestParamName, byte[] byteArray, String fileName,
Class<T> responseType) {
ByteArrayResource byteArrayAsResource = new ByteArrayResource(byteArray) {
#Override
public String getFilename() {
return fileName;
}
};
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add(requestParamName, byteArrayAsResource);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(map, headers);
return getRestTemplate().exchange(buildUriWithVariables(new HashMap<>()), HttpMethod.POST, requestEntity, responseType);
}
And the controller:
#RequestMapping("/multipleUpload")
public ModelAndView multipleUpload(HttpServletRequest request, HttpServletResponse response,
#RequestParam(value = "files", required = false) MultipartFile[] files,
#ModelAttribute("document") Document document,
BindingResult result) {}
It looks like Apache is complaining about the request body:
[Wed Jul 18 11:02:29.705758 2018] [:error] [pid 1313:tid
140177850750720] [client ] ModSecurity: Access denied with
code 400 (phase 2). Match of "eq 0" against "REQBODY_ERROR" required.
[file "/etc/modsecurity/modsecurity.conf"] [line "54"] [id "200001"]
[msg "Failed to parse request body."] [data "Multipart: Invalid
boundary in C-T (characters)."] [severity "CRITICAL"] [hostname
""] [uri "/restless/documentUpload/multipleUpload"]
[unique_id "W09WhX8AAAEAAAUhs7IAAABI"]

Resources