=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/sms/SmsConsumer.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/sms/SmsConsumer.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/sms/SmsConsumer.java 2013-07-16 06:53:26 +0000 @@ -0,0 +1,7 @@ +package org.hisp.dhis.sms; + +public interface SmsConsumer +{ + void start(); + void stop(); +} === added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/sms/SmsServiceManager.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/sms/SmsServiceManager.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/sms/SmsServiceManager.java 2013-07-16 06:53:26 +0000 @@ -0,0 +1,59 @@ +package org.hisp.dhis.sms; + +/* + * Copyright (c) 2004-2012, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 THE COPYRIGHT OWNER 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. + */ + +import java.util.Map; + +import org.hisp.dhis.sms.outbound.OutboundSms; + +public interface SmsServiceManager +{ + Map getGatewayMap(); + + void stopService(); + + void startService(); + + void reloadConfig() + throws SmsServiceException; + + String getServiceStatus(); + + String getMessageStatus(); + + String getDefaultGateway(); + + String sendMessage( OutboundSms sms, String gatewayId ) + throws SmsServiceException; + + String sendMessage( OutboundSms sms ) + throws SmsServiceException; + + String sendMessage( String message, String phoneNumber ) + throws SmsServiceException; +} === modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/sms/outbound/OutboundSmsService.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/sms/outbound/OutboundSmsService.java 2012-10-22 08:51:28 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/sms/outbound/OutboundSmsService.java 2013-07-16 06:53:26 +0000 @@ -51,13 +51,19 @@ String sendMessage( OutboundSms sms, String gatewayId ) throws SmsServiceException; + String sendMessage( OutboundSms sms ) + throws SmsServiceException; + + String sendMessage( String message, String phoneNumber ) + throws SmsServiceException; + List getAllOutboundSms(); - - int saveOutboundSms( OutboundSms sms); - - void updateOutboundSms( OutboundSms sms); - + + int saveOutboundSms( OutboundSms sms ); + + void updateOutboundSms( OutboundSms sms ); + void deleteById( Integer outboundSmsId ); - + List getOutboundSms( OutboundSmsStatus status ); } === modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/smscommand/SMSCommandService.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/smscommand/SMSCommandService.java 2013-03-14 07:19:34 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/smscommand/SMSCommandService.java 2013-07-16 06:53:26 +0000 @@ -30,6 +30,8 @@ import java.util.Collection; import java.util.Set; +import org.hisp.dhis.sms.parse.ParserType; + public interface SMSCommandService { void updateSMSCommand( SMSCommand cmd ); @@ -45,4 +47,6 @@ void delete( SMSCommand cmd ); Collection getJ2MESMSCommands(); + + SMSCommand getSMSCommand( String commandName, ParserType parserType ); } === modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/smscommand/SMSCommandStore.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/smscommand/SMSCommandStore.java 2013-03-14 07:19:34 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/smscommand/SMSCommandStore.java 2013-07-16 06:53:26 +0000 @@ -30,6 +30,8 @@ import java.util.Collection; import java.util.Set; +import org.hisp.dhis.sms.parse.ParserType; + public interface SMSCommandStore { Collection getSMSCommands(); @@ -43,4 +45,6 @@ void save( Set codes ); Collection getJ2MESMSCommands(); + + SMSCommand getSMSCommand( String commandName, ParserType parserType ); } === added directory 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/sms' === added file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/sms/DHISMessageAlertListener.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/sms/DHISMessageAlertListener.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/sms/DHISMessageAlertListener.java 2013-07-16 06:53:26 +0000 @@ -0,0 +1,212 @@ +package org.hisp.dhis.sms; + +/* + * Copyright (c) 2004-2012, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 THE COPYRIGHT OWNER 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. + */ + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.apache.commons.lang.StringUtils; +import org.hisp.dhis.message.Message; +import org.hisp.dhis.message.MessageConversation; +import org.hisp.dhis.message.MessageConversationStore; +import org.hisp.dhis.message.MessageSender; +import org.hisp.dhis.message.UserMessage; +import org.hisp.dhis.sms.incoming.IncomingSms; +import org.hisp.dhis.sms.incoming.IncomingSmsListener; +import org.hisp.dhis.sms.parse.ParserType; +import org.hisp.dhis.sms.parse.SMSParserException; +import org.hisp.dhis.smscommand.SMSCommand; +import org.hisp.dhis.smscommand.SMSCommandService; +import org.hisp.dhis.user.User; +import org.hisp.dhis.user.UserGroup; +import org.hisp.dhis.user.UserService; + +public class DHISMessageAlertListener + implements IncomingSmsListener +{ + private MessageSender smsMessageSender; + + private MessageSender emailMessageSender; + + private MessageConversationStore messageConversationStore; + + private SMSCommandService smsCommandService; + + private UserService userService; + + public SMSCommandService getSmsCommandService() + { + return smsCommandService; + } + + public void setSmsCommandService( SMSCommandService smsCommandService ) + { + this.smsCommandService = smsCommandService; + } + + @Override + public boolean accept( IncomingSms sms ) + { + String message = sms.getText(); + String commandString = null; + if ( message.indexOf( " " ) > 0 ) + { + commandString = message.substring( 0, message.indexOf( " " ) ); + message = message.substring( commandString.length() ); + } + else + { + commandString = message; + } + + return smsCommandService.getSMSCommand( commandString, ParserType.ALERT_PARSER ) != null; + } + + @Override + public void receive( IncomingSms sms ) + { + String message = sms.getText(); + String commandString = null; + if ( message.indexOf( " " ) > 0 ) + { + commandString = message.substring( 0, message.indexOf( " " ) ); + message = message.substring( commandString.length() ); + } + else + { + commandString = message; + } + + SMSCommand smsCommand = smsCommandService.getSMSCommand( commandString, ParserType.ALERT_PARSER ); + UserGroup userGroup = smsCommand.getUserGroup(); + String senderPhoneNumber = StringUtils.replace( sms.getOriginator(), "+", "" ); + + if ( userGroup != null ) + { + Collection users = userService.getUsersByPhoneNumber( senderPhoneNumber ); + + if ( users != null && users.size() > 1 ) + { + String messageMoreThanOneUser = "System only accepts sender's number assigned for one user, but found more than one user for this number: "; + for ( Iterator i = users.iterator(); i.hasNext(); ) + { + User user = i.next(); + messageMoreThanOneUser += " " + user.getName(); + if ( i.hasNext() ) + { + messageMoreThanOneUser += ","; + } + } + throw new SMSParserException( messageMoreThanOneUser ); + } + else if ( users != null && users.size() == 1 ) + { + User sender = users.iterator().next(); + + Set receivers = new HashSet( userGroup.getMembers() ); + + // forward to user group by SMS + smsMessageSender.sendMessage( smsCommand.getName(), message, sender, receivers, true ); + + // forward to user group by E-mail + emailMessageSender.sendMessage( smsCommand.getName(), message, sender, receivers, false ); + + // forward to user group by dhis message + if ( sender != null ) + { + receivers.add( sender ); + } + + MessageConversation conversation = new MessageConversation( smsCommand.getName(), sender ); + + conversation.addMessage( new Message( message, null, sender ) ); + + for ( User receiver : receivers ) + { + boolean read = receiver != null && receiver.equals( sender ); + + conversation.addUserMessage( new UserMessage( receiver, read ) ); + } + messageConversationStore.save( conversation ); + // confirm SMS was received and forwarded completely + Set feedbackList = new HashSet(); + feedbackList.add( sender ); + smsMessageSender.sendMessage( smsCommand.getName(), smsCommand.getReceivedMessage(), null, + feedbackList, true ); + } + else if ( users == null || users.size() == 0 ) + { + throw new SMSParserException( + "No user associated with this phone number. Please contact your supervisor." ); + + } + } + } + + public MessageSender getSmsMessageSender() + { + return smsMessageSender; + } + + public void setSmsMessageSender( MessageSender smsMessageSender ) + { + this.smsMessageSender = smsMessageSender; + } + + public MessageSender getEmailMessageSender() + { + return emailMessageSender; + } + + public void setEmailMessageSender( MessageSender emailMessageSender ) + { + this.emailMessageSender = emailMessageSender; + } + + public MessageConversationStore getMessageConversationStore() + { + return messageConversationStore; + } + + public void setMessageConversationStore( MessageConversationStore messageConversationStore ) + { + this.messageConversationStore = messageConversationStore; + } + + public UserService getUserService() + { + return userService; + } + + public void setUserService( UserService userService ) + { + this.userService = userService; + } +} === added file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/sms/DataValueSMSListener.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/sms/DataValueSMSListener.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/sms/DataValueSMSListener.java 2013-07-16 06:53:26 +0000 @@ -0,0 +1,605 @@ +package org.hisp.dhis.sms; + +/* + * Copyright (c) 2004-2012, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 THE COPYRIGHT OWNER 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. + */ + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.commons.lang.StringUtils; +import org.hisp.dhis.dataelement.DataElement; +import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo; +import org.hisp.dhis.dataelement.DataElementCategoryService; +import org.hisp.dhis.dataset.CompleteDataSetRegistration; +import org.hisp.dhis.dataset.CompleteDataSetRegistrationService; +import org.hisp.dhis.dataset.DataSet; +import org.hisp.dhis.dataset.DataSetService; +import org.hisp.dhis.datavalue.DataValue; +import org.hisp.dhis.datavalue.DataValueService; +import org.hisp.dhis.organisationunit.OrganisationUnit; +import org.hisp.dhis.period.CalendarPeriodType; +import org.hisp.dhis.period.Period; +import org.hisp.dhis.sms.incoming.IncomingSms; +import org.hisp.dhis.sms.incoming.IncomingSmsListener; +import org.hisp.dhis.sms.outbound.OutboundSmsService; +import org.hisp.dhis.sms.parse.ParserType; +import org.hisp.dhis.sms.parse.SMSParserException; +import org.hisp.dhis.smscommand.SMSCode; +import org.hisp.dhis.smscommand.SMSCommand; +import org.hisp.dhis.smscommand.SMSCommandService; +import org.hisp.dhis.user.User; +import org.hisp.dhis.user.UserService; + +public class DataValueSMSListener + implements IncomingSmsListener +{ + private static final String defaultPattern = "([a-zA-Z]+)\\s*(\\d+)"; + + private CompleteDataSetRegistrationService registrationService; + + private DataValueService dataValueService; + + private OutboundSmsService outboundSmsService; + + private DataElementCategoryService dataElementCategoryService; + + private SMSCommandService smsCommandService; + + private UserService userService; + + private DataSetService dataSetService; + + @Override + public boolean accept( IncomingSms sms ) + { + String message = sms.getText(); + String commandString = null; + if ( message.indexOf( " " ) > 0 ) + { + commandString = message.substring( 0, message.indexOf( " " ) ); + message = message.substring( commandString.length() ); + } + else + { + commandString = message; + } + return smsCommandService.getSMSCommand( commandString, ParserType.KEY_VALUE_PARSER ) != null; + } + + @Override + public void receive( IncomingSms sms ) + { + String message = sms.getText(); + String commandString = null; + if ( message.indexOf( " " ) > 0 ) + { + commandString = message.substring( 0, message.indexOf( " " ) ); + message = message.substring( commandString.length() ); + } + else + { + commandString = message; + } + SMSCommand smsCommand = smsCommandService.getSMSCommand( commandString, ParserType.KEY_VALUE_PARSER ); + Map parsedMessage = this.parse( message, smsCommand ); + Date date = lookForDate( message ); + String senderPhoneNumber = StringUtils.replace( sms.getOriginator(), "+", "" ); + Collection orgUnits = getOrganisationUnitsByPhoneNumber( senderPhoneNumber ); + + if ( orgUnits == null || orgUnits.size() == 0 ) + { + throw new SMSParserException( "No user associated with this phone number. Please contact your supervisor." ); + } + + OrganisationUnit orgUnit = this.selectOrganisationUnit( orgUnits, parsedMessage ); + Period period = getPeriod( smsCommand, date ); + + // Check if Data Set is locked + if ( dataSetService.isLocked( smsCommand.getDataset(), period, orgUnit, null ) ) + { + throw new SMSParserException( "Dataset is locked for the period " + period.getStartDate() + " - " + + period.getEndDate() ); + } + + boolean valueStored = false; + for ( SMSCode code : smsCommand.getCodes() ) + { + if ( parsedMessage.containsKey( code.getCode().toUpperCase() ) ) + { + valueStored = storeDataValue( senderPhoneNumber, orgUnit, parsedMessage, code, smsCommand, date, + smsCommand.getDataset() ); + } + } + + if ( parsedMessage.isEmpty() ) + { + if ( StringUtils.isEmpty( smsCommand.getDefaultMessage() ) ) + { + throw new SMSParserException( "No values reported for command '" + smsCommand.getName() + "'" ); + } + else + { + throw new SMSParserException( smsCommand.getDefaultMessage() ); + } + } + else if ( !valueStored ) + { + throw new SMSParserException( "Wrong format for command '" + smsCommand.getName() + "'" ); + } + + markCompleteDataSet( senderPhoneNumber, orgUnit, parsedMessage, smsCommand, date ); + sendSuccessFeedback( senderPhoneNumber, smsCommand, parsedMessage, date, orgUnit ); + } + + private Map parse( String sms, SMSCommand smsCommand ) + { + HashMap output = new HashMap(); + Pattern pattern = Pattern.compile( defaultPattern ); + if ( !StringUtils.isBlank( smsCommand.getSeparator() ) ) + { + String x = "(\\w+)\\s*\\" + smsCommand.getSeparator().trim() + "\\s*([\\w ]+)\\s*(\\" + + smsCommand.getSeparator().trim() + "|$)*\\s*"; + pattern = Pattern.compile( x ); + } + Matcher m = pattern.matcher( sms ); + while ( m.find() ) + { + String key = m.group( 1 ); + String value = m.group( 2 ); + + if ( !StringUtils.isEmpty( key ) && !StringUtils.isEmpty( value ) ) + { + output.put( key.toUpperCase(), value ); + } + } + + return output; + } + + private Date lookForDate( String message ) + { + if ( !message.contains( " " ) ) + { + return null; + } + + Date date = null; + String dateString = message.trim().split( " " )[0]; + SimpleDateFormat format = new SimpleDateFormat( "ddMM" ); + + try + { + Calendar cal = Calendar.getInstance(); + date = format.parse( dateString ); + cal.setTime( date ); + int year = Calendar.getInstance().get( Calendar.YEAR ); + int month = Calendar.getInstance().get( Calendar.MONTH ); + if ( cal.get( Calendar.MONTH ) < month ) + { + cal.set( Calendar.YEAR, year ); + } + else + { + cal.set( Calendar.YEAR, year - 1 ); + } + date = cal.getTime(); + } + catch ( Exception e ) + { + // no date found + } + return date; + } + + private Collection getOrganisationUnitsByPhoneNumber( String sender ) + { + Collection orgUnits = new ArrayList(); + Collection users = userService.getUsersByPhoneNumber( sender ); + for ( User u : users ) + { + if ( u.getOrganisationUnits() != null ) + { + orgUnits.addAll( u.getOrganisationUnits() ); + } + } + + return orgUnits; + } + + private OrganisationUnit selectOrganisationUnit( Collection orgUnits, + Map parsedMessage ) + { + OrganisationUnit orgUnit = null; + + for ( OrganisationUnit o : orgUnits ) + { + if ( orgUnits.size() == 1 ) + { + orgUnit = o; + } + if ( parsedMessage.containsKey( "ORG" ) && o.getCode().equals( parsedMessage.get( "ORG" ) ) ) + { + orgUnit = o; + break; + } + } + + if ( orgUnit == null && orgUnits.size() > 1 ) + { + String messageListingOrgUnits = "Found more than one org unit for this number. Please specify one of the following:"; + for ( Iterator i = orgUnits.iterator(); i.hasNext(); ) + { + OrganisationUnit o = i.next(); + messageListingOrgUnits += " " + o.getName() + ":" + o.getCode(); + if ( i.hasNext() ) + { + messageListingOrgUnits += ","; + } + } + throw new SMSParserException( messageListingOrgUnits ); + } + return orgUnit; + } + + private Period getPeriod( SMSCommand command, Date date ) + { + + Period period; + period = command.getDataset().getPeriodType().createPeriod(); + CalendarPeriodType cpt = (CalendarPeriodType) period.getPeriodType(); + if ( command.isCurrentPeriodUsedForReporting() ) + { + period = cpt.createPeriod( new Date() ); + } + else + { + period = cpt.getPreviousPeriod( period ); + } + + if ( date != null ) + { + period = cpt.createPeriod( date ); + } + + return period; + } + + private boolean storeDataValue( String sender, OrganisationUnit orgunit, Map parsedMessage, + SMSCode code, SMSCommand command, Date date, DataSet dataSet ) + { + String upperCaseCode = code.getCode().toUpperCase(); + + String storedBy = getUser( sender ).getUsername(); + + if ( StringUtils.isBlank( storedBy ) ) + { + storedBy = "[unknown] from [" + sender + "]"; + } + + DataElementCategoryOptionCombo optionCombo = dataElementCategoryService.getDataElementCategoryOptionCombo( code + .getOptionId() ); + + Period period = getPeriod( command, date ); + + DataValue dv = dataValueService.getDataValue( orgunit, code.getDataElement(), period, optionCombo ); + + String value = parsedMessage.get( upperCaseCode ); + if ( !StringUtils.isEmpty( value ) ) + { + boolean newDataValue = false; + if ( dv == null ) + { + dv = new DataValue(); + dv.setOptionCombo( optionCombo ); + dv.setSource( orgunit ); + dv.setDataElement( code.getDataElement() ); + dv.setPeriod( period ); + dv.setComment( "" ); + newDataValue = true; + } + + if ( StringUtils.equals( dv.getDataElement().getType(), DataElement.VALUE_TYPE_BOOL ) ) + { + if ( "Y".equals( value.toUpperCase() ) || "YES".equals( value.toUpperCase() ) ) + { + value = "true"; + } + else if ( "N".equals( value.toUpperCase() ) || "NO".equals( value.toUpperCase() ) ) + { + value = "false"; + } + } + else if ( StringUtils.equals( dv.getDataElement().getType(), DataElement.VALUE_TYPE_INT ) ) + { + try + { + Integer.parseInt( value ); + } + catch ( NumberFormatException e ) + { + return false; + } + + } + + dv.setValue( value ); + dv.setTimestamp( new java.util.Date() ); + dv.setStoredBy( storedBy ); + + if ( newDataValue ) + { + dataValueService.addDataValue( dv ); + } + else + { + dataValueService.updateDataValue( dv ); + } + } + + return true; + } + + private User getUser( String sender ) + { + OrganisationUnit orgunit = null; + User user = null; + for ( User u : userService.getUsersByPhoneNumber( sender ) ) + { + OrganisationUnit ou = u.getOrganisationUnit(); + + // Might be undefined if the user has more than one org.units + // "attached" + if ( orgunit == null ) + { + orgunit = ou; + } + else if ( orgunit.getId() == ou.getId() ) + { + // same orgunit, no problem... + } + else + { + throw new SMSParserException( + "User is associated with more than one orgunit. Please contact your supervisor." ); + } + user = u; + } + return user; + } + + /* Checks if all defined data codes have values in the database */ + private void markCompleteDataSet( String sender, OrganisationUnit orgunit, Map parsedMessage, + SMSCommand command, Date date ) + { + + Period period = null; + + for ( SMSCode code : command.getCodes() ) + { + + DataElementCategoryOptionCombo optionCombo = dataElementCategoryService + .getDataElementCategoryOptionCombo( code.getOptionId() ); + + period = getPeriod( command, date ); + + DataValue dv = dataValueService.getDataValue( orgunit, code.getDataElement(), period, optionCombo ); + + if ( dv == null && !StringUtils.isEmpty( code.getCode() ) ) + { + return; // not marked as complete + } + } + + String storedBy = getUser( sender ).getUsername(); + + if ( StringUtils.isBlank( storedBy ) ) + { + storedBy = "[unknown] from [" + sender + "]"; + } + + // if new values are submitted re-register as complete + deregisterCompleteDataSet( command.getDataset(), period, orgunit ); + registerCompleteDataSet( command.getDataset(), period, orgunit, storedBy ); + + } + + protected void sendSuccessFeedback( String sender, SMSCommand command, Map parsedMessage, + Date date, OrganisationUnit orgunit ) + { + String reportBack = "Thank you! Values entered: "; + String notInReport = "Missing values for: "; + + Period period = null; + + Map codesWithDataValues = new TreeMap(); + List codesWithoutDataValues = new ArrayList(); + + for ( SMSCode code : command.getCodes() ) + { + + DataElementCategoryOptionCombo optionCombo = dataElementCategoryService + .getDataElementCategoryOptionCombo( code.getOptionId() ); + + period = getPeriod( command, date ); + + DataValue dv = dataValueService.getDataValue( orgunit, code.getDataElement(), period, optionCombo ); + + if ( dv == null && !StringUtils.isEmpty( code.getCode() ) ) + { + codesWithoutDataValues.add( code.getCode() ); + } + else if ( dv != null ) + { + codesWithDataValues.put( code.getCode(), dv ); + } + } + + for ( String key : codesWithDataValues.keySet() ) + { + DataValue dv = codesWithDataValues.get( key ); + String value = dv.getValue(); + if ( StringUtils.equals( dv.getDataElement().getType(), DataElement.VALUE_TYPE_BOOL ) ) + { + if ( "true".equals( value ) ) + { + value = "Yes"; + } + else if ( "false".equals( value ) ) + { + value = "No"; + } + } + reportBack += key + "=" + value + " "; + } + + Collections.sort( codesWithoutDataValues ); + + for ( String key : codesWithoutDataValues ) + { + notInReport += key + ","; + } + notInReport = notInReport.substring( 0, notInReport.length() - 1 ); + + if ( codesWithoutDataValues.size() > 0 ) + { + outboundSmsService.sendMessage( reportBack + notInReport, sender ); + } + else + { + outboundSmsService.sendMessage( reportBack, sender ); + } + } + + private void registerCompleteDataSet( DataSet dataSet, Period period, OrganisationUnit organisationUnit, + String storedBy ) + { + CompleteDataSetRegistration registration = new CompleteDataSetRegistration(); + + if ( registrationService.getCompleteDataSetRegistration( dataSet, period, organisationUnit ) == null ) + { + registration.setDataSet( dataSet ); + registration.setPeriod( period ); + registration.setSource( organisationUnit ); + registration.setDate( new Date() ); + registration.setStoredBy( storedBy ); + registration.setPeriodName( registration.getPeriod().toString() ); + registrationService.saveCompleteDataSetRegistration( registration, false ); + } + } + + private void deregisterCompleteDataSet( DataSet dataSet, Period period, OrganisationUnit organisationUnit ) + { + CompleteDataSetRegistration registration = registrationService.getCompleteDataSetRegistration( dataSet, period, + organisationUnit ); + + if ( registration != null ) + { + registrationService.deleteCompleteDataSetRegistration( registration ); + } + } + + public CompleteDataSetRegistrationService getRegistrationService() + { + return registrationService; + } + + public void setRegistrationService( CompleteDataSetRegistrationService registrationService ) + { + this.registrationService = registrationService; + } + + public DataValueService getDataValueService() + { + return dataValueService; + } + + public void setDataValueService( DataValueService dataValueService ) + { + this.dataValueService = dataValueService; + } + + public OutboundSmsService getOutboundSmsService() + { + return outboundSmsService; + } + + public void setOutboundSmsService( OutboundSmsService outboundSmsService ) + { + this.outboundSmsService = outboundSmsService; + } + + public SMSCommandService getSmsCommandService() + { + return smsCommandService; + } + + public void setSmsCommandService( SMSCommandService smsCommandService ) + { + this.smsCommandService = smsCommandService; + } + + public UserService getUserService() + { + return userService; + } + + public void setUserService( UserService userService ) + { + this.userService = userService; + } + + public DataSetService getDataSetService() + { + return dataSetService; + } + + public void setDataSetService( DataSetService dataSetService ) + { + this.dataSetService = dataSetService; + } + + public DataElementCategoryService getDataElementCategoryService() + { + return dataElementCategoryService; + } + + public void setDataElementCategoryService( DataElementCategoryService dataElementCategoryService ) + { + this.dataElementCategoryService = dataElementCategoryService; + } + +} === added file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/sms/J2MEDataValueSMSListener.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/sms/J2MEDataValueSMSListener.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/sms/J2MEDataValueSMSListener.java 2013-07-16 06:53:26 +0000 @@ -0,0 +1,555 @@ +package org.hisp.dhis.sms; + +/* + * Copyright (c) 2004-2012, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 THE COPYRIGHT OWNER 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. + */ + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.regex.Pattern; +import org.apache.commons.lang.StringUtils; +import org.hisp.dhis.dataelement.DataElement; +import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo; +import org.hisp.dhis.dataelement.DataElementCategoryService; +import org.hisp.dhis.dataset.CompleteDataSetRegistration; +import org.hisp.dhis.dataset.CompleteDataSetRegistrationService; +import org.hisp.dhis.dataset.DataSet; +import org.hisp.dhis.datavalue.DataValue; +import org.hisp.dhis.datavalue.DataValueService; +import org.hisp.dhis.organisationunit.OrganisationUnit; +import org.hisp.dhis.period.DailyPeriodType; +import org.hisp.dhis.period.MonthlyPeriodType; +import org.hisp.dhis.period.Period; +import org.hisp.dhis.period.PeriodType; +import org.hisp.dhis.period.QuarterlyPeriodType; +import org.hisp.dhis.period.WeeklyPeriodType; +import org.hisp.dhis.period.YearlyPeriodType; +import org.hisp.dhis.sms.incoming.IncomingSms; +import org.hisp.dhis.sms.incoming.IncomingSmsListener; +import org.hisp.dhis.sms.outbound.OutboundSmsService; +import org.hisp.dhis.sms.parse.ParserType; +import org.hisp.dhis.sms.parse.SMSParserException; +import org.hisp.dhis.smscommand.SMSCode; +import org.hisp.dhis.smscommand.SMSCommand; +import org.hisp.dhis.smscommand.SMSCommandService; +import org.hisp.dhis.system.util.ValidationUtils; +import org.hisp.dhis.user.User; +import org.hisp.dhis.user.UserService; + +public class J2MEDataValueSMSListener + implements IncomingSmsListener +{ + private DataValueService dataValueService; + + private DataElementCategoryService dataElementCategoryService; + + private SMSCommandService smsCommandService; + + private UserService userService; + + private CompleteDataSetRegistrationService registrationService; + + private OutboundSmsService outboundSmsService; + + @Override + public boolean accept( IncomingSms sms ) + { + String message = sms.getText(); + String commandString = null; + if ( message.indexOf( " " ) > 0 ) + { + commandString = message.substring( 0, message.indexOf( " " ) ); + message = message.substring( commandString.length() ); + } + else + { + commandString = message; + } + + return smsCommandService.getSMSCommand( commandString, ParserType.J2ME_PARSER ) != null; + } + + @Override + public void receive( IncomingSms sms ) + { + String message = sms.getText(); + String commandString = null; + if ( message.indexOf( " " ) > 0 ) + { + commandString = message.substring( 0, message.indexOf( " " ) ); + message = message.substring( commandString.length() ); + } + else + { + commandString = message; + } + + SMSCommand smsCommand = smsCommandService.getSMSCommand( commandString, ParserType.J2ME_PARSER ); + String token[] = message.split( "!" ); + Map parsedMessage = this.parse( token[1], smsCommand ); + String senderPhoneNumber = StringUtils.replace( sms.getOriginator(), "+", "" ); + Collection orgUnits = getOrganisationUnitsByPhoneNumber( senderPhoneNumber ); + + if ( orgUnits == null || orgUnits.size() == 0 ) + { + throw new SMSParserException( "No user associated with this phone number. Please contact your supervisor." ); + } + + OrganisationUnit orgUnit = this.selectOrganisationUnit( orgUnits, parsedMessage ); + Period period = this.getPeriod( token[0].trim(), smsCommand.getDataset().getPeriodType() ); + boolean valueStored = false; + + for ( SMSCode code : smsCommand.getCodes() ) + { + if ( parsedMessage.containsKey( code.getCode().toUpperCase() ) ) + { + storeDataValue( senderPhoneNumber, orgUnit, parsedMessage, code, smsCommand, period, + smsCommand.getDataset() ); + valueStored = true; + } + } + + if ( parsedMessage.isEmpty() || !valueStored ) + { + if ( StringUtils.isEmpty( smsCommand.getDefaultMessage() ) ) + { + throw new SMSParserException( "No values reported for command '" + smsCommand.getName() + "'" ); + } + else + { + throw new SMSParserException( smsCommand.getDefaultMessage() ); + } + } + + this.registerCompleteDataSet( smsCommand.getDataset(), period, orgUnit, "mobile" ); + + this.sendSuccessFeedback( senderPhoneNumber, smsCommand, parsedMessage, period, orgUnit ); + } + + private Map parse( String sms, SMSCommand smsCommand ) + { + + String[] keyValuePairs = null; + + if ( sms.indexOf( "#" ) > -1 ) + { + keyValuePairs = sms.split( "#" ); + } + else + { + keyValuePairs = new String[1]; + keyValuePairs[0] = sms; + } + + Map keyValueMap = new HashMap(); + for ( String keyValuePair : keyValuePairs ) + { + String[] token = keyValuePair.split( Pattern.quote( smsCommand.getSeparator() ) ); + keyValueMap.put( token[0], token[1] ); + } + + return keyValueMap; + } + + private void storeDataValue( String sender, OrganisationUnit orgUnit, Map parsedMessage, + SMSCode code, SMSCommand command, Period period, DataSet dataset ) + { + String upperCaseCode = code.getCode().toUpperCase(); + + String storedBy = getUser( sender ).getUsername(); + + if ( StringUtils.isBlank( storedBy ) ) + { + storedBy = "[unknown] from [" + sender + "]"; + } + + DataElementCategoryOptionCombo optionCombo = dataElementCategoryService.getDataElementCategoryOptionCombo( code + .getOptionId() ); + + DataValue dv = dataValueService.getDataValue( orgUnit, code.getDataElement(), period, optionCombo ); + + String value = parsedMessage.get( upperCaseCode ); + if ( !StringUtils.isEmpty( value ) ) + { + boolean newDataValue = false; + if ( dv == null ) + { + dv = new DataValue(); + dv.setOptionCombo( optionCombo ); + dv.setSource( orgUnit ); + dv.setDataElement( code.getDataElement() ); + dv.setPeriod( period ); + dv.setComment( "" ); + newDataValue = true; + } + + if ( StringUtils.equals( dv.getDataElement().getType(), DataElement.VALUE_TYPE_BOOL ) ) + { + if ( "Y".equals( value.toUpperCase() ) || "YES".equals( value.toUpperCase() ) ) + { + value = "true"; + } + else if ( "N".equals( value.toUpperCase() ) || "NO".equals( value.toUpperCase() ) ) + { + value = "false"; + } + } + + dv.setValue( value ); + dv.setTimestamp( new java.util.Date() ); + dv.setStoredBy( storedBy ); + + if ( ValidationUtils.dataValueIsValid( value, dv.getDataElement() ) != null ) + { + return; // not a valid value for data element + } + + if ( newDataValue ) + { + dataValueService.addDataValue( dv ); + } + else + { + dataValueService.updateDataValue( dv ); + } + } + + } + + private OrganisationUnit selectOrganisationUnit( Collection orgUnits, + Map parsedMessage ) + { + OrganisationUnit orgUnit = null; + + for ( OrganisationUnit o : orgUnits ) + { + if ( orgUnits.size() == 1 ) + { + orgUnit = o; + } + if ( parsedMessage.containsKey( "ORG" ) && o.getCode().equals( parsedMessage.get( "ORG" ) ) ) + { + orgUnit = o; + break; + } + } + + if ( orgUnit == null && orgUnits.size() > 1 ) + { + String messageListingOrgUnits = "Found more than one org unit for this number. Please specify one of the following:"; + for ( Iterator i = orgUnits.iterator(); i.hasNext(); ) + { + OrganisationUnit o = i.next(); + messageListingOrgUnits += " " + o.getName() + ":" + o.getCode(); + if ( i.hasNext() ) + { + messageListingOrgUnits += ","; + } + } + throw new SMSParserException( messageListingOrgUnits ); + } + return orgUnit; + } + + private Collection getOrganisationUnitsByPhoneNumber( String sender ) + { + Collection orgUnits = new ArrayList(); + Collection users = userService.getUsersByPhoneNumber( sender ); + for ( User u : users ) + { + if ( u.getOrganisationUnits() != null ) + { + orgUnits.addAll( u.getOrganisationUnits() ); + } + } + + return orgUnits; + } + + private User getUser( String sender ) + { + OrganisationUnit orgunit = null; + User user = null; + for ( User u : userService.getUsersByPhoneNumber( sender ) ) + { + OrganisationUnit ou = u.getOrganisationUnit(); + + // Might be undefined if the user has more than one org.units + // "attached" + if ( orgunit == null ) + { + orgunit = ou; + } + else if ( orgunit.getId() == ou.getId() ) + { + // same orgunit, no problem... + } + else + { + throw new SMSParserException( + "User is associated with more than one orgunit. Please contact your supervisor." ); + } + user = u; + } + return user; + } + + private void registerCompleteDataSet( DataSet dataSet, Period period, OrganisationUnit organisationUnit, + String storedBy ) + { + CompleteDataSetRegistration registration = new CompleteDataSetRegistration(); + + if ( registrationService.getCompleteDataSetRegistration( dataSet, period, organisationUnit ) == null ) + { + registration.setDataSet( dataSet ); + registration.setPeriod( period ); + registration.setSource( organisationUnit ); + registration.setDate( new Date() ); + registration.setStoredBy( storedBy ); + registration.setPeriodName( registration.getPeriod().toString() ); + registrationService.saveCompleteDataSetRegistration( registration, false ); + } + } + + private void sendSuccessFeedback( String sender, SMSCommand command, Map parsedMessage, + Period period, OrganisationUnit orgunit ) + { + String reportBack = "Thank you! Values entered: "; + String notInReport = "Missing values for: "; + boolean missingElements = false; + + for ( SMSCode code : command.getCodes() ) + { + + DataElementCategoryOptionCombo optionCombo = dataElementCategoryService + .getDataElementCategoryOptionCombo( code.getOptionId() ); + + DataValue dv = dataValueService.getDataValue( orgunit, code.getDataElement(), period, optionCombo ); + + if ( dv == null && !StringUtils.isEmpty( code.getCode() ) ) + { + notInReport += code.getCode() + ","; + missingElements = true; + } + else if ( dv != null ) + { + String value = dv.getValue(); + if ( StringUtils.equals( dv.getDataElement().getType(), DataElement.VALUE_TYPE_BOOL ) ) + { + if ( "true".equals( value ) ) + { + value = "Yes"; + } + else if ( "false".equals( value ) ) + { + value = "No"; + } + } + reportBack += code.getCode() + "=" + value + " "; + } + } + + notInReport = notInReport.substring( 0, notInReport.length() - 1 ); + + if ( missingElements ) + { + reportBack += notInReport; + } + + outboundSmsService.sendMessage( reportBack, sender ); + } + + public Period getPeriod( String periodName, PeriodType periodType ) + throws IllegalArgumentException + { + + if ( periodType instanceof DailyPeriodType ) + { + String pattern = "yyyy-MM-dd"; + SimpleDateFormat formatter = new SimpleDateFormat( pattern ); + Date date; + try + { + date = formatter.parse( periodName ); + } + catch ( ParseException e ) + { + throw new IllegalArgumentException( "Couldn't make a period of type " + periodType.getName() + + " and name " + periodName, e ); + } + return periodType.createPeriod( date ); + + } + + if ( periodType instanceof WeeklyPeriodType ) + { + String pattern = "yyyy-MM-dd"; + SimpleDateFormat formatter = new SimpleDateFormat( pattern ); + Date date; + try + { + date = formatter.parse( periodName ); + } + catch ( ParseException e ) + { + throw new IllegalArgumentException( "Couldn't make a period of type " + periodType.getName() + + " and name " + periodName, e ); + } + return periodType.createPeriod( date ); + } + + if ( periodType instanceof MonthlyPeriodType ) + { + int dashIndex = periodName.indexOf( '-' ); + + if ( dashIndex < 0 ) + { + return null; + } + + int month = Integer.parseInt( periodName.substring( 0, dashIndex ) ); + int year = Integer.parseInt( periodName.substring( dashIndex + 1, periodName.length() ) ); + + Calendar cal = Calendar.getInstance(); + cal.set( Calendar.YEAR, year ); + cal.set( Calendar.MONTH, month ); + + return periodType.createPeriod( cal.getTime() ); + } + + if ( periodType instanceof YearlyPeriodType ) + { + Calendar cal = Calendar.getInstance(); + cal.set( Calendar.YEAR, Integer.parseInt( periodName ) ); + + return periodType.createPeriod( cal.getTime() ); + } + + if ( periodType instanceof QuarterlyPeriodType ) + { + Calendar cal = Calendar.getInstance(); + + int month = 0; + if ( periodName.substring( 0, periodName.indexOf( " " ) ).equals( "Jan" ) ) + { + month = 1; + } + else if ( periodName.substring( 0, periodName.indexOf( " " ) ).equals( "Apr" ) ) + { + month = 4; + } + else if ( periodName.substring( 0, periodName.indexOf( " " ) ).equals( "Jul" ) ) + { + month = 6; + } + else if ( periodName.substring( 0, periodName.indexOf( " " ) ).equals( "Oct" ) ) + { + month = 10; + } + + int year = Integer.parseInt( periodName.substring( periodName.lastIndexOf( " " ) + 1 ) ); + + cal.set( Calendar.MONTH, month ); + cal.set( Calendar.YEAR, year ); + + if ( month != 0 ) + { + return periodType.createPeriod( cal.getTime() ); + } + + } + + throw new IllegalArgumentException( "Couldn't make a period of type " + periodType.getName() + " and name " + + periodName ); + } + + public DataValueService getDataValueService() + { + return dataValueService; + } + + public void setDataValueService( DataValueService dataValueService ) + { + this.dataValueService = dataValueService; + } + + public SMSCommandService getSmsCommandService() + { + return smsCommandService; + } + + public void setSmsCommandService( SMSCommandService smsCommandService ) + { + this.smsCommandService = smsCommandService; + } + + public UserService getUserService() + { + return userService; + } + + public void setUserService( UserService userService ) + { + this.userService = userService; + } + + public CompleteDataSetRegistrationService getRegistrationService() + { + return registrationService; + } + + public void setRegistrationService( CompleteDataSetRegistrationService registrationService ) + { + this.registrationService = registrationService; + } + + public OutboundSmsService getOutboundSmsService() + { + return outboundSmsService; + } + + public void setOutboundSmsService( OutboundSmsService outboundSmsService ) + { + this.outboundSmsService = outboundSmsService; + } + + public DataElementCategoryService getDataElementCategoryService() + { + return dataElementCategoryService; + } + + public void setDataElementCategoryService( DataElementCategoryService dataElementCategoryService ) + { + this.dataElementCategoryService = dataElementCategoryService; + } +} === added file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/sms/UnregisteredSMSListener.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/sms/UnregisteredSMSListener.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/sms/UnregisteredSMSListener.java 2013-07-16 06:53:26 +0000 @@ -0,0 +1,141 @@ +package org.hisp.dhis.sms; + +/* + * Copyright (c) 2004-2012, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 THE COPYRIGHT OWNER 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. + */ + +import java.util.HashSet; +import java.util.Set; +import org.hisp.dhis.message.Message; +import org.hisp.dhis.message.MessageConversation; +import org.hisp.dhis.message.MessageConversationStore; +import org.hisp.dhis.message.UserMessage; +import org.hisp.dhis.sms.incoming.IncomingSms; +import org.hisp.dhis.sms.incoming.IncomingSmsListener; +import org.hisp.dhis.sms.parse.ParserType; +import org.hisp.dhis.smscommand.SMSCommand; +import org.hisp.dhis.smscommand.SMSCommandService; +import org.hisp.dhis.user.User; +import org.hisp.dhis.user.UserCredentials; +import org.hisp.dhis.user.UserGroup; +import org.hisp.dhis.user.UserService; + +public class UnregisteredSMSListener implements IncomingSmsListener +{ + private SMSCommandService smsCommandService; + + private MessageConversationStore messageConversationStore; + + private UserService userService; + + @Override + public boolean accept( IncomingSms sms ) + { + String message = sms.getText(); + String commandString = null; + if ( message.indexOf( " " ) > 0 ) + { + commandString = message.substring( 0, message.indexOf( " " ) ); + message = message.substring( commandString.length() ); + } + else + { + commandString = message; + } + + return smsCommandService.getSMSCommand( commandString, ParserType.UNREGISTERED_PARSER ) != null; + } + + @Override + public void receive( IncomingSms sms ) + { + String message = sms.getText(); + String commandString = null; + if ( message.indexOf( " " ) > 0 ) + { + commandString = message.substring( 0, message.indexOf( " " ) ); + message = message.substring( commandString.length() ); + } + else + { + commandString = message; + } + + SMSCommand smsCommand = smsCommandService.getSMSCommand( commandString, ParserType.UNREGISTERED_PARSER ); + + UserGroup userGroup = smsCommand.getUserGroup(); + + if ( userGroup != null ) + { + Set receivers = new HashSet( userGroup.getMembers() ); + + UserCredentials anonymousUser = userService.getUserCredentialsByUsername( "system" ); + + MessageConversation conversation = new MessageConversation( smsCommand.getName(), anonymousUser.getUser() ); + + conversation.addMessage( new Message( message, null, anonymousUser.getUser() ) ); + + for ( User receiver : receivers ) + { + boolean read = false; + + conversation.addUserMessage( new UserMessage( receiver, read ) ); + } + + messageConversationStore.save( conversation ); + } + } + + public SMSCommandService getSmsCommandService() + { + return smsCommandService; + } + + public void setSmsCommandService( SMSCommandService smsCommandService ) + { + this.smsCommandService = smsCommandService; + } + + public MessageConversationStore getMessageConversationStore() + { + return messageConversationStore; + } + + public void setMessageConversationStore( MessageConversationStore messageConversationStore ) + { + this.messageConversationStore = messageConversationStore; + } + + public UserService getUserService() + { + return userService; + } + + public void setUserService( UserService userService ) + { + this.userService = userService; + } +} === added directory 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/sms/manager' === added file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/sms/manager/DefaultSmsServiceManager.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/sms/manager/DefaultSmsServiceManager.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/sms/manager/DefaultSmsServiceManager.java 2013-07-16 06:53:26 +0000 @@ -0,0 +1,113 @@ +package org.hisp.dhis.sms.manager; + +/* + * Copyright (c) 2004-2012, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 THE COPYRIGHT OWNER 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. + */ + +import java.util.Map; +import org.hisp.dhis.sms.SmsServiceException; +import org.hisp.dhis.sms.SmsServiceManager; +import org.hisp.dhis.sms.outbound.OutboundSms; + +public class DefaultSmsServiceManager + implements SmsServiceManager +{ + + @Override + public Map getGatewayMap() + { + // TODO Auto-generated method stub + return null; + } + + @Override + public void stopService() + { + // TODO Auto-generated method stub + + } + + @Override + public void startService() + { + // TODO Auto-generated method stub + + } + + @Override + public void reloadConfig() + throws SmsServiceException + { + // TODO Auto-generated method stub + + } + + @Override + public String getServiceStatus() + { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getMessageStatus() + { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getDefaultGateway() + { + // TODO Auto-generated method stub + return null; + } + + @Override + public String sendMessage( OutboundSms sms, String gatewayId ) + throws SmsServiceException + { + // TODO Auto-generated method stub + return null; + } + + @Override + public String sendMessage( OutboundSms sms ) + throws SmsServiceException + { + // TODO Auto-generated method stub + return null; + } + + @Override + public String sendMessage( String message, String phoneNumber ) + throws SmsServiceException + { + // TODO Auto-generated method stub + return null; + } + +} === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/smscommand/DefaultSMSCommandService.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/smscommand/DefaultSMSCommandService.java 2013-03-14 07:19:34 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/smscommand/DefaultSMSCommandService.java 2013-07-16 06:53:26 +0000 @@ -3,42 +3,51 @@ import java.util.Collection; import java.util.Set; +import org.hisp.dhis.sms.parse.ParserType; import org.hisp.dhis.smscommand.SMSCommandStore; -public class DefaultSMSCommandService implements SMSCommandService{ - +public class DefaultSMSCommandService + implements SMSCommandService +{ + private SMSCommandStore smsCommandStore; @Override - public void updateSMSCommand(SMSCommand cmd) { + public void updateSMSCommand( SMSCommand cmd ) + { // TODO Auto-generated method stub - + } @Override - public Collection getSMSCommands() { + public Collection getSMSCommands() + { return smsCommandStore.getSMSCommands(); } - public void setSmsCommandStore(SMSCommandStore smsCommandStore) { + public void setSmsCommandStore( SMSCommandStore smsCommandStore ) + { this.smsCommandStore = smsCommandStore; } - public void save(SMSCommand cmd){ - smsCommandStore.save(cmd); - } - - public SMSCommand getSMSCommand(int id){ - return smsCommandStore.getSMSCommand(id); - } - - - public void save(Set codes){ - smsCommandStore.save(codes); - } - - public void delete(SMSCommand cmd){ - smsCommandStore.delete(cmd); + public void save( SMSCommand cmd ) + { + smsCommandStore.save( cmd ); + } + + public SMSCommand getSMSCommand( int id ) + { + return smsCommandStore.getSMSCommand( id ); + } + + public void save( Set codes ) + { + smsCommandStore.save( codes ); + } + + public void delete( SMSCommand cmd ) + { + smsCommandStore.delete( cmd ); } @Override @@ -46,4 +55,10 @@ { return smsCommandStore.getJ2MESMSCommands(); } + + @Override + public SMSCommand getSMSCommand( String commandName, ParserType parserType ) + { + return smsCommandStore.getSMSCommand( commandName, parserType ); + } } === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/smscommand/HibernateSMSCommandStore.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/smscommand/HibernateSMSCommandStore.java 2013-04-04 18:06:19 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/smscommand/HibernateSMSCommandStore.java 2013-07-16 06:53:26 +0000 @@ -59,12 +59,12 @@ { Criteria criteria = sessionFactory.getCurrentSession().createCriteria( SMSCommand.class ); criteria.add( Restrictions.eq( "id", id ) ); - + if ( criteria.list() != null && criteria.list().size() > 0 ) { return (SMSCommand) criteria.list().get( 0 ); } - + return null; } @@ -80,7 +80,7 @@ t.commit(); s.flush(); } - + @SuppressWarnings( "unchecked" ) @Override public Collection getJ2MESMSCommands() @@ -89,4 +89,18 @@ criteria.add( Restrictions.eq( "parserType", ParserType.J2ME_PARSER ) ); return criteria.list(); } + + @Override + public SMSCommand getSMSCommand( String commandName, ParserType parserType ) + { + Criteria criteria = sessionFactory.getCurrentSession().createCriteria( SMSCommand.class ); + criteria.add( Restrictions.eq( "parserType", parserType ) ); + criteria.add( Restrictions.eq( "name", commandName ) ); + if ( criteria.list() != null && criteria.list().size() > 0 ) + { + return (SMSCommand) criteria.list().get( 0 ); + } + + return null; + } } === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml' --- dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml 2013-06-19 13:43:51 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml 2013-07-16 06:53:26 +0000 @@ -971,6 +971,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + === modified file 'dhis-2/dhis-services/dhis-service-mobile/src/main/resources/META-INF/dhis/beans.xml' --- dhis-2/dhis-services/dhis-service-mobile/src/main/resources/META-INF/dhis/beans.xml 2013-04-03 08:06:46 +0000 +++ dhis-2/dhis-services/dhis-service-mobile/src/main/resources/META-INF/dhis/beans.xml 2013-07-16 06:53:26 +0000 @@ -54,5 +54,15 @@ + + + + + + + + + + === modified file 'dhis-2/dhis-services/dhis-service-sms/pom.xml' --- dhis-2/dhis-services/dhis-service-sms/pom.xml 2013-06-19 16:47:13 +0000 +++ dhis-2/dhis-services/dhis-service-sms/pom.xml 2013-07-16 06:53:26 +0000 @@ -15,16 +15,16 @@ - org.hisp.dhis dhis-api - + + org.hisp.dhis dhis-service-core - + === modified file 'dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/outbound/HibernateOutboundSmsStore.java' --- dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/outbound/HibernateOutboundSmsStore.java 2013-06-19 18:57:37 +0000 +++ dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/outbound/HibernateOutboundSmsStore.java 2013-07-16 06:53:26 +0000 @@ -31,7 +31,6 @@ import java.sql.SQLException; import java.util.Date; import java.util.List; - import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.criterion.Order; === modified file 'dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/outbound/OutboundSmsServiceImpl.java' --- dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/outbound/OutboundSmsServiceImpl.java 2013-06-19 18:57:37 +0000 +++ dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/outbound/OutboundSmsServiceImpl.java 2013-07-16 06:53:26 +0000 @@ -100,7 +100,7 @@ { throw new SmsServiceNotEnabledException(); } - + if ( transportService != null ) { return sendMessageInternal( sms, gatewayId ); @@ -110,6 +110,43 @@ } @Override + @Transactional + public String sendMessage( OutboundSms sms ) + throws SmsServiceException + { + if ( !enabled ) + { + throw new SmsServiceNotEnabledException(); + } + + if ( transportService != null ) + { + return sendMessageInternal( sms, transportService.getDefaultGateway() ); + } + + return "outboundsms_saved"; + } + + @Override + @Transactional + public String sendMessage( String message, String phoneNumber ) + throws SmsServiceException + { + if ( !enabled ) + { + throw new SmsServiceNotEnabledException(); + } + + if ( transportService != null ) + { + String defaultGatewayId = transportService.getDefaultGateway(); + return sendMessageInternal( new OutboundSms( message, phoneNumber ), defaultGatewayId ); + } + + return "outboundsms_saved"; + } + + @Override public List getAllOutboundSms() { return outboundSmsStore.getAll(); @@ -122,13 +159,14 @@ } @Override - public void updateOutboundSms( OutboundSms sms) + public void updateOutboundSms( OutboundSms sms ) { outboundSmsStore.update( sms ); } - + @Override - public int saveOutboundSms(OutboundSms sms) { + public int saveOutboundSms( OutboundSms sms ) + { return outboundSmsStore.save( sms ); } @@ -138,7 +176,7 @@ OutboundSms sms = outboundSmsStore.get( outboundSmsId ); outboundSmsStore.delete( sms ); } - + // ------------------------------------------------------------------------- // Support methods // ------------------------------------------------------------------------- @@ -148,7 +186,7 @@ try { String message = transportService.sendMessage( sms, id ); - + return message; } catch ( SmsServiceException e ) @@ -159,4 +197,5 @@ return "Exception sending message " + sms + e.getMessage(); } } + } === modified file 'dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/outbound/SmsSender.java' --- dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/outbound/SmsSender.java 2013-07-11 07:56:43 +0000 +++ dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/outbound/SmsSender.java 2013-07-16 06:53:26 +0000 @@ -32,7 +32,6 @@ import java.util.HashSet; import java.util.List; import java.util.Set; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hisp.dhis.message.MessageSender; === modified file 'dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/outbound/TestOutboundSmsService.java' --- dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/outbound/TestOutboundSmsService.java 2013-06-19 18:57:37 +0000 +++ dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/outbound/TestOutboundSmsService.java 2013-07-16 06:53:26 +0000 @@ -162,4 +162,20 @@ { return null; } + + @Override + public String sendMessage( OutboundSms sms ) + throws SmsServiceException + { + // TODO Auto-generated method stub + return null; + } + + @Override + public String sendMessage( String message, String phoneNumber ) + throws SmsServiceException + { + // TODO Auto-generated method stub + return null; + } } === modified file 'dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/parse/DefaultParserManager.java' --- dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/parse/DefaultParserManager.java 2013-07-11 07:56:43 +0000 +++ dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/parse/DefaultParserManager.java 2013-07-16 06:53:26 +0000 @@ -27,61 +27,18 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; - -import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.hisp.dhis.dataelement.DataElement; -import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo; -import org.hisp.dhis.dataelement.DataElementCategoryService; -import org.hisp.dhis.dataset.CompleteDataSetRegistration; -import org.hisp.dhis.dataset.CompleteDataSetRegistrationService; -import org.hisp.dhis.dataset.DataSet; -import org.hisp.dhis.dataset.DataSetService; -import org.hisp.dhis.datavalue.DataValue; -import org.hisp.dhis.datavalue.DataValueService; -import org.hisp.dhis.message.Message; -import org.hisp.dhis.message.MessageConversation; -import org.hisp.dhis.message.MessageConversationStore; -import org.hisp.dhis.message.MessageSender; -import org.hisp.dhis.message.UserMessage; -import org.hisp.dhis.organisationunit.OrganisationUnit; -import org.hisp.dhis.patient.Patient; -import org.hisp.dhis.period.CalendarPeriodType; -import org.hisp.dhis.period.DailyPeriodType; -import org.hisp.dhis.period.MonthlyPeriodType; -import org.hisp.dhis.period.Period; -import org.hisp.dhis.period.PeriodType; -import org.hisp.dhis.period.QuarterlyPeriodType; -import org.hisp.dhis.period.WeeklyPeriodType; -import org.hisp.dhis.period.YearlyPeriodType; +import org.hisp.dhis.sms.DHISMessageAlertListener; +import org.hisp.dhis.sms.DataValueSMSListener; +import org.hisp.dhis.sms.J2MEDataValueSMSListener; +import org.hisp.dhis.sms.UnregisteredSMSListener; import org.hisp.dhis.sms.incoming.IncomingSms; import org.hisp.dhis.sms.incoming.IncomingSmsService; import org.hisp.dhis.sms.incoming.SmsMessageStatus; import org.hisp.dhis.sms.outbound.OutboundSms; import org.hisp.dhis.sms.outbound.OutboundSmsService; import org.hisp.dhis.sms.outbound.OutboundSmsTransportService; -import org.hisp.dhis.smscommand.SMSCode; -import org.hisp.dhis.smscommand.SMSCommand; -import org.hisp.dhis.smscommand.SMSCommandService; -import org.hisp.dhis.system.util.ValidationUtils; -import org.hisp.dhis.user.User; -import org.hisp.dhis.user.UserCredentials; -import org.hisp.dhis.user.UserGroup; -import org.hisp.dhis.user.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Required; import org.springframework.transaction.annotation.Transactional; @@ -96,47 +53,20 @@ private static final Log log = LogFactory.getLog( DefaultParserManager.class ); - private CompleteDataSetRegistrationService registrationService; - - private DataValueService dataValueService; - - private UserService userService; - - private SMSCommandService smsCommandService; + private J2MEDataValueSMSListener j2meDataValueSMSListener; + + private DataValueSMSListener dataValueSMSListener; + + private UnregisteredSMSListener unregisteredSMSListener; + + private DHISMessageAlertListener dhisMessageAlertListener; private OutboundSmsService outboundSmsService; @Autowired - private DataElementCategoryService dataElementCategoryService; - - @Autowired private OutboundSmsTransportService transportService; @Autowired - private DataSetService dataSetService; - - private MessageConversationStore messageConversationStore; - - public void setMessageConversationStore( MessageConversationStore messageConversationStore ) - { - this.messageConversationStore = messageConversationStore; - } - - private MessageSender smsMessageSender; - - public void setSmsMessageSender( MessageSender smsMessageSender ) - { - this.smsMessageSender = smsMessageSender; - } - - private MessageSender emailMessageSender; - - public void setEmailMessageSender( MessageSender emailMessageSender ) - { - this.emailMessageSender = emailMessageSender; - } - - @Autowired private IncomingSmsService incomingSmsService; @Transactional @@ -145,13 +75,30 @@ { try { - parse( sms.getOriginator(), sms ); - sms.setStatus( SmsMessageStatus.PROCESSED ); - incomingSmsService.update( sms ); + if ( dataValueSMSListener.accept( sms ) ) + { + dataValueSMSListener.receive( sms ); + } + else if ( j2meDataValueSMSListener.accept( sms ) ) + { + j2meDataValueSMSListener.receive( sms ); + } + else if ( dhisMessageAlertListener.accept( sms ) ) + { + dhisMessageAlertListener.receive( sms ); + } + else if ( unregisteredSMSListener.accept( sms ) ) + { + unregisteredSMSListener.receive( sms ); + } + else + { + throw new SMSParserException( "Command does not exist" ); + } } catch ( SMSParserException e ) { - e.printStackTrace(); + log.error( e.getMessage() ); sms.setStatus( SmsMessageStatus.FAILED ); incomingSmsService.update( sms ); sendSMS( e.getMessage(), sms.getOriginator() ); @@ -168,884 +115,55 @@ } } - @Transactional - private void parse( String sender, IncomingSms sms ) - throws SMSParserException - { - String message = sms.getText(); - if ( StringUtils.isEmpty( sender ) ) - { - return; - } - - sender = StringUtils.replace( sender, "+", "" ); - - if ( StringUtils.isEmpty( message ) ) - { - throw new SMSParserException( "No command in SMS" ); - } - - String commandString = null; - // here, check command first - if ( message.indexOf( " " ) > 0 ) - { - commandString = message.substring( 0, message.indexOf( " " ) ); - message = message.substring( commandString.length() ); - } - else - { - commandString = message; - } - - boolean foundCommand = false; - - Collection orgUnits = getOrganisationUnitsByPhoneNumber( sender ); - - for ( SMSCommand command : smsCommandService.getSMSCommands() ) - { - if ( command.getName().equalsIgnoreCase( commandString ) ) - { - foundCommand = true; - if ( ParserType.KEY_VALUE_PARSER.equals( command.getParserType() ) ) - { - checkIfDHISUsers( orgUnits, sender ); - runKeyValueParser( sender, message, orgUnits, command ); - break; - } - else if ( ParserType.J2ME_PARSER.equals( command.getParserType() ) ) - { - checkIfDHISUsers( orgUnits, sender ); - runJ2MEParser( sender, message, orgUnits, command ); - break; - } - else if ( ParserType.ALERT_PARSER.equals( command.getParserType() ) ) - { - checkIfDHISUsers( orgUnits, sender ); - runDhisMessageAlertParser( sender, message, command ); - break; - } - else if ( ParserType.UNREGISTERED_PARSER.equals( command.getParserType() ) ) - { - runUnregisteredParser( sender, message, command ); - break; - } - } - } - if ( !foundCommand ) - { - Collection patientList = new ArrayList(); //TODO FIX! //patientService.getPatientsByPhone( sender, null, null ); - - if ( !patientList.isEmpty() ) - { - for ( Patient each : patientList ) - { - if ( each.getHealthWorker() != null ) - { - UserCredentials patientUser = userService.getUserCredentialsByUsername( "system" ); - - MessageConversation conversation = new MessageConversation( "Patients' Message", patientUser.getUser() ); - - conversation.addMessage( new Message( sms.getText().trim(), null, patientUser.getUser() ) ); - - conversation.addUserMessage( new UserMessage( each.getHealthWorker(), false ) ); - - messageConversationStore.save( conversation ); - } - } - } - else - { - throw new SMSParserException( "Command '" + commandString + "' does not exist" ); - } - } - } - - protected Collection getOrganisationUnitsByPhoneNumber( String sender ) - { - Collection orgUnits = new ArrayList(); - Collection users = userService.getUsersByPhoneNumber( sender ); - for ( User u : users ) - { - if ( u.getOrganisationUnits() != null ) - { - orgUnits.addAll( u.getOrganisationUnits() ); - } - } - - return orgUnits; - } - - private void checkIfDHISUsers( Collection orgUnits, String sender ) - { - if ( orgUnits == null || orgUnits.size() == 0 ) - { - log.info( "No user found for phone number: " + sender ); - throw new SMSParserException( "No user associated with this phone number. Please contact your supervisor." ); - } - } - - private void runKeyValueParser( String sender, String message, Collection orgUnits, - SMSCommand command ) - { - IParser p = new SMSParserKeyValue(); - if ( !StringUtils.isBlank( command.getSeparator() ) ) - { - p.setSeparator( command.getSeparator() ); - } - - Map parsedMessage = p.parse( message ); - Date date = lookForDate( message ); - OrganisationUnit orgUnit = selectOrganisationUnit( orgUnits, parsedMessage ); - Period period = getPeriod( command, date ); - - // Check if Data Set is locked - if ( dataSetService.isLocked( command.getDataset(), period, orgUnit, null ) ) - { - throw new SMSParserException( "Dataset is locked for the period " + period.getStartDate() + " - " - + period.getEndDate() ); - } - - boolean valueStored = false; - for ( SMSCode code : command.getCodes() ) - { - if ( parsedMessage.containsKey( code.getCode().toUpperCase() ) ) - { - valueStored = storeDataValue( sender, orgUnit, parsedMessage, code, command, date, - command.getDataset(), formIsComplete( command, parsedMessage ) ); - } - } - - if ( parsedMessage.isEmpty() ) - { - if ( StringUtils.isEmpty( command.getDefaultMessage() ) ) - { - throw new SMSParserException( "No values reported for command '" + command.getName() + "'" ); - } - else - { - throw new SMSParserException( command.getDefaultMessage() ); - } - } - else if ( !valueStored ) - { - throw new SMSParserException( "Wrong format for command '" + command.getName() + "'" ); - } - - markCompleteDataSet( sender, orgUnit, parsedMessage, command, date ); - sendSuccessFeedback( sender, command, parsedMessage, date, orgUnit ); - } - - private void runDhisMessageAlertParser( String senderNumber, String message, SMSCommand command ) - { - UserGroup userGroup = command.getUserGroup(); - - if ( userGroup != null ) - { - Collection users = userService.getUsersByPhoneNumber( senderNumber ); - - if ( users != null && users.size() > 1 ) - { - String messageMoreThanOneUser = "System only accepts sender's number assigned for one user, but found more than one user for this number: "; - for ( Iterator i = users.iterator(); i.hasNext(); ) - { - User user = i.next(); - messageMoreThanOneUser += " " + user.getName(); - if ( i.hasNext() ) - { - messageMoreThanOneUser += ","; - } - } - throw new SMSParserException( messageMoreThanOneUser ); - } - else if ( users != null && users.size() == 1 ) - { - User sender = users.iterator().next(); - - Set receivers = new HashSet( userGroup.getMembers() ); - - // forward to user group by SMS - smsMessageSender.sendMessage( command.getName(), message, sender, receivers, true ); - - // forward to user group by E-mail - emailMessageSender.sendMessage( command.getName(), message, sender, receivers, false ); - - // forward to user group by dhis message - if ( sender != null ) - { - receivers.add( sender ); - } - - MessageConversation conversation = new MessageConversation( command.getName(), sender ); - - conversation.addMessage( new Message( message, null, sender ) ); - - for ( User receiver : receivers ) - { - boolean read = receiver != null && receiver.equals( sender ); - - conversation.addUserMessage( new UserMessage( receiver, read ) ); - } - messageConversationStore.save( conversation ); - // confirm SMS was received and forwarded completely - Set feedbackList = new HashSet(); - feedbackList.add( sender ); - smsMessageSender.sendMessage( command.getName(), command.getReceivedMessage(), null, feedbackList, true ); - } - } - } - - private void runUnregisteredParser( String senderNumber, String message, SMSCommand command ) - { - UserGroup userGroup = command.getUserGroup(); - - if ( userGroup != null ) - { - Set receivers = new HashSet( userGroup.getMembers() ); - - UserCredentials anonymousUser = userService.getUserCredentialsByUsername( "system" ); - - MessageConversation conversation = new MessageConversation( command.getName(), anonymousUser.getUser() ); - - conversation.addMessage( new Message( message, null, anonymousUser.getUser() ) ); - - for ( User receiver : receivers ) - { - boolean read = false; - - conversation.addUserMessage( new UserMessage( receiver, read ) ); - } - - messageConversationStore.save( conversation ); - } - } - - protected OrganisationUnit selectOrganisationUnit( Collection orgUnits, - Map parsedMessage ) - { - OrganisationUnit orgUnit = null; - - for ( OrganisationUnit o : orgUnits ) - { - if ( orgUnits.size() == 1 ) - { - orgUnit = o; - } - if ( parsedMessage.containsKey( "ORG" ) && o.getCode().equals( parsedMessage.get( "ORG" ) ) ) - { - orgUnit = o; - break; - } - } - - if ( orgUnit == null && orgUnits.size() > 1 ) - { - String messageListingOrgUnits = "Found more than one org unit for this number. Please specify one of the following:"; - for ( Iterator i = orgUnits.iterator(); i.hasNext(); ) - { - OrganisationUnit o = i.next(); - messageListingOrgUnits += " " + o.getName() + ":" + o.getCode(); - if ( i.hasNext() ) - { - messageListingOrgUnits += ","; - } - } - throw new SMSParserException( messageListingOrgUnits ); - } - return orgUnit; - } - - protected void sendSuccessFeedback( String sender, SMSCommand command, Map parsedMessage, - Date date, OrganisationUnit orgunit ) - { - String reportBack = "Thank you! Values entered: "; - String notInReport = "Missing values for: "; - - Period period = null; - - Map codesWithDataValues = new TreeMap(); - List codesWithoutDataValues = new ArrayList(); - - for ( SMSCode code : command.getCodes() ) - { - - DataElementCategoryOptionCombo optionCombo = dataElementCategoryService - .getDataElementCategoryOptionCombo( code.getOptionId() ); - - period = getPeriod( command, date ); - - DataValue dv = dataValueService.getDataValue( orgunit, code.getDataElement(), period, optionCombo ); - - if ( dv == null && !StringUtils.isEmpty( code.getCode() ) ) - { - codesWithoutDataValues.add( code.getCode() ); - } - else if ( dv != null ) - { - codesWithDataValues.put( code.getCode(), dv ); - } - } - - for ( String key : codesWithDataValues.keySet() ) - { - DataValue dv = codesWithDataValues.get( key ); - String value = dv.getValue(); - if ( StringUtils.equals( dv.getDataElement().getType(), DataElement.VALUE_TYPE_BOOL ) ) - { - if ( "true".equals( value ) ) - { - value = "Yes"; - } - else if ( "false".equals( value ) ) - { - value = "No"; - } - } - reportBack += key + "=" + value + " "; - } - - Collections.sort( codesWithoutDataValues ); - - for ( String key : codesWithoutDataValues ) - { - notInReport += key + ","; - } - notInReport = notInReport.substring( 0, notInReport.length() - 1 ); - - if ( codesWithoutDataValues.size() > 0 ) - { - sendSMS( reportBack + notInReport, sender ); - } - else - { - sendSMS( reportBack, sender ); - } - } - - protected Period getPeriod( SMSCommand command, Date date ) - { - - Period period; - period = command.getDataset().getPeriodType().createPeriod(); - CalendarPeriodType cpt = (CalendarPeriodType) period.getPeriodType(); - if ( command.isCurrentPeriodUsedForReporting() ) - { - period = cpt.createPeriod( new Date() ); - } - else - { - period = cpt.getPreviousPeriod( period ); - } - - if ( date != null ) - { - period = cpt.createPeriod( date ); - } - - return period; - } - - private Date lookForDate( String message ) - { - if ( !message.contains( " " ) ) - { - return null; - } - - Date date = null; - String dateString = message.trim().split( " " )[0]; - SimpleDateFormat format = new SimpleDateFormat( "ddMM" ); - - try - { - Calendar cal = Calendar.getInstance(); - date = format.parse( dateString ); - cal.setTime( date ); - int year = Calendar.getInstance().get( Calendar.YEAR ); - int month = Calendar.getInstance().get( Calendar.MONTH ); - if ( cal.get( Calendar.MONTH ) < month ) - { - cal.set( Calendar.YEAR, year ); - } - else - { - cal.set( Calendar.YEAR, year - 1 ); - } - date = cal.getTime(); - } - catch ( Exception e ) - { - // no date found - } - return date; - } - - private boolean storeDataValue( String sender, OrganisationUnit orgunit, Map parsedMessage, - SMSCode code, SMSCommand command, Date date, DataSet dataSet, boolean completeForm ) - { - String upperCaseCode = code.getCode().toUpperCase(); - - String storedBy = getUser( sender ).getUsername(); - - if ( StringUtils.isBlank( storedBy ) ) - { - storedBy = "[unknown] from [" + sender + "]"; - } - - DataElementCategoryOptionCombo optionCombo = dataElementCategoryService.getDataElementCategoryOptionCombo( code - .getOptionId() ); - - Period period = getPeriod( command, date ); - - DataValue dv = dataValueService.getDataValue( orgunit, code.getDataElement(), period, optionCombo ); - - String value = parsedMessage.get( upperCaseCode ); - if ( !StringUtils.isEmpty( value ) ) - { - boolean newDataValue = false; - if ( dv == null ) - { - dv = new DataValue(); - dv.setOptionCombo( optionCombo ); - dv.setSource( orgunit ); - dv.setDataElement( code.getDataElement() ); - dv.setPeriod( period ); - dv.setComment( "" ); - newDataValue = true; - } - - if ( StringUtils.equals( dv.getDataElement().getType(), DataElement.VALUE_TYPE_BOOL ) ) - { - if ( "Y".equals( value.toUpperCase() ) || "YES".equals( value.toUpperCase() ) ) - { - value = "true"; - } - else if ( "N".equals( value.toUpperCase() ) || "NO".equals( value.toUpperCase() ) ) - { - value = "false"; - } - } - else if ( StringUtils.equals( dv.getDataElement().getType(), DataElement.VALUE_TYPE_INT ) ) - { - try - { - Integer.parseInt( value ); - } - catch ( NumberFormatException e ) - { - return false; - } - - } - - dv.setValue( value ); - dv.setTimestamp( new java.util.Date() ); - dv.setStoredBy( storedBy ); - - if ( newDataValue ) - { - dataValueService.addDataValue( dv ); - } - else - { - dataValueService.updateDataValue( dv ); - } - } - - return true; - } - - /* Checks if all defined data codes have values in the database */ - private void markCompleteDataSet( String sender, OrganisationUnit orgunit, Map parsedMessage, - SMSCommand command, Date date ) - { - - Period period = null; - - for ( SMSCode code : command.getCodes() ) - { - - DataElementCategoryOptionCombo optionCombo = dataElementCategoryService - .getDataElementCategoryOptionCombo( code.getOptionId() ); - - period = getPeriod( command, date ); - - DataValue dv = dataValueService.getDataValue( orgunit, code.getDataElement(), period, optionCombo ); - - if ( dv == null && !StringUtils.isEmpty( code.getCode() ) ) - { - return; // not marked as complete - } - } - - String storedBy = getUser( sender ).getUsername(); - - if ( StringUtils.isBlank( storedBy ) ) - { - storedBy = "[unknown] from [" + sender + "]"; - } - - // if new values are submitted re-register as complete - deregisterCompleteDataSet( command.getDataset(), period, orgunit ); - registerCompleteDataSet( command.getDataset(), period, orgunit, storedBy ); - - } - - private boolean formIsComplete( SMSCommand command, Map parsedMessage ) - { - for ( SMSCode code : command.getCodes() ) - { - if ( !parsedMessage.containsKey( code.getCode().toUpperCase() ) ) - { - return false; - } - } - return true; - } - - private void registerCompleteDataSet( DataSet dataSet, Period period, OrganisationUnit organisationUnit, - String storedBy ) - { - CompleteDataSetRegistration registration = new CompleteDataSetRegistration(); - - if ( registrationService.getCompleteDataSetRegistration( dataSet, period, organisationUnit ) == null ) - { - registration.setDataSet( dataSet ); - registration.setPeriod( period ); - registration.setSource( organisationUnit ); - registration.setDate( new Date() ); - registration.setStoredBy( storedBy ); - registration.setPeriodName( registration.getPeriod().toString() ); - registrationService.saveCompleteDataSetRegistration( registration, false ); - log.info( "DataSet registered as complete: " + registration ); - } - } - - private void deregisterCompleteDataSet( DataSet dataSet, Period period, OrganisationUnit organisationUnit ) - { - CompleteDataSetRegistration registration = registrationService.getCompleteDataSetRegistration( dataSet, period, - organisationUnit ); - - if ( registration != null ) - { - registrationService.deleteCompleteDataSetRegistration( registration ); - - log.info( "DataSet un-registered as complete: " + registration ); - } - } - - private User getUser( String sender ) - { - OrganisationUnit orgunit = null; - User user = null; - for ( User u : userService.getUsersByPhoneNumber( sender ) ) - { - OrganisationUnit ou = u.getOrganisationUnit(); - - // Might be undefined if the user has more than one org.units - // "attached" - if ( orgunit == null ) - { - orgunit = ou; - } - else if ( orgunit.getId() == ou.getId() ) - { - // same orgunit, no problem... - } - else - { - throw new SMSParserException( - "User is associated with more than one orgunit. Please contact your supervisor." ); - } - user = u; - } - return user; - } - - // Run the J2ME parser for mobile - private void runJ2MEParser( String sender, String message, Collection orgUnits, SMSCommand command ) - { - J2MEDataEntryParser j2meParser = new J2MEDataEntryParser(); - j2meParser.setSmsCommand( command ); - message = message.trim(); - - if ( !StringUtils.isBlank( command.getSeparator() ) ) - { - j2meParser.setSeparator( command.getSeparator() ); - } - String token[] = message.split( "!" ); - Period period = getPeriod( token[0].trim(), command.getDataset().getPeriodType() ); - Map parsedMessage = j2meParser.parse( token[1] ); - OrganisationUnit orgUnit = selectOrganisationUnit( orgUnits, parsedMessage ); - - boolean valueStored = false; - for ( SMSCode code : command.getCodes() ) - { - if ( parsedMessage.containsKey( code.getCode().toUpperCase() ) ) - { - storeDataValue( sender, orgUnit, parsedMessage, code, command, period, command.getDataset(), - formIsComplete( command, parsedMessage ) ); - valueStored = true; - } - } - - if ( parsedMessage.isEmpty() || !valueStored ) - { - if ( StringUtils.isEmpty( command.getDefaultMessage() ) ) - { - throw new SMSParserException( "No values reported for command '" + command.getName() + "'" ); - } - else - { - throw new SMSParserException( command.getDefaultMessage() ); - } - } - - registerCompleteDataSet( command.getDataset(), period, orgUnit, "mobile" ); - - sendSuccessFeedback( sender, command, parsedMessage, period, orgUnit ); - } - - private void sendSuccessFeedback( String sender, SMSCommand command, Map parsedMessage, - Period period, OrganisationUnit orgUnit ) - { - String reportBack = "Thank you! Values entered: "; - String notInReport = "Missing values for: "; - boolean missingElements = false; - - for ( SMSCode code : command.getCodes() ) - { - - DataElementCategoryOptionCombo optionCombo = dataElementCategoryService - .getDataElementCategoryOptionCombo( code.getOptionId() ); - - DataValue dv = dataValueService.getDataValue( orgUnit, code.getDataElement(), period, optionCombo ); - - if ( dv == null && !StringUtils.isEmpty( code.getCode() ) ) - { - notInReport += code.getCode() + ","; - missingElements = true; - } - else if ( dv != null ) - { - String value = dv.getValue(); - if ( StringUtils.equals( dv.getDataElement().getType(), DataElement.VALUE_TYPE_BOOL ) ) - { - if ( "true".equals( value ) ) - { - value = "Yes"; - } - else if ( "false".equals( value ) ) - { - value = "No"; - } - } - reportBack += code.getCode() + "=" + value + " "; - } - } - - notInReport = notInReport.substring( 0, notInReport.length() - 1 ); - - if ( missingElements ) - { - sendSMS( reportBack + notInReport, sender ); - } - else - { - sendSMS( reportBack, sender ); - } - - } - - private void storeDataValue( String sender, OrganisationUnit orgUnit, Map parsedMessage, - SMSCode code, SMSCommand command, Period period, DataSet dataset, boolean formIsComplete ) - { - String upperCaseCode = code.getCode().toUpperCase(); - - String storedBy = getUser( sender ).getUsername(); - - if ( StringUtils.isBlank( storedBy ) ) - { - storedBy = "[unknown] from [" + sender + "]"; - } - - DataElementCategoryOptionCombo optionCombo = dataElementCategoryService.getDataElementCategoryOptionCombo( code - .getOptionId() ); - - DataValue dv = dataValueService.getDataValue( orgUnit, code.getDataElement(), period, optionCombo ); - - String value = parsedMessage.get( upperCaseCode ); - if ( !StringUtils.isEmpty( value ) ) - { - boolean newDataValue = false; - if ( dv == null ) - { - dv = new DataValue(); - dv.setOptionCombo( optionCombo ); - dv.setSource( orgUnit ); - dv.setDataElement( code.getDataElement() ); - dv.setPeriod( period ); - dv.setComment( "" ); - newDataValue = true; - } - - if ( StringUtils.equals( dv.getDataElement().getType(), DataElement.VALUE_TYPE_BOOL ) ) - { - if ( "Y".equals( value.toUpperCase() ) || "YES".equals( value.toUpperCase() ) ) - { - value = "true"; - } - else if ( "N".equals( value.toUpperCase() ) || "NO".equals( value.toUpperCase() ) ) - { - value = "false"; - } - } - - dv.setValue( value ); - dv.setTimestamp( new java.util.Date() ); - dv.setStoredBy( storedBy ); - - if ( ValidationUtils.dataValueIsValid( value, dv.getDataElement() ) != null ) - { - return; // not a valid value for data element - } - - if ( newDataValue ) - { - dataValueService.addDataValue( dv ); - } - else - { - dataValueService.updateDataValue( dv ); - } - } - - } - - public static Period getPeriod( String periodName, PeriodType periodType ) - throws IllegalArgumentException - { - - if ( periodType instanceof DailyPeriodType ) - { - String pattern = "yyyy-MM-dd"; - SimpleDateFormat formatter = new SimpleDateFormat( pattern ); - Date date; - try - { - date = formatter.parse( periodName ); - } - catch ( ParseException e ) - { - throw new IllegalArgumentException( "Couldn't make a period of type " + periodType.getName() - + " and name " + periodName, e ); - } - return periodType.createPeriod( date ); - - } - - if ( periodType instanceof WeeklyPeriodType ) - { - String pattern = "yyyy-MM-dd"; - SimpleDateFormat formatter = new SimpleDateFormat( pattern ); - Date date; - try - { - date = formatter.parse( periodName ); - } - catch ( ParseException e ) - { - throw new IllegalArgumentException( "Couldn't make a period of type " + periodType.getName() - + " and name " + periodName, e ); - } - return periodType.createPeriod( date ); - } - - if ( periodType instanceof MonthlyPeriodType ) - { - int dashIndex = periodName.indexOf( '-' ); - - if ( dashIndex < 0 ) - { - return null; - } - - int month = Integer.parseInt( periodName.substring( 0, dashIndex ) ); - int year = Integer.parseInt( periodName.substring( dashIndex + 1, periodName.length() ) ); - - Calendar cal = Calendar.getInstance(); - cal.set( Calendar.YEAR, year ); - cal.set( Calendar.MONTH, month ); - - return periodType.createPeriod( cal.getTime() ); - } - - if ( periodType instanceof YearlyPeriodType ) - { - Calendar cal = Calendar.getInstance(); - cal.set( Calendar.YEAR, Integer.parseInt( periodName ) ); - - return periodType.createPeriod( cal.getTime() ); - } - - if ( periodType instanceof QuarterlyPeriodType ) - { - Calendar cal = Calendar.getInstance(); - - int month = 0; - if ( periodName.substring( 0, periodName.indexOf( " " ) ).equals( "Jan" ) ) - { - month = 1; - } - else if ( periodName.substring( 0, periodName.indexOf( " " ) ).equals( "Apr" ) ) - { - month = 4; - } - else if ( periodName.substring( 0, periodName.indexOf( " " ) ).equals( "Jul" ) ) - { - month = 6; - } - else if ( periodName.substring( 0, periodName.indexOf( " " ) ).equals( "Oct" ) ) - { - month = 10; - } - - int year = Integer.parseInt( periodName.substring( periodName.lastIndexOf( " " ) + 1 ) ); - - cal.set( Calendar.MONTH, month ); - cal.set( Calendar.YEAR, year ); - - if ( month != 0 ) - { - return periodType.createPeriod( cal.getTime() ); - } - - } - - throw new IllegalArgumentException( "Couldn't make a period of type " + periodType.getName() + " and name " - + periodName ); - } - - public void setDataElementCategoryService( DataElementCategoryService dataElementCategoryService ) - { - this.dataElementCategoryService = dataElementCategoryService; - } - - @Required - public void setSmsCommandService( SMSCommandService smsCommandService ) - { - this.smsCommandService = smsCommandService; - } - - @Required - public void setDataValueService( DataValueService dataValueService ) - { - this.dataValueService = dataValueService; - } - - @Required - public void setUserService( UserService userService ) - { - this.userService = userService; + @Required + public IncomingSmsService getIncomingSmsService() + { + return incomingSmsService; + } + + public J2MEDataValueSMSListener getJ2meDataValueSMSListener() + { + return j2meDataValueSMSListener; + } + + public void setJ2meDataValueSMSListener( J2MEDataValueSMSListener j2meDataValueSMSListener ) + { + this.j2meDataValueSMSListener = j2meDataValueSMSListener; + } + + public DataValueSMSListener getDataValueSMSListener() + { + return dataValueSMSListener; + } + + public void setDataValueSMSListener( DataValueSMSListener dataValueSMSListener ) + { + this.dataValueSMSListener = dataValueSMSListener; + } + + public UnregisteredSMSListener getUnregisteredSMSListener() + { + return unregisteredSMSListener; + } + + public void setUnregisteredSMSListener( UnregisteredSMSListener unregisteredSMSListener ) + { + this.unregisteredSMSListener = unregisteredSMSListener; + } + + public DHISMessageAlertListener getDhisMessageAlertListener() + { + return dhisMessageAlertListener; + } + + public void setDhisMessageAlertListener( DHISMessageAlertListener dhisMessageAlertListener ) + { + this.dhisMessageAlertListener = dhisMessageAlertListener; + } + + public OutboundSmsService getOutboundSmsService() + { + return outboundSmsService; } public void setOutboundSmsService( OutboundSmsService outboundSmsService ) @@ -1053,14 +171,4 @@ this.outboundSmsService = outboundSmsService; } - public void setRegistrationService( CompleteDataSetRegistrationService registrationService ) - { - this.registrationService = registrationService; - } - - @Required - public IncomingSmsService getIncomingSmsService() - { - return incomingSmsService; - } } === removed file 'dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/parse/DhisMessageAlertParser.java' --- dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/parse/DhisMessageAlertParser.java 2013-06-19 18:57:37 +0000 +++ dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/parse/DhisMessageAlertParser.java 1970-01-01 00:00:00 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2004-2012, University of Oslo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * * 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. - * * Neither the name of the HISP project nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 THE COPYRIGHT OWNER 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.hisp.dhis.sms.parse; - -import java.util.HashMap; -import java.util.Map; - - /** - * @author Nguyen Kim Lai - */ -public class DhisMessageAlertParser - implements IParser -{ - @Override - public Map parse( String sms ) - { - HashMap output = new HashMap(); - - String userGroupCode = sms.substring( 0, sms.indexOf( " " ) ); - String content = sms.substring( userGroupCode.length()); - - output.put( userGroupCode.trim(), content.trim() ); - - return output; - } - - @Override - public void setSeparator( String separator ) - { - } -} === removed file 'dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/parse/J2MEDataEntryParser.java' --- dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/parse/J2MEDataEntryParser.java 2013-06-19 18:57:37 +0000 +++ dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/parse/J2MEDataEntryParser.java 1970-01-01 00:00:00 +0000 @@ -1,90 +0,0 @@ -package org.hisp.dhis.sms.parse; - -/* - * Copyright (c) 2004-2012, University of Oslo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * * 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. - * * Neither the name of the HISP project nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 THE COPYRIGHT OWNER 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. - */ - -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Pattern; - -import org.hisp.dhis.smscommand.SMSCommand; - -public class J2MEDataEntryParser - implements IParser -{ - private SMSCommand smsCommand; - - public J2MEDataEntryParser() - { - } - - public J2MEDataEntryParser( SMSCommand smsCommand ) - { - this.smsCommand = smsCommand; - } - - @Override - public Map parse( String sms ) - { - String[] keyValuePairs = null; - - if ( sms.indexOf( "#" ) > -1 ) - { - keyValuePairs = sms.split( "#" ); - } - else - { - keyValuePairs = new String[1]; - keyValuePairs[0] = sms; - } - - Map keyValueMap = new HashMap(); - for ( String keyValuePair : keyValuePairs ) - { - String[] token = keyValuePair.split( Pattern.quote( smsCommand.getSeparator() ) ); - keyValueMap.put( token[0], token[1] ); - } - - return keyValueMap; - } - - @Override - public void setSeparator( String separator ) - { - // TODO Auto-generated method stub - } - - public SMSCommand getSmsCommand() - { - return smsCommand; - } - - public void setSmsCommand( SMSCommand smsCommand ) - { - this.smsCommand = smsCommand; - } -} === removed file 'dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/parse/SMSParserKeyValue.java' --- dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/parse/SMSParserKeyValue.java 2013-06-19 17:22:47 +0000 +++ dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/parse/SMSParserKeyValue.java 1970-01-01 00:00:00 +0000 @@ -1,51 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package org.hisp.dhis.sms.parse; - -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.commons.lang.StringUtils; - -/** - * @author Magnus Korvald - */ -public class SMSParserKeyValue - implements IParser -{ - // "(\\w+)\\s*\\*\\s*([\\w ]+)\\s*(\\*|$)*\\s*"; - // = "([a-zA-Z]+)\\s*(\\d+)"; - private String defaultPattern = "([a-zA-Z]+)\\s*(\\d+)"; - - private Pattern pattern = Pattern.compile( defaultPattern ); - - @Override - public Map parse( String sms ) - { - HashMap output = new HashMap(); - - Matcher m = pattern.matcher( sms ); - while ( m.find() ) - { - String key = m.group( 1 ); - String value = m.group( 2 ); - - if ( !StringUtils.isEmpty( key ) && !StringUtils.isEmpty( value ) ) - { - output.put( key.toUpperCase(), value ); - } - } - - return output; - } - - public void setSeparator( String separator ) - { - String x = "(\\w+)\\s*\\" + separator.trim() + "\\s*([\\w ]+)\\s*(\\" + separator.trim() + "|$)*\\s*"; - pattern = Pattern.compile( x ); - } -} === modified file 'dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/smslib/SmsLibService.java' --- dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/smslib/SmsLibService.java 2013-06-19 18:57:37 +0000 +++ dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/smslib/SmsLibService.java 2013-07-16 06:53:26 +0000 @@ -572,4 +572,20 @@ return gatewayId; } + + @Override + public String sendMessage( OutboundSms sms ) + throws SmsServiceException + { + // TODO Auto-generated method stub + return null; + } + + @Override + public String sendMessage( String message, String phoneNumber ) + throws SmsServiceException + { + // TODO Auto-generated method stub + return null; + } } === modified file 'dhis-2/dhis-services/dhis-service-sms/src/main/resources/META-INF/dhis/beans.xml' --- dhis-2/dhis-services/dhis-service-sms/src/main/resources/META-INF/dhis/beans.xml 2013-06-17 03:27:43 +0000 +++ dhis-2/dhis-services/dhis-service-sms/src/main/resources/META-INF/dhis/beans.xml 2013-07-16 06:53:26 +0000 @@ -55,14 +55,11 @@ - - - - - - - + + + + === modified file 'dhis-2/dhis-web/dhis-web-caseentry/src/main/java/org/hisp/dhis/caseentry/action/caseentry/GetDataRecordsAction.java' --- dhis-2/dhis-web/dhis-web-caseentry/src/main/java/org/hisp/dhis/caseentry/action/caseentry/GetDataRecordsAction.java 2013-06-07 08:28:04 +0000 +++ dhis-2/dhis-web/dhis-web-caseentry/src/main/java/org/hisp/dhis/caseentry/action/caseentry/GetDataRecordsAction.java 2013-07-16 06:53:26 +0000 @@ -33,7 +33,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; - import org.hisp.dhis.caseentry.state.SelectedStateManager; import org.hisp.dhis.common.Grid; import org.hisp.dhis.common.comparator.IdentifiableObjectNameComparator;