← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 11404: clean up service sms, default parser, move the sms listeners to dhis-service-core, add interface ...

 

------------------------------------------------------------
revno: 11404
committer: Long <Long@Long-Laptop>
branch nick: dhis2
timestamp: Tue 2013-07-16 13:53:26 +0700
message:
  clean up service sms, default parser, move the sms listeners to dhis-service-core, add interface for sms service to api
removed:
  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/J2MEDataEntryParser.java
  dhis-2/dhis-services/dhis-service-sms/src/main/java/org/hisp/dhis/sms/parse/SMSParserKeyValue.java
added:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/sms/SmsConsumer.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/sms/SmsServiceManager.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/sms/
  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/DataValueSMSListener.java
  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/UnregisteredSMSListener.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/sms/manager/
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/sms/manager/DefaultSmsServiceManager.java
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/sms/outbound/OutboundSmsService.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/smscommand/SMSCommandService.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/smscommand/SMSCommandStore.java
  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/HibernateSMSCommandStore.java
  dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-services/dhis-service-mobile/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-services/dhis-service-sms/pom.xml
  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/OutboundSmsServiceImpl.java
  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/TestOutboundSmsService.java
  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/smslib/SmsLibService.java
  dhis-2/dhis-services/dhis-service-sms/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-web/dhis-web-caseentry/src/main/java/org/hisp/dhis/caseentry/action/caseentry/GetDataRecordsAction.java


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== 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<String, String> 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<OutboundSms> getAllOutboundSms();
-    
-    int saveOutboundSms( OutboundSms sms);
-
-    void updateOutboundSms( OutboundSms sms);
-    
+
+    int saveOutboundSms( OutboundSms sms );
+
+    void updateOutboundSms( OutboundSms sms );
+
     void deleteById( Integer outboundSmsId );
-    
+
     List<OutboundSms> 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<SMSCommand> 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<SMSCommand> getSMSCommands();
@@ -43,4 +45,6 @@
     void save( Set<SMSCode> codes );
     
     Collection<SMSCommand> 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<User> 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<User> 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<User> receivers = new HashSet<User>( 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<User> feedbackList = new HashSet<User>();
+                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<String, String> parsedMessage = this.parse( message, smsCommand );
+        Date date = lookForDate( message );
+        String senderPhoneNumber = StringUtils.replace( sms.getOriginator(), "+", "" );
+        Collection<OrganisationUnit> 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<String, String> parse( String sms, SMSCommand smsCommand )
+    {
+        HashMap<String, String> output = new HashMap<String, String>();
+        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<OrganisationUnit> getOrganisationUnitsByPhoneNumber( String sender )
+    {
+        Collection<OrganisationUnit> orgUnits = new ArrayList<OrganisationUnit>();
+        Collection<User> users = userService.getUsersByPhoneNumber( sender );
+        for ( User u : users )
+        {
+            if ( u.getOrganisationUnits() != null )
+            {
+                orgUnits.addAll( u.getOrganisationUnits() );
+            }
+        }
+
+        return orgUnits;
+    }
+
+    private OrganisationUnit selectOrganisationUnit( Collection<OrganisationUnit> orgUnits,
+        Map<String, String> 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<OrganisationUnit> 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<String, String> 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<String, String> 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<String, String> parsedMessage,
+        Date date, OrganisationUnit orgunit )
+    {
+        String reportBack = "Thank you! Values entered: ";
+        String notInReport = "Missing values for: ";
+
+        Period period = null;
+
+        Map<String, DataValue> codesWithDataValues = new TreeMap<String, DataValue>();
+        List<String> codesWithoutDataValues = new ArrayList<String>();
+
+        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<String, String> parsedMessage = this.parse( token[1], smsCommand );
+        String senderPhoneNumber = StringUtils.replace( sms.getOriginator(), "+", "" );
+        Collection<OrganisationUnit> 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<String, String> parse( String sms, SMSCommand smsCommand )
+    {
+
+        String[] keyValuePairs = null;
+
+        if ( sms.indexOf( "#" ) > -1 )
+        {
+            keyValuePairs = sms.split( "#" );
+        }
+        else
+        {
+            keyValuePairs = new String[1];
+            keyValuePairs[0] = sms;
+        }
+
+        Map<String, String> keyValueMap = new HashMap<String, String>();
+        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<String, String> 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<OrganisationUnit> orgUnits,
+        Map<String, String> 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<OrganisationUnit> 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<OrganisationUnit> getOrganisationUnitsByPhoneNumber( String sender )
+    {
+        Collection<OrganisationUnit> orgUnits = new ArrayList<OrganisationUnit>();
+        Collection<User> 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<String, String> 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<User> receivers = new HashSet<User>( 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<String, String> 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<SMSCommand> getSMSCommands() {
+    public Collection<SMSCommand> 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<SMSCode> 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<SMSCode> 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<SMSCommand> 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 @@
     <property name="operandService" ref="org.hisp.dhis.dataelement.DataElementOperandService" />
   </bean>
 
+  <!-- SMS Listener -->
+  
+  <bean id="org.hisp.dhis.sms.DataValueSMSListener" class="org.hisp.dhis.sms.DataValueSMSListener">
+    <property name="registrationService" ref="org.hisp.dhis.dataset.CompleteDataSetRegistrationService" />
+    <property name="dataValueService" ref="org.hisp.dhis.datavalue.DataValueService" />
+    <property name="outboundSmsService" ref="org.hisp.dhis.sms.outbound.OutboundSmsService" />
+    <property name="userService" ref="org.hisp.dhis.user.UserService" />
+    <property name="smsCommandService" ref="smsCommandService" />
+    <property name="dataSetService" ref="org.hisp.dhis.dataset.DataSetService" />
+    <property name="dataElementCategoryService" ref="org.hisp.dhis.dataelement.DataElementCategoryService" />
+  </bean>
+  
+   <bean id="org.hisp.dhis.sms.UnregisteredSMSListener" class="org.hisp.dhis.sms.UnregisteredSMSListener">
+    <property name="messageConversationStore" ref="org.hisp.dhis.message.MessageConversationStore" />
+    <property name="userService" ref="org.hisp.dhis.user.UserService" />
+    <property name="smsCommandService" ref="smsCommandService" />
+  </bean>
+  
+   <bean id="org.hisp.dhis.sms.DHISMessageAlertListener" class="org.hisp.dhis.sms.DHISMessageAlertListener">
+    <property name="smsMessageSender" ref="org.hisp.dhis.sms.outbound.SmsSender" />
+    <property name="emailMessageSender" ref="emailMessageSender" />
+    <property name="messageConversationStore" ref="org.hisp.dhis.message.MessageConversationStore" />
+    <property name="userService" ref="org.hisp.dhis.user.UserService" />
+    <property name="smsCommandService" ref="smsCommandService" />
+  </bean>
+  
+   <bean id="org.hisp.dhis.sms.J2MEDataValueSMSListener" class="org.hisp.dhis.sms.J2MEDataValueSMSListener">
+    <property name="dataValueService" ref="org.hisp.dhis.datavalue.DataValueService" />
+    <property name="dataElementCategoryService" ref="org.hisp.dhis.dataelement.DataElementCategoryService" />
+    <property name="smsCommandService" ref="smsCommandService" />
+    <property name="userService" ref="org.hisp.dhis.user.UserService" />
+    <property name="registrationService" ref="org.hisp.dhis.dataset.CompleteDataSetRegistrationService" />
+    <property name="outboundSmsService" ref="org.hisp.dhis.sms.outbound.OutboundSmsService" />
+  </bean>
+  
   <!-- DeletionManager -->
 
   <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">

=== 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 @@
     <property name="clazz" value="org.hisp.dhis.patient.PatientMobileSetting"/>
     <property name="sessionFactory" ref="sessionFactory"/>
   </bean>
+  
+   <bean id="org.hisp.dhis.mobile.sms.J2MEDataValueSMSListener" class="org.hisp.dhis.mobile.sms.J2MEDataValueSMSListener">
+    <property name="dataValueService" ref="org.hisp.dhis.datavalue.DataValueService" />
+    <property name="dataElementCategoryService" ref="org.hisp.dhis.dataelement.DataElementCategoryService" />
+    <property name="smsCommandService" ref="smsCommandService" />
+    <property name="userService" ref="org.hisp.dhis.user.UserService" />
+    <property name="registrationService" ref="org.hisp.dhis.dataset.CompleteDataSetRegistrationService" />
+    <property name="outboundSmsService" ref="org.hisp.dhis.sms.outbound.OutboundSmsService" />
+  </bean>
+  
 
 </beans>

=== 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 @@
   <dependencies>
 
     <!-- DHIS -->
-
     <dependency>
       <groupId>org.hisp.dhis</groupId>
       <artifactId>dhis-api</artifactId>
     </dependency>
-    <dependency>
+    
+   <dependency>
       <groupId>org.hisp.dhis</groupId>
       <artifactId>dhis-service-core</artifactId>
     </dependency>
-
+    
     <!-- SMS -->
 
     <dependency>

=== 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<OutboundSms> 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<OrganisationUnit> 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<Patient> patientList = new ArrayList<Patient>(); //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<OrganisationUnit> getOrganisationUnitsByPhoneNumber( String sender )
-    {
-        Collection<OrganisationUnit> orgUnits = new ArrayList<OrganisationUnit>();
-        Collection<User> users = userService.getUsersByPhoneNumber( sender );
-        for ( User u : users )
-        {
-            if ( u.getOrganisationUnits() != null )
-            {
-                orgUnits.addAll( u.getOrganisationUnits() );
-            }
-        }
-
-        return orgUnits;
-    }
-
-    private void checkIfDHISUsers( Collection<OrganisationUnit> 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<OrganisationUnit> orgUnits,
-        SMSCommand command )
-    {
-        IParser p = new SMSParserKeyValue();
-        if ( !StringUtils.isBlank( command.getSeparator() ) )
-        {
-            p.setSeparator( command.getSeparator() );
-        }
-
-        Map<String, String> 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<User> 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<User> 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<User> receivers = new HashSet<User>( 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<User> feedbackList = new HashSet<User>();
-                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<User> receivers = new HashSet<User>( 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<OrganisationUnit> orgUnits,
-        Map<String, String> 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<OrganisationUnit> 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<String, String> parsedMessage,
-        Date date, OrganisationUnit orgunit )
-    {
-        String reportBack = "Thank you! Values entered: ";
-        String notInReport = "Missing values for: ";
-
-        Period period = null;
-
-        Map<String, DataValue> codesWithDataValues = new TreeMap<String, DataValue>();
-        List<String> codesWithoutDataValues = new ArrayList<String>();
-
-        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<String, String> 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<String, String> 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<String, String> 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<OrganisationUnit> 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<String, String> 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<String, String> 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<String, String> 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<String, String> parse( String sms )
-    {
-        HashMap<String, String> output = new HashMap<String, String>();
-        
-        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<String, String> parse( String sms )
-    {
-        String[] keyValuePairs = null;
-        
-        if ( sms.indexOf( "#" ) > -1 )
-        {
-            keyValuePairs = sms.split( "#" );
-        }
-        else
-        {
-            keyValuePairs = new String[1];
-            keyValuePairs[0] = sms;
-        }
-
-        Map<String, String> keyValueMap = new HashMap<String, String>();
-        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<String, String> parse( String sms )
-    {
-        HashMap<String, String> output = new HashMap<String, String>();
-
-        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 @@
 
   <bean id="org.hisp.dhis.sms.parse.DefaultParserManager" class="org.hisp.dhis.sms.parse.DefaultParserManager"
     depends-on="org.hisp.dhis.user.UserService">
-    <property name="userService" ref="org.hisp.dhis.user.UserService" />
-    <property name="smsCommandService" ref="smsCommandService" />
-    <property name="dataValueService" ref="org.hisp.dhis.datavalue.DataValueService" />
     <property name="outboundSmsService" ref="org.hisp.dhis.sms.outbound.OutboundSmsService" />  
-    <property name="registrationService" ref="org.hisp.dhis.dataset.CompleteDataSetRegistrationService" />
-    <property name="messageConversationStore" ref="org.hisp.dhis.message.MessageConversationStore" />
-    <property name="smsMessageSender" ref="org.hisp.dhis.sms.outbound.SmsSender" />
-    <property name="emailMessageSender" ref="emailMessageSender" />
+    <property name="dataValueSMSListener" ref="org.hisp.dhis.sms.DataValueSMSListener" />
+    <property name="j2meDataValueSMSListener" ref="org.hisp.dhis.sms.J2MEDataValueSMSListener" />
+    <property name="unregisteredSMSListener" ref="org.hisp.dhis.sms.UnregisteredSMSListener" />
+    <property name="dhisMessageAlertListener" ref="org.hisp.dhis.sms.DHISMessageAlertListener" />
   </bean>
   
 </beans>

=== 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;