dhis2-devs team mailing list archive
-
dhis2-devs team
-
Mailing list archive
-
Message #39133
[Branch ~dhis2-devs-core/dhis2/trunk] Rev 19846: Event analytics. Impl support for variables value_count and zero_pos_value_count
------------------------------------------------------------
revno: 19846
committer: Lars Helge Overland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Tue 2015-08-25 16:09:25 +0200
message:
Event analytics. Impl support for variables value_count and zero_pos_value_count
added:
dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/RegexUtils.java
dhis-2/dhis-api/src/test/java/org/hisp/dhis/program/
dhis-2/dhis-api/src/test/java/org/hisp/dhis/program/ProgramIndicatorTest.java
modified:
dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramIndicator.java
dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramIndicatorService.java
dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/program/DefaultProgramIndicatorService.java
dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/user/DefaultUserService.java
dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/util/TextUtils.java
dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/webapp/dhis-web-maintenance-program/programIndicatorForm.vm
--
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/common/RegexUtils.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/RegexUtils.java 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/RegexUtils.java 2015-08-25 14:09:25 +0000
@@ -0,0 +1,64 @@
+package org.hisp.dhis.common;
+
+/*
+ * Copyright (c) 2004-2015, 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 java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author Lars Helge Overland
+ */
+public class RegexUtils
+{
+ /**
+ * Return the matches in the given input based on the given pattern.
+ *
+ * @param pattern the pattern.
+ * @param input the input.
+ * @param group the group, can be null.
+ * @return a set of matches.
+ */
+ public static Set<String> getMatches( Pattern pattern, String input, Integer group )
+ {
+ group = group != null ? group : 0;
+
+ Set<String> set = new HashSet<>();
+
+ Matcher matcher = pattern.matcher( input );
+
+ while ( matcher.find() )
+ {
+ set.add( matcher.group( group ) );
+ }
+
+ return set;
+ }
+}
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramIndicator.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramIndicator.java 2015-08-25 09:48:55 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramIndicator.java 2015-08-25 14:09:25 +0000
@@ -28,6 +28,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+import java.util.Set;
import java.util.regex.Pattern;
import org.hisp.dhis.analytics.AggregationType;
@@ -36,6 +37,7 @@
import org.hisp.dhis.common.DxfNamespaces;
import org.hisp.dhis.common.IdentifiableObject;
import org.hisp.dhis.common.MergeStrategy;
+import org.hisp.dhis.common.RegexUtils;
import org.hisp.dhis.common.view.DetailedView;
import org.hisp.dhis.common.view.ExportView;
@@ -44,6 +46,7 @@
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
+import com.google.common.collect.Sets;
/**
* @author Chau Thu Tran
@@ -132,7 +135,21 @@
{
return aggregationType != null ? aggregationType : AggregationType.AVERAGE;
}
-
+
+ /**
+ * Returns a set of data element and attribute identifiers part of the given
+ * input expression.
+ *
+ * @param input the expression.
+ * @return a set of UIDs.
+ */
+ public static Set<String> getDataElementAndAttributeIdentifiers( String input )
+ {
+ return Sets.union(
+ RegexUtils.getMatches( DATAELEMENT_PATTERN, input, 2 ),
+ RegexUtils.getMatches( ATTRIBUTE_PATTERN, input, 1 ) );
+ }
+
// -------------------------------------------------------------------------
// Getters && Setters
// -------------------------------------------------------------------------
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramIndicatorService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramIndicatorService.java 2015-08-21 03:14:08 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramIndicatorService.java 2015-08-25 14:09:25 +0000
@@ -33,6 +33,7 @@
import java.util.Set;
import org.hisp.dhis.constant.Constant;
+import org.hisp.dhis.dataelement.DataElement;
import org.hisp.dhis.trackedentity.TrackedEntityAttribute;
/**
@@ -156,7 +157,7 @@
* {@link ProgramIndicator.INVALID_VARIABLES_IN_EXPRESSION}.
*/
String filterIsValid( String filter );
-
+
/**
* Get all {@link ProgramStageDataElement} part of the expression.
*
=== added directory 'dhis-2/dhis-api/src/test/java/org/hisp/dhis/program'
=== added file 'dhis-2/dhis-api/src/test/java/org/hisp/dhis/program/ProgramIndicatorTest.java'
--- dhis-2/dhis-api/src/test/java/org/hisp/dhis/program/ProgramIndicatorTest.java 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/test/java/org/hisp/dhis/program/ProgramIndicatorTest.java 2015-08-25 14:09:25 +0000
@@ -0,0 +1,51 @@
+package org.hisp.dhis.program;
+
+/*
+ * Copyright (c) 2004-2015, 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 static org.junit.Assert.assertEquals;
+
+import java.util.Set;
+import org.junit.Test;
+import com.google.common.collect.Sets;
+
+/**
+* @author Lars Helge Overland
+*/
+public class ProgramIndicatorTest
+{
+ @Test
+ public void testGetIdentifiers()
+ {
+ String expression = "#{chG8sINMf11.yD5mUKAm3aK} + #{chG8sINMf11.UaGD9u0kaur} - A{y1Bhi6xHtVk}";
+
+ Set<String> expected = Sets.newHashSet( "yD5mUKAm3aK", "UaGD9u0kaur", "y1Bhi6xHtVk" );
+
+ assertEquals( expected, ProgramIndicator.getDataElementAndAttributeIdentifiers( expression ) );
+ }
+}
=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/program/DefaultProgramIndicatorService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/program/DefaultProgramIndicatorService.java 2015-08-25 09:48:55 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/program/DefaultProgramIndicatorService.java 2015-08-25 14:09:25 +0000
@@ -353,7 +353,7 @@
while ( matcher.find() )
{
String key = matcher.group( 1 );
- String uid = statementBuilder.columnQuote( matcher.group( 2 ) );
+ String val = matcher.group( 2 );
if ( ProgramIndicator.KEY_DATAELEMENT.equals( key ) )
{
@@ -363,17 +363,26 @@
}
else if ( ProgramIndicator.KEY_ATTRIBUTE.equals( key ) )
{
- matcher.appendReplacement( buffer, uid );
+ matcher.appendReplacement( buffer, statementBuilder.columnQuote( val ) );
}
else if ( ProgramIndicator.KEY_CONSTANT.equals( key ) )
{
- Constant constant = constantService.getConstant( uid );
+ Constant constant = constantService.getConstant( val );
if ( constant != null )
{
matcher.appendReplacement( buffer, String.valueOf( constant.getValue() ) );
}
}
+ else if ( ProgramIndicator.KEY_PROGRAM_VARIABLE.equals( key ) )
+ {
+ String sql = getVariableAsSql( val, expression );
+
+ if ( sql != null )
+ {
+ matcher.appendReplacement( buffer, sql );
+ }
+ }
}
expression = TextUtils.appendTail( matcher, buffer );
@@ -758,6 +767,47 @@
return MathUtils.calculateExpression( expression );
}
+
+ /**
+ * Creates a SQL select clause from the given program indicator variable
+ * based on the given expression. Wraps the count variables with
+ * <code>nullif</code> to avoid potential division by zero.
+ *
+ * @param var the program indicator variable.
+ * @param expression the program indicator expression.
+ * @return a SQL select clause.
+ */
+ private String getVariableAsSql( String var, String expression )
+ {
+ if ( ProgramIndicator.VAR_EXECUTION_DATE.equals( var ) )
+ {
+ return "executiondate";
+ }
+ else if ( ProgramIndicator.VAR_VALUE_COUNT.equals( var ) )
+ {
+ String sql = "nullif((";
+
+ for ( String uid : ProgramIndicator.getDataElementAndAttributeIdentifiers( expression ) )
+ {
+ sql += "case when " + statementBuilder.columnQuote( uid ) + " is not null then 1 else 0 end + ";
+ }
+
+ return TextUtils.removeLast( sql, "+" ) + "),0)";
+ }
+ else if ( ProgramIndicator.VAR_ZERO_POS_VALUE_COUNT.equals( var ) )
+ {
+ String sql = "nullif((";
+
+ for ( String uid : ProgramIndicator.getDataElementAndAttributeIdentifiers( expression ) )
+ {
+ sql += "case when " + statementBuilder.columnQuote( uid ) + " > 0 then 1 else 0 end + ";
+ }
+
+ return TextUtils.removeLast( sql, "+" ) + "),0)";
+ }
+
+ return null;
+ }
private boolean isZeroOrPositive( String value )
{
=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/user/DefaultUserService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/user/DefaultUserService.java 2015-08-25 13:54:00 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/user/DefaultUserService.java 2015-08-25 14:09:25 +0000
@@ -267,19 +267,19 @@
public boolean validateUserQueryParams( UserQueryParams params )
{
- if ( params.isCanManage() && (params.getUser() == null || !params.getUser().hasManagedGroups()) )
+ if ( params.isCanManage() && ( params.getUser() == null || !params.getUser().hasManagedGroups() ) )
{
log.warn( "Cannot get managed users as user does not have any managed groups" );
return false;
}
- if ( params.isAuthSubset() && (params.getUser() == null || !params.getUser().getUserCredentials().hasAuthorities()) )
+ if ( params.isAuthSubset() && ( params.getUser() == null || !params.getUser().getUserCredentials().hasAuthorities() ) )
{
log.warn( "Cannot get users with authority subset as user does not have any authorities" );
return false;
}
- if ( params.isDisjointRoles() && (params.getUser() == null || !params.getUser().getUserCredentials().hasUserAuthorityGroups()) )
+ if ( params.isDisjointRoles() && ( params.getUser() == null || !params.getUser().getUserCredentials().hasUserAuthorityGroups() ) )
{
log.warn( "Cannot get users with disjoint roles as user does not have any user roles" );
return false;
=== modified file 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/util/TextUtils.java'
--- dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/util/TextUtils.java 2015-08-21 03:35:34 +0000
+++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/util/TextUtils.java 2015-08-25 14:09:25 +0000
@@ -193,8 +193,8 @@
}
/**
- * Removes the last occurence of the word "or" from the given string,
- * including potential trailing spaces, case-insentitive.
+ * Removes the last occurrence of the word "or" from the given string,
+ * including potential trailing spaces, case-insensitive.
*
* @param string the string.
* @return the chopped string.
@@ -207,8 +207,8 @@
}
/**
- * Removes the last occurence of the word "and" from the given string,
- * including potential trailing spaces, case-insentitive.
+ * Removes the last occurrence of the word "and" from the given string,
+ * including potential trailing spaces, case-insensitive.
*
* @param string the string.
* @return the chopped string.
@@ -221,7 +221,7 @@
}
/**
- * Removes the last occurence of comma (",") from the given string,
+ * Removes the last occurrence of comma (",") from the given string,
* including potential trailing spaces.
*
* @param string the string.
@@ -233,6 +233,20 @@
return StringUtils.removeEndIgnoreCase( string, "," );
}
+
+ /**
+ * Removes the last occurrence of the the given string, including potential
+ * trailing spaces.
+ *
+ * @param string the string.
+ * @return the chopped string.
+ */
+ public static String removeLast( String string, String remove )
+ {
+ string = StringUtils.stripEnd( string, " " );
+
+ return StringUtils.removeEndIgnoreCase( string, remove );
+ }
/**
* Trims the given string from the end.
=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/webapp/dhis-web-maintenance-program/programIndicatorForm.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/webapp/dhis-web-maintenance-program/programIndicatorForm.vm 2015-08-25 09:48:55 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/webapp/dhis-web-maintenance-program/programIndicatorForm.vm 2015-08-25 14:09:25 +0000
@@ -15,8 +15,8 @@
<li><a href="#expression-tab1">$i18n.getString("data_elements")</a></li>
#if($program.programType=='WITH_REGISTRATION')
<li><a href="#expression-tab2">$i18n.getString("attributes")</a></li>
- <li><a href="#expression-tab3">$i18n.getString("variables")</a></li>
#end
+ <li><a href="#expression-tab3">$i18n.getString("variables")</a></li>
<li><a href="#expression-tab4">$i18n.getString("constants")</a></li>
</ul>
@@ -43,7 +43,7 @@
</table>
</div>
- #if($program.programType=='WITH_REGISTRATION')
+ #if($program.programType=='WITH_REGISTRATION')
<div id="expression-tab2">
<table style="width:100%">
@@ -65,6 +65,8 @@
</table>
</div>
+ #end
+
<div id="expression-tab3">
<table style="width:100%">
<tr>
@@ -87,8 +89,6 @@
</tr>
</table>
</div>
-
- #end
<div id="expression-tab4">
<table style="width:100%">
@@ -158,10 +158,10 @@
<div id="filter-tabs" style="width:670px">
<ul>
<li><a href="#filter-tab1">$i18n.getString("data_elements")</a></li>
- #if($program.type!='3')
+ #if($program.programType=='WITH_REGISTRATION')
<li><a href="#filter-tab2">$i18n.getString("attributes")</a></li>
- <li><a href="#filter-tab3">$i18n.getString("variables")</a></li>
#end
+ <li><a href="#filter-tab3">$i18n.getString("variables")</a></li>
<li><a href="#filter-tab4">$i18n.getString("constants")</a></li>
</ul>
@@ -187,7 +187,7 @@
</table>
</div>
- #if($program.type!='3')
+ #if($program.programType=='WITH_REGISTRATION')
<div id="filter-tab2">
<table style="width:100%">
@@ -209,6 +209,8 @@
</table>
</div>
+ #end
+
<div id="filter-tab3">
<table style="width:100%">
<tr>
@@ -231,8 +233,6 @@
</tr>
</table>
</div>
-
- #end
<div id="filter-tab4">
<table style="width:100%">