ConcurrentHashMap Stuck in infinite loop in my java web app? - java

I am new to web development in general but so far am doing basic stuff so I don't know why this doesn't work. My servlet receives a request to add new users to my database, but before that I first want to check the values using regular expressions.
So my idea was to have all the parameter names and regex patterns in a hashmap, and then iterate that map, get the parameter from the request object and return an array(for now) containing only the invalid fields. However, it seems that I might get stuck in an infinite loop because I can't find a different explanation why this doesn't work.
I am not sure if this has anything to do with threads as I will only read it and never modify it at runtime, but I switched from HashMap to Concurrent anyway. It seemed too simple to go wrong. So here it is:
public class FormValidator {
public ArrayList<String> Validate(HttpServletRequest request) {
ArrayList<String> invalidFields = new ArrayList<String>();
ConcurrentHashMap<String, String> fieldRegexMap = new ConcurrentHashMap<String, String>();
fieldRegexMap.put("username", ".{8,}");
fieldRegexMap.put("email", "(^[a-zA-Z0-9_.+-]+#[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$)");
fieldRegexMap.put("password", "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[$#$!%*#?&])[A-Za-z\\d$#$!%*#?&]{8,10}$");
//fieldRegexMap.put("confirmPassword", "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[$#$!%*#?&])[A-Za-z\\d$#$!%*#?&]{8,10}$");
fieldRegexMap.put("firstname", ".{1,20}");
fieldRegexMap.put("lastname", ".{4,20}");
fieldRegexMap.put("DOB", "^(?:(?:31(\\/|-|\\.)(?:0?[13578]|1[02]))\\1|(?:(?:29|30)(\\/|-|\\.)(?:0?[1,3-9]|1[0-2])\\2))(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$|^(?:29(\\/|-|\\.)0?2\\3(?:(?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\\d|2[0-8])(\\/|-|\\.)(?:(?:0?[1-9])|(?:1[0-2]))\\4(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$\\");
fieldRegexMap.put("city", ".{2,20}");
fieldRegexMap.put("address", ".{2,20}");
fieldRegexMap.put("profession", ".{2,20}");
fieldRegexMap.put("interests", ".{,100}");
fieldRegexMap.put("moreinfo", ".{,500}");
//Get all parameters from the request and validate them key:parametername value:regex
for (Map.Entry<String, String> entry : fieldRegexMap.entrySet()) {
if (!(request.getParameter(entry.getKey()).matches(entry.getValue()))) {
invalidFields.add(entry.getKey());
}
}
return invalidFields;
}
}
Then my servlet's doPost calls ProcessRequest:
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
try (PrintWriter out = response.getWriter()) {
ArrayList<String> results = new ArrayList<String>();
out.println("<h1>Servlet lqRegisterServlet at " +
request.getContextPath() + "</h1>");
out.println("<h2>Method: " + request.getMethod() + "</h2>");
out.println("This Shows up");
FormValidator validator = new FormValidator();
out.println("Everything shows up to this point!");
results = validator.Validate(request);
out.println("This does not show");
for (String param : results) {
out.println("<p>Field:" + param + "</p>");
}
}
response.getOutputStream().println("This is servlet response");
}
I don't know if this is the best way to check the fields, this is a project for me to learn java web development. But it's the only way I could think of that made sense to me and seemed reusable. I plan to create and populate the hashmap outside the validate function.
Thank you for your time

