001/*
002 * Copyright (c) 2011-2017 Nexmo Inc
003 *
004 * Permission is hereby granted, free of charge, to any person obtaining a copy
005 * of this software and associated documentation files (the "Software"), to deal
006 * in the Software without restriction, including without limitation the rights
007 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
008 * copies of the Software, and to permit persons to whom the Software is
009 * furnished to do so, subject to the following conditions:
010 *
011 * The above copyright notice and this permission notice shall be included in
012 * all copies or substantial portions of the Software.
013 *
014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
017 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
019 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
020 * THE SOFTWARE.
021 */
022package com.nexmo.client.sns;
023
024import com.nexmo.client.HttpWrapper;
025import com.nexmo.client.NexmoClientException;
026import com.nexmo.client.NexmoResponseParseException;
027import com.nexmo.client.auth.SignatureAuthMethod;
028import com.nexmo.client.auth.TokenAuthMethod;
029import com.nexmo.client.legacyutils.XmlParser;
030import com.nexmo.client.sns.request.SnsRequest;
031import com.nexmo.client.sns.response.SnsPublishResponse;
032import com.nexmo.client.sns.response.SnsResponse;
033import com.nexmo.client.sns.response.SnsSubscribeResponse;
034import com.nexmo.client.voice.endpoints.AbstractMethod;
035import com.nexmo.client.legacyutils.XmlUtil;
036import org.apache.commons.logging.Log;
037import org.apache.commons.logging.LogFactory;
038import org.apache.http.HttpResponse;
039import org.apache.http.client.methods.RequestBuilder;
040import org.apache.http.impl.client.BasicResponseHandler;
041import org.w3c.dom.Document;
042import org.w3c.dom.Node;
043import org.w3c.dom.NodeList;
044
045import java.io.IOException;
046import java.io.UnsupportedEncodingException;
047import java.util.Map;
048
049public class SnsEndpoint extends AbstractMethod<SnsRequest, SnsResponse> {
050    private static final Log log = LogFactory.getLog(SnsClient.class);
051
052    private static final Class[] ALLOWED_AUTH_METHODS = new Class[]{SignatureAuthMethod.class, TokenAuthMethod.class};
053
054    private static final String DEFAULT_BASE_URL = "https://sns.nexmo.com/sns/xml";
055
056    private String uri = DEFAULT_BASE_URL;
057
058    private XmlParser xmlParser = new XmlParser();
059
060    public SnsEndpoint(HttpWrapper httpWrapper) {
061        super(httpWrapper);
062    }
063
064    @Override
065    protected Class[] getAcceptableAuthMethods() {
066        return ALLOWED_AUTH_METHODS;
067    }
068
069    @Override
070    public RequestBuilder makeRequest(SnsRequest snsRequest) throws NexmoClientException, UnsupportedEncodingException {
071        RequestBuilder requestBuilder = RequestBuilder
072                .post(this.uri)
073                .addParameter("cmd", snsRequest.getCommand());
074        for (Map.Entry<String, String> entry : snsRequest.getQueryParameters().entrySet()) {
075            requestBuilder.addParameter(entry.getKey(), entry.getValue());
076        }
077        return requestBuilder;
078    }
079
080    @Override
081    public SnsResponse parseResponse(HttpResponse response) throws IOException {
082        return parseSubmitResponse(new BasicResponseHandler().handleResponse(response));
083    }
084
085    protected SnsResponse parseSubmitResponse(String response) {
086        // parse the response doc ...
087
088        /*
089            We receive a response from the api that looks like this, parse the document
090            and turn it into an instance of SnsResponse
091
092                <nexmo-sns>
093                    <command>subscribe|publish</command>
094                    <resultCode>0</resultCode>
095                    <resultMessage>OK!</resultMessage>
096                    <transactionId>${transaction-id}</transactionId>
097                    <subscriberArn>${subscriber}</subscriberArn>
098                </nexmo-sns>
099
100        */
101
102        Document doc = xmlParser.parseXml(response);
103
104        String command = null;
105        int resultCode = -1;
106        String resultMessage = null;
107        String transactionId = null;
108        String subscriberArn = null;
109
110        NodeList replies = doc.getElementsByTagName("nexmo-sns");
111        Node reply = replies.item(0);   // If there's more than one reply, we ignore the extras.
112        NodeList nodes = reply.getChildNodes();
113
114        for (int i2 = 0; i2 < nodes.getLength(); i2++) {
115            Node node = nodes.item(i2);
116            if (node.getNodeType() == Node.ELEMENT_NODE) {
117                if (node.getNodeName().equals("command")) {
118                    command = XmlUtil.stringValue(node);
119                } else if (node.getNodeName().equals("resultCode")) {
120                    try {
121                        resultCode = XmlUtil.intValue(node);
122                    } catch (Exception e) {
123                        log.error("xml parser .. invalid value in <resultCode> node [ " + XmlUtil.stringValue(node) +
124                                " ] ");
125                        resultCode = SnsResponse.STATUS_INTERNAL_ERROR;
126                    }
127                } else if (node.getNodeName().equals("resultMessage")) {
128                    resultMessage = XmlUtil.stringValue(node);
129                } else if (node.getNodeName().equals("transactionId")) {
130                    transactionId = XmlUtil.stringValue(node);
131                } else if (node.getNodeName().equals("subscriberArn")) {
132                    subscriberArn = XmlUtil.stringValue(node);
133                } else
134                    log.error("xml parser .. unknown node found in nexmo-sns [ " + node.getNodeName() + " ] ");
135            }
136        }
137
138        if (resultCode == -1) {
139            throw new NexmoResponseParseException("Xml Parser - did not find a <resultCode> node");
140        }
141
142        if ("publish".equals(command)) {
143            return new SnsPublishResponse(resultCode, resultMessage, transactionId);
144        } else if ("subscribe".equals(command)) {
145            return new SnsSubscribeResponse(resultCode, resultMessage, subscriberArn);
146        } else {
147            throw new NexmoResponseParseException("Unknown command value: " + command);
148        }
149    }
150}