← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 18279: Improve Program Indicators.

 

------------------------------------------------------------
revno: 18279
committer: Tran Chau<tran.hispvietnam@xxxxxxxxx>
branch nick: dhis2
timestamp: Mon 2015-02-16 18:46:32 +0700
message:
  Improve Program Indicators.
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-tracker/src/main/java/org/hisp/dhis/program/DefaultProgramIndicatorService.java
  dhis-2/dhis-services/dhis-service-tracker/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-web/dhis-web-caseentry/src/main/webapp/dhis-web-caseentry/dataEntryForm.vm
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/java/org/hisp/dhis/trackedentity/action/program/GetProgramAction.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/java/org/hisp/dhis/trackedentity/action/programtindicator/GetProgramIndicatorAction.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/java/org/hisp/dhis/trackedentity/action/programtindicator/GetProgramIndicatorDescripttionAction.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/resources/org/hisp/dhis/trackedentity/i18n_module.properties
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/resources/struts.xml
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/webapp/dhis-web-maintenance-program/addProgramIndicator.vm
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/webapp/dhis-web-maintenance-program/javascript/programIndicator.js
  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/updateProgramIndicator.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
=== 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-02-05 06:53:38 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramIndicator.java	2015-02-16 11:46:32 +0000
@@ -33,6 +33,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 org.hisp.dhis.common.BaseIdentifiableObject;
 import org.hisp.dhis.common.BaseNameableObject;
 import org.hisp.dhis.common.DxfNamespaces;
@@ -49,17 +50,25 @@
     extends BaseNameableObject
 {
     public static final String SEPARATOR_ID = "\\.";
-    public static final String VALUE_TYPE_DATE = "date";
-    public static final String VALUE_TYPE_INT = "int";
+    public static final String KEY_DATAELEMENT = "\\$";
+    public static final String KEY_ATTRIBUTE = "A";
+    public static final String KEY_PROGRAM_VARIABLE = "V";
+    public static final String KEY_CONSTANT = "C";
     public static final String INCIDENT_DATE = "incident_date";
     public static final String ENROLLEMENT_DATE = "enrollment_date";
     public static final String CURRENT_DATE = "current_date";
+    public static final String VALUE_TYPE_DATE = "date";
+    public static final String VALUE_TYPE_INT = "int";
     private static final long serialVersionUID = 7920320128945484331L;
-    public static String OBJECT_PROGRAM_STAGE_DATAELEMENT = "DE";
     public static String SEPARATOR_OBJECT = ":";
-    public static final String regExp = "\\[" + OBJECT_PROGRAM_STAGE_DATAELEMENT + SEPARATOR_OBJECT + "([a-zA-Z0-9\\- ]+["
-        + SEPARATOR_ID + "[0-9]*]*)" + "\\]";
-
+
+    public static final String regExp = "("+KEY_DATAELEMENT+"|"+KEY_ATTRIBUTE+"|"+KEY_PROGRAM_VARIABLE+"|"+KEY_CONSTANT+")\\{([a-zA-Z0-9]+|" + INCIDENT_DATE + "|" + ENROLLEMENT_DATE + "|"
+        + CURRENT_DATE + ")" + SEPARATOR_ID + "*([a-zA-Z0-9]*)\\}";
+
+    public static final String VALID = "valid";
+
+    public static final String EXPRESSION_NOT_WELL_FORMED = "expression_not_well_formed";
+    
     private String valueType;
 
     private String expression;

=== 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-01-17 07:41:26 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramIndicatorService.java	2015-02-16 11:46:32 +0000
@@ -134,4 +134,12 @@
      */
     String getExpressionDescription( String expression );
 
+    /**
+     * Get description of an indicator expression
+     *
+     * @param expression A expression string
+     * @return The expression is valid or not
+     */
+    String expressionIsValid( String expression );
+
 }

=== modified file 'dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/program/DefaultProgramIndicatorService.java'
--- dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/program/DefaultProgramIndicatorService.java	2015-01-17 07:41:26 +0000
+++ dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/program/DefaultProgramIndicatorService.java	2015-02-16 11:46:32 +0000
@@ -37,10 +37,17 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.hisp.dhis.constant.Constant;
+import org.hisp.dhis.constant.ConstantService;
 import org.hisp.dhis.dataelement.DataElement;
 import org.hisp.dhis.dataelement.DataElementService;
 import org.hisp.dhis.i18n.I18nService;
 import org.hisp.dhis.system.util.DateUtils;
+import org.hisp.dhis.system.util.MathUtils;
+import org.hisp.dhis.trackedentity.TrackedEntityAttribute;
+import org.hisp.dhis.trackedentity.TrackedEntityAttributeService;
+import org.hisp.dhis.trackedentityattributevalue.TrackedEntityAttributeValue;
+import org.hisp.dhis.trackedentityattributevalue.TrackedEntityAttributeValueService;
 import org.hisp.dhis.trackedentitydatavalue.TrackedEntityDataValue;
 import org.hisp.dhis.trackedentitydatavalue.TrackedEntityDataValueService;
 import org.nfunk.jep.JEP;
@@ -94,6 +101,27 @@
         this.programStageInstanceService = programStageInstanceService;
     }
 
+    private TrackedEntityAttributeService attributeService;
+
+    public void setAttributeService( TrackedEntityAttributeService attributeService )
+    {
+        this.attributeService = attributeService;
+    }
+
+    private TrackedEntityAttributeValueService attributeValueService;
+
+    public void setAttributeValueService( TrackedEntityAttributeValueService attributeValueService )
+    {
+        this.attributeValueService = attributeValueService;
+    }
+    
+    private ConstantService constantService;
+
+    public void setConstantService( ConstantService constantService )
+    {
+        this.constantService = constantService;
+    }
+
     private I18nService i18nService;
 
     public void setI18nService( I18nService service )
@@ -200,8 +228,11 @@
 
         for ( ProgramIndicator programIndicator : programIndicators )
         {
-            result
-                .put( programIndicator.getDisplayName(), getProgramIndicatorValue( programInstance, programIndicator ) );
+            String value = getProgramIndicatorValue( programInstance, programIndicator );
+            if( value != null )
+            {
+                result.put( programIndicator.getDisplayName(), getProgramIndicatorValue( programInstance, programIndicator ) );
+            }
         }
 
         return result;
@@ -215,41 +246,122 @@
         Pattern patternCondition = Pattern.compile( ProgramIndicator.regExp );
 
         Matcher matcher = patternCondition.matcher( expression );
-
         while ( matcher.find() )
         {
-            String match = matcher.group();
-            match = match.replaceAll( "[\\[\\]]", "" );
-
-            String[] info = match.split( ProgramIndicator.SEPARATOR_OBJECT );
-
-            String[] ids = info[1].split( ProgramIndicator.SEPARATOR_ID );
-
-            int programStageId = Integer.parseInt( ids[0] );
-            ProgramStage programStage = programStageService.getProgramStage( programStageId );
-            String programStageName = "The program stage not exist";
-            if ( programStage != null )
-            {
-                programStageName = programStage.getDisplayName();
-            }
-
-            int dataElementId = Integer.parseInt( ids[1] );
-            DataElement dataElement = dataElementService.getDataElement( dataElementId );
-            String dataelementName = "The data element not exist";
-            if ( dataElement != null )
-            {
-                dataelementName = dataElement.getDisplayName();
-            }
-
-            matcher.appendReplacement( description, "[" + ProgramIndicator.OBJECT_PROGRAM_STAGE_DATAELEMENT
-                + ProgramIndicator.SEPARATOR_OBJECT + programStageName + ProgramIndicator.SEPARATOR_ID
-                + dataelementName + "]" );
+            String key = matcher.group( 1 );
+            String uid1 = matcher.group( 2 );
+
+            if ( key.equals( ProgramIndicator.KEY_DATAELEMENT ) )
+            {
+                String uid2 = matcher.group( 3 );
+
+                ProgramStage programStage = programStageService.getProgramStage( uid1 );
+                DataElement dataElement = dataElementService.getDataElement( uid2 );
+
+                if ( programStage != null && dataElement != null )
+                {
+                    String programStageName = programStage.getDisplayName();
+               
+                    String dataelementName = dataElement.getDisplayName();
+               
+                    matcher.appendReplacement( description, ProgramIndicator.KEY_DATAELEMENT + "{" + programStageName
+                    + ProgramIndicator.SEPARATOR_ID + dataelementName + "}" );
+                }
+            }
+            
+            else if ( key.equals( ProgramIndicator.KEY_ATTRIBUTE ) )
+            {
+                TrackedEntityAttribute attribute = attributeService.getTrackedEntityAttribute( uid1 );
+                if ( attribute != null )
+                {
+                    matcher.appendReplacement( description, ProgramIndicator.KEY_ATTRIBUTE + "{" + attribute.getDisplayName() + "}" );    
+                }
+            }
+            else if ( key.equals( ProgramIndicator.KEY_CONSTANT ) )
+            {
+                Constant constant = constantService.getConstant( uid1 );
+                if ( constant != null )
+                {
+                    matcher.appendReplacement( description, ProgramIndicator.KEY_CONSTANT + "{" + constant.getDisplayName() + "}" );
+                }
+            }
         }
 
         matcher.appendTail( description );
 
         return description.toString();
