Skip to content

Instantly share code, notes, and snippets.

@venkyvb
Last active March 16, 2016 13:16
Show Gist options
  • Save venkyvb/7461904 to your computer and use it in GitHub Desktop.
Save venkyvb/7461904 to your computer and use it in GitHub Desktop.
Consume A2X services using HTTP client. Dependencies: - Apache HTTPClient - Velocity Template - the usual apache dependencies like commons No proxy / stubs are generated, payload is created using velocity and plain HttpPost is used to make the SOAP call. Since velocity template is used extension fields can be handled easily. NOTE that this is on…
package a2x;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URI;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.SingleClientConnManager;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.util.StringUtils;
import com.google.gson.Gson;
public class A2XCall {
public String executeA2XCall(String payload) {
return executeSOAPCall(parsePostPayload(payload));
}
/**
* Parse the incoming JSON payload
*/
private static List<ClientData> parsePostPayload(String payload) {
Gson gson = new Gson();
ClientDataContainer data = gson.fromJson(payload,
ClientDataContainer.class);
return data.getPayload();
}
/**
* Returns a given node at the relative path.
*/
private String executeSOAPCall(List<ClientData> dataList) {
URI targetUri = null;
SOAPResponse r = new SOAPResponse();
JsonWrapper jsonResponse = new JsonWrapper();
try {
targetUri = new URI("https://tenant/sap/bc/srt/scs/sap/manageservicerequestextensionf");
HttpPost post = new HttpPost(targetUri);
post.addHeader("Content-Type", "text/xml;charset=utf-8");
boolean create = true;
ClientData cd = null;
ClientData modeEntry = null;
ClientData csrfToken = null;
Iterator<ClientData> it = dataList.iterator();
while (it.hasNext()) {
ClientData d = it.next();
if (d.getName().equals("csrfToken")) {
csrfToken = d;
}
}
if (modeEntry == null) {
modeEntry = new ClientData("", "", false);
}
StringEntity se = new StringEntity(getSOAPMessage(dataList,
cd.getValue(), modeEntry.getValue(), create));
post.setEntity(se);
HttpResponse targetResponse = getHttpClient(false).execute(post);
ByteArrayOutputStream os = new ByteArrayOutputStream();
targetResponse.getEntity().writeTo(os);
os.close();
String response = new String(os.toByteArray(), "UTF-8");
// Flush the attachment cache
if (!r.isFailed()) {
return jsonResponse.toJson();
} else {
// Handle errors
}
} catch (Exception e) {
e.printStackTrace();
}
return createSOAPResponse(r);
}
/**
* Returns the actual SOAP payload based on the Velocity template. The actual data is merged with the
* Velocity template to arrive at the final payload that would be executed against the tenant.
*/
private String getSOAPMessage(List<ClientData> dataList, String ticketId,
String id, boolean createMode) {
VelocityEngine ve = new VelocityEngine();
ve.setProperty("resource.loader", "class");
ve.setProperty("class.resource.loader.class",
"org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
ve.init();
Template t = ve.getTemplate(Constants.ResourceFiles.MNTN_PYLD_VM,
"UTF-8");
VelocityContext ctx = new VelocityContext();
ctx.put("dataList", dataList);
ctx.put("extNamespace", Constants.EXT_NAMESPACE);
ctx.put("language", "EN");
Writer writer = new StringWriter();
t.merge(ctx, writer);
String adjusted = writer.toString();
return adjusted;
}
public HttpClient getHttpClient(boolean uiDest) {
HttpClient httpClient = null;
// ADD YOUR LOGIC TO GET THE APACHE HTTPCLIENT INSTANCE HERE
// SchemeRegistry schemeRegistry = new SchemeRegistry();
// schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory
// .getSocketFactory()));
// try {
// schemeRegistry.register(new Scheme("https", 443,
// new CODSSLSocketFactory()));
// } catch (KeyManagementException e) {
// e.printStackTrace();
// } catch (UnrecoverableKeyException e) {
// e.printStackTrace();
// } catch (NoSuchAlgorithmException e) {
// e.printStackTrace();
// } catch (KeyStoreException e) {
// e.printStackTrace();
// }
//
// ClientConnectionManager cm = new SingleClientConnManager(schemeRegistry);
//
// httpClient = new DefaultHttpClient(cm);
//
// if (m_useProxy)
// ((DefaultHttpClient) httpClient).getParams()
// .setParameter(ConnRoutePNames.DEFAULT_PROXY,
// m_userSession.getProxyHost());
//
// ((DefaultHttpClient) httpClient).getParams().setParameter(
// ClientPNames.DEFAULT_HOST,
// new HttpHost(m_userSession.getHost()));
//
// Credentials defaultCredentials = new UsernamePasswordCredentials(
// m_userSession.getUserName(uiDest),
// m_userSession.getUserPassword(uiDest));
//
// ((DefaultHttpClient) httpClient).getCredentialsProvider()
// .setCredentials(
// new AuthScope(m_userSession.getHost(),
// AuthScope.ANY_PORT), defaultCredentials);
return httpClient;
}
private static String createSOAPResponse(SOAPResponse r) {
Gson gson = new Gson();
String response = gson.toJson(r, SOAPResponse.class);
return response;
}
}
package a2x;
/**
* Represents data coming in as a JSON payload from the client
*/
public class ClientData {
String name = null;
String value = null;
boolean ext = false;
public ClientData(String name, String value, boolean ext) {
super();
this.name = name;
this.value = value;
this.ext = ext;
}
public ClientData() {
super();
// TODO Auto-generated constructor stub
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public boolean isExt() {
return ext;
}
public void setExt(boolean ext) {
this.ext = ext;
}
@Override
public String toString() {
return "ClientData [name=" + name + ", value=" + value + ", ext=" + ext
+ "]";
}
}
package a2x;
import java.util.ArrayList;
import java.util.List;
/**
* JSON payload wrapper
*/
public class ClientDataContainer {
private ArrayList<ClientData> payload;
public List<ClientData> getPayload() {
return payload;
}
public void setPayload(ArrayList<ClientData> payload) {
this.payload = payload;
}
}
package a2x;
public final class Constants {
static final String ERROR = "Error";
// Note this value is not always fixed. This has to be queried from the specific tenant
static final String EXT_NAMESPACE = "http://sap.com/xi/AP/CustomerExtension/BYD/A02OF";
private Constants() {
super();
}
public final class ResourceFiles {
static final String MNTN_PYLD_VM = "/resources/maintain_payload.vm";
private ResourceFiles() {
super();
}
}
}
package a2x;
import com.google.gson.Gson;
/**
* JSON response after the A2X call
*/
public class JsonWrapper {
private String payload;
private String metadata;
private String listPayload;
private String csrfToken;
private String error;
public String getPayload() {
return payload;
}
public void setPayload(String payload) {
this.payload = payload;
}
public JsonWrapper addPayload(String payload) {
this.payload = payload;
return this;
}
public JsonWrapper addError(String error) {
this.error = error;
return this;
}
public JsonWrapper() {
super();
// TODO Auto-generated constructor stub
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
public String toJson() {
Gson gson = new Gson();
String response = gson.toJson(this, JsonWrapper.class);
return response;
}
public String getCsrfToken() {
return csrfToken;
}
public JsonWrapper addCsrfToken(String csrfToken) {
this.csrfToken = csrfToken;
return this;
}
public JsonWrapper addMetadata(String m) {
this.metadata = m;
return this;
}
public JsonWrapper addListPayload(String l) {
this.listPayload = l;
return this;
}
}
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:glob="http://sap.com/xi/SAPGlobal20/Global" xmlns:a02="$extNamespace">
<soapenv:Header/>
<soapenv:Body>
<glob:ServiceRequestBundleMaintainRequest_sync>
<ServiceRequest incidentServiceIssueCategoryListCompleteTransmissionIndicator="1">
#set($serviceTerms = false)
#set($material = false)
#set($priority = false)
#set($sicc = false)
#set($servicePriorityCode = "")
#set($serviceIssueCategoryID = "")
#set($productID = "")
#set($regproductID = "")
#set($srvRefObjID = "")
#set($userStatus = false)
#set($userStatusValue = "")
#foreach ($data in $dataList)
#if ($data.name == "DataOriginTypeCode")
<DataOriginTypeCode>4</DataOriginTypeCode>
#end
#if ($data.name == "ID")
<ID>$data.value</ID>
#end
#if ($data.name == "Description")
<Name languageCode="$language">$data.value</Name>
#end
#if ($data.name == "BuyerPartyID" )
<BuyerPartyID>$data.value</BuyerPartyID>
#end
#if ($data.name == "Status")
<ServiceRequestLifeCycleStatusCode>$data.value</ServiceRequestLifeCycleStatusCode>
#end
#if ($data.name == "UserStatus" || $data.name == "Status1")
#set($userStatus = true)
#set($userStatusValue = $data.value)
#set($serviceTerms = true)
#end
#if ($data.name == "ContactPartyEmail")
<ContactParty>
<AccountDeterminationContactPartyEmailID>$data.value</AccountDeterminationContactPartyEmailID>
</ContactParty>
#end
#if($data.name == "Priority")
#set($servicePriorityCode = $data.value)
#set($serviceTerms = true)
#set($priority = true)
#end
#if($data.name == "ServiceIssueCategoryCatalogueID")
#set($serviceIssueCategoryID = $data.value)
#set($serviceTerms = true)
#set($sicc = true)
#end
#if($data.name == "ServiceIssueCategoryID")
#set($serviceIssueCategoryID = $data.value)
#set($serviceTerms = true)
#set($sicc = true)
#end
#if($data.name == "IncidentCategoryID")
<IncidentServiceIssueCategory>
<ServiceIssueCategoryID>$data.value</ServiceIssueCategoryID>
<MainIndicator>1</MainIndicator>
</IncidentServiceIssueCategory>
#end
#if($data.name == "ProductID")
#set($productID = $data.value)
#set($material = true)
#end
#if ($data.name == "RegisteredProductSerialID")
#set($regproductID = $data.value)
#set($material = true)
#end
#if($data.name == "ServiceReferenceObjectID")
#set($srvRefObjID = $data.value)
#set($material = true)
#end
#if($data.name == "IncidentText")
<IncidentText actionCode="04">
<ContentText languageCode="$language">$data.value</ContentText>
</IncidentText>
#end
#if($data.name == "ReplyFromCustomerText")
<ReplyFromCustomerText actionCode="04">
<ContentText languageCode="$language">$data.value</ContentText>
</ReplyFromCustomerText>
#end
#if($data.ext)
<a02:$data.name>$data.value</a02:$data.name>
#end
#end
#if($material)
<Material>
<MaterialID>$productID</MaterialID>
<IndividualProductSerialID>$regproductID</IndividualProductSerialID>
<MainIndicator>1</MainIndicator>
#if($srvRefObjID != "")
<ID>$srvRefObjID</ID>
#end
</Material>
#end
#if($serviceTerms)
<ServiceTerms>
#if($priority)
<ServicePriorityCode>$servicePriorityCode</ServicePriorityCode>
#end
#if($sicc)
<ServiceIssueCategoryCatalogueCategoryID>$serviceIssueCategoryID</ServiceIssueCategoryCatalogueCategoryID>
#end
#if($userStatus)
<UserLifeCycleStatusCode>$userStatusValue</UserLifeCycleStatusCode>
#end
</ServiceTerms>
#end
</ServiceRequest>
</glob:ServiceRequestBundleMaintainRequest_sync>
</soapenv:Body>
</soapenv:Envelope>
package a2x;
public class SOAPResponse {
private String id;
private String uuid;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id.replaceFirst("^0+(?!$)", "");
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public boolean isFailed()
{
if(this.id == Constants.ERROR || this.uuid == Constants.ERROR)
return true;
return false;
}
}
@vaibhav-walia
Copy link

Can you please explain how the CORS(cross-origin resource sharing) policy was bypassed in this case

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment