/** * \package com.bluevia.messagery.mo.sms This package contains the classes in order to receive SMS using Bluevia API. * \package com.bluevia.messagery.mo.sms.client This package contains REST client to receive SMS using Bluevia API. */ package com.bluevia.messagery.mo.sms.client; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.log4j.Logger; import com.bluevia.commons.Encoding; import com.bluevia.commons.Entity; import com.bluevia.commons.GsdpConstants; import com.bluevia.commons.Utils; import com.bluevia.commons.connector.GenericResponse; import com.bluevia.commons.data.JaxbEntity; import com.bluevia.commons.data.UserId; import com.bluevia.commons.data.UserId.Type; import com.bluevia.commons.exception.BlueviaException; import com.bluevia.commons.exception.ConnectorException; import com.bluevia.commons.parser.xml.XmlConstants; import com.bluevia.commons.parser.xml.XmlParser; import com.bluevia.commons.parser.xml.XmlSerializer; import com.bluevia.messagery.mo.client.BVMoClient; import com.bluevia.messagery.mo.data.ReceivedMessageList; import com.bluevia.messagery.mo.sms.data.SmsMessage; import com.telefonica.schemas.unica.rest.common.v1.SimpleReferenceType; import com.telefonica.schemas.unica.rest.common.v1.UserIdType; import com.telefonica.schemas.unica.rest.sms.v1.ReceivedSMSType; import com.telefonica.schemas.unica.rest.sms.v1.SMSNotificationType; /** * * Abstract client interface for the REST binding of the Bluevia SMS MO Service. * * @author Telefonica R&D * */ public abstract class BVMoSmsClient extends BVMoClient { private static Logger log = Logger.getLogger(BVMoSmsClient.class.getName()); protected static final String FEED_SMS_BASE_URI = "/REST/SMS"; /** * Initializer of common attributes */ protected void init(){ mEncoding = Encoding.APPLICATION_XML; mParser = new XmlParser(); mSerializer= new XmlSerializer(); } /** * * Allow to request for the list of the received SMSs for the app provisioned and authorized * * @param registrationId The Bluevia service number for your country, including the country code without the + symbol * @return the list of the received messages * @throws BlueviaException * @throws IOException */ public ArrayList<SmsMessage> getAllMessages(String registrationId) throws BlueviaException, IOException { ArrayList<SmsMessage> receivedSmsList = null; // Check params checkRegistrationId(registrationId); // Build feed uri for the request String feedUri = "/" + registrationId + RECEIVED_MESSAGES; HashMap<String, String> parameters = new HashMap<String, String>(); parameters.put(XmlConstants.PARAM_VERSION_KEY, XmlConstants.VERSION_1); ((XmlParser) mParser).setParseClass(ReceivedSMSType.class); Entity response = retrieve(feedUri, parameters); receivedSmsList = getReceivedSmsListFromResponse(response); return receivedSmsList; } /** * Gets the received SMS list from the response Entity * * @param response response Entity that contains the result * @return the received SMS list * @throws BlueviaException if the response or the list are not valid. */ private ArrayList<SmsMessage> getReceivedSmsListFromResponse(Entity response) throws BlueviaException{ ArrayList<SmsMessage> receivedSmsList = null; //If there are no messages, return empty list if (response == null) return new ArrayList<SmsMessage>(); //Check if response is instance of JaxbEntity else if (! (response instanceof JaxbEntity)) throw new BlueviaException("Error during request. Response received does not correspond to an ReceivedSmsList", BlueviaException.INTERNAL_CLIENT_ERROR); JaxbEntity parseEntity= (JaxbEntity) response; //Check if parseEntity is instance of ReceivedSMSType ReceivedSMSType receivedSMSType= new ReceivedSMSType(); if ((parseEntity.getObject() == null) || (! (parseEntity.getObject() instanceof ReceivedSMSType))) throw new BlueviaException("Error during request. Response received does not correspond to an SMSMessageType", BlueviaException.INTERNAL_CLIENT_ERROR); receivedSMSType = (ReceivedSMSType) parseEntity.getObject(); log.debug("Creating response ReceivedMessageList"); Entity retEntity = new ReceivedMessageList(receivedSMSType); //Check if response is instance of DeliveryInfo if ((retEntity == null) || (! (retEntity instanceof ReceivedMessageList))) throw new BlueviaException("Error during request. Response received does not correspond to an ReceivedMessageList", BlueviaException.INTERNAL_CLIENT_ERROR); //Get received data receivedSmsList = ((ReceivedMessageList) retEntity).getList(); // Check list if (receivedSmsList == null) throw new BlueviaException("ReceivedSMS list is null", BlueviaException.INTERNAL_CLIENT_ERROR); return receivedSmsList; } /** * Subscribe notifications * * @param phoneNumber the phoneNumber * @param endpoint the uri to receive notifications * @param criteria field with keyword with criteria notifications * @return the correlator from the response. * @throws BlueviaException if the response or the result are not valid. * @throws IOException */ public String startNotification (String phoneNumber, String endpoint, String criteria) throws IOException, BlueviaException{ return startNotification(phoneNumber, endpoint, criteria, null); } /** * Subscribe notifications * * @param phoneNumber the phoneNumber * @param endpoint the uri to receive notifications * @param criteria field with keyword with criteria notifications * @param correlator field with correlator to identify subscriptions * @return the correlator from the response. * @throws BlueviaException if the response or the result are not valid. * @throws IOException */ public String startNotification (String phoneNumber, String endpoint, String criteria, String correlator) throws IOException, BlueviaException{ SMSNotificationType notification= new SMSNotificationType(); if (Utils.isEmpty(correlator)) { correlator= generateCorrelator(criteria); } //Endpoint and correlator SimpleReferenceType ref = new SimpleReferenceType(); ref.setEndpoint(endpoint); ref.setCorrelator(correlator); notification.setReference(ref); //Addresses UserId userId= new UserId(Type.PHONE_NUMBER, phoneNumber); List<UserIdType> addresses = new ArrayList<UserIdType>(); addresses.add(userId.toUserIdType()); notification.setDestinationAddress(addresses); notification.setDestinationAddress(addresses); //Criteria notification.setCriteria(criteria); return startNotification(notification); } /** * Subscribe notifications * * @param notification the messageNotificationType with all data to subscribe * @return the correlator from the response. * @throws BlueviaException if the response or the result are not valid. * @throws IOException */ protected String startNotification (SMSNotificationType notification) throws IOException, BlueviaException{ String result = null; GenericResponse response = null; InputStream is = null; try { // Build feed uri for the request String feedUri = SUBSCRIPTION_PATH; HashMap<String, String> params = new HashMap<String, String>(); params.put(XmlConstants.PARAM_VERSION_KEY, XmlConstants.VERSION_1); JaxbEntity messageEntity= new JaxbEntity(); messageEntity.setJcInstance(XmlConstants.XSD_SMS_API_INSTANCE); messageEntity.setNamespace(XmlConstants.NS_SMS_API_URI); messageEntity.setQname(XmlConstants.XSD_SMSNOTIFICATION_SMSMESSAGE); messageEntity.setObject(notification); byte[] bytes = serializeEntity(messageEntity); String uri = mBaseUri + feedUri; HashMap<String, String> headers = new HashMap<String, String>(); headers.put(GsdpConstants.HEADER_CONTENT_TYPE, getEncoding(mEncoding)); response = mConnector.create(uri, params, bytes, headers); is = response.getAdditionalData().getBody(); result = getMesageIdFromResponse(response.getAdditionalData().getHeaders(), uri); } catch (ConnectorException e){ log.error("Error during request. Connector Exception: " + e.getMessage()); throw new BlueviaException("Error during request: " + e.getMessage(), BlueviaException.INTERNAL_CLIENT_ERROR); } catch (IOException e) { log.error("Error during request. IO Exception: " + e.getMessage()); throw new IOException("Error during request: " + e.getMessage()); } finally { //Close the stream if (is != null) try { is.close(); } catch (IOException e) { log.info(e.getMessage(), e); } } return result; } /** * Unsubscribe notifications * * @param correlator the correlator to unsubscribe notification * @return boolean with result of operation * @throws BlueviaException if the response or the result are not valid. * @throws IOException */ public boolean stopNotification (String correlator) throws BlueviaException, IOException { boolean result = false; if (Utils.isEmpty(correlator)) throw new BlueviaException("Invalida parameter: correlator can't be empty", BlueviaException.INTERNAL_CLIENT_ERROR); GenericResponse response = null; InputStream is = null; try { // Build feed uri for the request String feedUri = SUBSCRIPTION_PATH + "/" + correlator; HashMap<String, String> params = new HashMap<String, String>(); params.put(XmlConstants.PARAM_VERSION_KEY, XmlConstants.VERSION_1); String uri = mBaseUri + feedUri; HashMap<String, String> headers = new HashMap<String, String>(); headers.put(GsdpConstants.HEADER_CONTENT_TYPE, getEncoding(mEncoding)); response = mConnector.delete(uri, params, headers); log.debug("[stopNotification] response status :" + response.getStatus()); log.debug("[stopNotification] response message:" + response.getMessage()); if (response.getStatus()== 204) { result= true; } } catch (ConnectorException e){ log.error("Error during request. Connector Exception: " + e.getMessage()); throw new BlueviaException("Error during request: " + e.getMessage(), BlueviaException.INTERNAL_CLIENT_ERROR); } catch (IOException e) { log.error("Error during request. IO Exception: " + e.getMessage()); throw new IOException("Error during request: " + e.getMessage()); } finally { //Close the stream if (is != null) try { is.close(); } catch (IOException e) { log.info(e.getMessage(), e); } } return result; } /** * Gets the messageId from the response headers. * * @param responseHeaders headers containing the messageId. * @param feed field of the uri to distinguish SMS and MMS * @return the messageId from the response. * @throws BlueviaException if the response or the result are not valid. */ protected static String getMesageIdFromResponse(HashMap<String, String> responseHeaders, String feed) throws BlueviaException{ // In this case, when sending a Message, the response is not returned using an XML (is is null) // but using header location String messageId = responseHeaders.get(MESSAGEID_LOCATION_HEADER); if (!Utils.isEmpty(messageId)) { // Extract the SMSID from the delivery http URL using Java patterns // Location Url is like "https://bluevia.com/gSDP/REST/{SMS|MMS}/outbound/requests/MessageId/deliverystatus" String regex = feed + "/(.*)"; Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(messageId); if (matcher.matches()) { log.debug("matcher.group(1): "+matcher.group(1)); return matcher.group(1); } else throw new BlueviaException("Error during request. Location received does not correspond to the pattern of an MessageID URI" + "LocationUri: "+messageId+" regex: "+regex, BlueviaException.INTERNAL_CLIENT_ERROR); } else throw new BlueviaException("Location header is empty", BlueviaException.INTERNAL_CLIENT_ERROR); } }