-    }
+        
+    }
+    
+    public String expressionIsValid( String expression )
+    {
+        StringBuffer description = new StringBuffer();
+
+        Pattern patternCondition = Pattern.compile( ProgramIndicator.regExp );
+
+        Matcher matcher = patternCondition.matcher( expression );
+        while ( matcher.find() )
+        {
+            String key = matcher.group( 1 );
+            String uid1 = matcher.group( 2 );
+
+            if ( key.equals( ProgramIndicator.KEY_DATAELEMENT ) )
+            {
+                String uid2 = matcher.group( 3 );
+
+                ProgramStage programStage = programStageService.getProgramStage( uid1 );
+                DataElement dataElement = dataElementService.getDataElement( uid2 );
+
+                if ( programStage != null && dataElement != null )
+                {
+                    matcher.appendReplacement( description, "1" );
+                }
+                else
+                {
+                    return ProgramIndicator.EXPRESSION_NOT_WELL_FORMED;
+                }
+            }
+            
+            else if ( key.equals( ProgramIndicator.KEY_ATTRIBUTE ) )
+            {
+                TrackedEntityAttribute attribute = attributeService.getTrackedEntityAttribute( uid1 );
+                if ( attribute != null )
+                {
+                    matcher.appendReplacement( description, "1" );
+                }
+                else
+                {
+                    return ProgramIndicator.EXPRESSION_NOT_WELL_FORMED;
+                }
+            }
+            else if ( key.equals( ProgramIndicator.KEY_CONSTANT ) )
+            {
+                Constant constant = constantService.getConstant( uid1 );
+                if ( constant != null )
+                {
+                    matcher.appendReplacement( description, constant.getValue() + "" );
+                }
+                else
+                {
+                    return ProgramIndicator.EXPRESSION_NOT_WELL_FORMED;
+                }
+            }
+        }
+
+        matcher.appendTail( description );
+        
+        // ---------------------------------------------------------------------
+        // Well-formed expression
+        // ---------------------------------------------------------------------
+        
+        if ( MathUtils.expressionHasErrors( description.toString() ) )
+        {
+            return ProgramIndicator.EXPRESSION_NOT_WELL_FORMED;
+        }
+
+        return ProgramIndicator.VALID;
+    }
+    
 
     // -------------------------------------------------------------------------
     // Supportive methods
