Created
November 14, 2017 11:06
-
-
Save johndstein/d226f0803d5a800ab2fa3717767b67bb to your computer and use it in GitHub Desktop.
Luminate Soap Service
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Handles all the communication with Luminate Online web service SOAP API. | |
*/ | |
public class LuminateSoapService { | |
public static final String FORMAT = 'yyyy-MM-dd\'T\'HH:mm:ssZ'; | |
public class MyException extends Exception {} | |
public class SoapResponse { | |
public String requestBody; | |
public String requestName; | |
public SObject[] records = new List<SObject>(); | |
SoapResponse(String requestName, String requestBody) { | |
this.requestName = requestName; | |
this.requestBody = requestBody; | |
} | |
} | |
public String loginSessionId; | |
public String syncSessionId; | |
public Luminate_Connection__c connection; | |
public Luminate_Sync_Session__c syncSession; | |
public String pullDonationInsertSoap(Integer page) { | |
String[] fields = new List<String>(); | |
fields.add('TransactionId'); | |
fields.add('CampaignId'); | |
fields.add('Organization'); | |
fields.add('Payment'); | |
fields.add('Donor'); | |
fields.add('ReceiptNumber'); | |
return pullSoap('Inserts', 'Donation', fields, page); | |
} | |
public String pullDonationUpdateSoap(Integer page) { | |
String[] fields = new List<String>(); | |
fields.add('TransactionId'); | |
fields.add('CampaignId'); | |
fields.add('Organization'); | |
fields.add('Payment'); | |
fields.add('Donor'); | |
fields.add('ReceiptNumber'); | |
return pullSoap('Updates', 'Donation', fields, page); | |
} | |
public String pullConstituentInsertSoap(Integer page) { | |
String[] fields = new List<String>(); | |
fields.add('ConsId'); | |
fields.add('ConsName'); | |
fields.add('HomeAddress'); | |
return pullSoap('Inserts', 'Constituent', fields, page); | |
} | |
public String pullConstituentUpdateSoap(Integer page) { | |
String[] fields = new List<String>(); | |
fields.add('ConsId'); | |
fields.add('ConsName'); | |
fields.add('HomeAddress'); | |
return pullSoap('Updates', 'Constituent', fields, page); | |
} | |
public String pullSoap(String insUpDel, String recordType, | |
String[] fields, Integer page) { | |
String soap = ''; | |
soap += '<?xml version=\'1.0\' encoding=\'UTF-8\' ?>'; | |
soap += '<soap:Envelope xmlns:soap=\'http://schemas.xmlsoap.org/soap/envelope/\'>'; | |
soap += ' <soap:Header>'; | |
soap += ' <Session xmlns=\'urn:soap.convio.com\'>'; | |
soap += ' <SessionId>' + this.loginSessionId + '</SessionId>'; | |
soap += ' </Session>'; | |
soap += ' </soap:Header>'; | |
soap += ' <soap:Body>'; | |
soap += ' <GetIncremental' + insUpDel + ' xmlns=\'urn:soap.convio.com\'>'; | |
soap += ' <PartitionId>' + this.connection.Partition_Id__c + '</PartitionId>'; | |
soap += ' <RecordType>' + recordType + '</RecordType>'; | |
soap += ' <Page>' + page + '</Page>'; | |
soap += ' <PageSize>' + this.connection.Page_Size__c + '</PageSize>'; | |
for (String fieldName : fields) { | |
soap += '<Field>' + fieldName + '</Field>'; | |
} | |
soap += ' </GetIncremental' + insUpDel + '>'; | |
soap += ' </soap:Body>'; | |
soap += '</soap:Envelope>'; | |
return soap; | |
} | |
// <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> | |
// <soap:Body> | |
// <GetIncrementalInsertsResponse xmlns="urn:soap.convio.com" xmlns:ens="urn:object.soap.convio.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | |
// <Record xsi:type="ens:Constituent"> | |
// <ens:ConsId>1164881</ens:ConsId> | |
// <ens:ConsName> | |
// <ens:FirstName>Cynthia</ens:FirstName> | |
// <ens:LastName>Osborne</ens:LastName> | |
// </ens:ConsName> | |
// <ens:Active>ACTIVE</ens:Active> | |
// <ens:HomeAddress> | |
// <ens:Street1 xsi:nil="true" /> | |
// <ens:Street2 xsi:nil="true" /> | |
// <ens:City xsi:nil="true" /> | |
// <ens:State xsi:nil="true" /> | |
// <ens:Zip xsi:nil="true" /> | |
// </ens:HomeAddress> | |
// </Record> | |
// | |
// Parses records out of the soap body and returns them as a string. | |
public String[] parseRecords(Dom.Document doc) { | |
Dom.XmlNode[] bodies = doc.getRootElement().getChildElements(); | |
Dom.XmlNode[] responses = bodies[0].getChildElements(); | |
Dom.XmlNode[] records = responses[0].getChildElements(); | |
String[] a = new List<String>(); | |
for (Dom.XmlNode n : records) { | |
a.add(toXmlString(n)); | |
} | |
return a; | |
} | |
// We assume all nodes EITHER have text OR have more nodes. | |
// Nothing else. | |
public static String toXmlString(DOM.XMLNode node) { | |
String result = ''; | |
if (node.getNodeType() == DOM.XMLNodeType.ELEMENT) { | |
result += '\n<' + node.getName() + '>'; | |
if (node.getText().trim() != '') { | |
result += node.getText().trim(); | |
return result + '</' + node.getName() + '>'; | |
} else { | |
for (Dom.XMLNode child : node.getChildElements()) { | |
result += toXmlString(child); | |
} | |
// Don't output empty elements. | |
if (result == '\n<' + node.getName() + '>') { | |
result = ''; | |
} else { | |
result += '\n</' + node.getName() + '>'; | |
} | |
return result; | |
} | |
} | |
throw new MyException('Should never reach here.'); | |
} | |
public SoapResponse[] pullDonationUpdates() { | |
SoapResponse[] soapResponses = new List<SoapResponse>(); | |
SoapResponse soapResponse; | |
Integer page = 1; | |
String[] records; | |
do { | |
String requestBody = pullDonationUpdateSoap(page); | |
soapResponse = | |
new SoapResponse('GetIncrementalUpdates Donation', requestBody); | |
soapResponses.add(soapResponse); | |
Dom.Document responseDoc = doSoapDoc(requestBody); | |
records = parseRecords(responseDoc); | |
for (String rec : records) { | |
soapResponse.records.add( | |
new Luminate_Record__c( | |
Sync_Session__c = this.syncSession.Id, | |
Record__c = rec | |
)); | |
} | |
page++; | |
} while (soapResponse.records.size() == this.connection.Page_Size__c); | |
return soapResponses; | |
} | |
public SoapResponse[] pullDonationInserts() { | |
SoapResponse[] soapResponses = new List<SoapResponse>(); | |
SoapResponse soapResponse; | |
Integer page = 1; | |
String[] records; | |
do { | |
String requestBody = pullDonationInsertSoap(page); | |
soapResponse = | |
new SoapResponse('GetIncrementalInserts Donation', requestBody); | |
soapResponses.add(soapResponse); | |
Dom.Document responseDoc = doSoapDoc(requestBody); | |
records = parseRecords(responseDoc); | |
for (String rec : records) { | |
soapResponse.records.add( | |
new Luminate_Record__c( | |
Sync_Session__c = this.syncSession.Id, | |
Record__c = rec | |
)); | |
} | |
page++; | |
} while (soapResponse.records.size() == this.connection.Page_Size__c); | |
return soapResponses; | |
} | |
public SoapResponse[] pullConstituentInserts() { | |
SoapResponse[] soapResponses = new List<SoapResponse>(); | |
SoapResponse soapResponse; | |
Integer page = 1; | |
String[] records; | |
do { | |
String requestBody = pullConstituentInsertSoap(page); | |
soapResponse = | |
new SoapResponse('GetIncrementalInserts Constituent', requestBody); | |
soapResponses.add(soapResponse); | |
Dom.Document responseDoc = doSoapDoc(requestBody); | |
records = parseRecords(responseDoc); | |
for (String rec : records) { | |
soapResponse.records.add( | |
new Luminate_Record__c( | |
Sync_Session__c = this.syncSession.Id, | |
Record__c = rec | |
)); | |
} | |
page++; | |
} while (soapResponse.records.size() == this.connection.Page_Size__c); | |
return soapResponses; | |
} | |
public SoapResponse[] pullConstituentUpdates() { | |
SoapResponse[] soapResponses = new List<SoapResponse>(); | |
SoapResponse soapResponse; | |
Integer page = 1; | |
String[] records; | |
do { | |
String requestBody = pullConstituentUpdateSoap(page); | |
soapResponse = | |
new SoapResponse('GetIncrementalUpdates Constituent', requestBody); | |
soapResponses.add(soapResponse); | |
Dom.Document responseDoc = doSoapDoc(requestBody); | |
records = parseRecords(responseDoc); | |
for (String rec : records) { | |
soapResponse.records.add( | |
new Luminate_Record__c( | |
Sync_Session__c = this.syncSession.Id, | |
Record__c = rec | |
)); | |
} | |
page++; | |
} while (soapResponse.records.size() == this.connection.Page_Size__c); | |
return soapResponses; | |
} | |
public void endSyncSession() { | |
String soap = ''; | |
soap += '<?xml version=\'1.0\' encoding=\'UTF-8\' ?>'; | |
soap += '<soap:Envelope xmlns:soap=\'http://schemas.xmlsoap.org/soap/envelope/\'>'; | |
soap += ' <soap:Header>'; | |
soap += ' <Session xmlns=\'urn:soap.convio.com\'>'; | |
soap += ' <SessionId>' + this.loginSessionId + '</SessionId>'; | |
soap += ' </Session>'; | |
soap += ' </soap:Header>'; | |
soap += ' <soap:Body>'; | |
soap += ' <EndSynchronization xmlns=\'urn:soap.convio.com\'>'; | |
soap += ' <PartitionId>' + this.connection.Partition_Id__c + '</PartitionId>'; | |
soap += ' </EndSynchronization>'; | |
soap += ' </soap:Body>'; | |
soap += '</soap:Envelope>'; | |
// See LuminateSoapMock.END_SYNC_RESPONSE | |
doSoapString(soap); | |
} | |
public Luminate_Sync_Session__c | |
getLatestSuccessfulSyncSession(String targetSystem) { | |
Luminate_Sync_Session__c lss = null; | |
for (Luminate_Sync_Session__c s : | |
[ | |
select End_Time__c | |
from Luminate_Sync_Session__c | |
where Success_Time__c != null | |
order by End_Time__c desc | |
]) { | |
lss = s; | |
break; | |
} | |
if (lss == null) { | |
Datetime dt = Datetime.now(); | |
dt = Datetime.newInstance(dt.year(), dt.month(), 1); | |
lss = new Luminate_Sync_Session__c( | |
End_Time__c = dt | |
); | |
} | |
return lss; | |
} | |
public void startSyncSession(String targetSystem) { | |
Luminate_Sync_Session__c lss = getLatestSuccessfulSyncSession(targetSystem); | |
Datetime dtNow = Datetime.now(); | |
String startTime = lss.End_Time__c.format(FORMAT); | |
String endTime = dtNow.format(FORMAT); | |
String soap = ''; | |
soap += '<soap:Envelope xmlns:soap=\'http://schemas.xmlsoap.org/soap/envelope/\'>'; | |
soap += ' <soap:Header>'; | |
soap += ' <Session xmlns=\'urn:soap.convio.com\'>'; | |
soap += ' <SessionId>' + this.loginSessionId + '</SessionId>'; | |
soap += ' </Session>'; | |
soap += ' </soap:Header>'; | |
soap += ' <soap:Body>'; | |
soap += ' <StartSynchronization xmlns=\'urn:soap.convio.com\'>'; | |
soap += ' <PartitionId>' + this.connection.Partition_Id__c + '</PartitionId>'; | |
soap += ' <Start>' + startTime + '</Start>'; | |
soap += ' <End>' + endTime + '</End>'; | |
soap += ' </StartSynchronization>'; | |
soap += ' </soap:Body>'; | |
soap += '</soap:Envelope>'; | |
// See LuminateSoapMock.START_SYNC_RESPONSE | |
String result = doSoapString(soap); | |
System.debug('RESULT ' + result); | |
try { | |
Dom.Document doc = new Dom.Document(); | |
doc.load(result); | |
this.syncSessionId = | |
doc | |
.getRootElement() | |
.getChildElement('Body', 'http://schemas.xmlsoap.org/soap/envelope/') | |
.getChildElement('StartSynchronizationResponse', 'urn:soap.convio.com') | |
.getChildElement('Result', 'urn:soap.convio.com') | |
.getChildElement('SyncId', 'urn:soap.convio.com') | |
.getText(); | |
this.syncSession = new Luminate_Sync_Session__c( | |
Name = this.syncSessionId, | |
End_Time__c = dtNow, | |
Start_Time__c = lss.End_Time__c | |
); | |
insert this.syncSession; | |
} catch (Exception e) { | |
sendErrorEmail('StartSynchronization', e); | |
throw e; | |
} | |
} | |
public void ensureConnection() { | |
if (this.connection == null) { | |
this.connection = | |
[ select Endpoint__c, | |
Error_Email_Address__c, | |
Name, | |
Partition_Id__c, | |
Password__c, | |
Username__c, | |
Page_Size__c | |
from Luminate_Connection__c | |
where Name = 'Prod'][0]; | |
} | |
} | |
public void login() { | |
ensureConnection(); | |
String soap = ''; | |
soap += '<?xml version=\'1.0\' encoding=\'UTF - 8\' ?>'; | |
soap += '<soap:Envelope xmlns:soap=\'http://schemas.xmlsoap.org/soap/envelope/\'>'; | |
soap += ' <soap:Body>'; | |
soap += ' <Login xmlns=\'urn: soap.convio.com\'>'; | |
soap += ' <UserName>' + this.connection.username__c + '</UserName>'; | |
soap += ' <Password>' + this.connection.password__c + '</Password>'; | |
soap += ' </Login>'; | |
soap += ' </soap:Body>'; | |
soap += '</soap:Envelope>'; | |
// See LuminateSoapMock.LOGIN_RESPONSE | |
try { | |
this.loginSessionId = | |
doSoapDoc(soap) | |
.getRootElement() | |
.getChildElement('Body', 'http://schemas.xmlsoap.org/soap/envelope/') | |
.getChildElement('LoginResponse', 'urn:soap.convio.com') | |
.getChildElement('Result', 'urn:soap.convio.com') | |
.getChildElement('SessionId', 'urn:soap.convio.com') | |
.getText(); | |
} catch (Exception e) { | |
sendErrorEmail('Login', e); | |
throw e; | |
} | |
} | |
public Dom.Document doSoapDoc(String requestBody) { | |
return (Dom.Document) doSoapPost(requestBody, true); | |
} | |
public String doSoapString(String requestBody) { | |
return (String) doSoapPost(requestBody, false); | |
} | |
public Object doSoapPost(String requestBody, Boolean domDoc) { | |
HttpRequest req = new HttpRequest(); | |
req.setEndpoint(this.connection.Endpoint__c); | |
req.setMethod('POST'); | |
req.setBody(requestBody); | |
HttpResponse res = new Http().send(req); | |
if (res.getStatusCode() != 200) { | |
Exception e = new MyException( | |
'Bad HTTP status code: ' + res.getStatusCode() | |
+ ' ' + res.getStatus()); | |
sendErrorEmail(e.getMessage(), e); | |
throw e; | |
} | |
if (domDoc) { | |
return res.getBodyDocument(); | |
} else { | |
return res.getBody(); | |
} | |
} | |
// TODO need to verify this works. Haven't got email from sandbox yet. | |
public void sendErrorEmail(String action, Exception err) { | |
ensureConnection(); | |
if (err == null) { | |
err = new MyException('Fake exception'); | |
} | |
System.debug(System.LoggingLevel.ERROR, err); | |
try { | |
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage(); | |
String[] toAddresses = new String[] {this.connection.Error_Email_Address__c}; | |
mail.setToAddresses(toAddresses); | |
mail.setSenderDisplayName('Luminate Online Sync'); | |
mail.setSubject('Error : ' + action + ' ' + err.getMessage()); | |
mail.setPlainTextBody('Error: ' + action + '\n\n' + err.getStackTraceString()); | |
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail }); | |
} catch (Exception e) { | |
System.debug(System.LoggingLevel.ERROR, e); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment