dhis2-devs team mailing list archive
-
dhis2-devs team
-
Mailing list archive
-
Message #22552
[Branch ~dhis2-devs-core/dhis2/trunk] Rev 10863: new ValidationService (currenly only used in EventService), will properly validate DataElement an...
------------------------------------------------------------
revno: 10863
committer: Morten Olav Hansen <mortenoh@xxxxxxxxx>
branch nick: dhis2
timestamp: Fri 2013-05-17 13:44:41 +0700
message:
new ValidationService (currenly only used in EventService), will properly validate DataElement and their values (including optionsets, usernames, etc)
added:
dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/DefaultValidationService.java
dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/ValidationService.java
modified:
dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/event/BaseEventService.java
dhis-2/dhis-dxf2/src/main/resources/META-INF/dhis/beans.xml
dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/ValidationUtils.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-dxf2/src/main/java/org/hisp/dhis/dxf2/DefaultValidationService.java'
--- dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/DefaultValidationService.java 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/DefaultValidationService.java 2013-05-17 06:44:41 +0000
@@ -0,0 +1,164 @@
+package org.hisp.dhis.dxf2;
+
+/*
+ * Copyright (c) 2004-2013, 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 org.hisp.dhis.dataelement.DataElement;
+import org.hisp.dhis.i18n.I18nFormat;
+import org.hisp.dhis.i18n.I18nManager;
+import org.hisp.dhis.i18n.I18nManagerException;
+import org.hisp.dhis.i18n.locale.LocaleManager;
+import org.hisp.dhis.system.util.MathUtils;
+import org.hisp.dhis.user.UserService;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+public class DefaultValidationService implements ValidationService
+{
+ // -------------------------------------------------------------------------
+ // Dependencies
+ // -------------------------------------------------------------------------
+
+ @Autowired
+ private I18nManager i18nManager;
+
+ @Autowired
+ private UserService userService;
+
+ // -------------------------------------------------------------------------
+ // ValidationService Implementation
+ // -------------------------------------------------------------------------
+
+ @Override
+ public ValidationStatus validateDataElement( DataElement dataElement, String value )
+ {
+ I18nFormat format;
+
+ try
+ {
+ format = i18nManager.getI18nFormat();
+ }
+ catch ( I18nManagerException ex )
+ {
+ return new ValidationStatus( false, ex.getMessage() );
+ }
+
+ value = value.trim();
+
+ if ( value.length() >= 255 )
+ {
+ return new ValidationStatus( false, value + " is more than 255 characters." );
+ }
+
+ if ( dataElement.getType().equals( DataElement.VALUE_TYPE_BOOL ) )
+ {
+ if ( !(value.equalsIgnoreCase( "true" ) || value.equalsIgnoreCase( "false" )) )
+ {
+ return new ValidationStatus( false, value + " is not a valid boolean expression." );
+ }
+ }
+ else if ( dataElement.getType().equals( DataElement.VALUE_TYPE_TRUE_ONLY ) )
+ {
+ if ( !value.equalsIgnoreCase( "true" ) )
+ {
+ return new ValidationStatus( false, value + " can only be true." );
+ }
+ }
+ else if ( dataElement.getType().equals( DataElement.VALUE_TYPE_DATE ) )
+ {
+ boolean dateIsValidated = format.parseDate( value ) != null;
+
+ if ( !dateIsValidated )
+ {
+ return new ValidationStatus( false, value + " is not a valid date expression." );
+ }
+ }
+ else if ( dataElement.getType().equals( DataElement.VALUE_TYPE_USER_NAME ) )
+ {
+ if ( userService.getUserCredentialsByUsername( value ) == null )
+ {
+ return new ValidationStatus( false, value + " is not a valid username." );
+ }
+ }
+ else if ( dataElement.getType().equals( DataElement.VALUE_TYPE_STRING ) )
+ {
+ if ( dataElement.getOptionSet() != null )
+ {
+ if ( !dataElement.getOptionSet().getOptions().contains( value ) )
+ {
+ return new ValidationStatus( false, value + " is not a valid option for this optionSet." );
+ }
+ }
+ else if ( dataElement.getTextType().equals( DataElement.VALUE_TYPE_TEXT ) ||
+ dataElement.getTextType().equals( DataElement.VALUE_TYPE_LONG_TEXT ) )
+ {
+ // no validation for this right now, we already to length validation
+ }
+ }
+ else if ( dataElement.getType().equals( DataElement.VALUE_TYPE_NUMBER ) )
+ {
+ if ( !MathUtils.isNumeric( value ) )
+ {
+ return new ValidationStatus( false, value + " is not a valid number." );
+ }
+
+ if ( dataElement.getOptionSet() != null )
+ {
+ if ( !dataElement.getOptionSet().getOptions().contains( value ) )
+ {
+ return new ValidationStatus( false, value + " is not a valid option for this optionSet." );
+ }
+ }
+
+ if ( dataElement.getNumberType().equals( DataElement.VALUE_TYPE_INT ) )
+ {
+ if ( !MathUtils.isInteger( value ) )
+ {
+ return new ValidationStatus( false, value + " is not a valid integer." );
+ }
+ }
+ else if ( dataElement.getNumberType().equals( DataElement.VALUE_TYPE_POSITIVE_INT ) )
+ {
+ if ( !MathUtils.isPositiveInteger( value ) )
+ {
+ return new ValidationStatus( false, value + " is not a valid positive integer." );
+ }
+ }
+ else if ( dataElement.getNumberType().equals( DataElement.VALUE_TYPE_NEGATIVE_INT ) )
+ {
+ if ( !MathUtils.isNegativeInteger( value ) )
+ {
+ return new ValidationStatus( false, value + " is not a valid negative integer." );
+ }
+ }
+ }
+
+ return new ValidationStatus( true );
+ }
+}
=== added file 'dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/ValidationService.java'
--- dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/ValidationService.java 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/ValidationService.java 2013-05-17 06:44:41 +0000
@@ -0,0 +1,66 @@
+package org.hisp.dhis.dxf2;
+
+/*
+ * Copyright (c) 2004-2013, 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 org.hisp.dhis.dataelement.DataElement;
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+public interface ValidationService
+{
+ class ValidationStatus
+ {
+ private boolean success;
+
+ private String message;
+
+ public ValidationStatus( boolean success )
+ {
+ this.success = success;
+ }
+
+ public ValidationStatus( boolean success, String message )
+ {
+ this.success = success;
+ this.message = message;
+ }
+
+ public boolean isSuccess()
+ {
+ return success;
+ }
+
+ public String getMessage()
+ {
+ return message;
+ }
+ }
+
+ ValidationStatus validateDataElement( DataElement dataElement, String value );
+}
=== modified file 'dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/event/BaseEventService.java'
--- dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/event/BaseEventService.java 2013-05-17 03:29:07 +0000
+++ dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/event/BaseEventService.java 2013-05-17 06:44:41 +0000
@@ -29,6 +29,7 @@
import org.hisp.dhis.dataelement.DataElement;
import org.hisp.dhis.dataelement.DataElementService;
+import org.hisp.dhis.dxf2.ValidationService;
import org.hisp.dhis.dxf2.importsummary.ImportConflict;
import org.hisp.dhis.dxf2.importsummary.ImportStatus;
import org.hisp.dhis.dxf2.importsummary.ImportSummary;
@@ -82,8 +83,13 @@
private PatientDataValueService patientDataValueService;
@Autowired
+ private ValidationService validationService;
+
+ @Autowired
private I18nManager i18nManager;
+ private I18nFormat format;
+
// -------------------------------------------------------------------------
// Implementation
// -------------------------------------------------------------------------
@@ -122,8 +128,6 @@
private ImportSummary saveSingleEventWithoutRegistration( Program program, OrganisationUnit organisationUnit, Event event )
{
- I18nFormat format = null;
-
try
{
format = i18nManager.getI18nFormat();
@@ -141,6 +145,7 @@
}
ImportSummary importSummary = new ImportSummary();
+ importSummary.setStatus( ImportStatus.SUCCESS );
ProgramStageInstance programStageInstance = saveExecutionDate( program, organisationUnit, executionDate, event.getCompleted() );
@@ -155,16 +160,31 @@
}
else
{
- saveDataValue( programStageInstance, dataElement, dataValue.getValue(), dataValue.getProvidedElsewhere() );
- importSummary.getDataValueCount().incrementImported();
+ if ( validateDataElement( dataElement, dataValue.getValue(), importSummary ) )
+ {
+ saveDataValue( programStageInstance, dataElement, dataValue.getValue(), dataValue.getProvidedElsewhere() );
+ importSummary.getDataValueCount().incrementImported();
+ }
}
}
- importSummary.setStatus( ImportStatus.SUCCESS );
-
return importSummary;
}
+ private boolean validateDataElement( DataElement dataElement, String value, ImportSummary importSummary )
+ {
+ ValidationService.ValidationStatus status = validationService.validateDataElement( dataElement, value );
+
+ if ( !status.isSuccess() )
+ {
+ importSummary.getConflicts().add( new ImportConflict( dataElement.getUid(), status.getMessage() ) );
+ importSummary.getDataValueCount().incrementIgnored();
+ return false;
+ }
+
+ return true;
+ }
+
private ProgramStageInstance saveExecutionDate( Program program, OrganisationUnit organisationUnit, Date date, Boolean completed )
{
ProgramStage programStage = program.getProgramStages().iterator().next();
=== modified file 'dhis-2/dhis-dxf2/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-dxf2/src/main/resources/META-INF/dhis/beans.xml 2013-05-17 03:29:07 +0000
+++ dhis-2/dhis-dxf2/src/main/resources/META-INF/dhis/beans.xml 2013-05-17 06:44:41 +0000
@@ -16,6 +16,8 @@
<bean id="org.hisp.dhis.dxf2.event.EventService" class="org.hisp.dhis.dxf2.event.JacksonEventService" />
+ <bean id="org.hisp.dhis.dxf2.ValidationService" class="org.hisp.dhis.dxf2.DefaultValidationService" />
+
<!-- register idObject handlers -->
<bean id="organisationUnitObjectHandler"
=== modified file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/ValidationUtils.java'
--- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/ValidationUtils.java 2013-04-19 15:58:28 +0000
+++ dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/ValidationUtils.java 2013-05-17 06:44:41 +0000
@@ -1,7 +1,7 @@
package org.hisp.dhis.system.util;
/*
- * Copyright (c) 2004-2012, University of Oslo
+ * Copyright (c) 2004-2013, University of Oslo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,17 +27,17 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+import org.apache.commons.validator.routines.DateValidator;
+import org.apache.commons.validator.routines.EmailValidator;
+import org.apache.commons.validator.routines.UrlValidator;
+import org.hisp.dhis.dataelement.DataElement;
+
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.apache.commons.validator.routines.DateValidator;
-import org.apache.commons.validator.routines.EmailValidator;
-import org.apache.commons.validator.routines.UrlValidator;
-import org.hisp.dhis.dataelement.DataElement;
-
import static org.hisp.dhis.dataelement.DataElement.*;
/**
@@ -49,15 +49,15 @@
private static Pattern POINT_PATTERN = Pattern.compile( "\\[(.+),\\s?(.+)\\]" );
private static Pattern DIGIT_PATTERN = Pattern.compile( ".*\\d.*" );
private static Pattern UPPERCASE_PATTERN = Pattern.compile( ".*[A-Z].*" );
-
+
private static int LONG_MAX = 180;
private static int LONG_MIN = -180;
private static int LAT_MAX = 90;
private static int LAT_MIN = -90;
-
+
/**
* Validates whether an email string is valid.
- *
+ *
* @param email the email string.
* @return true if the email string is valid, false otherwise.
*/
@@ -65,11 +65,11 @@
{
return EmailValidator.getInstance().isValid( email );
}
-
+
/**
* Validates whether a date string is valid for the given Locale.
- *
- * @param date the date string.
+ *
+ * @param date the date string.
* @param locale the Locale
* @return true if the date string is valid, false otherwise.
*/
@@ -80,7 +80,7 @@
/**
* Validates whether a date string is valid for the default Locale.
- *
+ *
* @param date the date string.
* @return true if the date string is valid, false otherwise.
*/
@@ -88,10 +88,10 @@
{
return dateIsValid( date, null );
}
-
+
/**
* Validates whether an URL string is valid.
- *
+ *
* @param url the URL string.
* @return true if the URL string is valid, false otherwise.
*/
@@ -99,16 +99,16 @@
{
return new UrlValidator().isValid( url );
}
-
+
/**
* Validates whether a password is valid. A password must:
- *
+ * <p/>
* <ul>
* <li>Be between 8 and 80 characters long</li>
* <li>Include at least one digit</li>
* <li>Include at least one uppercase letter</li>
* </ul>
- *
+ *
* @param password the password.
* @return true if the password is valid, false otherwise.
*/
@@ -118,13 +118,13 @@
{
return false;
}
-
+
return DIGIT_PATTERN.matcher( password ).matches() && UPPERCASE_PATTERN.matcher( password ).matches();
}
-
+
/**
* Validates whether a coordinate is valid.
- *
+ *
* @return true if the coordinate is valid, false otherwise.
*/
public static boolean coordinateIsValid( String coordinate )
@@ -133,17 +133,17 @@
{
return false;
}
-
+
Matcher matcher = POINT_PATTERN.matcher( coordinate );
-
+
if ( !matcher.find() )
{
return false;
}
-
+
double longitude = 0.0;
double latitude = 0.0;
-
+
try
{
longitude = Double.parseDouble( matcher.group( 1 ) );
@@ -153,15 +153,15 @@
{
return false;
}
-
+
return longitude >= LONG_MIN && longitude <= LONG_MAX && latitude >= LAT_MIN && latitude <= LAT_MAX;
}
-
+
/**
* Returns the longitude from the given coordinate. Returns null if the
* coordinate string is not valid. The coordinate is on the form
* longitude / latitude.
- *
+ *
* @param coordinate the coordinate string.
* @return the longitude.
*/
@@ -171,9 +171,9 @@
{
return null;
}
-
+
Matcher matcher = POINT_PATTERN.matcher( coordinate );
-
+
return matcher.find() ? matcher.group( 1 ) : null;
}
@@ -181,7 +181,7 @@
* Returns the latitude from the given coordinate. Returns null if the
* coordinate string is not valid. The coordinate is on the form
* longitude / latitude.
- *
+ *
* @param coordinate the coordinate string.
* @return the latitude.
*/
@@ -191,31 +191,31 @@
{
return null;
}
-
+
Matcher matcher = POINT_PATTERN.matcher( coordinate );
-
+
return matcher.find() ? matcher.group( 2 ) : null;
}
/**
- * Returns a coordinate string based on the given latitude and longitude.
+ * Returns a coordinate string based on the given latitude and longitude.
* The coordinate is on the form longitude / latitude.
- *
+ *
* @param longitude the longitude string.
- * @param latitude the latitude string.
+ * @param latitude the latitude string.
* @return a coordinate string.
*/
public static String getCoordinate( String longitude, String latitude )
{
return "[" + longitude + "," + latitude + "]";
}
-
+
/**
* Checks if the given data value is valid according to the value type of the
* given data element. Considers the value to be valid if null or empty.
* Returns a string if the valid is invalid, possible
* values are:
- *
+ * <p/>
* <ul>
* <li>value_null_or_empty</li>
* <li>data_element_or_type_null_or_empty</li>
@@ -226,8 +226,8 @@
* <li>value_not_negative_integer</li>
* <li>value_is_zero_and_not_zero_significant</li>
* </ul>
- *
- * @param value the data value.
+ *
+ * @param value the data value.
* @param dataElement the data element.
* @return null if the value is valid, a string if not.
*/
@@ -237,47 +237,47 @@
{
return null;
}
-
+
if ( dataElement == null || dataElement.getType() == null || dataElement.getType().isEmpty() )
{
return "data_element_or_type_null_or_empty";
}
-
+
List<String> types = Arrays.asList( VALUE_TYPE_STRING, VALUE_TYPE_INT, VALUE_TYPE_NUMBER, VALUE_TYPE_POSITIVE_INT, VALUE_TYPE_NEGATIVE_INT );
-
+
String type = dataElement.getDetailedNumberType();
-
+
if ( types.contains( type ) && value.length() > 255 )
{
return "value_length_greater_than_max_length";
}
-
+
if ( VALUE_TYPE_NUMBER.equals( type ) && !MathUtils.isNumeric( value ) )
{
return "value_not_numeric";
}
-
+
if ( VALUE_TYPE_INT.equals( type ) && !MathUtils.isInteger( value ) )
{
return "value_not_integer";
}
-
+
if ( VALUE_TYPE_POSITIVE_INT.equals( type ) && !MathUtils.isPositiveInteger( value ) )
{
return "value_not_positive_integer";
}
-
+
if ( VALUE_TYPE_NEGATIVE_INT.equals( type ) && !MathUtils.isNegativeInteger( value ) )
{
return "value_not_negative_integer";
}
-
- if ( VALUE_TYPE_INT.equals( dataElement.getType() ) && MathUtils.isZero( value ) &&
+
+ if ( VALUE_TYPE_INT.equals( dataElement.getType() ) && MathUtils.isZero( value ) &&
!dataElement.isZeroIsSignificant() && !AGGREGATION_OPERATOR_AVERAGE.equals( dataElement.getAggregationOperator() ) )
{
return "value_is_zero_and_not_zero_significant";
}
-
+
return null;
- }
+ }
}