@@ -259,61 +371,119 @@
     {
         String value = "";
 
-        if ( valueType.equals( ProgramIndicator.VALUE_TYPE_INT ) )
-        {
-            Date currentDate = new Date();
-            expression = expression.replaceAll( ProgramIndicator.ENROLLEMENT_DATE,
-                DateUtils.daysBetween( programInstance.getEnrollmentDate(), currentDate ) + "" );
-            expression = expression.replaceAll( ProgramIndicator.INCIDENT_DATE,
-                DateUtils.daysBetween( programInstance.getDateOfIncident(), currentDate ) + "" );
-            expression = expression.replaceAll( ProgramIndicator.CURRENT_DATE, "0" );
-        }
-
         StringBuffer description = new StringBuffer();
 
         Pattern pattern = Pattern.compile( ProgramIndicator.regExp );
         Matcher matcher = pattern.matcher( expression );
+        
         while ( matcher.find() )
         {
-            DataElement dataElement = null;
-
-            String key = matcher.group().replaceAll( "[\\[\\]]", "" ).split( ProgramIndicator.SEPARATOR_OBJECT )[1];
-            String[] infor = key.split( ProgramIndicator.SEPARATOR_ID );
-
-            Integer programStageId = Integer.parseInt( infor[0] );
-            ProgramStage programStage = programStageService.getProgramStage( programStageId );
-
-            ProgramStageInstance programStageInstance = programStageInstanceService.getProgramStageInstance(
-                programInstance, programStage );
-
-            Integer dataElementId = Integer.parseInt( infor[1] );
-            dataElement = dataElementService.getDataElement( dataElementId );
-
-            TrackedEntityDataValue dataValue = dataValueService.getTrackedEntityDataValue( programStageInstance,
-                dataElement );
-
-            if ( dataValue == null )
-            {
-                return null;
-            }
-
-            value = dataValue.getValue();
-
-            if ( valueType.equals( ProgramIndicator.VALUE_TYPE_INT )
-                && (dataElement == null || dataElement.getType().equals( DataElement.VALUE_TYPE_DATE )) )
-            {
-                value = DateUtils.daysBetween( new Date(), DateUtils.getDefaultDate( value ) ) + " ";
-            }
-
-            matcher.appendReplacement( description, value );
+            String key = matcher.group( 1 );
+            String uid1 = matcher.group( 2 );
+
+            if ( key.equals( ProgramIndicator.KEY_DATAELEMENT ) )
+            {
+                String uid2 = matcher.group( 3 );
+                ProgramStage programStage = programStageService.getProgramStage( uid1 );
+                DataElement dataElement = dataElementService.getDataElement( uid2 );
+                
+                if ( programStage != null && dataElement != null )
+                {
+                    ProgramStageInstance programStageInstance = programStageInstanceService.getProgramStageInstance(
+                        programInstance, programStage );
+                    
+                    TrackedEntityDataValue dataValue = dataValueService.getTrackedEntityDataValue( programStageInstance,
+                        dataElement );
+    
+                    if ( dataValue == null )
+                    {
+                        return null;
+                    }
+    
+                    value = dataValue.getValue();
+    
+                    if ( valueType.equals( ProgramIndicator.VALUE_TYPE_INT )
+                        && (dataElement == null || dataElement.getType().equals( DataElement.VALUE_TYPE_DATE )) )
+                    {
+                        value = DateUtils.daysBetween( new Date(), DateUtils.getDefaultDate( value ) ) + " ";
+                    }
+    
+                    matcher.appendReplacement( description, value );
+                }
+                else
+                {
+                    return null;
+                }
+            }
+            else if ( key.equals( ProgramIndicator.KEY_ATTRIBUTE ) )
+            {
+                TrackedEntityAttribute attribute = attributeService.getTrackedEntityAttribute( uid1 );
+                if ( attribute != null )
+                {
+                    TrackedEntityAttributeValue attrValue = attributeValueService.getTrackedEntityAttributeValue( programInstance.getEntityInstance(), attribute );
+
+                    if( attrValue != null )
+                    {
+                        matcher.appendReplacement( description, attrValue.getValue() );
+                    }
+                    else
+                    {
+                        return null;
+                    }
+                }
+                else
+                {
+                    return null;
+                }
+            }
+            else if ( key.equals( ProgramIndicator.KEY_CONSTANT ) )
+            {
+                Constant constant = constantService.getConstant( uid1 );
+                if ( constant != null )
+                {
+                    matcher.appendReplacement( description, constant.getValue() + "" );
+                }
+                else
+                {
+                    return null;
+                }
+            }
+            else if ( key.equals( ProgramIndicator.KEY_PROGRAM_VARIABLE ) )
+            {
+                  Date currentDate = new Date();
+                  Date date = null;
+                  if( uid1.equals( ProgramIndicator.ENROLLEMENT_DATE ))
+                  {
+                      date = programInstance.getEnrollmentDate();
+                  }
+                  else if( uid1.equals( ProgramIndicator.INCIDENT_DATE ))
+                  {
+                      date = programInstance.getDateOfIncident();
+                  }
+                  else if( uid1.equals( ProgramIndicator.CURRENT_DATE ))
+                  {
+                      date = programInstance.getDateOfIncident();
+                  }
+                  
+                  if ( date != null )
+                  { 
+                      matcher.appendReplacement( description, DateUtils.daysBetween( date, currentDate ) + "" );
+                  }
+            }
 
         }
+        
         matcher.appendTail( description );
-
-        final JEP parser = new JEP();
-        parser.parseExpression( description.toString() );
-
-        return parser.getValue();
-
+        try
+        {
+            final JEP parser = new JEP();
+            parser.parseExpression( description.toString() );
+    
+            return parser.getValue();
+        }
+        catch( Exception ex )
+        {
+            return null;
+        }
     }
 }

