src/org/ohmage/domain/campaign/Campaign.java
private static RepeatableSet processRepeatableSet(
			final String containerId,
			final Node repeatableSet, 
			final int index,
			final List<SurveyItem> alreadyProcessedItemsInSurveyItemGroup) 
			throws DomainException {
		
		Nodes ids = repeatableSet.query(XML_REPEATABLE_SET_ID);
		if(ids.size() == 0) {
			throw new DomainException(
					"The repeatable set ID is missing: " + containerId);
		}
		else if(ids.size() > 1) {
			throw new DomainException(
					"Multiple repeatable set IDs were found: " + containerId);
		}
		String id = ids.get(0).getValue().trim();
		if(id.length() == 0) {
			throw new DomainException(
					"The repeatable set's ID cannot be only whitespace in the survey item container: " +
						containerId);
		}
		if(! VALID_CHARACTERS_PATTERN.matcher(id).matches()) {
			throw new DomainException(
					"The repeatable set's ID contains illegal characters: " + 
						id);
		}
		
		String condition = null;
		Nodes conditions = repeatableSet.query(XML_REPEATABLE_SET_CONDITION);
		if(conditions.size() > 1) {
			throw new DomainException(
					"Multiple repeatable set conditions were found: " + id);
		}
		else if(conditions.size() == 1) {
			condition = conditions.get(0).getValue().trim();

			condition = validateCondition(
					condition, 
					id, 
					containerId, 
					alreadyProcessedItemsInSurveyItemGroup);
		}
		
		Nodes teminationQuestions =
			repeatableSet.query(XML_REPEATABLE_SET_TERMINATION_QUESTION);
		if(teminationQuestions.size() == 0) {
			throw new DomainException(
					"The repeatable set termination question is missing: " + 
						id);
		}
		else if(teminationQuestions.size() > 1) {
			throw new DomainException(
					"Multiple repeatable set termination questions were found: " + 
						id);
		}
		String terminationQuestion = teminationQuestions.get(0).getValue().trim();
		if(terminationQuestion.length() == 0) {
			throw new DomainException(
					"The termination question cannot be only whitespace: " +
						id);
		}
		
		Nodes terminationTrueLabels =
			repeatableSet.query(XML_REPEATABLE_SET_TERMINATION_TRUE_LABEL);
		if(terminationTrueLabels.size() == 0) {
			throw new DomainException(
					"The repeatable set termination true label is missing: " + 
						id);
		}
		else if(terminationTrueLabels.size() > 1) {
			throw new DomainException(
					"Multiple repeatable set termination true labels were found: " + 
						id);
		}
		String terminationTrueLabel = terminationTrueLabels.get(0).getValue().trim();
		if(terminationTrueLabel.length() == 0) {
			throw new DomainException(
					"The termination true label cannot be only whitespace: " +
						id);
		}
		
		Nodes terminationFalseLabels =
			repeatableSet.query(XML_REPEATABLE_SET_TERMINATION_FALSE_LABEL);
		if(terminationFalseLabels.size() == 0) {
			throw new DomainException(
					"The repeatable set termination false label is missing: " +
						id);
		}
		else if(terminationFalseLabels.size() > 1) {
			throw new DomainException(
					"Multiple repeatable set termination false labels were found: " + 
						id);
		}
		String terminationFalseLabel = terminationFalseLabels.get(0).getValue().trim();
		if(terminationFalseLabel.length() == 0) {
			throw new DomainException(
					"The termination false label cannot be only whitespace: " +
						id);
		}
		
		Nodes terminationSkipEnableds =
			repeatableSet.query(XML_REPEATABLE_SET_TERMINATION_SKIP_ENABLED);
		if(terminationSkipEnableds.size() == 0) {
			throw new DomainException(
					"The repeatable set termination skip enabled value is missing: " + 
						id);
		}
		else if(terminationSkipEnableds.size() > 1) {
			throw new DomainException(
					"Multiple repeatable set termination skip enabled value were found: " + 
						id);
		}
		Boolean terminationSkipEnabled = 
			StringUtils.decodeBoolean(
					terminationSkipEnableds.get(0).getValue().trim()
				);
		if(terminationSkipEnabled == null) {
			throw new DomainException(
					"The termination skip enabled value is not a valid boolean value: " + 
						id);
		}
		
		String terminationSkipLabel = null;
		Nodes terminationSkipLabels = 
			repeatableSet.query(XML_REPEATABLE_SET_TERMINATION_SKIP_LABEL);
		if((terminationSkipLabels.size() == 0) && (terminationSkipEnabled)) {
			throw new DomainException(
					"A termination skip label is required if the termination skip is enabled: " +
						id);
		}
		else if(terminationSkipLabels.size() > 1) {
			throw new DomainException(
					"Multiple repeatable set termination skip labels were found: " + 
						id);
		}
		else if(terminationSkipLabels.size() == 1) {
			terminationSkipLabel = terminationSkipLabels.get(0).getValue().trim();
			
			if(terminationSkipLabel.length() == 0) {
				throw new DomainException(
						"The termination skip label cannot be only whitespace: " +
							id);
			}
		}
		
		Nodes promptsNodes = repeatableSet.query(XML_REPEATABLE_SET_PROMPTS);
		if(promptsNodes.size() == 0) {
			throw new DomainException(
					"The repeatable set doesn't contain a prompts group: " + 
						id);
		}
		if(promptsNodes.size() > 1) {
			throw new DomainException(
					"The repeatable set contains multiple prompts groups: " + 
						id);
		}
		
		Nodes promptNodes = promptsNodes.get(0).query(XML_CONTENT_LIST_ITEMS);
		List<SurveyItem> promptGroup = processContentList(id, promptNodes);
		if(promptGroup.size() == 0) {
			throw new DomainException(
					"The repeatable set doesn't contain any prompts: " + id);
		}
		
		Map<Integer, SurveyItem> promptMap = 
			new HashMap<Integer, SurveyItem>(promptGroup.size());
		Set<String> promptIds = new HashSet<String>();
		for(SurveyItem currPrompt : promptGroup) {
			if(promptIds.add(currPrompt.getId())) {
				// This is where repeatable sets prevent sub repeatable sets.
				// To allow this restriction, remove this if statement.
				if(currPrompt instanceof RepeatableSet) {
					throw new DomainException(
							"Repeatable sets may not contain repeatable sets: " + 
								id);
				}

				promptMap.put(currPrompt.getIndex(), currPrompt);
			}
			else {
				throw new DomainException(
						"A repeatable set has multiple prompts with the same unique identifier: " + 
							currPrompt.getId());
			}
		}
		
		return new RepeatableSet(id, condition, terminationQuestion,
				terminationTrueLabel, terminationFalseLabel, 
				terminationSkipEnabled, terminationSkipLabel, 
				promptMap, index);
	}
