Java tutorial
/** * MOTECH PLATFORM OPENSOURCE LICENSE AGREEMENT * * Copyright (c) 2010-11 The Trustees of Columbia University in the City of * New York and Grameen Foundation USA. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of Grameen Foundation USA, Columbia University, or * their respective contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY GRAMEEN FOUNDATION USA, COLUMBIA UNIVERSITY * AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRAMEEN FOUNDATION * USA, COLUMBIA UNIVERSITY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.motechproject.mobile.imp.serivce; import org.apache.log4j.Logger; import org.jdom.JDOMException; import org.motechproject.mobile.core.manager.CoreManager; import org.motechproject.mobile.core.model.IncomingMessage; import org.motechproject.mobile.core.model.IncMessageFormStatus; import org.motechproject.mobile.core.model.IncomingMessageResponse; import org.motechproject.mobile.imp.manager.IMPManager; import org.motechproject.mobile.imp.util.CommandAction; import org.motechproject.mobile.imp.util.IncomingMessageParser; import org.motechproject.mobile.imp.util.IncomingMessageXMLParser; import org.motechproject.mobile.imp.util.exception.MotechParseException; import org.motechproject.mobile.model.dao.imp.IncomingMessageDAO; import org.motechproject.mobile.omi.manager.OMIManager; import org.springframework.transaction.annotation.Transactional; import java.io.IOException; import java.util.ArrayList; import java.util.Map; import java.util.regex.Pattern; /** * @author Kofi A. Asamoah (yoofi@dreamoval.com) * Date : Dec 5, 2009 */ @Transactional public class IMPServiceImpl implements IMPService { private static Logger logger = Logger.getLogger(IMPServiceImpl.class); private IMPManager impManager; private OMIManager omiManager; private CoreManager coreManager; private IncomingMessageParser parser; private Map<String, CommandAction> cmdActionMap; private IncomingMessageXMLParser xmlParser; private String formProcessSuccess; private int maxConcat; private int charsPerSMS; private int concatAllowance; private int maxSMS; private String localNumberExpression; private String defaultCountryCode; private MessageRegistry messageRegistry; @SuppressWarnings("unchecked") public IncomingMessageResponse processRequest(String message, String requesterPhone, boolean isDemo) { IncomingMessageDAO<IncomingMessage> msgDao = coreManager.createIncomingMessageDAO(); IncomingMessageResponse response = coreManager.createIncomingMessageResponse(); IncomingMessage inMsg = null; try { inMsg = messageRegistry.registerMessage(message); } catch (DuplicateProcessingException dpe) { logger.info("duplicate form in process, returning wait message"); response.setContent("Error: Duplicate in progress, please try again."); return response; } catch (DuplicateMessageException e) { logger.warn("duplicate form:\n" + message); response.setContent(formProcessSuccess); return response; } // Ensure object is attached to persistent context msgDao.save(inMsg); String cmd = parser.getCommand(message); CommandAction action = cmdActionMap.get(cmd.toUpperCase()); if (action == null) { //TODO change error to unknown form type or command response.setContent("Error: Unknown Form!\nPlease check the name of the form."); return response; } /** * Process the message according to its request type. Separate actions * may be performed for data entry or queries */ response = action.execute(inMsg, requesterPhone); /** Send an SMS response to the requester if required and the form is valid */ if (inMsg.getIncomingMessageForm() != null && inMsg.getIncomingMessageForm().getIncomingMsgFormDefinition().getSendResponse() && inMsg.getIncomingMessageForm().getMessageFormStatus() == IncMessageFormStatus.SERVER_VALID) { sendResponse(response.getContent(), response.getIncomingMessage().getIncomingMsgSession().getRequesterPhone()); } return response; } public String processRequest(String message) { IncomingMessageResponse result = null; //TODO We must also separate the processing of java forms - Logically result = processRequest(message, null, false); if (result.getContent().toLowerCase().indexOf("error") < 0) { return formProcessSuccess; } else { return result.getContent(); } } /** * <p>Processes xForms as Motech Forms by converting them to SMS format. It then goes through normal * SMS processing.</p> * * @param xForms * @return a List of responses * @throws org.jdom.JDOMException * @throws java.io.IOException * @throws org.motechproject.mobile.imp.util.exception.MotechParseException */ public ArrayList<String> processXForms(ArrayList<String> xForms) throws JDOMException, IOException, MotechParseException { ArrayList<String> result = null; if (xForms != null) { result = new ArrayList<String>(); ArrayList<String> smses = xmlParser.parseXML(xForms); for (String sms : smses) { result.add(processRequest(sms)); } } return result; } /** * Validates and processes an xForm. * * @param xForm the XForm to be validated and processed * @return ok if successful otherwise the specifics of the error for reporting * @throws org.jdom.JDOMException * @throws java.io.IOException * @throws org.motechproject.mobile.imp.util.exception.MotechParseException */ public String processXForm(String xForm) throws JDOMException, IOException, MotechParseException { String result = null; if (xForm != null) { result = processXFormSMS(xmlParser.toSMSMessage(xForm)); } return result; } /** * Processes motech mobile understandable name/value pair SMS * * @param xFormSMS * @return ok if processing is successfully otherwise error message */ private String processXFormSMS(String xFormSMS) { String result = null; if (xFormSMS != null) { result = processRequest(xFormSMS); } return result; } /** * Sends a response for a mobile query message * * @param response the response message * @param recipient the phone number to send the response to */ private void sendResponse(String response, String recipient) { /** Calculate the maximum number of characters that can be sent in a concatenated SMS */ int msgLength = (charsPerSMS - concatAllowance) * maxConcat; recipient = formatPhoneNumber(recipient); if (recipient == null || recipient.isEmpty()) { return; } if (response.length() <= msgLength) { /** response fits within a concatenated message */ omiManager.createOMIService().scheduleMessage(response, recipient); } else {/** response exceeds concatenated message length. Split into multiple messages */ int start = 0; int end = 0; for (byte smsNum = 1; smsNum <= maxSMS; smsNum++) {/** While maximum number of SMSes per response hasn't been exceeded */ String currSMS = ""; end = start + msgLength;/** get boundaries of current SMS within response */ if (response.length() < start) break; if (response.length() > start + 2) { currSMS = response.length() < end ? response.substring(start) : response.substring(start, end); } if (currSMS.contains( "\n")) {/** message contains line-separated details. Avoid splitting in the middle of a line. */ String message = ""; String[] lines = currSMS.split("\n"); for (String line : lines) { int currLen = message.length() + line.length() + 1; if (currLen < msgLength) {/** only add line if it will fit within current message. */ message += line + "\n"; } } currSMS = message.trim(); } omiManager.createOMIService().scheduleMessage(currSMS, recipient); start += currSMS.length(); } } } public String formatPhoneNumber(String requesterPhone) { if (requesterPhone == null || requesterPhone.isEmpty()) { return null; } String formattedNumber = requesterPhone; if (Pattern.matches(localNumberExpression, requesterPhone)) { formattedNumber = defaultCountryCode + requesterPhone.substring(1); } return formattedNumber; } /** * @return the coreManager */ public CoreManager getCoreManager() { return coreManager; } /** * @param coreManager the coreManager to set */ public void setCoreManager(CoreManager coreManager) { this.coreManager = coreManager; } /** * @return the parser */ public IncomingMessageParser getParser() { return parser; } /** * @param parser the parser to set */ public void setParser(IncomingMessageParser parser) { this.parser = parser; } /** * @return the cmdActionMap */ public Map<String, CommandAction> getCmdActionMap() { return cmdActionMap; } /** * @param cmdActionMap the cmdActionMap to set */ public void setCmdActionMap(Map<String, CommandAction> cmdActionMap) { this.cmdActionMap = cmdActionMap; } /** * @return the impManager */ public IMPManager getImpManager() { return impManager; } /** * @param impManager the impManager to set */ public void setImpManager(IMPManager impManager) { this.impManager = impManager; } /** * @return the xmlParser */ public IncomingMessageXMLParser getXmlParser() { return xmlParser; } /** * @param xmlParser the xmlParser to set */ public void setXmlParser(IncomingMessageXMLParser xmlParser) { this.xmlParser = xmlParser; } /** * @return the formProcessSuccess */ public String getFormProcessSuccess() { return formProcessSuccess; } /** * @param formProcessSuccess the formProcessSuccess to set */ public void setFormProcessSuccess(String formProcessSuccess) { this.formProcessSuccess = formProcessSuccess; } /** * @param omiManager the omiManager to set */ public void setOmiManager(OMIManager omiManager) { this.omiManager = omiManager; } /** * @param maxConcat the maxConcat to set */ public void setMaxConcat(int maxConcat) { this.maxConcat = maxConcat; } /** * @param charsPerSMS the charsPerSMS to set */ public void setCharsPerSMS(int charsPerSMS) { this.charsPerSMS = charsPerSMS; } /** * @param concatAllowance the concatAllowance to set */ public void setConcatAllowance(int concatAllowance) { this.concatAllowance = concatAllowance; } /** * @param maxSMS the maxSMS to set */ public void setMaxSMS(int maxSMS) { this.maxSMS = maxSMS; } /** * @param localNumberExpression the localNumberExpression to set */ public void setLocalNumberExpression(String localNumberExpression) { this.localNumberExpression = localNumberExpression; } /** * @param defaultCountryCode the defaultCountryCode to set */ public void setDefaultCountryCode(String defaultCountryCode) { this.defaultCountryCode = defaultCountryCode; } /** * @param messageRegistry */ public void setMessageRegistry(MessageRegistry messageRegistry) { this.messageRegistry = messageRegistry; } }