=== modified file 'dhis-2/dhis-services/dhis-service-tracker/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-services/dhis-service-tracker/src/main/resources/META-INF/dhis/beans.xml	2015-02-13 08:50:17 +0000
+++ dhis-2/dhis-services/dhis-service-tracker/src/main/resources/META-INF/dhis/beans.xml	2015-02-16 11:46:32 +0000
@@ -167,6 +167,9 @@
 		<property name="programStageInstanceService"
 			ref="org.hisp.dhis.program.ProgramStageInstanceService" />
 		<property name="i18nService" ref="org.hisp.dhis.i18n.I18nService" />
+		<property name="attributeService" ref="org.hisp.dhis.trackedentity.TrackedEntityAttributeService" />
+		<property name="constantService" ref="org.hisp.dhis.constant.ConstantService" />
+		<property name="attributeValueService" ref="org.hisp.dhis.trackedentityattributevalue.TrackedEntityAttributeValueService" />
 	</bean>
 
 	<bean id="org.hisp.dhis.relationship.RelationshipService" class="org.hisp.dhis.relationship.DefaultRelationshipService">

=== modified file 'dhis-2/dhis-web/dhis-web-caseentry/src/main/webapp/dhis-web-caseentry/dataEntryForm.vm'
--- dhis-2/dhis-web/dhis-web-caseentry/src/main/webapp/dhis-web-caseentry/dataEntryForm.vm	2014-07-29 17:14:27 +0000
+++ dhis-2/dhis-web/dhis-web-caseentry/src/main/webapp/dhis-web-caseentry/dataEntryForm.vm	2015-02-16 11:46:32 +0000
@@ -53,7 +53,7 @@
 		#foreach( $indicator in $programStage.programIndicators )
 		<tr>
 			<td>$indicator.displayName</td>
-			<td>$encoder.htmlEncode( $programIndicatorsMap.get($indicator.displayName) )</td>
+			<td>$!encoder.htmlEncode( $programIndicatorsMap.get($indicator.displayName) )</td>
 		</tr>
 		#end
 	</table>

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/java/org/hisp/dhis/trackedentity/action/program/GetProgramAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/java/org/hisp/dhis/trackedentity/action/program/GetProgramAction.java	2015-01-17 07:41:26 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/java/org/hisp/dhis/trackedentity/action/program/GetProgramAction.java	2015-02-16 11:46:32 +0000
@@ -33,6 +33,8 @@
 import java.util.List;
 
 import org.hisp.dhis.common.comparator.IdentifiableObjectNameComparator;
+import org.hisp.dhis.constant.Constant;
+import org.hisp.dhis.constant.ConstantService;
 import org.hisp.dhis.organisationunit.OrganisationUnitGroup;
 import org.hisp.dhis.organisationunit.OrganisationUnitLevel;
 import org.hisp.dhis.oust.manager.SelectionTreeManager;
@@ -80,6 +82,9 @@
     
     @Autowired
     private ProgramIndicatorService programIndicatorService;
+    
+    @Autowired
+    private ConstantService constantService;
 
     // -------------------------------------------------------------------------
     // Input/Output
@@ -144,6 +149,13 @@
         return programIndicators;
     }
     
+    private List<Constant> constants;
+
+    public List<Constant> getConstants()
+    {
+        return constants;
+    }
+
     // -------------------------------------------------------------------------
     // Action implementation
     // -------------------------------------------------------------------------
@@ -162,6 +174,10 @@
 
         Collections.sort( programIndicators, IdentifiableObjectNameComparator.INSTANCE );
 
+        constants = new ArrayList<>(constantService.getAllConstants());
+        
+        Collections.sort( constants, IdentifiableObjectNameComparator.INSTANCE );
+        
         return SUCCESS;
     }
 }

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/java/org/hisp/dhis/trackedentity/action/programtindicator/GetProgramIndicatorAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/java/org/hisp/dhis/trackedentity/action/programtindicator/GetProgramIndicatorAction.java	2015-01-17 07:41:26 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/java/org/hisp/dhis/trackedentity/action/programtindicator/GetProgramIndicatorAction.java	2015-02-16 11:46:32 +0000
@@ -28,8 +28,16 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.hisp.dhis.common.comparator.IdentifiableObjectNameComparator;
+import org.hisp.dhis.constant.Constant;
+import org.hisp.dhis.constant.ConstantService;
 import org.hisp.dhis.program.ProgramIndicator;
 import org.hisp.dhis.program.ProgramIndicatorService;
+import org.springframework.beans.factory.annotation.Autowired;
 
 import com.opensymphony.xwork2.Action;
 
@@ -51,6 +59,9 @@
         this.programIndicatorService = programIndicatorService;
     }
 
+    @Autowired
+    private ConstantService constantService;
+
     // -------------------------------------------------------------------------
     // Setters
     // -------------------------------------------------------------------------
@@ -76,6 +87,13 @@
         return description;
     }
 
+    private List<Constant> constants;
+
+    public List<Constant> getConstants()
+    {
+        return constants;
+    }
+
     // -------------------------------------------------------------------------
     // Action implementation
     // -------------------------------------------------------------------------
@@ -87,6 +105,10 @@
         programIndicator = programIndicatorService.getProgramIndicator( id );
 
         description = programIndicatorService.getExpressionDescription( programIndicator.getExpression() );
+
+        constants = new ArrayList<>(constantService.getAllConstants());
+        
+        Collections.sort( constants, IdentifiableObjectNameComparator.INSTANCE );
         
         return SUCCESS;
     }

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/java/org/hisp/dhis/trackedentity/action/programtindicator/GetProgramIndicatorDescripttionAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/java/org/hisp/dhis/trackedentity/action/programtindicator/GetProgramIndicatorDescripttionAction.java	2015-01-17 07:41:26 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/java/org/hisp/dhis/trackedentity/action/programtindicator/GetProgramIndicatorDescripttionAction.java	2015-02-16 11:46:32 +0000
@@ -28,9 +28,13 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+import org.hisp.dhis.i18n.I18n;
+import org.hisp.dhis.i18n.I18nFormat;
+import org.hisp.dhis.program.ProgramIndicator;
 import org.hisp.dhis.program.ProgramIndicatorService;
 
 import com.opensymphony.xwork2.Action;