/**
	 * Creates a RepeatableSet object from the repeatable set Node from the 
	 * XML.
	 * 
	 * @param containerId The unique identifier for the container of this
	 * 					  repeatable set.
	 * 
	 * @param repeatableSet The repeatable set Node from the XML.
	 * 
	 * @param index The index of this repeatable set in its collection of 
	 * 				survey items.
	 * 
	 * @return A RepeatableSet object that represents the repeatable set 
	 * 		   defined in the XML.
	 * 
	 * @throws DomainException Thrown if the repeatable set is malformed or if 
	 * 						   any of the prompts in the repeatable set are 
	 * 						   malformed.
	 */
Creates a RepeatableSet object from the repeatable set Node from the
XML.

@param containerId The unique identifier for the container of this
repeatable set.

@param repeatableSet The repeatable set Node from the XML.

@param index The index of this repeatable set in its collection of
survey items.

@return A RepeatableSet object that represents the repeatable set
defined in the XML.

@throws DomainException Thrown if the repeatable set is malformed or if
any of the prompts in the repeatable set are
malformed.
Creates a RepeatableSet object from the repeatable set Node from the XML . @param containerId The unique identifier for the container of this repeatable set . @param repeatableSet The repeatable set Node from the XML . @param index The index of this repeatable set in its collection of survey items . @return A RepeatableSet object that represents the repeatable set defined in the XML . @throws DomainException Thrown if the repeatable set is malformed or if any of the prompts in the repeatable set are malformed .
private static RepeatableSet processRepeatableSet(
			final String containerId,
			final Node repeatableSet, 
			final int index,
			final List<SurveyItem> alreadyProcessedItemsInSurveyItemGroup) 
			throws DomainException {
		Nodes ids = repeatableSet.query(XML_REPEATABLE_SET_ID);
		if(ids.size() == 0) {
			throw new DomainException(
					"The repeatable set ID is missing: " + containerId);
		}
		else if(ids.size() > 1) {
			throw new DomainException(
					"Multiple repeatable set IDs were found: " + containerId);
		}
		String id = ids.get(0).getValue().trim();
		if(id.length() == 0) {
			throw new DomainException(
					"The repeatable set's ID cannot be only whitespace in the survey item container: " +
						containerId);
		}
		if(! VALID_CHARACTERS_PATTERN.matcher(id).matches()) {
			throw new DomainException(
					"The repeatable set's ID contains illegal characters: " + 
						id);
		}
		String condition = null;
		Nodes conditions = repeatableSet.query(XML_REPEATABLE_SET_CONDITION);
		if(conditions.size() > 1) {
			throw new DomainException(
					"Multiple repeatable set conditions were found: " + id);
		}
		else if(conditions.size() == 1) {
			condition = conditions.get(0).getValue().trim();
			condition = validateCondition(
					condition, 
					id, 
					containerId, 
					alreadyProcessedItemsInSurveyItemGroup);
		}
		Nodes teminationQuestions =
			repeatableSet.query(XML_REPEATABLE_SET_TERMINATION_QUESTION);
		if(teminationQuestions.size() == 0) {
			throw new DomainException(
					"The repeatable set termination question is missing: " + 
						id);
		}
		else if(teminationQuestions.size() > 1) {
			throw new DomainException(
					"Multiple repeatable set termination questions were found: " + 
						id);
		}
		String terminationQuestion = teminationQuestions.get(0).getValue().trim();
		if(terminationQuestion.length() == 0) {
			throw new DomainException(
					"The termination question cannot be only whitespace: " +
						id);
		}
		Nodes terminationTrueLabels =
			repeatableSet.query(XML_REPEATABLE_SET_TERMINATION_TRUE_LABEL);
		if(terminationTrueLabels.size() == 0) {
			throw new DomainException(
					"The repeatable set termination true label is missing: " + 
						id);
		}
		else if(terminationTrueLabels.size() > 1) {
			throw new DomainException(
					"Multiple repeatable set termination true labels were found: " + 
						id);
		}
		String terminationTrueLabel = terminationTrueLabels.get(0).getValue().trim();
		if(terminationTrueLabel.length() == 0) {
			throw new DomainException(
					"The termination true label cannot be only whitespace: " +
						id);
		}
		Nodes terminationFalseLabels =
			repeatableSet.query(XML_REPEATABLE_SET_TERMINATION_FALSE_LABEL);
		if(terminationFalseLabels.size() == 0) {
			throw new DomainException(
					"The repeatable set termination false label is missing: " +
						id);
		}
		else if(terminationFalseLabels.size() > 1) {
			throw new DomainException(
					"Multiple repeatable set termination false labels were found: " + 
						id);
		}
		String terminationFalseLabel = terminationFalseLabels.get(0).getValue().trim();
		if(terminationFalseLabel.length() == 0) {
			throw new DomainException(
					"The termination false label cannot be only whitespace: " +
						id);
		}
		Nodes terminationSkipEnableds =
			repeatableSet.query(XML_REPEATABLE_SET_TERMINATION_SKIP_ENABLED);
		if(terminationSkipEnableds.size() == 0) {
			throw new DomainException(
					"The repeatable set termination skip enabled value is missing: " + 
						id);
		}
		else if(terminationSkipEnableds.size() > 1) {
			throw new DomainException(
					"Multiple repeatable set termination skip enabled value were found: " + 
						id);
		}
		Boolean terminationSkipEnabled = 
			StringUtils.decodeBoolean(
					terminationSkipEnableds.get(0).getValue().trim()
				);
		if(terminationSkipEnabled == null) {
			throw new DomainException(
					"The termination skip enabled value is not a valid boolean value: " + 
						id);
		}
		String terminationSkipLabel = null;
		Nodes terminationSkipLabels = 
			repeatableSet.query(XML_REPEATABLE_SET_TERMINATION_SKIP_LABEL);
		if((terminationSkipLabels.size() == 0) && (terminationSkipEnabled)) {
			throw new DomainException(
					"A termination skip label is required if the termination skip is enabled: " +
						id);
		}
		else if(terminationSkipLabels.size() > 1) {
			throw new DomainException(
					"Multiple repeatable set termination skip labels were found: " + 
						id);
		}
		else if(terminationSkipLabels.size() == 1) {
			terminationSkipLabel = terminationSkipLabels.get(0).getValue().trim();
			if(terminationSkipLabel.length() == 0) {
				throw new DomainException(
						"The termination skip label cannot be only whitespace: " +
							id);
			}
		}
		Nodes promptsNodes = repeatableSet.query(XML_REPEATABLE_SET_PROMPTS);
		if(promptsNodes.size() == 0) {
			throw new DomainException(
					"The repeatable set doesn't contain a prompts group: " + 
						id);
		}
		if(promptsNodes.size() > 1) {
			throw new DomainException(
					"The repeatable set contains multiple prompts groups: " + 
						id);
		}
		Nodes promptNodes = promptsNodes.get(0).query(XML_CONTENT_LIST_ITEMS);
		List<SurveyItem> promptGroup = processContentList(id, promptNodes);
		if(promptGroup.size() == 0) {
			throw new DomainException(
					"The repeatable set doesn't contain any prompts: " + id);
		}
		Map<Integer, SurveyItem> promptMap = 
			new HashMap<Integer, SurveyItem>(promptGroup.size());
		Set<String> promptIds = new HashSet<String>();
		for(SurveyItem currPrompt : promptGroup) {
			if(promptIds.add(currPrompt.getId())) {
				if(currPrompt instanceof RepeatableSet) {
					throw new DomainException(
							"Repeatable sets may not contain repeatable sets: " + 
								id);
				}
				promptMap.put(currPrompt.getIndex(), currPrompt);
			}
			else {
				throw new DomainException(
						"A repeatable set has multiple prompts with the same unique identifier: " + 
							currPrompt.getId());
			}
		}
		return new RepeatableSet(id, condition, terminationQuestion,
				terminationTrueLabel, terminationFalseLabel, 
				terminationSkipEnabled, terminationSkipLabel, 
				promptMap, index);
	}