You servlet-call isn't stuck but fails with an error because at least the regular expression for DOB is wrong. I found that out by writing a short main method:
public static void main(String[] args) {
ArrayList<String> invalidFields = null;
ConcurrentHashMap<String, String> fieldRegexMap = new ConcurrentHashMap<String, String>();
fieldRegexMap.put("username", ".{8,}");
fieldRegexMap.put("email", "(^[a-zA-Z0-9_.+-]+#[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$)");
fieldRegexMap.put("password", "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[$#$!%*#?&])[A-Za-z\\d$#$!%*#?&]{8,10}$");
//fieldRegexMap.put("confirmPassword", "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[$#$!%*#?&])[A-Za-z\\d$#$!%*#?&]{8,10}$");
fieldRegexMap.put("firstname", ".{1,20}");
fieldRegexMap.put("lastname", ".{4,20}");
fieldRegexMap.put("DOB", "^(?:(?:31(\\/|-|\\.)(?:0?[13578]|1[02]))\\1|(?:(?:29|30)(\\/|-|\\.)(?:0?[1,3-9]|1[0-2])\\2))(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$|^(?:29(\\/|-|\\.)0?2\\3(?:(?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\\d|2[0-8])(\\/|-|\\.)(?:(?:0?[1-9])|(?:1[0-2]))\\4(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$\\");
fieldRegexMap.put("city", ".{2,20}");
fieldRegexMap.put("address", ".{2,20}");
fieldRegexMap.put("profession", ".{2,20}");
fieldRegexMap.put("interests", ".{,100}");
fieldRegexMap.put("moreinfo", ".{,500}");
fieldRegexMap.entrySet().stream()
.forEach(elem -> {
System.out.println(elem.getKey());
System.out.println(Pattern.compile(elem.getValue()));
});
}
This results into the following output:
profession
.{2,20}
password
^(?=.*[A-Za-z])(?=.*\d)(?=.*[$#$!%*#?&])[A-Za-z\d$#$!%*#?&]{8,10}$
firstname
.{1,20}
address
.{2,20}
city
.{2,20}
DOB
Exception in thread "main" java.util.regex.PatternSyntaxException: Unexpected internal error near index 325
^(?:(?:31(\/|-|\.)(?:0?[13578]|1[02]))\1|(?:(?:29|30)(\/|-|\.)(?:0?[1,3-9]|1[0-2])\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(\/|-|\.)0?2\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/|-|\.)(?:(?:0?[1-9])|(?:1[0-2]))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$\
^
at java.util.regex.Pattern.error(Pattern.java:1955)
at java.util.regex.Pattern.compile(Pattern.java:1702)
at java.util.regex.Pattern.<init>(Pattern.java:1351)
at java.util.regex.Pattern.compile(Pattern.java:1028)
at IntArraySplitter.lambda$0(IntArraySplitter.java:30)
at IntArraySplitter$$Lambda$1/1995265320.accept(Unknown Source)
at java.util.concurrent.ConcurrentHashMap$EntrySpliterator.forEachRemaining(ConcurrentHashMap.java:3606)
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
at IntArraySplitter.main(IntArraySplitter.java:28)
The reason why you don't see this is the fact that you already send a response to the client. Because the server already returned an HTTP 200 response code it can't change that to HTTP 500 and therefor just closes the connection to the client when reaching this point. You should see some error message in the server's log, though.

Related

AWS SSM parameter store not fetching all key/values

Could someone let me know why the below code only fetching few entries from the parameter store ?
GetParametersByPathRequest getParametersByPathRequest = new GetParametersByPathRequest();
getParametersByPathRequest.withPath("/").setRecursive(true);
getParametersByPathRequest.setWithDecryption(true);
GetParametersByPathResult result = client.getParametersByPath(getParametersByPathRequest);
result.getParameters().forEach(parameter -> {
System.out.println(parameter.getName() + " - > " + parameter.getValue());
});
GetParametersByPath is a paged operation. After each call you must retrieve NextToken from the result object, and if it's not null and not empty you must make another call with it added to the request.
Here's an example using DescribeParameters, which has the same behavior:
DescribeParametersRequest request = new DescribeParametersRequest();
DescribeParametersResult response;
do
{
response = client.describeParameters(request);
for (ParameterMetadata param : response.getParameters())
{
// do something with metadata
}
request.setNextToken(response.getNextToken());
}
while ((response.getNextToken() != null) && ! respose.getNextToken.isEmpty());
Here is the code, based on the code above, for the new 2.0 version of AWS SSM manager. Notice I have set the maxResults to 1 to prove out the loop. You will want to remove that. AWS has mentioned that in the new code they wanted to emphasize immutability.
Using this dependency:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>ssm</artifactId>
<version>2.10.32</version>
</dependency>
I came up with this code:
private void refreshCache() {
StopWatch sw = StopWatch.createStarted();
GetParametersByPathRequest request = GetParametersByPathRequest.builder()
.path(prefix)
.withDecryption(useDecryption)
.maxResults(1)
.build();
GetParametersByPathResponse response;
do {
response = ssm.getParametersByPath(request);
for (Parameter p : response.parameters()) {
//do something with the values.
}
request = GetParametersByPathRequest.builder()
.path(prefix)
.withDecryption(useDecryption)
.nextToken(response.nextToken())
.maxResults(1)
.build();
}
while (StringUtils.isNotBlank(response.nextToken()));
LOG.trace("Refreshed parameters in {}ms", sw.getTime());
}
private void getSsmParams() {
AWSSimpleSystemsManagement client = AWSSimpleSystemsManagementClientBuilder.defaultClient();
GetParametersByPathRequest request = new GetParametersByPathRequest();
request.withRecursive(true);
request.withPath('/your/path/parameterName').setWithDecryption(true);
GetParametersByPathResult response;
do {
response = client.getParametersByPath(request);
for (Parameter p : response.parameters()) {
//do something with the values. maybe add to a list
}
request.setNextToken(response.getNextToken())
}
while (StringUtils.isNotBlank(response.getNextToken()));
}
Above piece of code worked for me .ssm only sends 10 parameters at a time, so if you want to fetch more than 10 parameters from ssm parameter store programatically you will have to use multiple calls to fetch them. here the token is important , if there are more values in the path (request.withPath('/your/path/parameterName')) you have given, it will send a token indicating that there are more values in the given path ,and you will have to make the following request with the token received from the previous request in order to get the rest of the values.

Passing phone input via Twilio

I'm working on a basic Twilio web application using Java and the Spark Java framework. I'm trying to have the user enter a number as input after the initial prompt through a Gather verb and then process that input. So far, I am able to call my Twilio number and it responds with the initial prompt, but after I enter a number it goes to /handle-number and crashes because the request did not contain any params and it can't find the "Digits" param (params is empty when I print it).
I have tried to mimic the API call via the Postman Chrome extension to debug it, but I get a 500 internal server error.
EDIT: Here is a screenshot of the postman request : Postman screenshot
I am new to Java web applications, HTTP requests, and Twilio, so I am unfamiliar with much of this. I have gone thought the twiml documentation and tutorials and tried to follow along but my I'm definitely missing something in my implementation.
How do I properly pass the phone input to the processNumber Route? Any help is appreciated!
App.java
import static spark.Spark.*;
public class App {
public static void main (String[] args){
post("/receive-call", ReceiveCall.call);
post("/handle-number", ReceiveCall.processNumber);
}
}
ReceiveCall.java
import com.twilio.twiml.voice.Gather;
import com.twilio.twiml.voice.Say;
import com.twilio.twiml.*;
import spark.Route;
public class ReceiveCall {
public static Route call = (request, response) -> {
Say sayMessage = new Say.Builder("Hello! Please enter a number as input. Enter # when finished.").build();
Gather input = new Gather.Builder().timeout(3).say(sayMessage).action("/handle-number").build();
VoiceResponse twiml = new VoiceResponse.Builder().gather(input).build();
System.out.println(response.body());
return twiml.toXml();
};
public static Route processNumber = ((request, response) -> {
String digit = request.params("Digits");
//CRASHES HERE BECAUSE digit IS NULL
int number = Integer.parseInt(digit);
Say message = process(number);
VoiceResponse twiml = new VoiceResponse.Builder().say(message).build();
return twiml.toXml();
});
The reason of "digit IS NULL" is: you are using request.params(...), which is for path parameter.
What is "path parameter"?
"path parameter" means passing parameter as part of URL path, especially in RESTful style request.
For example, if you want to send an HTTP GET request to retrieve a book by its ISBN, the request URL could be: /books/9787121022982 or /books/9787101054491, where the ISBN parameter is passed as part of URL path (9787121022982 and 9787101054491). In Spark framework, the corresponding Route code would be:
get("/books/:isbn", (request, response) -> {
return "Book ISBN is: " + request.params(":isbn");
});
What is "query parameter"?
"query parameter" means passing parameter as part of URL queries (entities after the ? character in URL).
Take the previous book ISBN case for example, if you want to pass ISBN as query parameter, the HTTP GET URL would be: /books?isbn=9787121022982, and the corresponding Spark Route code is:
get("/books", (request, response) -> {
return "Book ISBN is: " + request.queryParams("isbn");
});
What is the best practice to pass data in POST request?
In your case, the /handle-number route accept POST request. For HTTP POST request, it's not a good practice to pass data as parameter in URL. Instead, you need to pass data as request body, and get data from body in Spark code:
post("/handle-number", (request, response) -> {
String body = request.body();
// extract ISBN from request body string
});

Is it possible to "send" a cookie via Jsoup to a server?

I'm trying to retrieve an article price from a website. The problem is, that the prices differ if you choose online price or store price. After selecting a store the website creates a cookie called: CP_GEODATA with a specific value. I tried to send the cookie in different ways, but I keep getting the online price.
public class Parser {
public static void main(String[] args) throws Exception {
Map<String, String> cookies = new HashMap<String, String>();
cookies.put("CP_COUNTRY ", "%7B%22country%22%3A%22DE%22%7D ");
cookies.put("CP_GEODATA ", "%7B%22location%22%3A-1%2C%22firstlocation%22%3A11%2C%22name%22%3A%22Hamburg%22%7D");
String url = "https://www.cyberport.de/?token=7a2d9b195e32082fec015dca45ba3aa4&sSearchId=565eee12d987b&EVENT=itemsearch&view=liste&query=&filterkategorie=";
Connection.Response res = Jsoup.connect(url).cookies(cookies).data("query", "4B05-525").execute();
Document doc = res.parse();
String tester = doc.select("span[id=articlePrice] > span[class=basis fl]").text();
String tester2 = doc.select("span[id=articlePrice] > span[class=decimal fl]").text();
System.out.println(tester + tester2 + " €");
}
}
The value I'm getting back right now is 2,90 € but it should be 4,90 €. I already tried everything and searched the internet a lot but I did not find any solution working for me.
This is the article I'm receiving the price from:
https://www.cyberport.de/micro-usb-2-0-kabel-usb-a-stecker-micro-b-stecker-0-5m--4B05-525_9374.html
I'm trying to receive the price for the store in Hamburg, Germany.
You can see the cookies I'm setting at the top.
Thank you for any help!
It seems that zone info is stored in session and zone code is sent to server in a post when you select it.
Then you need to do the following steps:
Do the POST with the desired zone
Get the session cookies
Using these cookes do your original POST
Hopefully get the correct results
Here is the code
public static void main(String[] args) throws Exception {
Connection.Response res;
//11 is for Hamburg
String zoneId = "11";
//Set the zone and get the session cookies
res = Jsoup.connect("https://www.cyberport.de/newajaxpass/catalog/itemlist/0/costinfo/" + zoneId)
.ignoreContentType(true)
.method(Method.POST).execute();
final Map<String, String> cookies = res.cookies();
//print the cookies, we'll see session cookies here
System.out.println(cookies);
//If we use that cookies, your code runs Ok
String url = "https://www.cyberport.de/?token=7a2d9b195e32082fec015dca45ba3aa4&sSearchId=565eee12d987b&EVENT=itemsearch&view=liste&query=&filterkategorie=";
res = Jsoup.connect(url).cookies(cookies).data("query", "4B05-525").execute();
Document doc = res.parse();
String tester = doc.select("span[id=articlePrice] > span[class=basis fl]").text();
String tester2 = doc.select("span[id=articlePrice] > span[class=decimal fl]").text();
System.out.println(tester + tester2 + " €");
//Extra check
System.out.println(doc.select("div.townName").text());
}
You'll see:
{SERVERID=realmN03, SCS=76fe7473007c80ea2cfa059f180c603d, SID=pphdh7otcefvc5apdh2r9g0go2}
4,90 €
Hamburg
Which, I hope, is the desired result.

Using a Commonj Work Manager to send Asynchronous HTTP calls

I switched from making sequential HTTP calls to 4 REST services, to making 4 simultaneous calls using a commonj4 work manager task executor. I'm using WebLogic 12c. This new code works on my development environment, but in our test environment under load conditions, and occasionally while not under load, the results map is not populated with all of the results. The logging suggests that each work item did receive back the results though. Could this be a problem with the ConcurrentHashMap? In this example from IBM, they use their own version of Work and there's a getData() method, although it doesn't like that method really exists in their class definition. I had followed a different example that just used the Work class but didn't demonstrate how to get the data out of those threads into the main thread. Should I be using execute() instead of schedule()? The API doesn't appear to be well documented. The stuckthreadtimeout is sufficiently high. component.processInbound() actually contains the code for the HTTP call, but I the problem isn't there because I can switch back to the synchronous version of the class below and not have any issues.
http://publib.boulder.ibm.com/infocenter/wsdoc400/v6r0/index.jsp?topic=/com.ibm.websphere.iseries.doc/info/ae/asyncbns/concepts/casb_workmgr.html
My code:
public class WorkManagerAsyncLinkedComponentRouter implements
MessageDispatcher<Object, Object> {
private List<Component<Object, Object>> components;
protected ConcurrentHashMap<String, Object> workItemsResultsMap;
protected ConcurrentHashMap<String, Exception> componentExceptionsInThreads;
...
//components is populated at this point with one component for each REST call to be made.
public Object route(final Object message) throws RouterException {
...
try {
workItemsResultsMap = new ConcurrentHashMap<String, Object>();
componentExceptionsInThreads = new ConcurrentHashMap<String, Exception>();
final String parentThreadID = Thread.currentThread().getName();
List<WorkItem> producerWorkItems = new ArrayList<WorkItem>();
for (final Component<Object, Object> component : this.components) {
producerWorkItems.add(workManagerTaskExecutor.schedule(new Work() {
public void run() {
//ExecuteThread th = (ExecuteThread) Thread.currentThread();
//th.setName(component.getName());
LOG.info("Child thread " + Thread.currentThread().getName() +" Parent thread: " + parentThreadID + " Executing work item for: " + component.getName());
try {
Object returnObj = component.processInbound(message);
if (returnObj == null)
LOG.info("Object returned to work item is null, not adding to producer components results map, for this producer: "
+ component.getName());
else {
LOG.info("Added producer component thread result for: "
+ component.getName());
workItemsResultsMap.put(component.getName(), returnObj);
}
LOG.info("Finished executing work item for: " + component.getName());
} catch (Exception e) {
componentExceptionsInThreads.put(component.getName(), e);
}
}
...
}));
} // end loop over producer components
// Block until all items are done
workManagerTaskExecutor.waitForAll(producerWorkItems, stuckThreadTimeout);
LOG.info("Finished waiting for all producer component threads.");
if (componentExceptionsInThreads != null
&& componentExceptionsInThreads.size() > 0) {
...
}
List<Object> resultsList = new ArrayList<Object>(workItemsResultsMap.values());
if (resultsList.size() == 0)
throw new RouterException(
"The producer thread results are all empty. The threads were likely not created. In testing this was observed when either 1)the system was almost out of memory (Perhaps the there is not enough memory to create a new thread for each producer, for this REST request), or 2)Timeouts were reached for all producers.");
//** The problem is identified here. The results in the ConcurrentHashMap aren't the number expected .
if (workItemsResultsMap.size() != this.components.size()) {
StringBuilder sb = new StringBuilder();
for (String str : workItemsResultsMap.keySet()) {
sb.append(str + " ");
}
throw new RouterException(
"Did not receive results from all threads within the thread timeout period. Only retrieved:"
+ sb.toString());
}
LOG.info("Returning " + String.valueOf(resultsList.size()) + " results.");
LOG.debug("List of returned feeds: " + String.valueOf(resultsList));
return resultsList;
}
...
}
}
I ended up cloning the DOM document used as a parameter. There must be some downstream code that has side effects on the parameter.

Android-Magento- How to Get the Details of Multiple Products in Android using XML-RPC

How to get the details of Multiple products in a Single Call in Android using XMLRPC from Magento.I am able to get the list of products using the function catalog_product.list using XMLRPC.
Now, i have the SKU id's of all the products.I am able to get the media details of each product using the function product_media.list.
If suppose I have 10 products,i have to call 10 times product_media.list method for each product which takes long time.
So,how can I call the multiCall function of Magento in Android. Many tutorials in php for calling the multiCall function are posted but I am not able to imitate the same in Android.
So please help me if you have similar code snippet that can make me understand multiCall function(for Android) so that I can Advance further using that.
Thanks.
PHP code Example from Josua Marcel C 's Answer:
$session = $client->call('login', array('apiUser', 'apiKey'));
$client->call('call', array($session,'somestuff.method', array('arg1', 'arg2', 'arg3')));
$client->call('call', array($session, 'somestuff.method', 'arg1'));
$client->call('call', array($session, 'somestuff.method'));
$client->call('multiCall',
array($session,
array(
array('somestuff.method', 'arg1'),
array('somestuff.method', array('arg1', 'arg2')),
array('somestuff.method')
)
)
);
I would like to imitate the above php code in Android that calls the multiCall() function of the Magento.
After making long long Research, I got half-way Solution that calls the multiCall() method without any Error,but Still I don't know how to get the response of the Server in a variable and use it.
AnyOne who has knowledge of it can Edit my Answer, I will be thankful to him.
The Code that I have Used is :
Object[] skuid=new Object[product_list.size()];
Object calling[]=new Object[product_list.size()];
for(int m=0;m<product_list.size();m++)
{
skuid[m]=new Object[]{product_list.get(m).getp_Sku()};
calling[m]=new Object[]{"catalog_product_attribute_media.list",skuid[m]};
}
try
{
client.callEx("multiCall",new Object[]{Utils.sessionId,calling});
}
catch (XMLRPCException e)
{
e.printStackTrace();
}
AcknowledgeMents :
I have worked on the Answer posted by Iain.
The Answer
since android is based java application, You can use this.
package org.apache.xmlrpc;
import java.util.Hashtable;
import java.util.Vector;
public class MultiCall
implements ContextXmlRpcHandler
{
public Object execute(String method, Vector params, XmlRpcContext context)
throws Exception
{
if ("multicall".equals(method))
{
return multicall(params, context);
}
throw new NoSuchMethodException("No method '" + method + "' in " + this.getClass().getName());
}
public Vector multicall(Vector requests, XmlRpcContext context)
{
// The array of calls is passed as a single parameter of type array.
requests=(Vector)requests.elementAt(0);
Vector response = new Vector();
XmlRpcServerRequest request;
for (int i = 0; i < requests.size(); i++)
{
try
{
Hashtable call = (Hashtable) requests.elementAt(i);
request = new XmlRpcRequest((String) call.get("methodName"),
(Vector) call.get("params"));
Object handler = context.getHandlerMapping().getHandler(request.getMethodName());
Vector v = new Vector();
v.addElement(XmlRpcWorker.invokeHandler(handler, request, context));
response.addElement(v);
}
catch (Exception x)
{
String message = x.toString();
int code = (x instanceof XmlRpcException ?
((XmlRpcException) x).code : 0);
Hashtable h = new Hashtable();
h.put("faultString", message);
h.put("faultCode", new Integer(code));
response.addElement(h);
}
}
return response;
}
}
Source
Since Magento support SOAP API why didn't you use SOAP API v1? because SOAP is powerful. try to go here What's the difference between XML-RPC and SOAP?
Parsing of Soap messages is not included in Android runtime, so it isn't really straightforward. You should use an external library. I'm using ksoap2.
If you search here on StackOverflow you'll see many examples on how to use it. For instance here
more references: link 1 link 2
MultiCall with PHP
$client = new Zend_XmlRpc_Client('http://magentohost/api/xmlrpc/');
// If somestuff requires api authentification,
// we should get session token
$session = $client->call('login', array('apiUser', 'apiKey'));
$client->call('call', array($session, 'somestuff.method', array('arg1', 'arg2', 'arg3')));
$client->call('call', array($session, 'somestuff.method', 'arg1'));
$client->call('call', array($session, 'somestuff.method'));
$client->call('multiCall', array($session,
array(
array('somestuff.method', 'arg1'),
array('somestuff.method', array('arg1', 'arg2')),
array('somestuff.method')
)
));
// If you don't need the session anymore
$client->call('endSession', array($session));
First login in whatever way works for calling catalog_product.list. Make sure session, client and product_ids have the right values. If you don't need to log in for these operations, set session = null (and if that doesn't work, try not passing session at all :) ). Then:
Object[][] calls = new Object[product_ids.length];
for (int i = 0; i < product_ids.length; i++) {
calls[i] = new Object[] { "product_media.list", product_ids[i] };
}
product_media_ids = client.call("multiCall", new Object[] { session, calls });
product_media_ids should then be an array of arrays of product images - that is, each element of product_media_ids will be a return value from product_media.list.
The code is untested, I'm afraid.

Categories

Resources