+import com.sun.imageio.plugins.common.I18N;
 
 /**
  * @author Chau Thu Tran
@@ -51,6 +55,13 @@
         this.programIndicatorService = programIndicatorService;
     }
 
+    private I18n i18n;
+
+    public void setI18n( I18n i18n )
+    {
+        this.i18n = i18n;
+    }
+
     // -------------------------------------------------------------------------
     // Setters
     // -------------------------------------------------------------------------
@@ -77,8 +88,15 @@
     public String execute()
         throws Exception
     {
-        message = programIndicatorService.getExpressionDescription( expression );
-
-        return SUCCESS;
+        String valid = programIndicatorService.expressionIsValid( expression );
+        if ( valid.equals( ProgramIndicator.VALID ) )
+        {
+            message = programIndicatorService.getExpressionDescription( expression );
+            return SUCCESS;
+        }
+       
+        message = i18n.getString( "expression_is_not_well_formed" );
+        
+        return ERROR;
     }
 }

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/resources/org/hisp/dhis/trackedentity/i18n_module.properties'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/resources/org/hisp/dhis/trackedentity/i18n_module.properties	2015-02-11 16:59:36 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/resources/org/hisp/dhis/trackedentity/i18n_module.properties	2015-02-16 11:46:32 +0000
@@ -504,4 +504,5 @@
 enter_a_key = Enter a key
 date_diff = Date diff
 program_stage_sort_order = Program stage sort order
-sort_order = Sort order
\ No newline at end of file
+sort_order = Sort order
+expression_is_not_well_formed = Expression is not well-formed
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/resources/struts.xml'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/resources/struts.xml	2015-02-02 13:58:48 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/resources/struts.xml	2015-02-16 11:46:32 +0000
@@ -1075,6 +1075,8 @@
       class="org.hisp.dhis.trackedentity.action.programtindicator.GetProgramIndicatorDescripttionAction">
       <result name="success" type="velocity-json">
         /dhis-web-commons/ajax/jsonResponseSuccess.vm
+      </result> <result name="error" type="velocity-json">
+        /dhis-web-commons/ajax/jsonResponseError.vm
       </result>
     </action>
 

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/webapp/dhis-web-maintenance-program/addProgramIndicator.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/webapp/dhis-web-maintenance-program/addProgramIndicator.vm	2014-08-06 15:20:54 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/webapp/dhis-web-maintenance-program/addProgramIndicator.vm	2015-02-16 11:46:32 +0000
@@ -19,7 +19,9 @@
 </script>
 
 <h3>$i18n.getString( "create_new_program_indicator" ) #openHelp( "program_indicator" )</h3>
-									
+
+<h4>$encoder.htmlEncode($program.displayName)</h4>
+							
 <form id="programIndicatorForm" action="addProgramIndicator.action" method="post" class="inputForm">
 <input type='hidden' id='programId' name='programId' value='$program.id'>
 
@@ -77,7 +79,7 @@
 				<select id="programStageId" name="programStageId" onChange="getTrackedEntityDataElements();">
 					<option value=''>[$i18n.getString('please_select')]</option>
 					#foreach( $programStage in $program.programStages )
-					<option value='$programStage.id'>$programStage.displayName</option>
+					<option value='$programStage.uid'>$programStage.displayName</option>
 					#end
 				</select>
 			</td>

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/webapp/dhis-web-maintenance-program/javascript/programIndicator.js'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/webapp/dhis-web-maintenance-program/javascript/programIndicator.js	2014-06-13 10:58:05 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/webapp/dhis-web-maintenance-program/javascript/programIndicator.js	2015-02-16 11:46:32 +0000
@@ -63,7 +63,14 @@
   var programStageId = getFieldValue('programStageId');
   var dataElementId = element.options[element.selectedIndex].value;
 
-  insertTextCommon('expression', "[DE:" + programStageId + "." + dataElementId + "]");
+  insertTextCommon('expression', "${" + programStageId + "." + dataElementId + "}");
+  getConditionDescription();
+}
+
+function insertAttribute( element ){
+   var attributeId = element.options[element.selectedIndex].value;
+
+  insertTextCommon('expression', "A{" + attributeId + "}");
   getConditionDescription();
 }
 
@@ -91,7 +98,13 @@
     {
       expression: getFieldValue('expression')
     }, function( json ) {
-      byId('aggregationDescription').innerHTML = json.message;
+		if( json.response =='error' ){
+			setFieldValue('checkExpression','');
+		}
+		else{
+			setFieldValue('checkExpression', json.message);
+		}
+		setInnerHTML('aggregationDescription', json.message);
     })
 }
 

=== 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-02-11 16:59:36 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/webapp/dhis-web-maintenance-program/programIndicatorForm.vm	2015-02-16 11:46:32 +0000
@@ -2,6 +2,8 @@
 	<ul>
 		<li><a href="#tab-1">$i18n.getString("dataelements")</a></li>
 		<li><a href="#tab-2">$i18n.getString("program")</a></li>
+		<li><a href="#tab-3">$i18n.getString("attributes")</a></li>
+		<li><a href="#tab-4">$i18n.getString("constant")</a></li>
 	</ul>	
 	
 	<div id="tab-1">
@@ -31,14 +33,63 @@
 			<tr>
 				<td>
 					<select id="programProperty" name="programProperty" size="10" ondblclick="insertInfo(this, false);" >
-						<option value="incident_date">$i18n.getString( "incident_date" )</option>
-						<option value="enrollment_date">$i18n.getString( "date_of_enrollment" )</option>
-						<option value="current_date">$i18n.getString( "current_date" )</option>
+						<option value="V{incident_date}">$i18n.getString( "incident_date" )</option>
+						<option value="V{enrollment_date}">$i18n.getString( "date_of_enrollment" )</option>
+						<option value="V{current_date}">$i18n.getString( "current_date" )</option>
 					</select>
 				</td>
 			</tr>
 		</table>
 	</div>
+
+	<div id="tab-3">
+		<table>
+        <tr>
+			<td><label for="attributes">$i18n.getString( "attribute" )</label></td>
+		</tr>
+        <tr>
+			<td>
+				<input type='text' id='txtSearchAttrValue' name='txtSearchAttrValue' onKeyUp="filterAttr(event, this.value, 'attributes');" style='width:265px;'/>
+				<input type='button' value='$i18n.getString("clear")' onClick="setFieldValue('txtSearchAttrValue', '');" style='width:50px'>			
+			</td>
+        </tr>
+        <tr>
+			<td>
+				<select id="attributes" name="attributes" size="8" style="height:120px;" ondblclick="insertAttribute(this);">
+					#foreach( $programAttribute in $program.programAttributes )
+						#if( $programAttribute.attribute.valueType=='number' )
+							<option value='$programAttribute.attribute.uid'>$encoder.htmlEncode($programAttribute.attribute.displayName)</option>
+						#end
+					#end
+				</select>
+			</td>
+		</tr>
+      </table>
+	</div>
+	
+	<div id="tab-4">
+		<table>
+        <tr>
+			<td><label for="constant">$i18n.getString( "constant" )</label></td>
+		</tr>
+        <tr>
+			<td>
+				<input type='text' id='txtSearchContsValue' name='txtSearchAttrValue' onKeyUp="filterAttr(event, this.value, 'attributes');" style='width:265px;'/>
+				<input type='button' value='$i18n.getString("clear")' onClick="setFieldValue('txtSearchAttrValue', '');" style='width:50px'>			
+			</td>
+        </tr>
+        <tr>
+			<td>
+				<select id="constants" name="constants" size="8" style="height:120px;" ondblclick="insertAttribute(this);">
+					#foreach( $constant in $constants )
+						<option value='$constant.uid'>$encoder.htmlEncode($constant.displayName)</option>
+					#end
+				</select>
+			</td>
+		</tr>
+      </table>
+	</div>
+	
 </div>
 
 <tr>
@@ -77,6 +128,7 @@
 			<fieldset>
 				<legend>$i18n.getString( "description" )</legend>
 				<div id='aggregationDescription'>$!encoder.htmlEncode($!description)</div>
+				<input type="hidden" id="checkExpression" name="checkExpression" title="$i18n.getString('expression_is_not_well_formed')" class="{validate:{required:true}}"  />
 			</fieldset>
 		</td>
 	</tr>

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/webapp/dhis-web-maintenance-program/updateProgramIndicator.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/webapp/dhis-web-maintenance-program/updateProgramIndicator.vm	2014-11-03 13:35:42 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/webapp/dhis-web-maintenance-program/updateProgramIndicator.vm	2015-02-16 11:46:32 +0000
@@ -18,8 +18,12 @@
 });
 </script>
 
+#set($program = $programIndicator.program)
+
 <h3>$i18n.getString( "update_program_indicator" ) #openHelp( "program_indicator" )</h3>
-									
+		
+<h4>$encoder.htmlEncode($program.displayName)</h4>
+							
 <form id="programIndicatorForm" action="updateProgramIndicator.action" method="post" class="inputForm">
 <input type='hidden' id='programId' name='programId' value='$program.id'>
 <input type='hidden' id='id' name='id' value='$programIndicator.id'>
@@ -77,7 +81,7 @@
 				<select id="programStageId" name="programStageId" onChange="getTrackedEntityDataElements();">
 					<option value=''>[$i18n.getString('please_select')]</option>
 					#foreach( $programStage in $programIndicator.program.programStages )
-					<option value='$programStage.id'>$encoder.htmlEncode($programStage.displayName)</option>
+					<option value='$programStage.uid'>$encoder.htmlEncode($programStage.displayName)</option>
 					#end
 				</select>
 			</td>