4

In our business project we need to integrate with an external system which uses amazon sqs WS in order to manage client requests. Is there an example implementation in apex for sending/receiving messages to/from an amazon simple queue?

I've started from this point: https://webmonkeyswithlaserbeams.wordpress.com/2011/03/08/salesforce-and-amazon-sqs/

Is this correct?

public class AmazonSqsSender{


private String getCurrentDate() {
    return DateTime.now().formatGmt('yyyy-MM-dd\'T\'HH:mm:ss.SSS\'Z\'');
}

public void sendMessage(String message) {
    //AmazonAws__c is a custom setting object that stores our keys, an Amazon Host, and a queue name
    //You can just put your keys, host and queue below as strings             /CUSTOM SETTINGS
    AmazonAws__c aws = AmazonAws__c.getOrgDefaults();

    String accessKey =aws.accessKey__c;
    String secretKey = aws.secretKey__c;
    String host = aws.host__c;
    String queue = aws.queue__c;

    Map<String,String> params = new Map<String,String>();

    params.put('AWSAccessKeyId',encode(accessKey));
    params.put('Action','SendMessage');
    params.put('MessageBody',encode(message));
    params.put('Timestamp',encode(getCurrentDate()));
    params.put('SignatureMethod','HmacSHA1');
    params.put('SignatureVersion','2');
    params.put('Version','2009-02-01');

    //The string to sign has to be sorted by keys
    List<String> sortedKeys = new List<String>();
    sortedKeys.addAll(params.keySet());
    sortedKeys.sort();

    String toSign = 'GET\n' + host +'\n'+queue+'\n';
    Integer p = 0;
    for (String key : sortedKeys) {
        String value = params.get(key);
        if (p > 0) {
            toSign += '&';
        }
        p++;
        toSign += key+'='+value;
    }
    params.put('Signature',getMac(toSign,secretKey));

    String url = 'https://'+ host+queue+'?';
    p = 0;
    for (String key : params.keySet()) {
        if (p > 0) {
            url += '&';
        }
        p++;
        url += key+'='+params.get(key);
    }

    HttpRequest req = new HttpRequest();
    req.setEndPoint(url);
    req.setMethod('GET');
    Http http = new Http();
    try {
        //System.debug('Signed string: ' + toSign);
        //System.debug('Url: ' + url);
        HttpResponse res = http.send(req);
        //System.debug('Status: ' + res.getStatus());
        //System.debug('Code  : ' + res.getStatusCode());
        //System.debug('Body  : ' + res.getBody());
    }
    catch (System.CalloutException e) {
        System.debug('ERROR: ' + e);
    }

}


public void receiveMessage(String message) {

    //MAYBE I NEED TO CHANGE THE QUERIES

    AmazonAws__c aws = AmazonAws__c.getOrgDefaults();

    String accessKey =aws.accessKey__c;
    String secretKey = aws.secretKey__c;
    String host = aws.host__c;
    String queue = aws.queue__c;

    Map<String,String> params = new Map<String,String>();

    params.put('AWSAccessKeyId',encode(accessKey));
    params.put('Action','ReceiveMessage');
    params.put('MessageBody',encode(message));
    params.put('Timestamp',encode(getCurrentDate()));
    params.put('SignatureMethod','HmacSHA1');
    params.put('SignatureVersion','2');
    params.put('Version','2009-02-01');

    //The string to sign has to be sorted by keys
    List<String> sortedKeys = new List<String>();
    sortedKeys.addAll(params.keySet());
    sortedKeys.sort();

    String toSign = 'GET\n' + host +'\n'+queue+'\n';
    Integer p = 0;
    for (String key : sortedKeys) {
        String value = params.get(key);
        if (p > 0) {
            toSign += '&';
        }
        p++;
        toSign += key+'='+value;
    }
    params.put('Signature',getMac(toSign,secretKey));

    String url = 'https://'+ host+queue+'?';
    p = 0;
    for (String key : params.keySet()) {
        if (p > 0) {
            url += '&';
        }
        p++;
        url += key+'='+params.get(key);
    }

    HttpRequest req = new HttpRequest();
    req.setEndPoint(url);
    req.setMethod('GET');
    Http http = new Http();
    try {
        //System.debug('Signed string: ' + toSign);
        //System.debug('Url: ' + url);
        HttpResponse res = http.send(req);
        //System.debug('Status: ' + res.getStatus());
        //System.debug('Code  : ' + res.getStatusCode());
        //System.debug('Body  : ' + res.getBody());
    }
    catch (System.CalloutException e) {
        System.debug('ERROR: ' + e);
    }

}



private String encode(String message){
    return EncodingUtil.urlEncode(message,'UTF-8').replace('+', '%20').replace('*', '%2A').replace('%7E','~');
}

private String getMac(String RequestString, String secretkey) {
    String algorithmName = 'hmacSHA1';
    Blob input = Blob.valueOf(RequestString);
    Blob key = Blob.valueOf(secretkey);
    Blob signing =Crypto.generateMac(algorithmName, input, key);
    return EncodingUtil.urlEncode(EncodingUtil.base64Encode(signing), 'UTF-8');
}

public static void sendTest() {
    AmazonSqsSender t = new AmazonSqsSender();
    t.sendMessage('Hello from Salesforce ' + Math.random());
}

EDIT: After testing the first method i've encountered the anouthorized endpoint error, even if the endpoint has been inserted in the remote site setting, could it depend on the 'builded' url used in the method?

11
  • 4
    Have you looked at the docs?
    – Adrian Larson
    Jun 27, 2017 at 13:01
  • 1
    There are no references to apex or salesforce in amazon docs , unfortunately. And java implementations use some amazon libraries that are not available for apex.
    – Maxxpower
    Jun 27, 2017 at 13:02
  • 1
    Well, it doestn mean that there are no descriptions about how to do that in generic case
    – kurunve
    Jun 27, 2017 at 13:03
  • 1
    You just have to adapt them. I suggest you make an attempt and edit this post with where you get stuck. Apex docs are pretty clear about how to make callouts.
    – Adrian Larson
    Jun 27, 2017 at 13:04
  • 3
    I've written code for sending to SQS, but I don't have code for reading it, since it wasn't relevant to my needs at the time. You can start from there.
    – sfdcfox
    Jun 27, 2017 at 13:06

2 Answers 2

3

I think this code is now out of date since AWS is not signed any longer with SignatureVersion 2. Maybe you could try to implement Signature Version 4. Here is an excellent example: https://github.com/mattandneil/aws-sdk.

2

Below is the code for receive Message from AWS SQS in salesforce

`

public class AmazonSqsReceiver
{
    private String getCurrentDate() {
        return DateTime.now().formatGmt('yyyy-MM-dd\'T\'HH:mm:ss.SSS\'Z\'');
    }

    public void receiveMessage() {
        //AmazonAws__c is a custom setting object that stores our keys, an Amazon Host, and a queue name
        //You can just put your keys, host and queue below as strings
        AmazonAws__c aws = AmazonAws__c.getOrgDefaults();

        String accessKey =aws.accessKey__c;
        String secretKey = aws.secretKey__c;
        String host = aws.host__c;
        String queue = aws.queue__c;

        Map<String,String> params = new Map<String,String>();

        params.put('AWSAccessKeyId',encode(accessKey));
        params.put('Action','ReceiveMessage');
        params.put('MaxNumberOfMessages','5');
        params.put('AttributeName','All');
        params.put('SignatureMethod','HmacSHA1');
        params.put('Expires', '2020-04-18T22%3A52%3A43PST');
        params.put('SignatureVersion','2');
        params.put('Version','2009-02-01');

        //The string to sign has to be sorted by keys
        List<String> sortedKeys = new List<String>();
        sortedKeys.addAll(params.keySet());
        sortedKeys.sort();

        String toSign = 'GET\n' + host +'\n'+queue+'\n';
        Integer p = 0;
        for (String key : sortedKeys) {
            String value = params.get(key);
            if (p > 0) {
                toSign += '&';
            }
            p++;
            toSign += key+'='+value;
        }
        params.put('Signature',getMac(toSign,secretKey));

        String url = 'https://'+ host+queue+'?';
        p = 0;
        for (String key : params.keySet()) {
            if (p > 0) {
                url += '&';
            }
            p++;
            url += key+'='+params.get(key);
        }

        HttpRequest req = new HttpRequest();
        req.setEndPoint(url);
        req.setMethod('GET');
        Http http = new Http();
        try {
            //System.debug('Signed string: ' + toSign);
            System.debug('Url: ' + url);
            HttpResponse res = http.send(req);
            System.debug('Status: ' + res.getStatus());
            System.debug('Code  : ' + res.getStatusCode());
            System.debug('Body  : ' + res.getBody());
        }
        catch (System.CalloutException e) {
            System.debug('ERROR: ' + e);
        }

    }
    private String encode(String message){
        return EncodingUtil.urlEncode(message,'UTF-8').replace('+', '%20').replace('*', '%2A').replace('%7E','~');
    }

    private String getMac(String RequestString, String secretkey) {
        String algorithmName = 'hmacSHA1';
        Blob input = Blob.valueOf(RequestString);
        Blob key = Blob.valueOf(secretkey);
        Blob signing =Crypto.generateMac(algorithmName, input, key);
        return EncodingUtil.urlEncode(EncodingUtil.base64Encode(signing), 'UTF-8');
    }

    public static void sendTest() {
        AmazonSqsSender t = new AmazonSqsSender();
        t.sendMessage('Hello from Salesforce ' + Math.random());
    }
}`
1
  • @Dave Humm Can I use this in my new integration ?
    – Srujan
    Jan 10, 2019 at 9:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .