You need to sign in to do that
Don't have an account?
Apex Callouts to Apex Web Service (Automated S2S), Possible ?
Note : Following is a small development being carried out to demystify salesforce apex webservice and callout features, please correct me if you find my understanding to be incorrect.
I am trying to integrate two Salesforce Orgs using Apex. Apex supports both callouts and webservices, then why not leverage both to achieve a 360 connectivity between two Salesforce instances.
Org1 : Create a Apex Web Service, Generate its WSDL
global class AccountPlan {
webservice String area;
webservice String region;
//Define an object in apex that is exposed in apex web service
global class Plan {
webservice String name;
webservice Integer planNumber;
webservice Date planningPeriod;
webservice Id planId;
}
webservice static Plan createAccountPlan(Plan vPlan) {
//A plan maps to the Account object in salesforce.com.
//So need to map the Plan class object to Account standard object
Account acct = new Account();
acct.Name = vPlan.name;
acct.AccountNumber = String.valueOf(vPlan.planNumber);
insert acct;
vPlan.planId=acct.Id;
return vPlan;
}
}
Org2: Consume above generated WSDL to generate following Apex Class viz.,AccountPlanClasses
public class AccountPlanClasses {
public class LogInfo {
public String category;
public String level;
private String[] category_type_info = new String[]{'category','http://soap.sforce.com/schemas/class/TCSSAAS/AccountPlan','LogCategory','1','1','false'};
private String[] level_type_info = new String[]{'level','http://soap.sforce.com/schemas/class/TCSSAAS/AccountPlan','LogCategoryLevel','1','1','false'};
private String[] apex_schema_type_info = new String[]{'http://soap.sforce.com/schemas/class/TCSSAAS/AccountPlan','true','false'};
private String[] field_order_type_info = new String[]{'category','level'};
}
public class AllowFieldTruncationHeader_element {
............................
............................
Now lets try to connect to Org1 from Org2
AccountPlanClasses.Plan plan = new AccountPlanClasses.Plan();
plan.name = 'Chirag';
plan.planNumber = 111;
AccountPlanClasses.AccountPlan a = new AccountPlanClasses.AccountPlan();
a.createAccountPlan(plan);
Execution of above code runs into following error
WebService returned a SOAP Fault: INVALID_SESSION_ID: Invalid Session ID found in SessionHeader: Illegal Session faultcode=sf:INVALID_SESSION_ID faultactor=
I to feel that somewhere I am missing User Credentials to be supplied, but I dont know exactly where. Please guide me to complete this 360 connectivity between two orgs using Apex.
Hey guys, I've been researching this topic of communicating between multiple Salesforce instances in the past days.
With the idea TLF had in mind, here is the extracted parts of the Partner WSDL that I used, which only have the essential parts needed for the login to work:
<?xml version="1.0" encoding="UTF-8"?> <definitions targetNamespace="urn:partner.soap.sforce.com" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:fns="urn:fault.partner.soap.sforce.com" xmlns:tns="urn:partner.soap.sforce.com" xmlns:ens="urn:sobject.partner.soap.sforce.com"> <types> <schema elementFormDefault="qualified" xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:partner.soap.sforce.com"> <import namespace="urn:sobject.partner.soap.sforce.com"/> <!-- Our simple ID Type --> <simpleType name="ID"> <restriction base="xsd:string"> <length value="18"/> <pattern value='[a-zA-Z0-9]{18}'/> </restriction> </simpleType> <complexType name="GetUserInfoResult"> <sequence> <element name="accessibilityMode" type="xsd:boolean"/> <element name="currencySymbol" type="xsd:string" nillable="true"/> <element name="orgDefaultCurrencyIsoCode" type="xsd:string" nillable="true"/> <element name="organizationId" type="tns:ID"/> <element name="organizationMultiCurrency" type="xsd:boolean"/> <element name="organizationName" type="xsd:string"/> <element name="profileId" type="tns:ID"/> <element name="roleId" type="tns:ID" nillable="true"/> <element name="userDefaultCurrencyIsoCode" type="xsd:string" nillable="true"/> <element name="userEmail" type="xsd:string"/> <element name="userFullName" type="xsd:string"/> <element name="userId" type="tns:ID"/> <element name="userLanguage" type="xsd:string"/> <element name="userLocale" type="xsd:string"/> <element name="userName" type="xsd:string"/> <element name="userTimeZone" type="xsd:string"/> <element name="userType" type="xsd:string"/> <element name="userUiSkin" type="xsd:string"/> </sequence> </complexType> <complexType name="LoginResult"> <sequence> <element name="metadataServerUrl" type="xsd:string" nillable="true"/> <element name="passwordExpired" type="xsd:boolean" /> <element name="serverUrl" type="xsd:string" nillable="true"/> <element name="sessionId" type="xsd:string" nillable="true"/> <element name="userId" type="tns:ID" nillable="true"/> <element name="userInfo" type="tns:GetUserInfoResult" minOccurs="0"/> </sequence> </complexType> <!-- Login Message Types --> <element name="login"> <complexType> <sequence> <element name="username" type="xsd:string"/> <element name="password" type="xsd:string"/> </sequence> </complexType> </element> <element name="loginResponse"> <complexType> <sequence> <element name="result" type="tns:LoginResult"/> </sequence> </complexType> </element> <!-- Header Elements --> <element name="SessionHeader"> <complexType> <sequence> <element name="sessionId" type="xsd:string"/> </sequence> </complexType> </element> <element name="LoginScopeHeader"> <complexType> <sequence> <element name="organizationId" type="tns:ID"/> <element name="portalId" type="tns:ID" minOccurs="0"/> </sequence> </complexType> </element> <element name="CallOptions"> <complexType> <sequence> <element name="client" type="xsd:string" nillable="true"/> <element name="defaultNamespace" type="xsd:string" nillable="true"/> </sequence> </complexType> </element> </schema> </types> <!-- Header Message --> <message name="Header"> <part element="tns:LoginScopeHeader" name="LoginScopeHeader"/> <part element="tns:SessionHeader" name="SessionHeader"/> <part element="tns:CallOptions" name="CallOptions"/> <part element="tns:QueryOptions" name="QueryOptions"/> <part element="tns:AssignmentRuleHeader" name="AssignmentRuleHeader"/> <part element="tns:MruHeader" name="MruHeader"/> <part element="tns:EmailHeader" name="EmailHeader"/> <part element="tns:UserTerritoryDeleteHeader" name="UserTerritoryDeleteHeader"/> <part element="tns:DebuggingHeader" name="DebuggingHeader"/> <part element="tns:DebuggingInfo" name="DebuggingInfo"/> </message> <!-- Fault Messages --> <message name="ApiFault"> <part name="fault" element="fns:fault"/> </message> <message name="LoginFault"> <part name="fault" element="fns:LoginFault"/> </message> <!-- Method Messages --> <message name="loginRequest"> <part element="tns:login" name="parameters"/> </message> <message name="loginResponse"> <part element="tns:loginResponse" name="parameters"/> </message> <!-- Soap PortType --> <portType name="Soap"> <operation name="login"> <documentation>Login to the Salesforce.com SOAP Api</documentation> <input message="tns:loginRequest"/> <output message="tns:loginResponse"/> <fault message="tns:LoginFault" name="LoginFault"/> <fault message="tns:UnexpectedErrorFault" name="UnexpectedErrorFault"/> <fault message="tns:InvalidIdFault" name="InvalidIdFault"/> </operation> </portType> <!-- Soap Binding --> <binding name="SoapBinding" type="tns:Soap"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="login"> <soap:operation soapAction=""/> <input> <soap:header use="literal" message="tns:Header" part="LoginScopeHeader"/> <soap:header use="literal" message="tns:Header" part="CallOptions"/> <soap:body parts="parameters" use="literal"/> </input> <output> <soap:body use="literal"/> </output> <fault name="LoginFault"> <soap:fault name="LoginFault" use="literal"/> </fault> <fault name="UnexpectedErrorFault"> <soap:fault name="UnexpectedErrorFault" use="literal"/> </fault> <fault name="InvalidIdFault"> <soap:fault name="InvalidIdFault" use="literal"/> </fault> </operation> </binding> <!-- Soap Service Endpoint --> <service name="SforceService"> <documentation>Sforce SOAP API</documentation> <port binding="tns:SoapBinding" name="Soap"> <soap:address location="https://www.salesforce.com/services/Soap/u/11.1"/> </port> </service> </definitions>
This modified/extracted version of the Partner WSDL should be accepted cleanly by the Apex generator.
After doing so, you should be able to call the login operation and obtain the session id of that login and pass it into your webservice as a SessionHeader element as such:
// new instance of the partner SOAP class partnerSoapSforceCom.Soap myPartnerSoap = new partnerSoapSforceCom.Soap(); // call login partnerSoapSforceCom.LoginResult partnerLoginResult = myPartnerSoap.login('your_username', 'your_password'); // from here, the session id can be accessed via partnerLoginResult.sessionId // now construct a SessionHeader element for your webservice and set the session id webserviceSOAP.SessionHeader_element webserviceSessionHeader = new webserviceSOAP.SessionHeader_element(); webserviceSessionHeader.sessionId = partnerLoginResult.sessionId; // now construct a new instance of your webservice class and set the SessionHeader webserviceSOAP.webserviceClass myWebservice = new webserviceSOAP.webserviceClass(); myWebservice.SessionHeader = webserviceSessionHeader; // at this point you should be connected to your webservice and be able to call methods against it myWebservice.doStuff();
What I'm concerned about are the Apex Callout Governor Limits (you can read about these in the Apex reference).
Your feedback and input into how fesiable using the Apex Callout to Apex Webservice approach is vs Salesforce to Salesforce would be appreciated!
All Answers
S2S involves manual intervention of clicking button to forward record to another Org.Let me take this reply to state what exactly is in my mind and what i am trying to develop.
Business Scenario
Suppose a firm is using two Salesforce Orgs for two diff process implementation, due to some reasons it wasnt possible to get both these process implementation on a single org. But there's a functionality which need to be replicated on both org, for instance say you want a particular record to be created on second org too as soon as created on first org.
Solutions Possible
Approach 1 : Use S2S
Approach 2: Apex Callouts to Apex Web Service
Apporach 2 is more preferred as it wouldnt require any manual intervention at all. I am trying to build this new feature as this will make our S2S more strong with two options
I feel this to be a cool new feature/app which will be helpful in S2S implementation.
Community commuters, what say ?
Harmpie, Thanks !
Can you share that how can we make a login call to the second org? To my knowledge there's no API alike to login in APEX language.
Unless i login to second org, i wont be able to fetch session Id.
Are you stating me to perform something like(In Org1)
a. Grab Partner WSDL which will generate Apex Stubs mainly Login Apex Stub
b. Grab my custom webservice WSDL which holds API to create records
Now in my second Org I will consume above both WSDL to make first a login call and then custom method call which will perform insertion in Org1.
Also please confirm on following ?
1. Will Partner WSDL contain definition of my custom defined webservice too? Ans : No
2. Unable to consume Partner WSDL due to big Apex File Size generation, cant we generate only Login Stub ? Ans: Edit Partner WSDL to contain only XML definition of login and dependant classes and then try to generate Apex Stub
Regarding #1, you are correct. The Partner WSDL will not contain your custom defined webservice. You'll still have to parse the WSDL generated from your webservice class and generate an Apex class from that WSDL to call your webservice. Keep in mind that your custom webservice cannot return Salesforce object types, nor can it take Salesforce object types as parameters. Only basic types like string, integer, etc, are supported by the Salesforce WSDL parser.
Regarding #2, I'm not sure if you will be able to strip down the Partner WSDL file enough to be able to generate an Apex class from it. I started down that path. I had to strip out type definitions for Salesforce object types like Contact, Account, etc, since the WSDL parser doesn't know how to handle these. Once I got the WSDL to parse, then I ran into the 100,000 character Apex script limitation. I really didn't pursue it any farther than that.
Regarding #1
I got the solution. It goes as follows ...
Step1 : Login to SFDC, using Enterprise/Partner WSDL and obtain SessionId
binding1 = (SoapBindingStub) new SforceServiceLocator().getSoap();
loginResult = binding1.login("username","PwdToken");
SessionHeader sh = new SessionHeader();
sh.setSessionId(loginResult.getSessionId());
Step2 : Set above fetched SessionId as the sessionHeader on your Apex Webservice WSDL stub and then call the required methods.
binding2 = (checkForLeadNumberBindingStub) new checkForLeadNumberServiceLocator().getcheckForLeadNumber();
binding2.setHeader(new checkForLeadNumberServiceLocator().getServiceName().getNamespaceURI(), "SessionHeader", sh);
binding2.extractLeadId("123456","123456");
So that's it, you are all done! nJoy!!
Note : binding1 and binding2 are pointers to Enterprise WSDL and Apex Webservice WSDL respectively.
private SoapBindingStub binding;
private checkForLeadNumberBindingStub binding2;
Chirag,
Are you saying you got this to work? What was the full implementation in the end, for both Org1 and Org2? I just posted a thread http://community.salesforce.com/sforce/board/message?board.id=general_development&thread.id=30405
because now that Summer '09 release is out we want to set up an automated sharing of Cases between orgs rather than having to manually share each Case.
Would what you have acheived be a viable solution?
Thanks,
Mattybme
No, it wasn't solution for Apex Callouts to Apex Web Service. I am still waiting from bloggers/commuters to respond to a solution for Apex Callouts to Apex Web Service.
Apex Callouts to Apex Web Service is nothing other than Automated S2S. We are trying to develop something called as automated Salesforce 2 Salesforce using 2 classy features of Salesforce 1) Apex Callouts & 2) Apex Web Service, but unable to find a perfect n complete solution.
The solution mentioned by me was solution on part1 question posted below my reply.
Regarding #1, you are correct. The Partner WSDL will not contain your custom defined webservice. You'll still have to parse the WSDL generated from your webservice class and generate an Apex class from that WSDL to call your webservice. Keep in mind that your custom webservice cannot return Salesforce object types, nor can it take Salesforce object types as parameters. Only basic types like string, integer, etc, are supported by the Salesforce WSDL parser.
Hi Chirag
Can you please post the entire process that you followed to achieve this?
And if possible, the complete code on both the orgs please.
Thanks
metaforce
Hi,
Exactly what you are looking for ?
Right now two topics discussion is being carried on the same post, so just clarify me what you are looking to achieve. What is your business requirement ?
Thanks
Hi Chirag
Thanks for your response.
Here's my business scenario. I have two orgs:
Org 1: where my master data resides
Org 2: custom application is being developed, which I plan to launch commercially on Appexchange and will be distributed to customers
Org 2 application has a requirement to lookup master data from Org 1 through web services, but am not able to do that.
Can you please let me know the steps of entire process that you followed to successfully call Org 1 web service from Org 2 and the code that you have written in both the Orgs. Let me know if the code is too large to be posted here, in which case I can send you my email Id in a private message.
Thanks.
I'm going to chime in here because I have experimented with trying to do exactly what you are describing. I can shed some light into the challenges you will face.
The challenge first is that you indicate that Org 2 must look up master data from Org 1 through web services. In order to achieve this, you must write Apex code on that resides on Org 1 that will be exposed as a web service method. You indicate that you are trying to develop a commercial app that you will distribute to customers. This means that you would have to deploy code to both Org 1 (the code that implements and exposes the web services) and Org 2 (the code that calls these web services). Writing the code to expose your web services from Org 1 is the relatively easy part, as implementing Apex web services is fairly well documented.
The second challenge is that Org 2 must somehow log in to Org 1 in order to use the web services. This is where I (and I think Chirag too) got stuck. Salesforce provides the Partner WSDL document that can be used to generate code that allows you to log in and use Salesforce as a web service. The process for this is relatively well documented for PHP and Java code. However, doing it using Apex code is not documented as far as I know. What I tried to do, is to use the Salesforce WSDL parser against this Partner WSDL document to parse the WSDL and generate Apex code that would allow you to log in to one Salesforce org from another and make web service calls. This is where things fell apart. The Salesforce WSDL parser cannot parse the Salesforce Partner WSDL for a couple of reasons:
Hi TLF,
Sorry unaware of your name - referring you with your community nickname. Thanks for doucmenting what was in our minds, but why did you stopped.. you seemed to be on success ...
Lets give a try as together and i think we can get a new thing .. Automated S2S using Apex Web Services and Callouts. if needed, lets connect either on email or call, what say?
I got stuck in some other important work, so i couldnt carry on. Anyhow I am sure it will work, lest try together.
I stopped because my requirements changed and I too got diverted other tasks. Unfortunately, I don't have a lot of time to get involved in this right now.
By the way, I went back and tried parsing partner WSDL document and generating the Apex stubs. It seems that the Summer 09 release of Salesforce gets you a bit closer to your goal. I didn't get any parser errors complaining about lack of support for complex types. After parsing, it tried to generate three Apex classes; faultPartnerSoapSforceCom, sobjectPartnerSoapSforceCom and partnerSoapSforceCom. The first two classes were generated successfully, but the third (and probably most important) class failed code generation because of the 100,000 character limitation on the size of Apex scripts. My only suggestion would be to edit the partner WSDL to remove some of the complexType definitions that you probably won't need like "EmptyRecyleBinResult" and "UndeleteResult" to try to get the generated WSDL down below the 100,000 limit. Sorry I can't be more helpful than this.
Hey guys, I've been researching this topic of communicating between multiple Salesforce instances in the past days.
With the idea TLF had in mind, here is the extracted parts of the Partner WSDL that I used, which only have the essential parts needed for the login to work:
<?xml version="1.0" encoding="UTF-8"?> <definitions targetNamespace="urn:partner.soap.sforce.com" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:fns="urn:fault.partner.soap.sforce.com" xmlns:tns="urn:partner.soap.sforce.com" xmlns:ens="urn:sobject.partner.soap.sforce.com"> <types> <schema elementFormDefault="qualified" xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:partner.soap.sforce.com"> <import namespace="urn:sobject.partner.soap.sforce.com"/> <!-- Our simple ID Type --> <simpleType name="ID"> <restriction base="xsd:string"> <length value="18"/> <pattern value='[a-zA-Z0-9]{18}'/> </restriction> </simpleType> <complexType name="GetUserInfoResult"> <sequence> <element name="accessibilityMode" type="xsd:boolean"/> <element name="currencySymbol" type="xsd:string" nillable="true"/> <element name="orgDefaultCurrencyIsoCode" type="xsd:string" nillable="true"/> <element name="organizationId" type="tns:ID"/> <element name="organizationMultiCurrency" type="xsd:boolean"/> <element name="organizationName" type="xsd:string"/> <element name="profileId" type="tns:ID"/> <element name="roleId" type="tns:ID" nillable="true"/> <element name="userDefaultCurrencyIsoCode" type="xsd:string" nillable="true"/> <element name="userEmail" type="xsd:string"/> <element name="userFullName" type="xsd:string"/> <element name="userId" type="tns:ID"/> <element name="userLanguage" type="xsd:string"/> <element name="userLocale" type="xsd:string"/> <element name="userName" type="xsd:string"/> <element name="userTimeZone" type="xsd:string"/> <element name="userType" type="xsd:string"/> <element name="userUiSkin" type="xsd:string"/> </sequence> </complexType> <complexType name="LoginResult"> <sequence> <element name="metadataServerUrl" type="xsd:string" nillable="true"/> <element name="passwordExpired" type="xsd:boolean" /> <element name="serverUrl" type="xsd:string" nillable="true"/> <element name="sessionId" type="xsd:string" nillable="true"/> <element name="userId" type="tns:ID" nillable="true"/> <element name="userInfo" type="tns:GetUserInfoResult" minOccurs="0"/> </sequence> </complexType> <!-- Login Message Types --> <element name="login"> <complexType> <sequence> <element name="username" type="xsd:string"/> <element name="password" type="xsd:string"/> </sequence> </complexType> </element> <element name="loginResponse"> <complexType> <sequence> <element name="result" type="tns:LoginResult"/> </sequence> </complexType> </element> <!-- Header Elements --> <element name="SessionHeader"> <complexType> <sequence> <element name="sessionId" type="xsd:string"/> </sequence> </complexType> </element> <element name="LoginScopeHeader"> <complexType> <sequence> <element name="organizationId" type="tns:ID"/> <element name="portalId" type="tns:ID" minOccurs="0"/> </sequence> </complexType> </element> <element name="CallOptions"> <complexType> <sequence> <element name="client" type="xsd:string" nillable="true"/> <element name="defaultNamespace" type="xsd:string" nillable="true"/> </sequence> </complexType> </element> </schema> </types> <!-- Header Message --> <message name="Header"> <part element="tns:LoginScopeHeader" name="LoginScopeHeader"/> <part element="tns:SessionHeader" name="SessionHeader"/> <part element="tns:CallOptions" name="CallOptions"/> <part element="tns:QueryOptions" name="QueryOptions"/> <part element="tns:AssignmentRuleHeader" name="AssignmentRuleHeader"/> <part element="tns:MruHeader" name="MruHeader"/> <part element="tns:EmailHeader" name="EmailHeader"/> <part element="tns:UserTerritoryDeleteHeader" name="UserTerritoryDeleteHeader"/> <part element="tns:DebuggingHeader" name="DebuggingHeader"/> <part element="tns:DebuggingInfo" name="DebuggingInfo"/> </message> <!-- Fault Messages --> <message name="ApiFault"> <part name="fault" element="fns:fault"/> </message> <message name="LoginFault"> <part name="fault" element="fns:LoginFault"/> </message> <!-- Method Messages --> <message name="loginRequest"> <part element="tns:login" name="parameters"/> </message> <message name="loginResponse"> <part element="tns:loginResponse" name="parameters"/> </message> <!-- Soap PortType --> <portType name="Soap"> <operation name="login"> <documentation>Login to the Salesforce.com SOAP Api</documentation> <input message="tns:loginRequest"/> <output message="tns:loginResponse"/> <fault message="tns:LoginFault" name="LoginFault"/> <fault message="tns:UnexpectedErrorFault" name="UnexpectedErrorFault"/> <fault message="tns:InvalidIdFault" name="InvalidIdFault"/> </operation> </portType> <!-- Soap Binding --> <binding name="SoapBinding" type="tns:Soap"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="login"> <soap:operation soapAction=""/> <input> <soap:header use="literal" message="tns:Header" part="LoginScopeHeader"/> <soap:header use="literal" message="tns:Header" part="CallOptions"/> <soap:body parts="parameters" use="literal"/> </input> <output> <soap:body use="literal"/> </output> <fault name="LoginFault"> <soap:fault name="LoginFault" use="literal"/> </fault> <fault name="UnexpectedErrorFault"> <soap:fault name="UnexpectedErrorFault" use="literal"/> </fault> <fault name="InvalidIdFault"> <soap:fault name="InvalidIdFault" use="literal"/> </fault> </operation> </binding> <!-- Soap Service Endpoint --> <service name="SforceService"> <documentation>Sforce SOAP API</documentation> <port binding="tns:SoapBinding" name="Soap"> <soap:address location="https://www.salesforce.com/services/Soap/u/11.1"/> </port> </service> </definitions>
This modified/extracted version of the Partner WSDL should be accepted cleanly by the Apex generator.
After doing so, you should be able to call the login operation and obtain the session id of that login and pass it into your webservice as a SessionHeader element as such:
// new instance of the partner SOAP class partnerSoapSforceCom.Soap myPartnerSoap = new partnerSoapSforceCom.Soap(); // call login partnerSoapSforceCom.LoginResult partnerLoginResult = myPartnerSoap.login('your_username', 'your_password'); // from here, the session id can be accessed via partnerLoginResult.sessionId // now construct a SessionHeader element for your webservice and set the session id webserviceSOAP.SessionHeader_element webserviceSessionHeader = new webserviceSOAP.SessionHeader_element(); webserviceSessionHeader.sessionId = partnerLoginResult.sessionId; // now construct a new instance of your webservice class and set the SessionHeader webserviceSOAP.webserviceClass myWebservice = new webserviceSOAP.webserviceClass(); myWebservice.SessionHeader = webserviceSessionHeader; // at this point you should be connected to your webservice and be able to call methods against it myWebservice.doStuff();
What I'm concerned about are the Apex Callout Governor Limits (you can read about these in the Apex reference).
Your feedback and input into how fesiable using the Apex Callout to Apex Webservice approach is vs Salesforce to Salesforce would be appreciated!
Alex,
Thanks to complete successfully and post what me and rest other users where trying to do. TLF, I think now we have got a cut-down WSDL which we were talking.
We always had that idea to cut short the WSDL and generate the stubs, but we were unable to do so due to some other prioriry works. Anyhow thanks to Alex to complete the pending task and post a complete reply
Thanks to everyone to make this post complete on Automating S2S.
excellent!!!!
Thanks for your post. That works for mine app.
I was struggling with the Login related to S2S.
Suzan
Hi All,
I am Also suffer from same Situation (Exchange Data from Sales force Organization 1 to Sales force Organization 2 )
I wrote Apex class for SF Org1 has TestWebService class.
I want get data from SF Org1 to SF Org2 by using webservice methods in Apex class in SF Org1 and that class generates WSDL file and upload WSDL file into SF Org2 and it generate Stub class from WSDL file.
Apex class for SF Org1 has one web method below
global class TestWebService{
webService static String testWebMethod(String testname ){
return 'Hello '+testname;
}
}
And Generated WSDL file from above class called TestWebService
<?xml version="1.0" encoding="UTF-8"?>
<!--
Web Services API : TestWebService
-->
<definitions targetNamespace="http://soap.sforce.com/schemas/class/TestWebService" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://soap.sforce.com/schemas/class/TestWebService">
<types>
<xsd:schema elementFormDefault="qualified" targetNamespace="http://soap.sforce.com/schemas/class/TestWebService">
<xsd:element name="DebuggingInfo">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="debugLog" type="xsd:string"/>
</xsd:sequence>
I deployed wsdl file into Another SF Org2 it generates Stub class from above wsdl file called TestWebServiceStub
And I wrote controller in SF Org2 , Access SF Org1 from TestWebService class in that method testWebMethod(String testname)
Controller in SF Org2
TestWebServiceStub.TestWebService testStub = new TestWebServiceStub.TestWebService();
testStub.inputHttpHeaders_x = new Map<String, String>();
testStub.inputHttpHeaders_x.put('Authorization','Basic YXJ1bmFAYm9kaHRyZWUuY29tOmJvZGh0cmVlMTIzVW9RSFJPVFBaWjRWcko3NUZrWFg0TUJEeA==');
Here I Provided Encode 63 bit code is --- username:passwordsecurtytoken
String nameresp = testStub.testWebMethod('Hi Hello ');
I got I Exception Called InValid SessionHeader and System.callout Exception
Can u any give a solutions for this
Thanks
Vasu
Hi All,
I am Also suffer from same Situation (Exchange Data from Sales force Organization 1 to Sales force Organization 2 )
I wrote Apex class for SF Org1 has TestWebService class.
I want get data from SF Org1 to SF Org2 by using webservice methods in Apex class in SF Org1 and that class generates WSDL file and upload WSDL file into SF Org2 and it generate Stub class from WSDL file.
Apex class for SF Org1 has one web method below
global class TestWebService{
webService static String testWebMethod(String testname ){
return 'Hello '+testname;
}
}
And Generated WSDL file from above class called TestWebService
<?xml version="1.0" encoding="UTF-8"?>
<!--
Web Services API : TestWebService
-->
<definitions targetNamespace="http://soap.sforce.com/schemas/class/TestWebService" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://soap.sforce.com/schemas/class/TestWebService">
<types>
<xsd:schema elementFormDefault="qualified" targetNamespace="http://soap.sforce.com/schemas/class/TestWebService">
<xsd:element name="DebuggingInfo">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="debugLog" type="xsd:string"/>
</xsd:sequence>
I deployed wsdl file into Another SF Org2 it generates Stub class from above wsdl file called TestWebServiceStub
And I wrote controller in SF Org2 , Access SF Org1 from TestWebService class in that method testWebMethod(String testname)
Controller in SF Org2
TestWebServiceStub.TestWebService testStub = new TestWebServiceStub.TestWebService();
testStub.inputHttpHeaders_x = new Map<String, String>();
testStub.inputHttpHeaders_x.put('Authorization','Basic YXJ1bmFAYm9kaHRyZWUuY29tOmJvZGh0cmVlMTIzVW9RSFJPVFBaWjRWcko3NUZrWFg0TUJEeA==');
Here I Provided Encode 63 bit code is --- username:passwordsecurtytoken
String nameresp = testStub.testWebMethod('Hi Hello ');
I got I Exception Called InValid SessionHeader and System.callout Exception
Can u any give a solutions for this
Thanks
Vasu
Great post Alex, this works excellent.
I use this to test my own webservices from 1 sandbox to another. That way I don't have to create a client webserver.
hi Alex I have implemented the same that described in the post in my sandbox but i am getting error
as mentioned
Web service callout failed: Unable to parse callout response. Apex type not found for element urn:partner.soap.sforce.com=sandbox
An unexpected error has occurred. Your development organization has been notified.
please help me to solve this error
i have changed the <soap:address location=https://test.salesforce.com/services/Soap/u/20.0
Thanks for this great post, this solved my issue!
Hi All,
I have a similar situation where I need trigger firing in org1 to update data in org2.
I am trying to do callouts to org2, but there is already a SSO established between the two orgs.
How do I make use of the established connection instead of trying to log in again?
Thanks in advance
kpr
Hi Chirag,
Can u brief the steps to follow to develop the same.
I have the same requirement to do. N me new to the concept.
What has to done in two org;s(Org1, org2), and how to execute.
can u post complete code and steps for executing the same. As i have the same requiremen
How to execute the same, need code too!!!
Can u Please send me hte webservice code.
my mail id : salesforceglobal@gmail.com
While I can't say I've actually done it, seems to me that it would be much easier to achieve this using Apex REST web services, rather than SOAP-based web services now that Apex REST is generally available. This would preclude the need to have to work mentioned by AlexPHP in his post. The step of trying to generate Apex stubs from the partner WSDL so that you can log in and invoke your SOAP web service is unnecessary with REST web services.
CAn you plz share the code?
appreciated in advance
I hv the same issue.
i dont want to use S2S(Connection), but i wana communicate using webservices(between twon instance).
Plz help..
Hi
Thanks AlexPHP for the wonderful solution for connecting two salesforce orgs using callouts and webservices.
I was doing something similar, got stuck somewhere and then the solution u provided by parsing cut down partner wsdl helped me
I thought everything is done and was checking whether its working fine but its not
I am getting the following error:
Web service callout failed: Unable to parse callout response. Apex type not found for element urn:partner.soap.sforce.com=sandbox
Please help me to resolve this issue.
Thanks.
Hi AlexPHP/chirag
I have a question on the approach used here for SF webservice
if i have to use SF webservice from other system also we need to provide username, password in the header.
Providing username & password to any other third party to use it as input in the request they form is not acceptable in any organisation.
Please clarify me, how this can be done.
You probably should be looking at the Salesforce REST API and/or Apex REST web services, which utilize OAuth rather than username/password authentication.
I am facing the below issue, can some please help on this.
System.CalloutException: Web service callout failed: WebService returned a SOAP Fault: Element {http://soap.sforce.com/schemas/class/AccountInsert}SessionId invalid at this location faultcode=soapenv:Client faultactor=
more detail, plz link the below link
https://developer.salesforce.com/forums/ForumsMain?id=906F0000000BIiBIAW