I am trying to pull discussions for a given defect. I understand from a prior question I asked that it is not possible to pull the discussion data as a property of the defect itself rather I must run a separate fetch request.
The problem is that I can not identify any query filter to use when pulling conversation posts. This leads me to believe I would have to loop through every single conversation post and try to find the matching defect number in the actual data returned which would be highly inefficient.
Rather I would prefer to simply run a query fetch for each defect that uses a query filter for the formatted ID that will only return the conversation posts that apply for that defect.
import com.google.gson.JsonElement;
import com.rallydev.rest.RallyRestApi;
import com.rallydev.rest.request.QueryRequest;
import com.rallydev.rest.response.QueryResponse;
import com.rallydev.rest.util.Fetch;
import com.rallydev.rest.util.QueryFilter;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
public class ExtractFull {
#SuppressWarnings("unchecked")
public static void main(String args[]) throws URISyntaxException, IOException {
RallyRestApi restApi = new RallyRestApi(new URI("https://rally1.rallydev.com"), "_myapikey");
restApi.setApplicationName("DANA Example");
restApi.setProxy(new URI("http://myproxy:8080"), "username", "pass");
System.out.println("Querying Rally for defects, this may take some time");
try {
QueryRequest defectRequest = new QueryRequest("ConversationPost");
defectRequest.setPageSize(2000);
defectRequest.setLimit(5000);
QueryFilter filter = new QueryFilter("FormattedID","=","DE10101");
defectRequest.setQueryFilter(filter);
defectRequest.setFetch(new Fetch());
QueryResponse queryResponse = restApi.query(defectRequest);
for(JsonElement result: queryResponse.getResults()){
System.out.println(result);
}
} finally {
restApi.close();
}
}
}
This code doesn't work. I assume because "FormattedId" isn't a valid object of the "ConversationPost" type. I don't know if it's possible to filter for parent defect ID when querying a conversation post but that is what I need to do.
Specifically the code I am referring to is here:
QueryRequest defectRequest = new QueryRequest("ConversationPost");
defectRequest.setPageSize(2000);
defectRequest.setLimit(5000);
QueryFilter filter = new QueryFilter("FormattedID","=","DE10101");
defectRequest.setQueryFilter(filter);
Use the standard WSAPI, I can query like this:
(Artifact.FormattedID = "US123")
Was able to solve this issue on my own. The problem was that I was attempting to use "QueryRequest" without having a valid "type" to pass to the constructor.
The correct solution was to use "GetRequest" with the path to the defect discussion page being passed as the url (without requiring me to set an object type in the constructor). This returned a GetRequest object which contained a result set with all of the conversation posts.
GetRequest getRequest = new GetRequest(discussionURL);
GetResponse getResponse = restApi.get(getRequest);
The "discussion url" did not contain the "https://rally1.rallydev.com" which was declared when creating the rallyApi - the discussionURL variable contains the entire defect discussion page URL but without the above rally api url so for example "/slm/webservice/v2.0/Defect/106032660792/Discussion"
Related
On the server side, I develop a REST API with Java and Jersey / Jackson, and this API makes calls to the Stripe API.
The Stripe API returns all objects with properties names in snake case, such as client_secret for class PaymentIntent.
The JSON returned by my REST API using Jersey automatically converts these properties to camel case, with names such as clientSecret.
On the client side, I use the Stripe JS library, which also expects properties names in snake case, and therefore I get errors when I try to read properties of objects returned by my REST API.
I have seen many posts about configuring Jersey to use snake case instead of camel case, but I have not been able to apply what I found to my use case, which is using camel case for my own classes, and snake case for Stripe classes I have no control on.
Here is my current code on the server site:
package com.knowledgeplaces.metalmsapi.resources;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import com.knowledgeplaces.metalmsapi.records.PaymentIntentArgsRec;
import com.knowledgeplaces.metalmsapi.records.PaymentIntentResponseRec;
import com.knowledgeplaces.metalmsapi.utils.MetaLmsConstants;
import com.stripe.Stripe;
import com.stripe.model.PaymentIntent;
import com.stripe.exception.StripeException;
import com.stripe.net.ApiResource;
#Path("/eShops/{eShopId}/stripePaymentIntent")
public class StripePaymentIntentRest {
// request one Payment Intent
#POST
#Produces({ MediaType.APPLICATION_JSON })
public PaymentIntentResponseRec createService(
#Context HttpServletRequest req,
#PathParam("eShopId") Integer eShopId,
PaymentIntentArgsRec paymentIntentArgs) {
PaymentIntent paymentIntent;
PaymentIntentResponseRec paymentIntentResponse;
// get Stripe API secret key
if (paymentIntentArgs.stripeTestMode()) {
Stripe.apiKey = "***********************";
} else {
Stripe.apiKey = "***********************";
}
// create Payment Intent
List<Object> paymentMethodTypes = new ArrayList<>();
paymentMethodTypes.add("card");
Map<String, Object> params = new HashMap<>();
params.put("amount", paymentIntentArgs.amount());
params.put("currency", paymentIntentArgs.currency());
params.put(
"payment_method_types",
paymentMethodTypes);
try {
// paymentIntent = PaymentIntent.create(params);
paymentIntent = ApiResource.GSON.fromJson(PaymentIntent.create(params).toJson(), PaymentIntent.class);
paymentIntentResponse = new PaymentIntentResponseRec(null, paymentIntent);
} catch (StripeException ex) {
paymentIntentResponse = new PaymentIntentResponseRec(MetaLmsConstants.StripeApiError, null);
}
return paymentIntentResponse;
}
}
With this code, I get a Payment Intent object with properties in camel case.
If I uncomment the line
paymentIntent = PaymentIntent.create(params);
And comment the line
paymentIntent = ApiResource.GSON.fromJson(PaymentIntent.create(params).toJson(), PaymentIntent.class);
Then I get the following error:
No serializer found for class com.stripe.net.StripeResponse and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.knowledgeplaces.metalmsapi.records.PaymentIntentResponseRec["paymentIntent"]->com.stripe.model.PaymentIntent["lastResponse"])
Please advise on how to get rid off this error.
I have reviewed my code and here is a working solution:
try {
paymentIntent = PaymentIntent.create(params);
String paymentIntentJson = paymentIntent.toJson();
stringResponse = new StringResponseRec(null, paymentIntentJson);
} catch (StripeException ex) {
stringResponse = new StringResponseRec(ex.getMessage(), null);
}
return stringResponse;
The problem was related to snake case support in Jersey Jackson or records in Java 16, I don't know.
So, instead of loading a record of type PaymentIntentResponseRec which has a Stripe PaymentIntent object as a property, I load a record of type StringResponseRec which has a property of type string, and I load that string from the paymentIntent.toJson() provided by the Stripe API.
On the client side, my Angular app which uses the Stripe JS library gets my PaymentIntent object fine.
It works, but if you think there is a more elegant solution, feel free to comment.
I am trying to determine how to extract the discussion data for a defect in Rally using the Java Rally API. Unfortunately I can find no help online or in the documentation that tells me how to do this. I am able to obtain the URL to the discussion data and return it as a JSON element but I am not sure how to take the final step of querying that URL to get the discussions as another JSON object - I'd really appreciate help!
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.rallydev.rest.RallyRestApi;
import com.rallydev.rest.request.*;
import com.rallydev.rest.response.*;
import com.rallydev.rest.util.Fetch;
import com.rallydev.rest.util.QueryFilter;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
public class ExtractDiscussions
{
public static void main(String args[]) throws URISyntaxException, IOException {
RallyRestApi restApi = new RallyRestApi(new URI("https://rally1.rallydev.com"), "myApiKey");
restApi.setApplicationName("DANA Example");
restApi.setProxy(new URI("myProxy"),"myUsername","myPassword");
try {
QueryRequest defectRequest = new QueryRequest("defect");
defectRequest.setQueryFilter(new QueryFilter("FormattedID","=","DE123456"));
defectRequest.setFetch(new Fetch());
//defectRequest.setPageSize(25);
//defectRequest.setLimit(100);
QueryResponse queryResponse = restApi.query(defectRequest);
System.out.println(queryResponse.getTotalResultCount());
JsonObject obj = queryResponse.getResults().get(0).getAsJsonObject();
obj = obj.getAsJsonObject("Discussion");
JsonElement discussionLink = obj.get("_ref");
System.out.println(discussionLink);
//Code would go here to fetch the discussion using the discussion link
}finally{
restApi.close();
}
}
}
My Results:
1
"https://rally1.rallydev.com/slm/webservice/v2.0/Defect/1321234562/Discussion"
If you do a GetRequest on that URL, you will be given back the collection of Conversation Posts. Handy tips are in here: https://rally1.rallydev.com/slm/doc/webservice/
I am attempting to create a simple Java script which will connect to Rally, fetch all of the defects and return the defect details including the discussion as a Java object. The problem here is that the Discussion is returned as what I believe is a collection because only a URL is given. I am stuck on how to return the discussion for the defect as an object within the JSON rather than only another query which would have to be run separately (thousands of times I presume since we have thousands of defects).
Here is my code:
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.rallydev.rest.RallyRestApi;
import com.rallydev.rest.request.GetRequest;
import com.rallydev.rest.request.QueryRequest;
import com.rallydev.rest.request.UpdateRequest;
import com.rallydev.rest.response.QueryResponse;
import com.rallydev.rest.util.Fetch;
import com.rallydev.rest.util.QueryFilter;
import com.rallydev.rest.util.Ref;
import org.json.simple.JSONArray;
public class ExtractData{
public static void main(String[] args) throws URISyntaxException, IOException, NumberFormatException
{
RallyRestApi restApi = new RallyRestApi(new URI("https://rally1.rallydev.com"), "apiKeyHere");
restApi.setProxy(URI.create("http://usernameHere:passwordHere0#proxyHere:8080"));
restApi.setApplicationName("QueryExample");
//Will store all of the parsed defect data
JSONArray defectData = new JSONArray();
try{
QueryRequest defects = new QueryRequest("defect");
defects.setFetch(new Fetch("FormattedID","Discussion","Resolution"));
defects.setQueryFilter(new QueryFilter("Resolution","=","Configuration Change"));
defects.setPageSize(5000);
defects.setLimit(5000);
QueryResponse queryResponse = restApi.query(defects);
if(queryResponse.wasSuccessful()){
System.out.println(String.format("\nTotal results: %d",queryResponse.getTotalResultCount()));
for(JsonElement result: queryResponse.getResults()){
JsonObject defect = result.getAsJsonObject();
System.out.println(defect);
}
}else{
System.err.print("The following errors occured: ");
for(String err: queryResponse.getErrors()){
System.err.println("\t+err");
}
}
}finally{
restApi.close();
}
}
}
Here is an example of what I am getting when I attempt this:
{"_rallyAPIMajor":"2","_rallyAPIMinor":"0","_ref":"https://rally1.rallydev.com/slm/webservice/v2.0/defect/30023232168","_refObjectUUID":"cea42323c2f-d276-4078-92cc-6fc32323ae","_objectVersion":"6","_refObjectName":"Example defect name","Discussion":{"_rallyAPIMajor":"2","_rallyAPIMinor":"0","_ref":"https://rally1.rallydev.com/slm/webservice/v2.0/Defect/32323912168/Discussion","_type":"ConversationPost","Count":0},"FormattedID":"DE332322","Resolution":"Configuration Change","Summary":{"Discussion":{"Count":0}},"_type":"Defect"}
As you can see the discussion is being returned as a URL rather than fetching the actual discussion. As this query will be used at runtime I'd prefer the entire object.
Unfortunately there is no way to get all of that data in one request- you'll have to load the Discussion collection for each defect you read. Also of note, the max page size is 2000.
This isn't exactly the same as what you're trying to do, but this example shows loading child stories much like you'd load discussions...
https://github.com/RallyCommunity/rally-java-rest-apps/blob/master/GetChildStories.java#L37
I need to extract coinmarket cap volume (ex: Market Cap: $306,020,249,332) from top of page with Java, please see picture attached.
I have used jsoup library in Java Eclipse but didn't extract volume. Jsoup extract only other attributes. Probably problem is from a java script library.
Also I have used html unit without success:
import java.io.IOException;
import java.util.List;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
public class Testss {
public static void main(String\[\] args) throws IOException {
String url = "https://coinmarketcap.com/faq/";
WebClient client = new WebClient();
HtmlPage page = client.getPage(url);
List<?> anchors = page.getByXPath("//div\[#class='col-sm-6 text-center'\]//a");
for (Object obj : anchors) {
HtmlAnchor a = (HtmlAnchor) obj;
System.out.println(a.getTextContent().trim());
}
}
}
How can I extract volume from this site with Java?
Thanks!
Check the network tab findout the exact request which is fetching the data, In your case its https://files.coinmarketcap.com/generated/stats/global.json
Also the request URL is the below one
So, Fetching the main URL will not give you what you require, For that you have to fetch the data from the request URL directly and parse it using any JSON library. SimpleJSON I can suggest in one of those.
The JSON data which you will get after hitting the url.
{
"bitcoin_percentage_of_market_cap": 55.95083004655126,
"active_cryptocurrencies": 1324,
"total_volume_usd": 21503093761,
"active_markets": 7009,
"total_market_cap_by_available_supply_usd": 301100436864
}
After many hours of tinkering and reading the whole internet several times I just can't figure out how to sign requests for use with the Product Advertising API.
So far I managed to generate a client from the provided WSDL file. I used a tutorial by Amazon for this. You can find it here:
Tutorial for generating the web service client
So far no problems. To test the client I wrote a small piece of code. The code is intended to simply get some information about a product. The product is specified by its ASIN.
The code:
package client;
import com.ECS.client.jax.AWSECommerceService;
import com.ECS.client.jax.AWSECommerceServicePortType;
import com.ECS.client.jax.ItemLookup;
import com.ECS.client.jax.ItemLookupResponse;
import com.ECS.client.jax.ItemLookupRequest;
public class Client {
public static void main(String[] args) {
System.out.println("API Test startet");
AWSECommerceService service = new AWSECommerceService();
AWSECommerceServicePortType port = service.getAWSECommerceServicePort();
ItemLookupRequest itemLookup = new ItemLookupRequest();
itemLookup.setIdType("ASIN");
itemLookup.getItemId().add("B000RE216U");
ItemLookup lookup = new ItemLookup();
lookup.setAWSAccessKeyId("<mykeyishere>");
lookup.getRequest().add(itemLookup);
ItemLookupResponse response = port.itemLookup(lookup);
String r = response.toString();
System.out.println("response: " + r);
System.out.println("API Test stopped");
}
}
As you can see there is no part where I sign the request. I have worked my way through a lot of the classes used and found no methods for signing the request.
So, how to sign a request?
I actually found something in the documentation: request authentication
But they don't use their own API. The proposed solutions are more or less for manual use only. So I looked in the client classes to sort out if I could get the request URL and put all the parts needed for request signing in myself. But there are no such methods.
I hope someone can point out what I am doing wrong.
This is what I did to solve the problem. All the credit goes to Jon and the guys of the Amazon forums.
Before I outline what I did, here is a link to the post which helped me to solve the problem: Forum Post on Amazon forums.
I downloaded the awshandlerresolver.java which is linked in the post. Than I modified my own code so it looks like this:
package client;
import com.ECS.client.jax.AWSECommerceService;
import com.ECS.client.jax.AWSECommerceServicePortType;
import com.ECS.client.jax.ItemLookup;
import com.ECS.client.jax.ItemLookupResponse;
import com.ECS.client.jax.ItemLookupRequest;
public class Client {
public static void main(String[] args) {
System.out.println("API Test startet");
AWSECommerceService service = new AWSECommerceService();
service.setHandlerResolver(new AwsHandlerResolver("<Secret Key>")); // important
AWSECommerceServicePortType port = service.getAWSECommerceServicePort();
ItemLookupRequest itemLookup = new ItemLookupRequest();
itemLookup.setIdType("ASIN");
itemLookup.getItemId().add("B000RE216U");
ItemLookup lookup = new ItemLookup();
lookup.setAWSAccessKeyId("<Access Key>"); // important
lookup.getRequest().add(itemLookup);
ItemLookupResponse response = port.itemLookup(lookup);
String r = response.toString();
System.out.println("response: " + r);
System.out.println("API Test stopped");
}
}
The println on the end are more or less useless. But it works. I also used the WSDL Jon linked to generate a new webservice client. I just changed the URLs in the tutorial I posted in my question.
Try this afer you create the service
service.setHandlerResolver(new AwsHandlerResolver(my_AWS_SECRET_KEY));
You'll need this class and this jar file to add as a reference to your project as AwsHandlerResolver uses Base64 encoding.
You'll need to rename the AwsHandlerResolver file to the name of the class as the file name is all lower case.
I think the rest of the code you have is fine.
The WSDL is http://webservices.amazon.com/AWSECommerceService/AWSECommerceService.wsdl
This discussion and the related Amazon post helped me get the client working. That being said, I felt that the solution could be improved with regards to the following:
Setting WebService handlers in code is discouraged. A XML configuration file and a corresponding #HandlerChain annotation are recommended.
A SOAPHandler is not required in this case, LogicalHandler would do just fine. A SOAPHandler has more reach than a LogicalHandler and when it comes to code, more access is not always good.
Stuffing the signature generation, addition of a Node and printing the request in one handler seems like a little too much. These could be separated out for separation of responsibility and ease of testing. One approach would be to add the Node using a XSLT transformation so that the handler could remain oblivious of the transformation logic. Another handler could then be chained which just prints the request.
Example
i did this in spring it's working fine.
package com.bookbub.application;
import com.ECS.client.jax.*;
import com.ECS.client.jax.ItemSearch;
import javax.xml.ws.Holder;
import java.math.BigInteger;
import java.util.List;
public class TestClient {
private static final String AWS_ACCESS_KEY_ID = "AI*****2Y7Z****DIHQ";
private static final String AWS_SECRET_KEY = "lIm*****dJuiy***YA+g/vnj/Ix*****Oeu";
private static final String ASSOCIATE_TAG = "****-**";
public static void main(String[] args) {
TestClient ist = new TestClient();
ist.runSearch();
}
public void runSearch()
{
AWSECommerceService service = new AWSECommerceService();
service.setHandlerResolver(new AwsHandlerResolver(AWS_SECRET_KEY));
AWSECommerceServicePortType port = service.getAWSECommerceServicePort();
ItemSearchRequest request = new ItemSearchRequest();
request.setSearchIndex("Books");
request.setKeywords("java web services up and running oreilly");
ItemSearch search = new ItemSearch();
search.getRequest().add(request);
search.setAWSAccessKeyId(AWS_ACCESS_KEY_ID);
Holder<OperationRequest> operation_request =null;
Holder<List<Items>> items = new Holder<List<Items>>();
port.itemSearch(
search.getMarketplaceDomain(),
search.getAWSAccessKeyId(),
search.getAssociateTag(),
search.getXMLEscaping(),
search.getValidate(),
search.getShared(),
search.getRequest(),
operation_request,
items);
java.util.List<Items> result = items.value;
BigInteger totalPages = result.get(0).getTotalResults();
System.out.println(totalPages);
for (int i = 0; i < result.get(0).getItem().size(); ++i)
{ Item myItem = result.get(0).getItem().get(i);
System.out.print(myItem.getASIN());
System.out.print(", ");
System.out.println(myItem.getDetailPageURL());
System.out.print(", ");
System.out.println(myItem.getSmallImage() == null ? "" : myItem.getSmallImage().getURL());
}
}
}
You could achieve the same monetization outcomes with the IntentBrite API as well