private static RepeatableSet processRepeatableSet ( final String containerId , final Node repeatableSet , final int index , final List < SurveyItem > alreadyProcessedItemsInSurveyItemGroup ) throws DomainException { Nodes ids = repeatableSet . query ( XML_REPEATABLE_SET_ID ) ; if ( ids . size ( ) == 0 ) { throw new DomainException ( "The repeatable set ID is missing: " + containerId ) ; } else if ( ids . size ( ) > 1 ) { throw new DomainException ( "Multiple repeatable set IDs were found: " + containerId ) ; } String id = ids . get ( 0 ) . getValue ( ) . trim ( ) ; if ( id . length ( ) == 0 ) { throw new DomainException ( "The repeatable set's ID cannot be only whitespace in the survey item container: " + containerId ) ; } if ( ! VALID_CHARACTERS_PATTERN . matcher ( id ) . matches ( ) ) { throw new DomainException ( "The repeatable set's ID contains illegal characters: " + id ) ; } String condition = null ; Nodes conditions = repeatableSet . query ( XML_REPEATABLE_SET_CONDITION ) ; if ( conditions . size ( ) > 1 ) { throw new DomainException ( "Multiple repeatable set conditions were found: " + id ) ; } else if ( conditions . size ( ) == 1 ) { condition = conditions . get ( 0 ) . getValue ( ) . trim ( ) ; condition = validateCondition ( condition , id , containerId , alreadyProcessedItemsInSurveyItemGroup ) ; } Nodes teminationQuestions = repeatableSet . query ( XML_REPEATABLE_SET_TERMINATION_QUESTION ) ; if ( teminationQuestions . size ( ) == 0 ) { throw new DomainException ( "The repeatable set termination question is missing: " + id ) ; } else if ( teminationQuestions . size ( ) > 1 ) { throw new DomainException ( "Multiple repeatable set termination questions were found: " + id ) ; } String terminationQuestion = teminationQuestions . get ( 0 ) . getValue ( ) . trim ( ) ; if ( terminationQuestion . length ( ) == 0 ) { throw new DomainException ( "The termination question cannot be only whitespace: " + id ) ; } Nodes terminationTrueLabels = repeatableSet . query ( XML_REPEATABLE_SET_TERMINATION_TRUE_LABEL ) ; if ( terminationTrueLabels . size ( ) == 0 ) { throw new DomainException ( "The repeatable set termination true label is missing: " + id ) ; } else if ( terminationTrueLabels . size ( ) > 1 ) { throw new DomainException ( "Multiple repeatable set termination true labels were found: " + id ) ; } String terminationTrueLabel = terminationTrueLabels . get ( 0 ) . getValue ( ) . trim ( ) ; if ( terminationTrueLabel . length ( ) == 0 ) { throw new DomainException ( "The termination true label cannot be only whitespace: " + id ) ; } Nodes terminationFalseLabels = repeatableSet . query ( XML_REPEATABLE_SET_TERMINATION_FALSE_LABEL ) ; if ( terminationFalseLabels . size ( ) == 0 ) { throw new DomainException ( "The repeatable set termination false label is missing: " + id ) ; } else if ( terminationFalseLabels . size ( ) > 1 ) { throw new DomainException ( "Multiple repeatable set termination false labels were found: " + id ) ; } String terminationFalseLabel = terminationFalseLabels . get ( 0 ) . getValue ( ) . trim ( ) ; if ( terminationFalseLabel . length ( ) == 0 ) { throw new DomainException ( "The termination false label cannot be only whitespace: " + id ) ; } Nodes terminationSkipEnableds = repeatableSet . query ( XML_REPEATABLE_SET_TERMINATION_SKIP_ENABLED ) ; if ( terminationSkipEnableds . size ( ) == 0 ) { throw new DomainException ( "The repeatable set termination skip enabled value is missing: " + id ) ; } else if ( terminationSkipEnableds . size ( ) > 1 ) { throw new DomainException ( "Multiple repeatable set termination skip enabled value were found: " + id ) ; } Boolean terminationSkipEnabled = StringUtils . decodeBoolean ( terminationSkipEnableds . get ( 0 ) . getValue ( ) . trim ( ) ) ; if ( terminationSkipEnabled == null ) { throw new DomainException ( "The termination skip enabled value is not a valid boolean value: " + id ) ; } String terminationSkipLabel = null ; Nodes terminationSkipLabels = repeatableSet . query ( XML_REPEATABLE_SET_TERMINATION_SKIP_LABEL ) ; if ( ( terminationSkipLabels . size ( ) == 0 ) && ( terminationSkipEnabled ) ) { throw new DomainException ( "A termination skip label is required if the termination skip is enabled: " + id ) ; } else if ( terminationSkipLabels . size ( ) > 1 ) { throw new DomainException ( "Multiple repeatable set termination skip labels were found: " + id ) ; } else if ( terminationSkipLabels . size ( ) == 1 ) { terminationSkipLabel = terminationSkipLabels . get ( 0 ) . getValue ( ) . trim ( ) ; if ( terminationSkipLabel . length ( ) == 0 ) { throw new DomainException ( "The termination skip label cannot be only whitespace: " + id ) ; } } Nodes promptsNodes = repeatableSet . query ( XML_REPEATABLE_SET_PROMPTS ) ; if ( promptsNodes . size ( ) == 0 ) { throw new DomainException ( "The repeatable set doesn't contain a prompts group: " + id ) ; } if ( promptsNodes . size ( ) > 1 ) { throw new DomainException ( "The repeatable set contains multiple prompts groups: " + id ) ; } Nodes promptNodes = promptsNodes . get ( 0 ) . query ( XML_CONTENT_LIST_ITEMS ) ; List < SurveyItem > promptGroup = processContentList ( id , promptNodes ) ; if ( promptGroup . size ( ) == 0 ) { throw new DomainException ( "The repeatable set doesn't contain any prompts: " + id ) ; } Map < Integer , SurveyItem > promptMap = new HashMap < Integer , SurveyItem > ( promptGroup . size ( ) ) ; Set < String > promptIds = new HashSet < String > ( ) ; for ( SurveyItem currPrompt : promptGroup ) { if ( promptIds . add ( currPrompt . getId ( ) ) ) { if ( currPrompt instanceof RepeatableSet ) { throw new DomainException ( "Repeatable sets may not contain repeatable sets: " + id ) ; } promptMap . put ( currPrompt . getIndex ( ) , currPrompt ) ; } else { throw new DomainException ( "A repeatable set has multiple prompts with the same unique identifier: " + currPrompt . getId ( ) ) ; } } return new RepeatableSet ( id , condition , terminationQuestion , terminationTrueLabel , terminationFalseLabel , terminationSkipEnabled , terminationSkipLabel , promptMap , index ) ; }
Creates a RepeatableSet object from the repeatable set Node from the
 XML.
Creates a RepeatableSet object from the repeatable set Node from the XML .
// This is where repeatable sets prevent sub repeatable sets. // To allow this restriction, remove this if statement.