docs: protected String replaceAllProperties(String str,
  			final Properties submittedProps, final Properties xmlProperties) {
  
  		int startIndex = 0;
  		NextProperty nextProp = this.findNextProperty(str, startIndex);
  		
  		
  		while (nextProp != null) {
  
  			// get the start index past this property for the next property in
  			// the string
  			//startIndex = this.getEndIndexOfNextProperty(str, startIndex);
  			startIndex = nextProp.endIndex;
  
  			// resolve the property
  			String nextPropValue = this.resolvePropertyValue(nextProp.propName, nextProp.propType, submittedProps, xmlProperties);
  			
  			//if the property didn't resolve use the default value if it exists
  			if (nextPropValue.equals(UNRESOLVED_PROP_VALUE)){
  			    if (nextProp.defaultValueExpression != null) { 
  			        nextPropValue = this.replaceAllProperties(nextProp.defaultValueExpression, submittedProps, xmlProperties);
  			    }
  			}
  			
  
  			// After we get this value the lenght of the string might change so
  			// we need to reset the start index
  			int lengthDifference = 0;
  			switch(nextProp.propType) {
  			
  				case JOB_PARAMETERS:
  					lengthDifference = nextPropValue.length() - (nextProp.propName.length() + "#{jobParameters['']}".length()); // this can be a negative value
  					startIndex = startIndex + lengthDifference; // move start index for next property
  					str = str.replace("#{jobParameters['" + nextProp.propName + "']}" + nextProp.getDefaultValExprWithDelimitersIfExists(), nextPropValue);
  					break;
  				case JOB_PROPERTIES:
  					lengthDifference = nextPropValue.length() - (nextProp.propName.length() + "#{jobProperties['']}".length()); // this can be a negative value
  					startIndex = startIndex + lengthDifference; // move start index for next property
  					str = str.replace("#{jobProperties['" + nextProp.propName + "']}" + nextProp.getDefaultValExprWithDelimitersIfExists(), nextPropValue);
  					break;
  				case SYSTEM_PROPERTIES:
  					lengthDifference = nextPropValue.length() - (nextProp.propName.length() + "#{systemProperties['']}".length()); // this can be a negative value
  					startIndex = startIndex + lengthDifference; // move start index for next property
  					str = str.replace("#{systemProperties['" + nextProp.propName + "']}" + nextProp.getDefaultValExprWithDelimitersIfExists(), nextPropValue);
  					break;
  				case PARTITION_PROPERTIES:
  					lengthDifference = nextPropValue.length() - (nextProp.propName.length() + "#{partitionPlan['']}".length()); // this can be a negative value
  					startIndex = startIndex + lengthDifference; // move start index for next property
  					str = str.replace("#{partitionPlan['" + nextProp.propName + "']}" + nextProp.getDefaultValExprWithDelimitersIfExists(), nextPropValue);
  					break;					
  
  			}
  
  			// find the next property
  			nextProp = this.findNextProperty(str, startIndex);
  		}
  
  		return str;
  	}