diff --git a/hapi-fhir-base/examples/.classpath b/hapi-fhir-base/examples/.classpath new file mode 100644 index 00000000000..ce99802b301 --- /dev/null +++ b/hapi-fhir-base/examples/.classpath @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hapi-fhir-base/examples/.gitignore b/hapi-fhir-base/examples/.gitignore new file mode 100644 index 00000000000..b83d22266ac --- /dev/null +++ b/hapi-fhir-base/examples/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/hapi-fhir-base/examples/.project b/hapi-fhir-base/examples/.project new file mode 100644 index 00000000000..a0b8364c52b --- /dev/null +++ b/hapi-fhir-base/examples/.project @@ -0,0 +1,23 @@ + + + hapi-fhir-base-examples + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/hapi-fhir-base/examples/.settings/org.eclipse.core.resources.prefs b/hapi-fhir-base/examples/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000000..e9441bb123e --- /dev/null +++ b/hapi-fhir-base/examples/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding/=UTF-8 diff --git a/hapi-fhir-base/examples/.settings/org.eclipse.jdt.core.prefs b/hapi-fhir-base/examples/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..96bb6730c79 --- /dev/null +++ b/hapi-fhir-base/examples/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,289 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_assignment=0 +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 +org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 +org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_field=0 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.format_block_comments=true +org.eclipse.jdt.core.formatter.comment.format_header=false +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true +org.eclipse.jdt.core.formatter.comment.format_line_comments=true +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true +org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert +org.eclipse.jdt.core.formatter.comment.line_length=80 +org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true +org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true +org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false +org.eclipse.jdt.core.formatter.compact_else_if=true +org.eclipse.jdt.core.formatter.continuation_indentation=2 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 +org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off +org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on +org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false +org.eclipse.jdt.core.formatter.indentation.size=3 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.join_lines_in_comments=true +org.eclipse.jdt.core.formatter.join_wrapped_lines=true +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false +org.eclipse.jdt.core.formatter.lineSplit=160 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.tabulation.char=space +org.eclipse.jdt.core.formatter.tabulation.size=3 +org.eclipse.jdt.core.formatter.use_on_off_tags=false +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true +org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true diff --git a/hapi-fhir-base/examples/.settings/org.eclipse.jdt.ui.prefs b/hapi-fhir-base/examples/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 00000000000..fb44b15814d --- /dev/null +++ b/hapi-fhir-base/examples/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +formatter_profile=_examples-format +formatter_settings_version=12 diff --git a/hapi-fhir-base/examples/.settings/org.eclipse.m2e.core.prefs b/hapi-fhir-base/examples/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 00000000000..f897a7f1cb2 --- /dev/null +++ b/hapi-fhir-base/examples/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/hapi-fhir-base/examples/pom.xml b/hapi-fhir-base/examples/pom.xml new file mode 100644 index 00000000000..1a2e015b06d --- /dev/null +++ b/hapi-fhir-base/examples/pom.xml @@ -0,0 +1,47 @@ + + 4.0.0 + + + ca.uhn.hapi.fhir + hapi-fhir + 0.6-SNAPSHOT + ../../pom.xml + + + hapi-fhir-base-examples + jar + + HAPI FHIR - Examples (for site) + + + + ca.uhn.hapi.fhir + hapi-fhir-base + 0.6-SNAPSHOT + + + javax.servlet + javax.servlet-api + 3.1.0 + provided + + + junit + junit + ${junit_version} + + + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + + + diff --git a/hapi-fhir-base/examples/src/main/java/example/ClientExamples.java b/hapi-fhir-base/examples/src/main/java/example/ClientExamples.java new file mode 100644 index 00000000000..564feef7ee5 --- /dev/null +++ b/hapi-fhir-base/examples/src/main/java/example/ClientExamples.java @@ -0,0 +1,89 @@ +package example; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.rest.client.IGenericClient; +import ca.uhn.fhir.rest.client.IRestfulClientFactory; +import ca.uhn.fhir.rest.client.api.IBasicClient; +import ca.uhn.fhir.rest.client.interceptor.BasicAuthInterceptor; +import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; +import ca.uhn.fhir.rest.server.EncodingEnum; + +public class ClientExamples { + + public interface IPatientClient extends IBasicClient { + // nothing yet + } + + @SuppressWarnings("unused") + public void createProxy() { + // START SNIPPET: proxy + FhirContext ctx = new FhirContext(); + ctx.getRestfulClientFactory().setProxy("example.com", 8888); + + IGenericClient genericClient = ctx.newRestfulGenericClient("http://localhost:9999/fhir"); + // END SNIPPET: proxy + } + + @SuppressWarnings("unused") + public void createSecurity() { + // START SNIPPET: security + // Create a context and get the client factory so it can be configured + FhirContext ctx = new FhirContext(); + IRestfulClientFactory clientFactory = ctx.getRestfulClientFactory(); + + // Create an HTTP basic auth interceptor + String username = "foobar"; + String password = "boobear"; + BasicAuthInterceptor authInterceptor = new BasicAuthInterceptor(username, password); + + // Register the interceptor with your client (either style) + IPatientClient annotationClient = ctx.newRestfulClient(IPatientClient.class, "http://localhost:9999/fhir"); + annotationClient.registerInterceptor(authInterceptor); + + IGenericClient genericClient = ctx.newRestfulGenericClient("http://localhost:9999/fhir"); + annotationClient.registerInterceptor(authInterceptor); + // END SNIPPET: security + } + + @SuppressWarnings("unused") + public void createLogging() { + { + // START SNIPPET: logging + // Create a context and get the client factory so it can be configured + FhirContext ctx = new FhirContext(); + IRestfulClientFactory clientFactory = ctx.getRestfulClientFactory(); + + // Create a logging interceptor + LoggingInterceptor loggingInterceptor = new LoggingInterceptor(); + + // Optionally you may configure the interceptor (by default only + // summary info is logged) + loggingInterceptor.setLogRequestSummary(true); + loggingInterceptor.setLogRequestBody(true); + + // Register the interceptor with your client (either style) + IPatientClient annotationClient = ctx.newRestfulClient(IPatientClient.class, "http://localhost:9999/fhir"); + annotationClient.registerInterceptor(loggingInterceptor); + + IGenericClient genericClient = ctx.newRestfulGenericClient("http://localhost:9999/fhir"); + genericClient.registerInterceptor(loggingInterceptor); + // END SNIPPET: logging + } + + /******************************/ + { + // START SNIPPET: clientConfig + // Create a client + FhirContext ctx = new FhirContext(); + IPatientClient client = ctx.newRestfulClient(IPatientClient.class, "http://localhost:9999/"); + + // Request JSON encoding from the server (_format=json) + client.setEncoding(EncodingEnum.JSON); + + // Request pretty printing from the server (_pretty=true) + client.setPrettyPrint(true); + // END SNIPPET: clientConfig + } + } + +} diff --git a/hapi-fhir-base/examples/src/main/java/example/CompleteExampleClient.java b/hapi-fhir-base/examples/src/main/java/example/CompleteExampleClient.java new file mode 100644 index 00000000000..50f6a4263a1 --- /dev/null +++ b/hapi-fhir-base/examples/src/main/java/example/CompleteExampleClient.java @@ -0,0 +1,66 @@ +package example; + +//START SNIPPET: client +import java.io.IOException; +import java.util.List; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.dstu.composite.IdentifierDt; +import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; +import ca.uhn.fhir.model.dstu.resource.Organization; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.client.api.IRestfulClient; + +public class CompleteExampleClient { + + /** + * This is a simple client interface. It can have many methods for various + * searches but in this case it has only 1. + */ + public static interface ClientInterface extends IRestfulClient { + + /** + * This is translated into a URL similar to the following: + * http://fhir.healthintersections.com.au/open/Patient?identifier=urn:oid:1.2.36.146.595.217.0.1%7C12345 + */ + @Search + List findPatientsForMrn(@RequiredParam(name = Patient.SP_IDENTIFIER) IdentifierDt theIdentifier); + + } + + /** + * The main method here will directly call an open FHIR server and retrieve a + * list of resources matching a given criteria, then load a linked resource. + */ + public static void main(String[] args) throws IOException { + + // Create a client factory + FhirContext ctx = new FhirContext(); + + // Create the client + String serverBase = "http://fhir.healthintersections.com.au/open"; + ClientInterface client = ctx.newRestfulClient(ClientInterface.class, serverBase); + + // Invoke the client to search for patient + List patients = client.findPatientsForMrn(new IdentifierDt("urn:oid:1.2.36.146.595.217.0.1", "12345")); + + System.out.println("Found " + patients.size() + " patients"); + + // Print a value from the loaded resource + Patient patient = patients.get(0); + System.out.println("Patient Last Name: " + patient.getName().get(0).getFamily().get(0).getValue()); + + // Load a referenced resource + ResourceReferenceDt managingRef = patient.getManagingOrganization(); + Organization org = (Organization) managingRef.loadResource(client); + + // Print organization name + System.out.println(org.getName().getValue()); + + } + +} +// END SNIPPET: client + diff --git a/hapi-fhir-base/src/site/example/java/example/ExampleProviders.java b/hapi-fhir-base/examples/src/main/java/example/ExampleProviders.java similarity index 100% rename from hapi-fhir-base/src/site/example/java/example/ExampleProviders.java rename to hapi-fhir-base/examples/src/main/java/example/ExampleProviders.java diff --git a/hapi-fhir-base/src/site/example/java/example/ExampleRestfulClient.java b/hapi-fhir-base/examples/src/main/java/example/ExampleRestfulClient.java similarity index 100% rename from hapi-fhir-base/src/site/example/java/example/ExampleRestfulClient.java rename to hapi-fhir-base/examples/src/main/java/example/ExampleRestfulClient.java diff --git a/hapi-fhir-base/src/site/example/java/example/ExampleRestfulServlet.java b/hapi-fhir-base/examples/src/main/java/example/ExampleRestfulServlet.java similarity index 100% rename from hapi-fhir-base/src/site/example/java/example/ExampleRestfulServlet.java rename to hapi-fhir-base/examples/src/main/java/example/ExampleRestfulServlet.java diff --git a/hapi-fhir-base/src/site/example/java/example/Extensions.java b/hapi-fhir-base/examples/src/main/java/example/Extensions.java similarity index 100% rename from hapi-fhir-base/src/site/example/java/example/Extensions.java rename to hapi-fhir-base/examples/src/main/java/example/Extensions.java diff --git a/hapi-fhir-base/src/site/example/java/example/FhirContextIntro.java b/hapi-fhir-base/examples/src/main/java/example/FhirContextIntro.java similarity index 100% rename from hapi-fhir-base/src/site/example/java/example/FhirContextIntro.java rename to hapi-fhir-base/examples/src/main/java/example/FhirContextIntro.java diff --git a/hapi-fhir-base/src/site/example/java/example/FhirDataModel.java b/hapi-fhir-base/examples/src/main/java/example/FhirDataModel.java similarity index 100% rename from hapi-fhir-base/src/site/example/java/example/FhirDataModel.java rename to hapi-fhir-base/examples/src/main/java/example/FhirDataModel.java diff --git a/hapi-fhir-base/src/site/example/java/example/GenericClientExample.java b/hapi-fhir-base/examples/src/main/java/example/GenericClientExample.java similarity index 91% rename from hapi-fhir-base/src/site/example/java/example/GenericClientExample.java rename to hapi-fhir-base/examples/src/main/java/example/GenericClientExample.java index 97920283720..4805c3f3411 100644 --- a/hapi-fhir-base/src/site/example/java/example/GenericClientExample.java +++ b/hapi-fhir-base/examples/src/main/java/example/GenericClientExample.java @@ -17,22 +17,19 @@ import ca.uhn.fhir.rest.method.SearchStyleEnum; public class GenericClientExample { -@SuppressWarnings("unused") public static void simpleExample() { // START SNIPPET: simple FhirContext ctx = new FhirContext(); -String serverBase = "http://fhir.healthintersections.com.au/open"; +String serverBase = "http://fhirtest.uhn.ca/base"; IGenericClient client = ctx.newRestfulGenericClient(serverBase); -// Read a patient -Patient patient = client.read(Patient.class, "1"); +// Perform a search +Bundle results = client.search() + .forResource(Patient.class) + .where(Patient.FAMILY.matches().value("duck")) + .execute(); -// Change the patient and update it to the server -patient.getNameFirstRep().getFamilyFirstRep().setValue("Jones"); -client.update("1", patient); - -// Return the version history for that patient -Bundle versions = client.history(Patient.class, "1",null,null); +System.out.println("Found " + results.size() + " patients named 'duck'"); // END SNIPPET: simple } @@ -177,7 +174,7 @@ List response = client.transaction() } public static void main(String[] args) { - // nothing + simpleExample(); } } diff --git a/hapi-fhir-base/src/site/example/java/example/IRestfulClient.java b/hapi-fhir-base/examples/src/main/java/example/IRestfulClient.java similarity index 100% rename from hapi-fhir-base/src/site/example/java/example/IRestfulClient.java rename to hapi-fhir-base/examples/src/main/java/example/IRestfulClient.java diff --git a/hapi-fhir-base/src/site/example/java/example/MyPatient.java b/hapi-fhir-base/examples/src/main/java/example/MyPatient.java similarity index 100% rename from hapi-fhir-base/src/site/example/java/example/MyPatient.java rename to hapi-fhir-base/examples/src/main/java/example/MyPatient.java diff --git a/hapi-fhir-base/examples/src/main/java/example/MyPatientUse.java b/hapi-fhir-base/examples/src/main/java/example/MyPatientUse.java new file mode 100644 index 00000000000..1604fb237c4 --- /dev/null +++ b/hapi-fhir-base/examples/src/main/java/example/MyPatientUse.java @@ -0,0 +1,86 @@ +package example; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.RuntimeResourceDefinition; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.api.annotation.Extension; +import ca.uhn.fhir.model.api.annotation.ResourceDef; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.DateTimeDt; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.parser.DataFormatException; +import ca.uhn.fhir.parser.IParser; + +public class MyPatientUse { + + @ResourceDef + public static class MyPatient extends Patient { + + @Child(name="petName") + @Extension(url="http://example.com/dontuse#petname", definedLocally=false, isModifier=false) + @Description(shortDefinition="The name of the patient's favourite pet") + private StringDt myPetName; + + public StringDt getPetName() { + if(myPetName==null) { + myPetName = new StringDt(); + } + return myPetName; + } + + public void setPetName(StringDt thePetName) { + myPetName = thePetName; + } + + public List getImportantDates() { + if (myImportantDates==null) { + myImportantDates=new ArrayList(); + } + return myImportantDates; + } + + public void setImportantDates(List theImportantDates) { + myImportantDates = theImportantDates; + } + + @Child(name="importantDates", max=Child.MAX_UNLIMITED) + @Extension(url="http://example.com/dontuse#importantDates", definedLocally=false, isModifier=true) + @Description(shortDefinition="Some dates of note for the patient") + private List myImportantDates; + + } + +@SuppressWarnings("unused") +public static void main(String[] args) throws DataFormatException, IOException { +//START SNIPPET: patientUse +MyPatient patient = new MyPatient(); +patient.setPetName(new StringDt("Fido")); +patient.getImportantDates().add(new DateTimeDt("2010-01-02")); +patient.getImportantDates().add(new DateTimeDt("2014-01-26T11:11:11")); + +patient.addName().addFamily("Smith").addGiven("John").addGiven("Quincy").addSuffix("Jr"); + +IParser p = new FhirContext().newXmlParser().setPrettyPrint(true); +String messageString = p.encodeResourceToString(patient); + +System.out.println(messageString); +//END SNIPPET: patientUse + +//START SNIPPET: patientParse +IParser parser = new FhirContext().newXmlParser(); +MyPatient newPatient = parser.parseResource(MyPatient.class, messageString); +//END SNIPPET: patientParse + +{ + FhirContext ctx2 = new FhirContext(); + RuntimeResourceDefinition def = ctx2.getResourceDefinition(patient); + System.out.println(ctx2.newXmlParser().setPrettyPrint(true).encodeResourceToString(def.toProfile())); +} +} + +} diff --git a/hapi-fhir-base/src/site/example/java/example/Narrative.java b/hapi-fhir-base/examples/src/main/java/example/Narrative.java similarity index 100% rename from hapi-fhir-base/src/site/example/java/example/Narrative.java rename to hapi-fhir-base/examples/src/main/java/example/Narrative.java diff --git a/hapi-fhir-base/src/site/example/java/example/NarrativeGenerator.java b/hapi-fhir-base/examples/src/main/java/example/NarrativeGenerator.java similarity index 100% rename from hapi-fhir-base/src/site/example/java/example/NarrativeGenerator.java rename to hapi-fhir-base/examples/src/main/java/example/NarrativeGenerator.java diff --git a/hapi-fhir-base/src/site/example/java/example/PagingPatientProvider.java b/hapi-fhir-base/examples/src/main/java/example/PagingPatientProvider.java similarity index 100% rename from hapi-fhir-base/src/site/example/java/example/PagingPatientProvider.java rename to hapi-fhir-base/examples/src/main/java/example/PagingPatientProvider.java diff --git a/hapi-fhir-base/src/site/example/java/example/PagingServer.java b/hapi-fhir-base/examples/src/main/java/example/PagingServer.java similarity index 100% rename from hapi-fhir-base/src/site/example/java/example/PagingServer.java rename to hapi-fhir-base/examples/src/main/java/example/PagingServer.java diff --git a/hapi-fhir-base/src/site/example/java/example/QuickUsage.java b/hapi-fhir-base/examples/src/main/java/example/QuickUsage.java similarity index 100% rename from hapi-fhir-base/src/site/example/java/example/QuickUsage.java rename to hapi-fhir-base/examples/src/main/java/example/QuickUsage.java diff --git a/hapi-fhir-base/src/site/example/java/example/RestfulObservationResourceProvider.java b/hapi-fhir-base/examples/src/main/java/example/RestfulObservationResourceProvider.java similarity index 100% rename from hapi-fhir-base/src/site/example/java/example/RestfulObservationResourceProvider.java rename to hapi-fhir-base/examples/src/main/java/example/RestfulObservationResourceProvider.java diff --git a/hapi-fhir-base/src/site/example/java/example/RestfulPatientResourceProvider.java b/hapi-fhir-base/examples/src/main/java/example/RestfulPatientResourceProvider.java similarity index 100% rename from hapi-fhir-base/src/site/example/java/example/RestfulPatientResourceProvider.java rename to hapi-fhir-base/examples/src/main/java/example/RestfulPatientResourceProvider.java diff --git a/hapi-fhir-base/src/site/example/java/example/RestfulPatientResourceProviderMore.java b/hapi-fhir-base/examples/src/main/java/example/RestfulPatientResourceProviderMore.java similarity index 99% rename from hapi-fhir-base/src/site/example/java/example/RestfulPatientResourceProviderMore.java rename to hapi-fhir-base/examples/src/main/java/example/RestfulPatientResourceProviderMore.java index 6f4c3c1d6f8..1bb652fbafd 100644 --- a/hapi-fhir-base/src/site/example/java/example/RestfulPatientResourceProviderMore.java +++ b/hapi-fhir-base/examples/src/main/java/example/RestfulPatientResourceProviderMore.java @@ -19,7 +19,7 @@ import ca.uhn.fhir.model.api.Tag; import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.api.TemporalPrecisionEnum; import ca.uhn.fhir.model.api.annotation.Description; -import ca.uhn.fhir.model.api.annotation.TagListParam; +import ca.uhn.fhir.rest.annotation.TagListParam; import ca.uhn.fhir.model.dstu.composite.CodingDt; import ca.uhn.fhir.model.dstu.resource.Conformance; import ca.uhn.fhir.model.dstu.resource.DiagnosticReport; @@ -57,7 +57,6 @@ import ca.uhn.fhir.rest.annotation.Validate; import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.SortOrderEnum; import ca.uhn.fhir.rest.api.SortSpec; -import ca.uhn.fhir.rest.client.ITestClient; import ca.uhn.fhir.rest.client.api.IBasicClient; import ca.uhn.fhir.rest.client.api.IRestfulClient; import ca.uhn.fhir.rest.param.CompositeParam; @@ -78,6 +77,14 @@ import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; @SuppressWarnings("unused") public abstract class RestfulPatientResourceProviderMore implements IResourceProvider { + public interface ITestClient extends IBasicClient + { + + @Search + List getPatientByDob(@RequiredParam(name=Patient.SP_BIRTHDATE) DateParam theParam); + + } + private boolean detectedVersionConflict; private boolean conflictHappened; private boolean couldntFindThisId; diff --git a/hapi-fhir-base/examples/src/main/java/example/ServerMetadataExamples.java b/hapi-fhir-base/examples/src/main/java/example/ServerMetadataExamples.java new file mode 100644 index 00000000000..d9f5621e3a8 --- /dev/null +++ b/hapi-fhir-base/examples/src/main/java/example/ServerMetadataExamples.java @@ -0,0 +1,56 @@ +package example; + +import java.util.ArrayList; +import java.util.List; + +import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; +import ca.uhn.fhir.model.api.Tag; +import ca.uhn.fhir.model.api.TagList; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.InstantDt; +import ca.uhn.fhir.rest.annotation.Search; + +public class ServerMetadataExamples { + + // START SNIPPET: serverMethod + @Search + public List getAllPatients() { + ArrayList retVal = new ArrayList(); + + // Create a patient to return + Patient patient = new Patient(); + retVal.add(patient); + patient.setId("Patient/123"); + patient.addName().addFamily("Smith").addGiven("John"); + + // Create a tag list and add it to the resource + TagList tags = new TagList(); + tags.addTag(Tag.HL7_ORG_FHIR_TAG, "http://foo/tag1.html", "Some tag"); + tags.addTag(Tag.HL7_ORG_FHIR_TAG, "http://foo/tag2.html", "Another tag"); + ResourceMetadataKeyEnum.TAG_LIST.put(patient, tags); + + // Set some links (these can be provided as relative links or absolute) + // and the server will convert to absolute as appropriate + String linkAlternate = "Patient/7736"; + ResourceMetadataKeyEnum.LINK_ALTERNATE.put(patient, linkAlternate); + String linkSearch = "Patient?name=smith&name=john"; + ResourceMetadataKeyEnum.LINK_SEARCH.put(patient, linkSearch); + + // Set the published and updated dates + InstantDt pubDate = new InstantDt("2011-02-22"); + ResourceMetadataKeyEnum.PUBLISHED.put(patient, pubDate); + InstantDt updatedDate = new InstantDt("2014-07-12T11:22:27Z"); + ResourceMetadataKeyEnum.UPDATED.put(patient, updatedDate); + + // Set the resource title (note that if you are using HAPI's narrative + // generation capability, the narrative generator will often create + // useful titles automatically, and the server will create a default + // title if none is provided) + String title = "Patient John SMITH"; + ResourceMetadataKeyEnum.TITLE.put(patient, title); + + return retVal; + } + // END SNIPPET: serverMethod + +} diff --git a/hapi-fhir-base/examples/src/main/java/example/TagsExamples.java b/hapi-fhir-base/examples/src/main/java/example/TagsExamples.java new file mode 100644 index 00000000000..fd4ac010d41 --- /dev/null +++ b/hapi-fhir-base/examples/src/main/java/example/TagsExamples.java @@ -0,0 +1,71 @@ +package example; + +import java.util.ArrayList; +import java.util.List; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; +import ca.uhn.fhir.model.api.Tag; +import ca.uhn.fhir.model.api.TagList; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.client.IGenericClient; + +public class TagsExamples { + + public static void main(String[] args) { + new TagsExamples().getResourceTags(); + } + + @SuppressWarnings("unused") + public void getResourceTags() { + // START SNIPPET: getResourceTags + IGenericClient client = new FhirContext().newRestfulGenericClient("http://fhir.healthintersections.com.au/open"); + Patient p = client.read(Patient.class, "1"); + + // Retrieve the list of tags from the resource metadata + TagList tags = ResourceMetadataKeyEnum.TAG_LIST.get(p); + + // tags may be null if no tags were read in + if (tags == null) { + System.out.println("No tags!"); + } else { + + // You may iterate over all the tags + for (Tag next : tags) { + System.out.println(next.getScheme() + " - " + next.getTerm()); + } + + // You may also get a list of tags matching a given scheme + List someTags = tags.getTagsWithScheme("http://hl7.org/fhir/tag"); + + // Or a specific tag (by scheme and term) + Tag specificTag = tags.getTag("http://hl7.org/fhir/tag", "http://foo"); + + } + // END SNIPPET: getResourceTags + } + + // START SNIPPET: serverMethod + @Search + public List getAllPatients() { + ArrayList retVal = new ArrayList(); + + // Create a patient to return + Patient patient = new Patient(); + patient.setId("Patient/123"); + patient.addName().addFamily("Smith").addGiven("John"); + + // Create a tag list and add it to the resource + TagList tags = new TagList(); + ResourceMetadataKeyEnum.TAG_LIST.put(patient, tags); + + // Add some tags to the list + tags.addTag(Tag.HL7_ORG_FHIR_TAG, "http://foo/tag1.html", "Some tag"); + tags.addTag(Tag.HL7_ORG_FHIR_TAG, "http://foo/tag2.html", "Another tag"); + + return retVal; + } + // END SNIPPET: serverMethod + +} diff --git a/hapi-fhir-base/pom.xml b/hapi-fhir-base/pom.xml index 55aa2383028..25a1be95a15 100644 --- a/hapi-fhir-base/pom.xml +++ b/hapi-fhir-base/pom.xml @@ -8,10 +8,10 @@ ../pom.xml - ca.uhn.hapi.fhir hapi-fhir-base jar - http://hl7api.sourceforge.net/hapi-fhir/ + + http://jamesagnew.github.io/hapi-fhir/ HAPI FHIR - Core Library @@ -20,14 +20,11 @@ git.server scm:git:git@github.com:jamesagnew/hapi-fhir.git - - - javax.json javax.json-api diff --git a/hapi-fhir-base/src/changes/changes.xml b/hapi-fhir-base/src/changes/changes.xml index 8ac10dd3579..70ee8f7634a 100644 --- a/hapi-fhir-base/src/changes/changes.xml +++ b/hapi-fhir-base/src/changes/changes.xml @@ -7,9 +7,11 @@ + Tester UI created double _format and _pretty param entries in searches. Thanks to Gered King of University Health Network for reporting! @@ -72,14 +74,26 @@ is "yyyy-mm-dd" anyhow, and this is correctly handled). Thanks to Jeffrey Ting of Systems Made Simple for reporting! - - Server now adds a profile tag to returned results if the resource being returned - doesn't already have one - Server search method for an unnamed query gets called if the client requests a named query with the same parameter list. Thanks to Neal Acharya of University Health Network for reporting! + + Category header (for tags) is correctly read in client for "read" operation + + + Transaction method in server can now have parameter type Bundle instead of + List<IResource> + + + HAPI parsers now use field access to get/set values instead of method accessors and mutators. + This should give a small performance boost. + + + JSON parser encodes resource references incorrectly, using the name "resource" instead + of the name "reference" for the actual reference. Thanks to + Ricky Nguyen for reporting and tracking down the issue! + diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeDeclaredChildDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeDeclaredChildDefinition.java index 0d78457d8aa..a917d150cce 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeDeclaredChildDefinition.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeDeclaredChildDefinition.java @@ -204,8 +204,7 @@ public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChil if (values == null) { return Collections.emptyList(); } - @SuppressWarnings("unchecked") - List retVal = (List) Collections.singletonList(values); + List retVal = (List) Collections.singletonList((IElement)values); return retVal; } catch (IllegalArgumentException e) { throw new ConfigurationException("Failed to get value", e); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java index 34cb0a692d6..ae4450aab70 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java @@ -585,25 +585,37 @@ class ModelScanner { private String scanResource(Class theClass, ResourceDef resourceDefinition) { ourLog.debug("Scanning resource class: {}", theClass.getName()); + boolean primaryNameProvider = true; String resourceName = resourceDefinition.name(); if (isBlank(resourceName)) { - throw new ConfigurationException("Resource type @" + ResourceDef.class.getSimpleName() + " annotation contains no resource name: " + theClass.getCanonicalName()); - } - - if (myNameToResourceDefinitions.containsKey(resourceName)) { - if (!myNameToResourceDefinitions.get(resourceName).getImplementingClass().equals(theClass)) { - // throw new - // ConfigurationException("Detected duplicate element name '" + - // resourceName + "' in types '" + theClass.getCanonicalName() + - // "' and '" - // + - // myNameToResourceDefinitions.get(resourceName).getImplementingClass() - // + "'"); - } else { - return resourceName; + Class parent = theClass.getSuperclass(); + primaryNameProvider=false; + while (parent.equals(Object.class)==false && isBlank(resourceName)) { + ResourceDef nextDef = parent.getAnnotation(ResourceDef.class); + if (nextDef != null) { + resourceName = nextDef.name(); + } + parent = parent.getSuperclass(); + } + if (isBlank(resourceName)) { + throw new ConfigurationException("Resource type @" + ResourceDef.class.getSimpleName() + " annotation contains no resource name(): " + theClass.getCanonicalName() + " - This is only allowed for types that extend other resource types "); } } +// if (myNameToResourceDefinitions.containsKey(resourceName)) { +// if (!myNameToResourceDefinitions.get(resourceName).getImplementingClass().equals(theClass)) { +// // throw new +// // ConfigurationException("Detected duplicate element name '" + +// // resourceName + "' in types '" + theClass.getCanonicalName() + +// // "' and '" +// // + +// // myNameToResourceDefinitions.get(resourceName).getImplementingClass() +// // + "'"); +// } else { +// return resourceName; +// } +// } + String resourceId = resourceDefinition.id(); if (isBlank(resourceId)) { // throw new ConfigurationException("Resource type @" + @@ -619,10 +631,11 @@ class ModelScanner { String profile = resourceDefinition.profile(); - RuntimeResourceDefinition resourceDef = new RuntimeResourceDefinition(theClass, resourceDefinition); + RuntimeResourceDefinition resourceDef = new RuntimeResourceDefinition(resourceName, theClass, resourceDefinition); myClassToElementDefinitions.put(theClass, resourceDef); - myNameToResourceDefinitions.put(resourceName, resourceDef); - + if (primaryNameProvider) { + myNameToResourceDefinitions.put(resourceName, resourceDef); + } scanCompositeElementForChildren(theClass, resourceDef); myIdToResourceDefinition.put(resourceId, resourceDef); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildChoiceDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildChoiceDefinition.java index cf5b18f96ec..2d7d02377f6 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildChoiceDefinition.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildChoiceDefinition.java @@ -34,6 +34,7 @@ import ca.uhn.fhir.model.api.IElement; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.annotation.Child; import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; public class RuntimeChildChoiceDefinition extends BaseRuntimeDeclaredChildDefinition { @@ -103,6 +104,11 @@ public class RuntimeChildChoiceDefinition extends BaseRuntimeDeclaredChildDefini if (alternateElementName != null) { myNameToChildDefinition.put(alternateElementName, nextDef); } + + if (IResource.class.isAssignableFrom(next)) { + myDatatypeToElementDefinition.put(ResourceReferenceDt.class, nextDef); + } + myDatatypeToElementDefinition.put(next, nextDef); myDatatypeToElementName.put(next, elementName); } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeResourceDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeResourceDefinition.java index 62c91ceefe5..74195f4bf05 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeResourceDefinition.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeResourceDefinition.java @@ -60,8 +60,8 @@ public class RuntimeResourceDefinition extends BaseRuntimeElementCompositeDefini private List mySearchParams; private String myId; - public RuntimeResourceDefinition(Class theClass, ResourceDef theResourceAnnotation) { - super(theResourceAnnotation.name(), theClass); + public RuntimeResourceDefinition(String theResourceName, Class theClass, ResourceDef theResourceAnnotation) { + super(theResourceName, theClass); myResourceProfile = theResourceAnnotation.profile(); myId = theResourceAnnotation.id(); } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Bundle.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Bundle.java index 4f242e019c3..8db3a1aeba1 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Bundle.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Bundle.java @@ -20,7 +20,7 @@ package ca.uhn.fhir.model.api; * #L% */ -import static org.apache.commons.lang3.StringUtils.isNotBlank; +import static org.apache.commons.lang3.StringUtils.*; import java.util.ArrayList; import java.util.HashMap; @@ -38,16 +38,12 @@ import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.model.primitive.IntegerDt; import ca.uhn.fhir.model.primitive.StringDt; import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.util.UrlUtil; public class Bundle extends BaseBundle /* implements IElement */{ private volatile transient Map myIdToEntries; - //@formatter:off - /* **************************************************** - * NB: add any new fields to the isEmpty() method!!! - *****************************************************/ - //@formatter:on private List myEntries; private StringDt myBundleId; private StringDt myLinkBase; @@ -60,6 +56,7 @@ public class Bundle extends BaseBundle /* implements IElement */{ private StringDt myTitle; private IntegerDt myTotalResults; private InstantDt myUpdated; + private TagList myCategories; /** * Returns true if this bundle contains zero entries @@ -69,6 +66,16 @@ public class Bundle extends BaseBundle /* implements IElement */{ return getEntries().isEmpty(); } + public Tag addCategory() { + Tag retVal = new Tag(); + getCategories().add(retVal); + return retVal; + } + + public void addCategory(Tag theTag) { + getCategories().add(theTag); + } + /** * Adds and returns a new bundle entry */ @@ -81,12 +88,15 @@ public class Bundle extends BaseBundle /* implements IElement */{ /** * Retrieves a resource from a bundle given its logical ID. *

- * Important usage notes: This method ignores base URLs (so passing in an ID of http://foo/Patient/123 will return a resource if it has the logical ID of - * http://bar/Patient/123. Also, this method is intended to be used for bundles which have already been populated. It will cache its results for fast performance, but that means that - * modifications to the bundle after this method is called may not be accurately reflected. + * Important usage notes: This method ignores base URLs (so passing in an ID of + * http://foo/Patient/123 will return a resource if it has the logical ID of + * http://bar/Patient/123. Also, this method is intended to be used for bundles which have already been + * populated. It will cache its results for fast performance, but that means that modifications to the bundle after + * this method is called may not be accurately reflected. *

* - * @param theId The resource ID + * @param theId + * The resource ID * @return Returns the resource with the given ID, or null if none is found */ public IResource getResourceById(IdDt theId) { @@ -103,31 +113,43 @@ public class Bundle extends BaseBundle /* implements IElement */{ return map.get(theId.toUnqualified()); } -// public static void main(String[] args) { -// -// FhirContext ctx = new FhirContext(); -// String txt = "\n" + -// " \n" + -// " \n" + -// " \n" + -// " \n" + -// " \n" + -// "
\n" + -// " \n" + -// " \n" + -// " \n" + -// " \n" + -// " \n" + -// ""; -// -// IGenericClient c = ctx.newRestfulGenericClient("http://fhirtest.uhn.ca/base"); -// c.registerInterceptor(new LoggingInterceptor(true)); -// c.update().resource(txt).withId("1665").execute(); -// } -// + // public static void main(String[] args) { + // + // FhirContext ctx = new FhirContext(); + // String txt = "\n" + + // " \n" + + // " \n" + + // " \n" + + // " \n" + + // " \n" + + // "
\n" + + // " \n" + + // " \n" + + // " \n" + + // " \n" + + // " \n" + + // ""; + // + // IGenericClient c = ctx.newRestfulGenericClient("http://fhirtest.uhn.ca/base"); + // c.registerInterceptor(new LoggingInterceptor(true)); + // c.update().resource(txt).withId("1665").execute(); + // } + // + + public TagList getCategories() { + if (myCategories == null) { + myCategories = new TagList(); + } + return myCategories; + } + + public void setCategories(TagList theCategories) { + myCategories = theCategories; + } + public List getEntries() { if (myEntries == null) { myEntries = new ArrayList(); @@ -263,14 +285,12 @@ public class Bundle extends BaseBundle /* implements IElement */{ * * @param theResource * The resource to add - * @return Returns the newly created bundle entry that was added to the bundle + * @return Returns the newly created bundle entry that was added to the bundle */ public BundleEntry addResource(IResource theResource, FhirContext theContext, String theServerBase) { BundleEntry entry = addEntry(); entry.setResource(theResource); - entry.setResource(theResource); - RuntimeResourceDefinition def = theContext.getResourceDefinition(theResource); String title = ResourceMetadataKeyEnum.TITLE.get(theResource); @@ -279,7 +299,7 @@ public class Bundle extends BaseBundle /* implements IElement */{ } else { entry.getTitle().setValue(def.getName() + " " + StringUtils.defaultString(theResource.getId().getValue(), "(no ID)")); } - + if (theResource.getId() != null && StringUtils.isNotBlank(theResource.getId().getValue())) { StringBuilder b = new StringBuilder(); @@ -311,7 +331,25 @@ public class Bundle extends BaseBundle /* implements IElement */{ String qualifiedId = b.toString(); entry.getLinkSelf().setValue(qualifiedId); - + + // String resourceType = theContext.getResourceDefinition(theResource).getName(); + + String linkSearch = ResourceMetadataKeyEnum.LINK_SEARCH.get(theResource); + if (isNotBlank(linkSearch)) { + if (!UrlUtil.isAbsolute(linkSearch)) { + linkSearch = (theServerBase + "/" + linkSearch); + } + entry.getLinkSearch().setValue(linkSearch); + } + + String linkAlternate = ResourceMetadataKeyEnum.LINK_ALTERNATE.get(theResource); + if (isNotBlank(linkAlternate)) { + if (!UrlUtil.isAbsolute(linkAlternate)) { + linkSearch = (theServerBase + "/" + linkAlternate); + } + entry.getLinkAlternate().setValue(linkSearch); + } + } InstantDt published = ResourceMetadataKeyEnum.PUBLISHED.get(theResource); @@ -346,9 +384,9 @@ public class Bundle extends BaseBundle /* implements IElement */{ return entry; } - public static Bundle withResources(ArrayList theUploadBundle, FhirContext theContext, String theServerBase) { + public static Bundle withResources(List theResources, FhirContext theContext, String theServerBase) { Bundle retVal = new Bundle(); - for (IResource next : theUploadBundle) { + for (IResource next : theResources) { retVal.addResource(next, theContext, theServerBase); } return retVal; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/ResourceMetadataKeyEnum.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/ResourceMetadataKeyEnum.java index d73cf580001..3997550f8ca 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/ResourceMetadataKeyEnum.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/ResourceMetadataKeyEnum.java @@ -197,6 +197,52 @@ public abstract class ResourceMetadataKeyEnum { } }; + /** + * If present and populated with a string, provides the "search link" (the link + * element in the bundle entry with rel="search"). Server implementations + * may populate this with a complete URL, in which case the URL will be + * placed as-is in the bundle. They may alternately specify a + * resource relative URL (e.g. "Patient?name=tester") in which case the + * server will convert this to an absolute URL at runtime. + *

+ * Values for this key are of type {@link String} + *

+ */ + public static final ResourceMetadataKeyEnum LINK_SEARCH = new ResourceMetadataKeyEnum("LINK_SEARCH") { + @Override + public String get(IResource theResource) { + return getStringFromMetadataOrNullIfNone(theResource.getResourceMetadata(), LINK_SEARCH); + } + + @Override + public void put(IResource theResource, String theObject) { + theResource.getResourceMetadata().put(LINK_SEARCH, theObject); + } + }; + + /** + * If present and populated with a string, provides the "alternate link" (the link + * element in the bundle entry with rel="alternate"). Server implementations + * may populate this with a complete URL, in which case the URL will be + * placed as-is in the bundle. They may alternately specify a + * resource relative URL (e.g. "Patient/1243") in which case the + * server will convert this to an absolute URL at runtime. + *

+ * Values for this key are of type {@link String} + *

+ */ + public static final ResourceMetadataKeyEnum LINK_ALTERNATE = new ResourceMetadataKeyEnum("LINK_ALTERNATE") { + @Override + public String get(IResource theResource) { + return getStringFromMetadataOrNullIfNone(theResource.getResourceMetadata(), LINK_ALTERNATE); + } + + @Override + public void put(IResource theResource, String theObject) { + theResource.getResourceMetadata().put(LINK_ALTERNATE, theObject); + } + }; + private final String myValue; public ResourceMetadataKeyEnum(String theValue) { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Tag.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Tag.java index cebbf68d328..a238d27b832 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Tag.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Tag.java @@ -35,6 +35,18 @@ public class Tag extends BaseElement implements IElement { */ public static final String HL7_ORG_FHIR_TAG = "http://hl7.org/fhir/tag"; + /** + * Convenience constant containing the "http://hl7.org/fhir/tag/security" scheme + * value + */ + public static final String HL7_ORG_SECURITY_TAG = "http://hl7.org/fhir/tag/security"; + + /** + * Convenience constant containing the "http://hl7.org/fhir/tag/profile" scheme + * value + */ + public static final String HL7_ORG_PROFILE_TAG = "http://hl7.org/fhir/tag/profile"; + public static final String ATTR_TERM = "term"; public static final String ATTR_LABEL = "label"; public static final String ATTR_SCHEME = "scheme"; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/TagList.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/TagList.java index 9818c57a9c7..458540976bb 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/TagList.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/TagList.java @@ -21,6 +21,7 @@ package ca.uhn.fhir.model.api; */ import java.util.ArrayList; +import java.util.List; public class TagList extends ArrayList { @@ -48,7 +49,7 @@ public class TagList extends ArrayList { return null; } - public ArrayList getTagsWithScheme(String theScheme) { + public List getTagsWithScheme(String theScheme) { ArrayList retVal = new ArrayList(); for (Tag next : this) { if (theScheme.equals(next.getScheme())) { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/annotation/ResourceDef.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/annotation/ResourceDef.java index 6d9668de911..817b981b01f 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/annotation/ResourceDef.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/annotation/ResourceDef.java @@ -35,7 +35,7 @@ public @interface ResourceDef { /** * The name of the resource (e.g. "Patient" or "DiagnosticReport") */ - String name(); + String name() default ""; /** * Not currently used diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/IdDt.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/IdDt.java index dc36af0bc05..1654f7a3721 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/IdDt.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/IdDt.java @@ -34,6 +34,7 @@ import ca.uhn.fhir.model.api.annotation.DatatypeDef; import ca.uhn.fhir.model.api.annotation.SimpleSetter; import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.util.UrlUtil; /** * Represents the FHIR ID type. This is the actual resource ID, meaning the ID that will be used in RESTful URLs, @@ -253,6 +254,14 @@ public class IdDt extends BasePrimitive { return isNotBlank(getVersionIdPart()); } + /** + * Returns true if this ID contains an absolute URL (in other words, a URL starting with "http://" or + * "https://" + */ + public boolean isAbsolute() { + return UrlUtil.isAbsolute(getValue()); + } + /** * Returns true if the unqualified ID is a valid {@link Long} value (in other words, it consists only * of digits) diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/view/ViewGenerator.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/view/ViewGenerator.java index afa06b84f47..27807d57331 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/view/ViewGenerator.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/view/ViewGenerator.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.model.view; +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.util.List; import ca.uhn.fhir.context.BaseRuntimeChildDefinition; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java index fae9a39f18a..79490dcef92 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java @@ -166,6 +166,8 @@ public class JsonParser extends BaseParser implements IParser { if (linkStarted) { eventWriter.writeEnd(); } + + writeCategories(eventWriter, theBundle.getCategories()); writeOptionalTagWithTextNode(eventWriter, "totalResults", theBundle.getTotalResults()); @@ -193,17 +195,7 @@ public class JsonParser extends BaseParser implements IParser { writeOptionalTagWithTextNode(eventWriter, "updated", nextEntry.getUpdated()); writeOptionalTagWithTextNode(eventWriter, "published", nextEntry.getPublished()); - if (nextEntry.getCategories() != null && nextEntry.getCategories().size() > 0) { - eventWriter.writeStartArray("category"); - for (Tag next : nextEntry.getCategories()) { - eventWriter.writeStartObject(); - eventWriter.write("term", defaultString(next.getTerm())); - eventWriter.write("label", defaultString(next.getLabel())); - eventWriter.write("scheme", defaultString(next.getScheme())); - eventWriter.writeEnd(); - } - eventWriter.writeEnd(); - } + writeCategories(eventWriter, nextEntry.getCategories()); writeAuthor(nextEntry, eventWriter); @@ -221,6 +213,20 @@ public class JsonParser extends BaseParser implements IParser { eventWriter.flush(); } + private void writeCategories(JsonGenerator eventWriter, TagList categories) { + if (categories != null && categories.size() > 0) { + eventWriter.writeStartArray("category"); + for (Tag next : categories) { + eventWriter.writeStartObject(); + eventWriter.write("term", defaultString(next.getTerm())); + eventWriter.write("label", defaultString(next.getLabel())); + eventWriter.write("scheme", defaultString(next.getScheme())); + eventWriter.writeEnd(); + } + eventWriter.writeEnd(); + } + } + private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, JsonGenerator theWriter, IElement theValue, BaseRuntimeElementDefinition theChildDef, String theChildName) throws IOException { @@ -291,10 +297,10 @@ public class JsonParser extends BaseParser implements IParser { } if (StringUtils.isNotBlank(reference)) { - theWriter.write("resource", reference); + theWriter.write(XmlParser.RESREF_REFERENCE, reference); } if (referenceDt.getDisplay().isEmpty() == false) { - theWriter.write("display", referenceDt.getDisplay().getValueAsString()); + theWriter.write(XmlParser.RESREF_DISPLAY, referenceDt.getDisplay().getValueAsString()); } theWriter.writeEnd(); break; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java index 3018c2f7f6e..a78a5679161 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java @@ -20,8 +20,7 @@ package ca.uhn.fhir.parser; * #L% */ -import static org.apache.commons.lang3.StringUtils.defaultIfBlank; -import static org.apache.commons.lang3.StringUtils.isNotBlank; +import static org.apache.commons.lang3.StringUtils.*; import java.util.ArrayList; import java.util.HashMap; @@ -67,6 +66,7 @@ import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.model.primitive.XhtmlDt; import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.util.IModelVisitor; class ParserState { @@ -474,6 +474,12 @@ class ParserState { metadata.put(ResourceMetadataKeyEnum.VERSION_ID, linkSelf); } } + if (!myEntry.getLinkAlternate().isEmpty()) { + ResourceMetadataKeyEnum.LINK_ALTERNATE.put(myEntry.getResource(), myEntry.getLinkAlternate().getValue()); + } + if (!myEntry.getLinkSearch().isEmpty()) { + ResourceMetadataKeyEnum.LINK_SEARCH.put(myEntry.getResource(), myEntry.getLinkSearch().getValue()); + } } @@ -622,6 +628,8 @@ class ParserState { push(new AtomPrimitiveState(myInstance.getUpdated())); } else if ("author".equals(theLocalPart)) { push(new AtomAuthorState(myInstance)); + } else if ("category".equals(theLocalPart)) { + push(new AtomCategoryState(myInstance.getCategories().addTag())); } else if ("deleted-entry".equals(theLocalPart) && verifyNamespace(XmlParser.TOMBSTONES_NS, theNamespaceURI)) { push(new AtomDeletedEntryState(myInstance, myResourceType)); } else { @@ -902,7 +910,7 @@ class ParserState { public void attributeValue(String theName, String theValue) throws DataFormatException { if ("id".equals(theName)) { if (myInstance instanceof IIdentifiableElement) { - ((IIdentifiableElement) myInstance).setId(new IdDt(theValue)); + ((IIdentifiableElement) myInstance).setElementSpecificId((theValue)); } else if (myInstance instanceof IResource) { ((IResource) myInstance).setId(new IdDt(theValue)); } @@ -1249,20 +1257,32 @@ class ParserState { myObject = (T) myInstance; } - for (ResourceReferenceDt nextRef : myResourceReferences) { - String ref = nextRef.getReference().getValue(); - if (isNotBlank(ref)) { - if (ref.startsWith("#")) { - IResource target = myContainedResources.get(ref.substring(1)); - if (target != null) { - nextRef.setResource(target); - } else { - ourLog.warn("Resource contains unknown local ref: " + ref); + myContext.newTerser().visit(myInstance, new IModelVisitor() { + + @Override + public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, ExtensionDt theNextExt) { + acceptElement(theNextExt.getValue(), null, null); + } + + @Override + public void acceptElement(IElement theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition) { + if (theElement instanceof ResourceReferenceDt) { + ResourceReferenceDt nextRef = (ResourceReferenceDt)theElement; + String ref = nextRef.getReference().getValue(); + if (isNotBlank(ref)) { + if (ref.startsWith("#")) { + IResource target = myContainedResources.get(ref.substring(1)); + if (target != null) { + nextRef.setResource(target); + } else { + ourLog.warn("Resource contains unknown local ref: " + ref); + } + } } } } - } - + }); + } } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java index 571dd838bc8..071ce0b5ff5 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java @@ -80,6 +80,8 @@ import ca.uhn.fhir.util.NonPrettyPrintWriterWrapper; import ca.uhn.fhir.util.PrettyPrintWriterWrapper; public class XmlParser extends BaseParser implements IParser { + static final String RESREF_DISPLAY = "display"; + static final String RESREF_REFERENCE = "reference"; private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParser.class); static final String ATOM_NS = "http://www.w3.org/2005/Atom"; static final String FHIR_NS = "http://hl7.org/fhir"; @@ -144,6 +146,8 @@ public class XmlParser extends BaseParser implements IParser { eventWriter.writeEndElement(); } + writeCategories(eventWriter, theBundle.getCategories()); + for (BundleEntry nextEntry : theBundle.getEntries()) { boolean deleted = false; if (nextEntry.getDeletedAt() != null && nextEntry.getDeletedAt().isEmpty() == false) { @@ -182,15 +186,7 @@ public class XmlParser extends BaseParser implements IParser { writeOptionalTagWithTextNode(eventWriter, "updated", nextEntry.getUpdated()); writeOptionalTagWithTextNode(eventWriter, "published", nextEntry.getPublished()); - if (nextEntry.getCategories() != null) { - for (Tag next : nextEntry.getCategories()) { - eventWriter.writeStartElement("category"); - eventWriter.writeAttribute("term", defaultString(next.getTerm())); - eventWriter.writeAttribute("label", defaultString(next.getLabel())); - eventWriter.writeAttribute("scheme", defaultString(next.getScheme())); - eventWriter.writeEndElement(); - } - } + writeCategories(eventWriter, nextEntry.getCategories()); if (!nextEntry.getLinkSelf().isEmpty()) { writeAtomLink(eventWriter, "self", nextEntry.getLinkSelf()); @@ -224,6 +220,18 @@ public class XmlParser extends BaseParser implements IParser { } } + private void writeCategories(XMLStreamWriter eventWriter, TagList categories) throws XMLStreamException { + if (categories != null) { + for (Tag next : categories) { + eventWriter.writeStartElement("category"); + eventWriter.writeAttribute("term", defaultString(next.getTerm())); + eventWriter.writeAttribute("label", defaultString(next.getLabel())); + eventWriter.writeAttribute("scheme", defaultString(next.getScheme())); + eventWriter.writeEndElement(); + } + } + } + @Override public String encodeResourceToString(IResource theResource) throws DataFormatException { if (theResource == null) { @@ -550,12 +558,12 @@ public class XmlParser extends BaseParser implements IParser { // } if (!(theRef.getDisplay().isEmpty())) { - theEventWriter.writeStartElement("display"); + theEventWriter.writeStartElement(RESREF_DISPLAY); theEventWriter.writeAttribute("value", theRef.getDisplay().getValue()); theEventWriter.writeEndElement(); } if (StringUtils.isNotBlank(reference)) { - theEventWriter.writeStartElement("reference"); + theEventWriter.writeStartElement(RESREF_REFERENCE); theEventWriter.writeAttribute("value", reference); theEventWriter.writeEndElement(); } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/annotation/TransactionParam.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/annotation/TransactionParam.java index 63c854f7a08..415562a5723 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/annotation/TransactionParam.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/annotation/TransactionParam.java @@ -24,7 +24,15 @@ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.util.List; +import ca.uhn.fhir.model.api.Bundle; + +/** + * Parameter annotation for the "transaction" operation. The parameter annotated with this + * annotation must be either of type {@link Bundle} or of type + * {@link List}<IResource> + */ @Target(value=ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface TransactionParam { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java index cc8028d595f..cdabdedb088 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java @@ -20,8 +20,6 @@ package ca.uhn.fhir.rest.method; * #L% */ -import static org.apache.commons.lang3.StringUtils.isBlank; - import java.io.IOException; import java.io.Reader; import java.io.Writer; @@ -39,7 +37,6 @@ import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; -import ca.uhn.fhir.model.api.Tag; import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum; import ca.uhn.fhir.model.primitive.IdDt; @@ -54,9 +51,7 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding { - private static final String LABEL = "label=\""; static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseOutcomeReturningMethodBinding.class); - private static final String SCHEME = "scheme=\""; private boolean myReturnVoid; @@ -118,7 +113,7 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding enumeration = theRequest.getServletRequest().getHeaders(Constants.HEADER_CATEGORY); enumeration.hasMoreElements();) { String nextTagComplete = enumeration.nextElement(); - parseTagValue(tagList, nextTagComplete); + MethodUtil.parseTagValue(tagList, nextTagComplete); } if (tagList.isEmpty() == false) { resource.getResourceMetadata().put(ResourceMetadataKeyEnum.TAG_LIST, tagList); @@ -218,19 +213,25 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding 0 && theBuffer.charAt(0) == ' ') { - theBuffer.deleteCharAt(0); - } - - while (theBuffer.length() > 0) { - boolean foundSomething = false; - if (theBuffer.length() > SCHEME.length() && theBuffer.substring(0, SCHEME.length()).equals(SCHEME)) { - int closeIdx = theBuffer.indexOf("\"", SCHEME.length()); - scheme = theBuffer.substring(SCHEME.length(), closeIdx); - theBuffer.delete(0, closeIdx + 1); - foundSomething = true; - } - if (theBuffer.length() > LABEL.length() && theBuffer.substring(0, LABEL.length()).equals(LABEL)) { - int closeIdx = theBuffer.indexOf("\"", LABEL.length()); - label = theBuffer.substring(LABEL.length(), closeIdx); - theBuffer.delete(0, closeIdx + 1); - foundSomething = true; - } - // TODO: support enc2231-string as described in - // http://tools.ietf.org/html/draft-johnston-http-category-header-02 - // TODO: support multiple tags in one header as described in - // http://hl7.org/implement/standards/fhir/http.html#tags - - while (theBuffer.length() > 0 && (theBuffer.charAt(0) == ' ' || theBuffer.charAt(0) == ';')) { - theBuffer.deleteCharAt(0); - } - - if (!foundSomething) { - break; - } - } - - if (theBuffer.length() > 0 && theBuffer.charAt(0) == ',') { - theBuffer.deleteCharAt(0); - while (theBuffer.length() > 0 && theBuffer.charAt(0) == ' ') { - theBuffer.deleteCharAt(0); - } - theTagList.add(new Tag(scheme, term, label)); - parseTagValue(theTagList, theCompleteHeaderValue, theBuffer); - } else { - theTagList.add(new Tag(scheme, term, label)); - } - - if (theBuffer.length() > 0) { - ourLog.warn("Ignoring extra text at the end of " + Constants.HEADER_CATEGORY + " tag '" + theBuffer.toString() + "' - Complete tag value was: " + theCompleteHeaderValue); - } - - } - protected abstract void addParametersForServerRequest(Request theRequest, Object[] theParams); /** @@ -366,6 +274,16 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding provideAllowableRequestTypes(); /** @@ -425,4 +343,5 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding categoryHeaders = theHeaders.get(Constants.HEADER_CATEGORY_LC); + if (categoryHeaders != null && categoryHeaders.size() > 0 && StringUtils.isNotBlank(categoryHeaders.get(0))) { + TagList tagList = new TagList(); + for (String header : categoryHeaders) { + parseTagValue(tagList, header); + } + ResourceMetadataKeyEnum.TAG_LIST.put(resource, tagList); + } } + public static void parseTagValue(TagList tagList, String nextTagComplete) { + StringBuilder next = new StringBuilder(nextTagComplete); + parseTagValue(tagList, nextTagComplete, next); + } + + private static void parseTagValue(TagList theTagList, String theCompleteHeaderValue, StringBuilder theBuffer) { + int firstSemicolon = theBuffer.indexOf(";"); + int deleteTo; + if (firstSemicolon == -1) { + firstSemicolon = theBuffer.indexOf(","); + if (firstSemicolon == -1) { + firstSemicolon = theBuffer.length(); + deleteTo = theBuffer.length(); + } else { + deleteTo = firstSemicolon; + } + } else { + deleteTo = firstSemicolon + 1; + } + + String term = theBuffer.substring(0, firstSemicolon); + String scheme = null; + String label = null; + if (isBlank(term)) { + return; + } + + theBuffer.delete(0, deleteTo); + while (theBuffer.length() > 0 && theBuffer.charAt(0) == ' ') { + theBuffer.deleteCharAt(0); + } + + while (theBuffer.length() > 0) { + boolean foundSomething = false; + if (theBuffer.length() > SCHEME.length() && theBuffer.substring(0, SCHEME.length()).equals(SCHEME)) { + int closeIdx = theBuffer.indexOf("\"", SCHEME.length()); + scheme = theBuffer.substring(SCHEME.length(), closeIdx); + theBuffer.delete(0, closeIdx + 1); + foundSomething = true; + } + if (theBuffer.length() > LABEL.length() && theBuffer.substring(0, LABEL.length()).equals(LABEL)) { + int closeIdx = theBuffer.indexOf("\"", LABEL.length()); + label = theBuffer.substring(LABEL.length(), closeIdx); + theBuffer.delete(0, closeIdx + 1); + foundSomething = true; + } + // TODO: support enc2231-string as described in + // http://tools.ietf.org/html/draft-johnston-http-category-header-02 + // TODO: support multiple tags in one header as described in + // http://hl7.org/implement/standards/fhir/http.html#tags + + while (theBuffer.length() > 0 && (theBuffer.charAt(0) == ' ' || theBuffer.charAt(0) == ';')) { + theBuffer.deleteCharAt(0); + } + + if (!foundSomething) { + break; + } + } + + if (theBuffer.length() > 0 && theBuffer.charAt(0) == ',') { + theBuffer.deleteCharAt(0); + while (theBuffer.length() > 0 && theBuffer.charAt(0) == ' ') { + theBuffer.deleteCharAt(0); + } + theTagList.add(new Tag(scheme, term, label)); + parseTagValue(theTagList, theCompleteHeaderValue, theBuffer); + } else { + theTagList.add(new Tag(scheme, term, label)); + } + + if (theBuffer.length() > 0) { + ourLog.warn("Ignoring extra text at the end of " + Constants.HEADER_CATEGORY + " tag '" + theBuffer.toString() + "' - Complete tag value was: " + theCompleteHeaderValue); + } + + } + + static void addTagsToPostOrPut(IResource resource, BaseHttpClientInvocation retVal) { TagList list = (TagList) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.TAG_LIST); if (list != null) { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/TransactionMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/TransactionMethodBinding.java index e95f3f4cc6a..9f04d473a4c 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/TransactionMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/TransactionMethodBinding.java @@ -20,11 +20,11 @@ package ca.uhn.fhir.rest.method; * #L% */ -import static org.apache.commons.lang3.StringUtils.isNotBlank; +import static org.apache.commons.lang3.StringUtils.*; import java.io.IOException; import java.lang.reflect.Method; -import java.util.ArrayList; +import java.util.IdentityHashMap; import java.util.List; import ca.uhn.fhir.context.ConfigurationException; @@ -52,9 +52,9 @@ public class TransactionMethodBinding extends BaseResourceReturningMethodBinding public TransactionMethodBinding(Method theMethod, FhirContext theConetxt, Object theProvider) { super(null, theMethod, theConetxt, theProvider); - + myTransactionParamIndex = -1; - int index=0; + int index = 0; for (IParameter next : getParameters()) { if (next instanceof TransactionParamBinder) { myTransactionParamIndex = index; @@ -62,7 +62,7 @@ public class TransactionMethodBinding extends BaseResourceReturningMethodBinding index++; } - if (myTransactionParamIndex==-1) { + if (myTransactionParamIndex == -1) { throw new ConfigurationException("Method '" + theMethod.getName() + "' in type " + theMethod.getDeclaringClass().getCanonicalName() + " does not have a parameter annotated with the @" + TransactionParam.class + " annotation"); } } @@ -72,7 +72,6 @@ public class TransactionMethodBinding extends BaseResourceReturningMethodBinding return RestfulOperationSystemEnum.TRANSACTION; } - @Override public boolean incomingServerRequestMatchesMethod(Request theRequest) { if (theRequest.getRequestType() != RequestType.POST) { @@ -95,16 +94,24 @@ public class TransactionMethodBinding extends BaseResourceReturningMethodBinding @SuppressWarnings("unchecked") @Override public IBundleProvider invokeServer(Request theRequest, Object[] theMethodParams) throws InvalidRequestException, InternalErrorException { - List resources = (List) theMethodParams[myTransactionParamIndex]; - - List oldIds= new ArrayList(); - for (IResource next : resources) { - oldIds.add(next.getId()); + // Grab the IDs of all of the resources in the transaction + List resources; + if (theMethodParams[myTransactionParamIndex] instanceof Bundle) { + resources = ((Bundle) theMethodParams[myTransactionParamIndex]).toListOfResources(); + } else { + resources = (List) theMethodParams[myTransactionParamIndex]; } - Object response= invokeServerMethod(theMethodParams); + IdentityHashMap oldIds = new IdentityHashMap(); + for (IResource next : resources) { + oldIds.put(next, next.getId()); + } + + // Call the server implementation method + Object response = invokeServerMethod(theMethodParams); IBundleProvider retVal = toResourceList(response); - + + /* int offset = 0; if (retVal.size() != resources.size()) { if (retVal.size() > 0 && retVal.getResources(0, 1).get(0) instanceof OperationOutcome) { @@ -113,24 +120,30 @@ public class TransactionMethodBinding extends BaseResourceReturningMethodBinding throw new InternalErrorException("Transaction bundle contained " + resources.size() + " entries, but server method response contained " + retVal.size() + " entries (must be the same)"); } } + */ - List retResources = retVal.getResources(offset, retVal.size()); - for (int i =0; i < resources.size(); i++) { - IdDt oldId = oldIds.get(i); + List retResources = retVal.getResources(0, retVal.size()); + for (int i = 0; i < retResources.size(); i++) { + IdDt oldId = oldIds.get(retResources.get(i)); IResource newRes = retResources.get(i); if (newRes.getId() == null || newRes.getId().isEmpty()) { - throw new InternalErrorException("Transaction method returned resource at index " + i + " with no id specified - IResource#setId(IdDt)"); + if (!(newRes instanceof OperationOutcome)) { + throw new InternalErrorException("Transaction method returned resource at index " + i + " with no id specified - IResource#setId(IdDt)"); + } } - + if (oldId != null && !oldId.isEmpty()) { if (!oldId.equals(newRes.getId())) { newRes.getResourceMetadata().put(ResourceMetadataKeyEnum.PREVIOUS_ID, oldId); } } } - + return retVal; - } + + + + } @Override protected Object parseRequestObject(Request theRequest) throws IOException { @@ -147,11 +160,15 @@ public class TransactionMethodBinding extends BaseResourceReturningMethodBinding @Override public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException { - @SuppressWarnings("unchecked") - List resources = (List) theArgs[myTransactionParamIndex]; FhirContext context = getContext(); - - return createTransactionInvocation(resources, context); + if (theArgs[myTransactionParamIndex] instanceof Bundle) { + Bundle bundle = (Bundle) theArgs[myTransactionParamIndex]; + return createTransactionInvocation(bundle, context); + } else { + @SuppressWarnings("unchecked") + List resources = (List) theArgs[myTransactionParamIndex]; + return createTransactionInvocation(resources, context); + } } public static BaseHttpClientInvocation createTransactionInvocation(List theResources, FhirContext theContext) { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/TransactionParamBinder.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/TransactionParamBinder.java index 0f4ef87a5c9..22e23b9d6e2 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/TransactionParamBinder.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/TransactionParamBinder.java @@ -38,40 +38,56 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; class TransactionParamBinder implements IParameter { + private boolean myParamIsBundle; + public TransactionParamBinder() { } - + @Override public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map> theTargetQueryArguments, BaseHttpClientInvocation theClientInvocation) throws InternalErrorException { // TODO Auto-generated method stub - + } @Override public Object translateQueryParametersIntoServerArgument(Request theRequest, Object theRequestContents) throws InternalErrorException, InvalidRequestException { Bundle resource = (Bundle) theRequestContents; - + if (myParamIsBundle) { + return resource; + } + ArrayList retVal = new ArrayList(); for (BundleEntry next : resource.getEntries()) { if (next.getResource() != null) { retVal.add(next.getResource()); } } - + return retVal; } @Override public void initializeTypes(Method theMethod, Class> theOuterCollectionType, Class> theInnerCollectionType, Class theParameterType) { if (theOuterCollectionType != null) { - throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" +theMethod.getDeclaringClass().getCanonicalName()+ "' is annotated with @" + TransactionParam.class.getName() + " but can not be a collection of collections"); + throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" + theMethod.getDeclaringClass().getCanonicalName() + "' is annotated with @" + TransactionParam.class.getName() + " but can not be a collection of collections"); } - if (theInnerCollectionType.equals(List.class)==false) { - throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" +theMethod.getDeclaringClass().getCanonicalName()+ "' is annotated with @" + TransactionParam.class.getName() + " but is not of type List<" + IResource.class.getCanonicalName()+">"); - } - if (theParameterType.equals(IResource.class)==false) { - throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" +theMethod.getDeclaringClass().getCanonicalName()+ "' is annotated with @" + TransactionParam.class.getName() + " but is not of type List<" + IResource.class.getCanonicalName()+">"); + if (theParameterType.equals(Bundle.class)) { + myParamIsBundle=true; + if (theInnerCollectionType!=null) { + throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" + theMethod.getDeclaringClass().getCanonicalName() + "' is annotated with @" + TransactionParam.class.getName() + " but is not of type List<" + IResource.class.getCanonicalName() + + "> or Bundle"); + } + } else { + myParamIsBundle=false; + if (theInnerCollectionType.equals(List.class) == false) { + throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" + theMethod.getDeclaringClass().getCanonicalName() + "' is annotated with @" + TransactionParam.class.getName() + " but is not of type List<" + IResource.class.getCanonicalName() + + "> or Bundle"); + } + if (theParameterType.equals(IResource.class) == false) { + throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" + theMethod.getDeclaringClass().getCanonicalName() + "' is annotated with @" + TransactionParam.class.getName() + " but is not of type List<" + IResource.class.getCanonicalName() + + "> or Bundle"); + } } } - + } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/BaseParam.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/BaseParam.java index 7b3a1cfae2e..91b44f85f8a 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/BaseParam.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/BaseParam.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.rest.param; +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.rest.server.Constants; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/Constants.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/Constants.java index 2e71ec2d5e7..24b414793eb 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/Constants.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/Constants.java @@ -48,6 +48,7 @@ public class Constants { public static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding"; public static final String HEADER_AUTHORIZATION = "Authorization"; public static final String HEADER_CATEGORY = "Category"; + public static final String HEADER_CATEGORY_LC = HEADER_CATEGORY.toLowerCase(); public static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition"; public static final String HEADER_CONTENT_ENCODING = "Content-Encoding"; public static final String HEADER_CONTENT_LOCATION = "Content-Location"; @@ -97,8 +98,6 @@ public class Constants { public static final int STATUS_HTTP_500_INTERNAL_ERROR = 500; public static final int STATUS_HTTP_501_NOT_IMPLEMENTED = 501; public static final String URL_TOKEN_HISTORY = "_history"; - public static final String TAG_SCHEME_PROFILE = "http://hl7.org/fhir/tag/profile "; - static { Map valToEncoding = new HashMap(); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java index 6632894eced..ac48f1eaca4 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java @@ -844,46 +844,48 @@ public class RestfulServer extends HttpServlet { } } } - + // Linked resources may themselves have linked resources references = new ArrayList(); for (IResource iResource : addedResourcesThisPass) { List newReferences = theContext.newTerser().getAllPopulatedChildElementsOfType(iResource, ResourceReferenceDt.class); references.addAll(newReferences); } - + addedResources.addAll(addedResourcesThisPass); - + } while (references.isEmpty() == false); - - BundleEntry entry = bundle.addResource(next, theContext, theServerBase); - addProfileToBundleEntry(theContext, next, entry); - + + bundle.addResource(next, theContext, theServerBase); +// addProfileToBundleEntry(theContext, next, entry); + } /* * Actually add the resources to the bundle */ for (IResource next : addedResources) { - BundleEntry entry = bundle.addResource(next, theContext, theServerBase); - addProfileToBundleEntry(theContext, next, entry); + bundle.addResource(next, theContext, theServerBase); +// addProfileToBundleEntry(theContext, next, entry); } bundle.getTotalResults().setValue(theTotalResults); return bundle; } + /* private static void addProfileToBundleEntry(FhirContext theContext, IResource next, BundleEntry entry) { - ArrayList profileTags = entry.getCategories().getTagsWithScheme(Constants.TAG_SCHEME_PROFILE); + List profileTags = entry.getCategories().getTagsWithScheme(Tag.HL7_ORG_PROFILE_TAG); if (profileTags.isEmpty()) { RuntimeResourceDefinition nextDef = theContext.getResourceDefinition(next); String profile = nextDef.getResourceProfile(); if (isNotBlank(profile)) { - entry.addCategory(new Tag(Constants.TAG_SCHEME_PROFILE, profile, null)); + entry.addCategory(new Tag(Tag.HL7_ORG_PROFILE_TAG, profile, null)); } } } - + */ + public static String createPagingLink(String theServerBase, String theSearchId, int theOffset, int theCount, EncodingEnum theResponseEncoding, boolean thePrettyPrint) { StringBuilder b = new StringBuilder(); b.append(theServerBase); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/AuthenticationException.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/AuthenticationException.java index c863964832e..ca8a931e68c 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/AuthenticationException.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/AuthenticationException.java @@ -1,7 +1,5 @@ package ca.uhn.fhir.rest.server.exceptions; -import java.text.ParseException; - import ca.uhn.fhir.rest.server.Constants; /* @@ -41,7 +39,7 @@ public class AuthenticationException extends BaseServerResponseException { super(STATUS_CODE, theMessage); } - public AuthenticationException(String theMessage, ParseException theCause) { + public AuthenticationException(String theMessage, Throwable theCause) { super(STATUS_CODE, theMessage, theCause); } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/BaseServerResponseException.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/BaseServerResponseException.java index c8a1dd95ea8..4725ef95c2b 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/BaseServerResponseException.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/BaseServerResponseException.java @@ -27,9 +27,8 @@ import ca.uhn.fhir.model.dstu.resource.OperationOutcome; */ /** - * Base class for RESTful client and server exceptions. RESTful client methods - * will only throw exceptions which are subclasses of this exception type, and - * RESTful server methods should also only call subclasses of this exception + * Base class for RESTful client and server exceptions. RESTful client methods will only throw exceptions which are + * subclasses of this exception type, and RESTful server methods should also only call subclasses of this exception * type. */ public abstract class BaseServerResponseException extends RuntimeException { @@ -50,10 +49,8 @@ public abstract class BaseServerResponseException extends RuntimeException { } private final OperationOutcome myOperationOutcome; - private String myResponseBody; private String myResponseMimeType; - private int myStatusCode; /** @@ -77,6 +74,9 @@ public abstract class BaseServerResponseException extends RuntimeException { * The HTTP status code corresponding to this problem * @param theMessage * The message + * @param theOperationOutcome + * An OperationOutcome resource to return to the calling client (in a server) or the OperationOutcome + * that was returned from the server (in a client) */ public BaseServerResponseException(int theStatusCode, String theMessage, OperationOutcome theOperationOutcome) { super(theMessage); @@ -100,6 +100,25 @@ public abstract class BaseServerResponseException extends RuntimeException { myOperationOutcome = null; } + /** + * Constructor + * + * @param theStatusCode + * The HTTP status code corresponding to this problem + * @param theMessage + * The message + * @param theCause + * The underlying cause exception + * @param theOperationOutcome + * An OperationOutcome resource to return to the calling client (in a server) or the OperationOutcome + * that was returned from the server (in a client) + */ + public BaseServerResponseException(int theStatusCode, String theMessage, Throwable theCause, OperationOutcome theOperationOutcome) { + super(theMessage, theCause); + myStatusCode = theStatusCode; + myOperationOutcome = theOperationOutcome; + } + /** * Constructor * @@ -115,17 +134,32 @@ public abstract class BaseServerResponseException extends RuntimeException { } /** - * Returns the {@link OperationOutcome} resource if any which was supplied - * in the response, or null + * Constructor + * + * @param theStatusCode + * The HTTP status code corresponding to this problem + * @param theCause + * The underlying cause exception + * @param theOperationOutcome + * An OperationOutcome resource to return to the calling client (in a server) or the OperationOutcome + * that was returned from the server (in a client) + */ + public BaseServerResponseException(int theStatusCode, Throwable theCause, OperationOutcome theOperationOutcome) { + super(theCause.toString(), theCause); + myStatusCode = theStatusCode; + myOperationOutcome = theOperationOutcome; + } + + /** + * Returns the {@link OperationOutcome} resource if any which was supplied in the response, or null */ public OperationOutcome getOperationOutcome() { return myOperationOutcome; } /** - * In a RESTful client, this method will be populated with the body of the - * HTTP respone if one was provided by the server, or null - * otherwise. + * In a RESTful client, this method will be populated with the body of the HTTP respone if one was provided by the + * server, or null otherwise. *

* In a restful server, this method is currently ignored. *

@@ -135,8 +169,8 @@ public abstract class BaseServerResponseException extends RuntimeException { } /** - * In a RESTful client, this method will be populated with the HTTP status - * code that was returned with the HTTP response. + * In a RESTful client, this method will be populated with the HTTP status code that was returned with the HTTP + * response. *

* In a restful server, this method is currently ignored. *

@@ -153,16 +187,14 @@ public abstract class BaseServerResponseException extends RuntimeException { } /** - * This method is currently only called internally by HAPI, it should not be - * called by user code. + * This method is currently only called internally by HAPI, it should not be called by user code. */ public void setResponseBody(String theResponseBody) { myResponseBody = theResponseBody; } /** - * This method is currently only called internally by HAPI, it should not be - * called by user code. + * This method is currently only called internally by HAPI, it should not be called by user code. */ public void setResponseMimeType(String theResponseMimeType) { myResponseMimeType = theResponseMimeType; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java index 1aa4144ff21..3557348d702 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java @@ -37,6 +37,7 @@ import ca.uhn.fhir.model.api.IElement; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions; import ca.uhn.fhir.model.dstu.composite.ContainedDt; +import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; import ca.uhn.fhir.model.primitive.StringDt; import ca.uhn.fhir.parser.DataFormatException; @@ -108,31 +109,69 @@ public class FhirTerser { } /** - * Returns a list containing all child elements (including the resource itself) which are non-empty - * and are either of the exact type specified, or are a subclass of that type. + * Visit all elements in a given resource + * + * @param theResource The resource to visit + * @param theVisitor The visitor + */ + public void visit(IResource theResource, IModelVisitor theVisitor) { + BaseRuntimeElementCompositeDefinition def = myContext.getResourceDefinition(theResource); + visit(theResource, null, def, theVisitor); + } + + /** + * Returns a list containing all child elements (including the resource itself) which are non-empty and are + * either of the exact type specified, or are a subclass of that type. *

- * For example, specifying a type of {@link StringDt} would return all non-empty string instances within - * the message. Specifying a type of {@link IResource} would return the resource itself, as well as any contained resources. - *

- * @param theResourceT The resource instance to search. Must not be null. - * @param theType The type to search for. Must not be null. + * For example, specifying a type of {@link StringDt} would return all non-empty string instances within the + * message. Specifying a type of {@link IResource} would return the resource itself, as well as any contained + * resources. + *

+ * + * @param theResourceT + * The resource instance to search. Must not be null. + * @param theType + * The type to search for. Must not be null. * @return */ - public List getAllPopulatedChildElementsOfType(IResource theResource, Class theType) { - ArrayList retVal = new ArrayList(); + public List getAllPopulatedChildElementsOfType(IResource theResource, final Class theType) { + final ArrayList retVal = new ArrayList(); BaseRuntimeElementCompositeDefinition def = myContext.getResourceDefinition(theResource); - getAllChildElementsOfType(theResource, def, theType, retVal); + visit(theResource, null, def, new IModelVisitor() { + @SuppressWarnings("unchecked") + @Override + public void acceptElement(IElement theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition) { + if (theElement.isEmpty()) { + return; + } + + if (theElement != null && theType.isAssignableFrom(theElement.getClass())) { + retVal.add((T) theElement); + } + } + + @SuppressWarnings("unchecked") + @Override + public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, ExtensionDt theNextExt) { + if (theType.isAssignableFrom(theNextExt.getClass())) { + retVal.add((T) theNextExt); + } + if (theNextExt.getValue() != null && theType.isAssignableFrom(theNextExt.getValue().getClass())) { + retVal.add((T) theNextExt.getValue()); + } + } + }); return retVal; } - private void getAllChildElementsOfType(IElement theElement, BaseRuntimeElementDefinition theDefinition, Class theType, ArrayList theList) { - if (theElement.isEmpty()) { - return; - } - - addIfCorrectType(theElement, theType, theList); - addUndeclaredExtensions(theElement, theType, theList); + private void visit(IElement theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, IModelVisitor theCallback) { + theCallback.acceptElement(theElement, theChildDefinition, theDefinition); + addUndeclaredExtensions(theElement, theDefinition, theChildDefinition, theCallback); +// if (theElement.isEmpty()) { +// return; +// } + switch (theDefinition.getChildType()) { case PRIMITIVE_XHTML: case PRIMITIVE_DATATYPE: @@ -153,7 +192,9 @@ public class FhirTerser { if (nextValue.isEmpty()) { continue; } - BaseRuntimeElementDefinition childElementDef = nextChild.getChildElementDefinitionByDatatype(nextValue.getClass()); + BaseRuntimeElementDefinition childElementDef; + childElementDef = nextChild.getChildElementDefinitionByDatatype(nextValue.getClass()); + if (childElementDef == null) { StringBuilder b = new StringBuilder(); b.append("Found value of type["); @@ -171,7 +212,7 @@ public class FhirTerser { } throw new DataFormatException(b.toString()); } - getAllChildElementsOfType(nextValue, childElementDef, theType, theList); + visit(nextValue, nextChild, childElementDef, theCallback); } } } @@ -181,7 +222,7 @@ public class FhirTerser { ContainedDt value = (ContainedDt) theElement; for (IResource next : value.getContainedResources()) { BaseRuntimeElementCompositeDefinition def = myContext.getResourceDefinition(next); - getAllChildElementsOfType(next, def, theType, theList); + visit(next, null, def, theCallback); } break; } @@ -192,22 +233,14 @@ public class FhirTerser { } } - private void addUndeclaredExtensions(IElement theElement, Class theType, ArrayList theList) { + private void addUndeclaredExtensions(IElement theElement, BaseRuntimeElementDefinition theDefinition, BaseRuntimeChildDefinition theChildDefinition, IModelVisitor theCallback) { if (theElement instanceof ISupportsUndeclaredExtensions) { - ISupportsUndeclaredExtensions elem = (ISupportsUndeclaredExtensions) theElement; - for (ExtensionDt nextExt : elem.getUndeclaredExtensions()) { - addIfCorrectType(nextExt, theType, theList); - addIfCorrectType(nextExt.getValue(), theType, theList); - addUndeclaredExtensions(nextExt, theType, theList); + ISupportsUndeclaredExtensions containingElement = (ISupportsUndeclaredExtensions) theElement; + for (ExtensionDt nextExt : containingElement.getUndeclaredExtensions()) { + theCallback.acceptUndeclaredExtension(containingElement, theChildDefinition, theDefinition, nextExt); + addUndeclaredExtensions(nextExt, theDefinition, theChildDefinition, theCallback); } } } - @SuppressWarnings("unchecked") - private void addIfCorrectType(IElement theElement, Class theType, ArrayList theList) { - if (theElement != null && theType.isAssignableFrom(theElement.getClass())) { - theList.add((T) theElement); - } - } - } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/IModelVisitor.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/IModelVisitor.java new file mode 100644 index 00000000000..47fd52f6757 --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/IModelVisitor.java @@ -0,0 +1,53 @@ +package ca.uhn.fhir.util; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import ca.uhn.fhir.context.BaseRuntimeChildDefinition; +import ca.uhn.fhir.context.BaseRuntimeElementDefinition; +import ca.uhn.fhir.model.api.ExtensionDt; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions; + +/** + * @see FhirTerser#visit(ca.uhn.fhir.model.api.IResource, IModelVisitor) + */ +public interface IModelVisitor { + + /** + * + * @param theElement + * @param theChildDefinition May be null if this is a root element + * @param theDefinition + */ + void acceptElement(IElement theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition); + + /** + * + * @param theContainingElement + * @param theChildDefinition May be null if this is a root element + * @param theDefinition + * @param theNextExt + */ + void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, ExtensionDt theNextExt); + + + +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/UrlUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/UrlUtil.java new file mode 100644 index 00000000000..3d3eee15854 --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/UrlUtil.java @@ -0,0 +1,30 @@ +package ca.uhn.fhir.util; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +public class UrlUtil { + + public static boolean isAbsolute(String theValue) { + String value = theValue.toLowerCase(); + return value.startsWith("http://") || value.startsWith("https://"); + } + +} diff --git a/hapi-fhir-base/src/site/example/java/example/ClientExamples.java b/hapi-fhir-base/src/site/example/java/example/ClientExamples.java deleted file mode 100644 index 24ce61cc761..00000000000 --- a/hapi-fhir-base/src/site/example/java/example/ClientExamples.java +++ /dev/null @@ -1,90 +0,0 @@ -package example; - -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.rest.client.IGenericClient; -import ca.uhn.fhir.rest.client.IRestfulClientFactory; -import ca.uhn.fhir.rest.client.api.IBasicClient; -import ca.uhn.fhir.rest.client.interceptor.BasicAuthInterceptor; -import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; -import ca.uhn.fhir.rest.server.EncodingEnum; - -public class ClientExamples { - - public interface IPatientClient extends IBasicClient { - // nothing yet - } - - @SuppressWarnings("unused") - public void createProxy() { -//START SNIPPET: proxy -FhirContext ctx = new FhirContext(); -ctx.getRestfulClientFactory().setProxy("example.com", 8888); - -IGenericClient genericClient = ctx.newRestfulGenericClient("http://localhost:9999/fhir"); -//START SNIPPET: end - } - - @SuppressWarnings("unused") - public void createSecurity() { -//START SNIPPET: security -// Create a context and get the client factory so it can be configured -FhirContext ctx = new FhirContext(); -IRestfulClientFactory clientFactory = ctx.getRestfulClientFactory(); - -//Create an HTTP basic auth interceptor -String username = "foobar"; -String password = "boobear"; -BasicAuthInterceptor authInterceptor = new BasicAuthInterceptor(username, password); - -// Register the interceptor with your client (either style) -IPatientClient annotationClient = ctx.newRestfulClient(IPatientClient.class, "http://localhost:9999/fhir"); -annotationClient.registerInterceptor(authInterceptor); - -IGenericClient genericClient = ctx.newRestfulGenericClient("http://localhost:9999/fhir"); -annotationClient.registerInterceptor(authInterceptor); -//END SNIPPET: security -} - -@SuppressWarnings("unused") -public void createLogging() { -{ -//START SNIPPET: logging -//Create a context and get the client factory so it can be configured -FhirContext ctx = new FhirContext(); -IRestfulClientFactory clientFactory = ctx.getRestfulClientFactory(); - -//Create a logging interceptor -LoggingInterceptor loggingInterceptor = new LoggingInterceptor(); - -// Optionally you may configure the interceptor (by default only summary info is logged) -loggingInterceptor.setLogRequestSummary(true); -loggingInterceptor.setLogRequestBody(true); - -//Register the interceptor with your client (either style) -IPatientClient annotationClient = ctx.newRestfulClient(IPatientClient.class, "http://localhost:9999/fhir"); -annotationClient.registerInterceptor(loggingInterceptor); - -IGenericClient genericClient = ctx.newRestfulGenericClient("http://localhost:9999/fhir"); -genericClient.registerInterceptor(loggingInterceptor); -//END SNIPPET: logging -} - - - -/******************************/ -{ -//START SNIPPET: clientConfig -//Create a client -FhirContext ctx = new FhirContext(); -IPatientClient client = ctx.newRestfulClient(IPatientClient.class, "http://localhost:9999/"); - -// Request JSON encoding from the server (_format=json) -client.setEncoding(EncodingEnum.JSON); - -// Request pretty printing from the server (_pretty=true) -client.setPrettyPrint(true); -//END SNIPPET: clientConfig -} - } - -} diff --git a/hapi-fhir-base/src/site/example/java/example/CompleteExampleClient.java b/hapi-fhir-base/src/site/example/java/example/CompleteExampleClient.java deleted file mode 100644 index dbfa386f777..00000000000 --- a/hapi-fhir-base/src/site/example/java/example/CompleteExampleClient.java +++ /dev/null @@ -1,68 +0,0 @@ -package example; - -//START SNIPPET: client -import java.io.IOException; -import java.util.List; - -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.model.dstu.composite.IdentifierDt; -import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; -import ca.uhn.fhir.model.dstu.resource.Organization; -import ca.uhn.fhir.model.dstu.resource.Patient; -import ca.uhn.fhir.rest.annotation.RequiredParam; -import ca.uhn.fhir.rest.annotation.Search; -import ca.uhn.fhir.rest.client.api.IRestfulClient; - -public class CompleteExampleClient { - - /** - * This is a simple client interface. It can have many methods - * for various searches but in this case it has only 1. - */ - public static interface ClientInterface extends IRestfulClient - { - - /** - * This is translated into a URL similar to the following: - * http://fhir.healthintersections.com.au/open/Patient?identifier=urn:oid:1.2.36.146.595.217.0.1%7C12345 - */ - @Search - List findPatientsForMrn(@RequiredParam(name=Patient.SP_IDENTIFIER) IdentifierDt theIdentifier); - - } - - /** - * The main method here will directly call an open FHIR server - * and retrieve a list of resources matching a given criteria, - * then load a linked resource. - */ - public static void main(String[] args) throws IOException { - - // Create a client factory - FhirContext ctx = new FhirContext(); - - //Create the client - String serverBase = "http://fhir.healthintersections.com.au/open"; - ClientInterface client = ctx.newRestfulClient(ClientInterface.class, serverBase); - - // Invoke the client to search for patient - List patients = client.findPatientsForMrn(new IdentifierDt("urn:oid:1.2.36.146.595.217.0.1", "12345")); - - System.out.println("Found "+ patients.size() + " patients"); - - // Print a value from the loaded resource - Patient patient = patients.get(0); - System.out.println("Patient Last Name: " + patient.getName().get(0).getFamily().get(0).getValue()); - - // Load a referenced resource - ResourceReferenceDt managingRef = patient.getManagingOrganization(); - Organization org = (Organization) managingRef.loadResource(client); - - // Print organization name - System.out.println(org.getName().getValue()); - - } - -} -//END SNIPPET: client - diff --git a/hapi-fhir-base/src/site/example/java/example/MyPatientUse.java b/hapi-fhir-base/src/site/example/java/example/MyPatientUse.java deleted file mode 100644 index eed0fd197be..00000000000 --- a/hapi-fhir-base/src/site/example/java/example/MyPatientUse.java +++ /dev/null @@ -1,43 +0,0 @@ -package example; - -import java.io.IOException; - -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.context.RuntimeResourceDefinition; -import ca.uhn.fhir.model.primitive.DateTimeDt; -import ca.uhn.fhir.model.primitive.StringDt; -import ca.uhn.fhir.parser.DataFormatException; -import ca.uhn.fhir.parser.IParser; -import ca.uhn.fhir.parser.MyPatient; - -public class MyPatientUse { - -@SuppressWarnings("unused") -public static void main(String[] args) throws DataFormatException, IOException { -//START SNIPPET: patientUse -MyPatient patient = new MyPatient(); -patient.setPetName(new StringDt("Fido")); -patient.getImportantDates().add(new DateTimeDt("2010-01-02")); -patient.getImportantDates().add(new DateTimeDt("2014-01-26T11:11:11")); - -patient.addName().addFamily("Smith").addGiven("John").addGiven("Quincy").addSuffix("Jr"); - -IParser p = new FhirContext().newXmlParser().setPrettyPrint(true); -String messageString = p.encodeResourceToString(patient); - -System.out.println(messageString); -//END SNIPPET: patientUse - -//START SNIPPET: patientParse -IParser parser = new FhirContext().newXmlParser(); -MyPatient newPatient = parser.parseResource(MyPatient.class, messageString); -//END SNIPPET: patientParse - -{ - FhirContext ctx2 = new FhirContext(); - RuntimeResourceDefinition def = ctx2.getResourceDefinition(patient); - System.out.println(ctx2.newXmlParser().setPrettyPrint(true).encodeResourceToString(def.toProfile())); -} -} - -} diff --git a/hapi-fhir-base/src/site/site.xml b/hapi-fhir-base/src/site/site.xml index 6bef354a5e2..6ce7a5bd2fd 100644 --- a/hapi-fhir-base/src/site/site.xml +++ b/hapi-fhir-base/src/site/site.xml @@ -61,6 +61,7 @@ + diff --git a/hapi-fhir-base/src/site/xdoc/doc_extensions.xml b/hapi-fhir-base/src/site/xdoc/doc_extensions.xml index 2f822f711ed..003c86bf4f7 100644 --- a/hapi-fhir-base/src/site/xdoc/doc_extensions.xml +++ b/hapi-fhir-base/src/site/xdoc/doc_extensions.xml @@ -28,7 +28,7 @@

- +

@@ -36,7 +36,7 @@

- + @@ -48,7 +48,7 @@

- +
@@ -61,7 +61,7 @@

- + @@ -78,7 +78,7 @@ - +

@@ -88,7 +88,7 @@ - +

@@ -121,7 +121,7 @@ - + diff --git a/hapi-fhir-base/src/site/xdoc/doc_fhirobjects.xml b/hapi-fhir-base/src/site/xdoc/doc_fhirobjects.xml index 237e94cb3ec..167f54eecbe 100644 --- a/hapi-fhir-base/src/site/xdoc/doc_fhirobjects.xml +++ b/hapi-fhir-base/src/site/xdoc/doc_fhirobjects.xml @@ -31,7 +31,7 @@ - + @@ -45,7 +45,7 @@ - + @@ -65,7 +65,7 @@ - + @@ -87,7 +87,7 @@ - +

@@ -97,7 +97,7 @@ - + diff --git a/hapi-fhir-base/src/site/xdoc/doc_intro.xml b/hapi-fhir-base/src/site/xdoc/doc_intro.xml index 3f472f1e039..699e8871c1b 100644 --- a/hapi-fhir-base/src/site/xdoc/doc_intro.xml +++ b/hapi-fhir-base/src/site/xdoc/doc_intro.xml @@ -70,7 +70,7 @@ - + @@ -93,7 +93,7 @@ - + @@ -107,7 +107,7 @@ - + \n" + - " \n" + - " \n" + - " \n" + - " \n" + - ""; - Query query = ourCtx.newXmlParser().parseResource(Query.class, msg); - - assertEquals("urn:uuid:42b253f5-fa17-40d0-8da5-44aeb4230376", query.getIdentifier().getValueAsString()); - assertEquals("http://hl7.org/fhir/query#_query", query.getParameterFirstRep().getUrlAsString()); - assertEquals("example", query.getParameterFirstRep().getValueAsPrimitive().getValueAsString()); - - } - - @Test - public void testEncodeQuery() { - Query q = new Query(); - ExtensionDt parameter = q.addParameter(); - parameter.setUrl("http://foo").setValue(new StringDt("bar")); - - - String val = ourCtx.newXmlParser().encodeResourceToString(q); - ourLog.info(val); - - assertEquals("", val); - - } - - - @Test - public void testEncodeBinaryResource() { - - Binary patient = new Binary(); - patient.setContentType("foo"); - patient.setContent(new byte[] {1,2,3,4}); - - String val = ourCtx.newXmlParser().encodeResourceToString(patient); - assertEquals("AQIDBA==", val); - - } - - - @Test - public void testParseBinaryResource() { - - Binary val = ourCtx.newXmlParser().parseResource(Binary.class, "AQIDBA=="); - assertEquals("foo", val.getContentType()); - assertArrayEquals(new byte[] {1,2,3,4}, val.getContent()); - - } - - @Test - public void testTagList() { - - //@formatter:off - String tagListStr = " \n" + - " \n" + - " \n" + - " \n" + - ""; - //@formatter:on - - TagList tagList = ourCtx.newXmlParser().parseTagList(tagListStr); - assertEquals(3, tagList.size()); - assertEquals("term0", tagList.get(0).getTerm()); - assertEquals("label0", tagList.get(0).getLabel()); - assertEquals("scheme0", tagList.get(0).getScheme()); - assertEquals("term1", tagList.get(1).getTerm()); - assertEquals("label1", tagList.get(1).getLabel()); - assertEquals(null, tagList.get(1).getScheme()); - assertEquals("term2", tagList.get(2).getTerm()); - assertEquals("label2", tagList.get(2).getLabel()); - assertEquals(null, tagList.get(2).getScheme()); - - /* - * Encode - */ - - //@formatter:off - String expected = "" + - "" + - "" + - "" + - ""; - //@formatter:on - - String encoded = ourCtx.newXmlParser().encodeTagListToString(tagList); - assertEquals(expected,encoded); - - } - - - @Test - public void testTotalResultsUsingOldNamespace() { - - //@formatter:off - String bundle = "\n" + - " Search results for Patient\n" + - " urn:uuid:374f2876-0da7-4441-87da-526e2fc624f8\n" + - " 15\n" + - " 2014-05-04T13:19:47.027-04:00\n" + - " \n" + - " AEGIS Wildfhir Server\n" + - " " + - ""; - //@formatter:off - - Bundle bundleR = ourCtx.newXmlParser().parseBundle(bundle); - assertEquals(15, bundleR.getTotalResults().getValue().intValue()); - } - - @Test - public void testEncodeExtensionWithResourceContent() { - IParser parser = ourCtx.newXmlParser(); - - Patient patient = new Patient(); - patient.addAddress().setUse(AddressUseEnum.HOME); - patient.addUndeclaredExtension(false, "urn:foo", new ResourceReferenceDt("Organization/123")); - - String val = parser.encodeResourceToString(patient); - ourLog.info(val); - assertThat(val, StringContains.containsString("")); - - Patient actual = parser.parseResource(Patient.class, val); - assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum()); - List ext = actual.getUndeclaredExtensionsByUrl("urn:foo"); - assertEquals(1, ext.size()); - ResourceReferenceDt ref = (ResourceReferenceDt) ext.get(0).getValue(); - assertEquals("Organization/123", ref.getReference().getValue()); - - } - - @Test - public void testEncodeDeclaredExtensionWithResourceContent() { - IParser parser = ourCtx.newXmlParser(); - - MyPatientWithOneDeclaredExtension patient = new MyPatientWithOneDeclaredExtension(); - patient.addAddress().setUse(AddressUseEnum.HOME); - patient.setFoo(new ResourceReferenceDt("Organization/123")); - - String val = parser.encodeResourceToString(patient); - ourLog.info(val); - assertThat(val, StringContains.containsString("")); - - MyPatientWithOneDeclaredExtension actual = parser.parseResource(MyPatientWithOneDeclaredExtension.class, val); - assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum()); - ResourceReferenceDt ref = actual.getFoo(); - assertEquals("Organization/123", ref.getReference().getValue()); - - } - - @Test - public void testEncodeDeclaredExtensionWithAddressContent() { - IParser parser = ourCtx.newXmlParser(); - - MyPatientWithOneDeclaredAddressExtension patient = new MyPatientWithOneDeclaredAddressExtension(); - patient.addAddress().setUse(AddressUseEnum.HOME); - patient.setFoo(new AddressDt().addLine("line1")); - - String val = parser.encodeResourceToString(patient); - ourLog.info(val); - assertThat(val, StringContains.containsString("")); - - MyPatientWithOneDeclaredAddressExtension actual = parser.parseResource(MyPatientWithOneDeclaredAddressExtension.class, val); - assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum()); - AddressDt ref = actual.getFoo(); - assertEquals("line1", ref.getLineFirstRep().getValue()); - - } - - @Test - public void testEncodeUndeclaredExtensionWithAddressContent() { - IParser parser = ourCtx.newXmlParser(); - - Patient patient = new Patient(); - patient.addAddress().setUse(AddressUseEnum.HOME); - patient.addUndeclaredExtension(false, "urn:foo", new AddressDt().addLine("line1")); - - String val = parser.encodeResourceToString(patient); - ourLog.info(val); - assertThat(val, StringContains.containsString("")); - - MyPatientWithOneDeclaredAddressExtension actual = parser.parseResource(MyPatientWithOneDeclaredAddressExtension.class, val); - assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum()); - AddressDt ref = actual.getFoo(); - assertEquals("line1", ref.getLineFirstRep().getValue()); - - } - - @Test - public void testEncodeBundleResultCount() { - - Bundle b = new Bundle(); - b.getTotalResults().setValue(123); - - String val = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(b); - ourLog.info(val); - - assertThat(val, StringContains.containsString("123")); - - } - - @Test - public void testEncodeBundleCategory() { - - Bundle b = new Bundle(); - BundleEntry e = b.addEntry(); - e.setResource(new Patient()); - e.addCategory().setLabel("label").setTerm("term").setScheme("scheme"); - - String val = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(b); - ourLog.info(val); - - assertThat(val, StringContains.containsString("")); - - b = ourCtx.newXmlParser().parseBundle(val); - assertEquals(1, b.getEntries().size()); - assertEquals(1, b.getEntries().get(0).getCategories().size()); - assertEquals("term", b.getEntries().get(0).getCategories().get(0).getTerm()); - assertEquals("label", b.getEntries().get(0).getCategories().get(0).getLabel()); - assertEquals("scheme", b.getEntries().get(0).getCategories().get(0).getScheme()); - assertNull(b.getEntries().get(0).getResource()); - - } - @Test public void testEncodeBundle() throws InterruptedException { Bundle b= new Bundle(); - + b.getCategories().addTag("http://hl7.org/fhir/tag", "http://hl7.org/fhir/tag/message", "Message"); + InstantDt pub = InstantDt.withCurrentTime(); b.setPublished(pub); Thread.sleep(2); @@ -393,6 +123,7 @@ public class XmlParserTest { List strings = new ArrayList(); strings.addAll(Arrays.asList("", pub.getValueAsString(), "")); + strings.add(""); strings.addAll(Arrays.asList("", "1", "")); strings.addAll(Arrays.asList("", "2", "", "","")); strings.addAll(Arrays.asList("")); @@ -402,6 +133,44 @@ public class XmlParserTest { } + + @Test + public void testEncodeBundleCategory() { + + Bundle b = new Bundle(); + BundleEntry e = b.addEntry(); + e.setResource(new Patient()); + e.addCategory().setLabel("label").setTerm("term").setScheme("scheme"); + + String val = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(b); + ourLog.info(val); + + assertThat(val, StringContains.containsString("")); + + b = ourCtx.newXmlParser().parseBundle(val); + assertEquals(1, b.getEntries().size()); + assertEquals(1, b.getEntries().get(0).getCategories().size()); + assertEquals("term", b.getEntries().get(0).getCategories().get(0).getTerm()); + assertEquals("label", b.getEntries().get(0).getCategories().get(0).getLabel()); + assertEquals("scheme", b.getEntries().get(0).getCategories().get(0).getScheme()); + assertNull(b.getEntries().get(0).getResource()); + + } + + @Test + public void testEncodeBundleResultCount() { + + Bundle b = new Bundle(); + b.getTotalResults().setValue(123); + + String val = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(b); + ourLog.info(val); + + assertThat(val, StringContains.containsString("123")); + + } + + @Test public void testEncodeContainedAndIncludedResources() { @@ -421,8 +190,6 @@ public class XmlParserTest { } - - @Test public void testEncodeContainedResources() { @@ -446,6 +213,66 @@ public class XmlParserTest { } + @Test + public void testEncodeDeclaredExtensionWithAddressContent() { + IParser parser = ourCtx.newXmlParser(); + + MyPatientWithOneDeclaredAddressExtension patient = new MyPatientWithOneDeclaredAddressExtension(); + patient.addAddress().setUse(AddressUseEnum.HOME); + patient.setFoo(new AddressDt().addLine("line1")); + + String val = parser.encodeResourceToString(patient); + ourLog.info(val); + assertThat(val, StringContains.containsString("")); + + MyPatientWithOneDeclaredAddressExtension actual = parser.parseResource(MyPatientWithOneDeclaredAddressExtension.class, val); + assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum()); + AddressDt ref = actual.getFoo(); + assertEquals("line1", ref.getLineFirstRep().getValue()); + + } + + + @Test + public void testEncodeDeclaredExtensionWithResourceContent() { + IParser parser = ourCtx.newXmlParser(); + + MyPatientWithOneDeclaredExtension patient = new MyPatientWithOneDeclaredExtension(); + patient.addAddress().setUse(AddressUseEnum.HOME); + patient.setFoo(new ResourceReferenceDt("Organization/123")); + + String val = parser.encodeResourceToString(patient); + ourLog.info(val); + assertThat(val, StringContains.containsString("")); + + MyPatientWithOneDeclaredExtension actual = parser.parseResource(MyPatientWithOneDeclaredExtension.class, val); + assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum()); + ResourceReferenceDt ref = actual.getFoo(); + assertEquals("Organization/123", ref.getReference().getValue()); + + } + + @Test + public void testEncodeExtensionWithResourceContent() { + IParser parser = ourCtx.newXmlParser(); + + Patient patient = new Patient(); + patient.addAddress().setUse(AddressUseEnum.HOME); + patient.addUndeclaredExtension(false, "urn:foo", new ResourceReferenceDt("Organization/123")); + + String val = parser.encodeResourceToString(patient); + ourLog.info(val); + assertThat(val, StringContains.containsString("")); + + Patient actual = parser.parseResource(Patient.class, val); + assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum()); + List ext = actual.getUndeclaredExtensionsByUrl("urn:foo"); + assertEquals(1, ext.size()); + ResourceReferenceDt ref = (ResourceReferenceDt) ext.get(0).getValue(); + assertEquals("Organization/123", ref.getReference().getValue()); + + } + @Test public void testEncodeInvalidChildGoodException() { Observation obs = new Observation(); @@ -502,7 +329,20 @@ public class XmlParserTest { } - + @Test + public void testEncodeQuery() { + Query q = new Query(); + ExtensionDt parameter = q.addParameter(); + parameter.setUrl("http://foo").setValue(new StringDt("bar")); + + + String val = ourCtx.newXmlParser().encodeResourceToString(q); + ourLog.info(val); + + assertEquals("", val); + + } + @Test public void testEncodeResourceRef() throws DataFormatException { @@ -525,6 +365,76 @@ public class XmlParserTest { } + @Test + public void testEncodeUndeclaredExtensionWithAddressContent() { + IParser parser = ourCtx.newXmlParser(); + + Patient patient = new Patient(); + patient.addAddress().setUse(AddressUseEnum.HOME); + patient.addUndeclaredExtension(false, "urn:foo", new AddressDt().addLine("line1")); + + String val = parser.encodeResourceToString(patient); + ourLog.info(val); + assertThat(val, StringContains.containsString("")); + + MyPatientWithOneDeclaredAddressExtension actual = parser.parseResource(MyPatientWithOneDeclaredAddressExtension.class, val); + assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum()); + AddressDt ref = actual.getFoo(); + assertEquals("line1", ref.getLineFirstRep().getValue()); + + } + + @Test + public void testExtensionOnComposite() throws Exception { + + Patient patient = new Patient(); + + HumanNameDt name = patient.addName(); + name.addFamily().setValue("Shmoe"); + HumanNameDt given = name.addGiven("Joe"); + ExtensionDt ext2 = new ExtensionDt(false, "http://examples.com#givenext", new StringDt("Hello")); + given.addUndeclaredExtension(ext2); + String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient); + ourLog.info(output); + + String enc = ourCtx.newXmlParser().encodeResourceToString(patient); + assertThat(enc, containsString("")); + + Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, new StringReader(enc)); + assertEquals(1, parsed.getNameFirstRep().getUndeclaredExtensionsByUrl("http://examples.com#givenext").size()); + ExtensionDt ext = parsed.getNameFirstRep().getUndeclaredExtensionsByUrl("http://examples.com#givenext").get(0); + assertEquals("Hello", ext.getValueAsPrimitive().getValue()); + + } + + + @Test + public void testExtensionOnPrimitive() throws Exception { + + Patient patient = new Patient(); + + HumanNameDt name = patient.addName(); + StringDt family = name.addFamily(); + family.setValue("Shmoe"); + + ExtensionDt ext2 = new ExtensionDt(false, "http://examples.com#givenext", new StringDt("Hello")); + family.addUndeclaredExtension(ext2); + String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient); + ourLog.info(output); + + String enc = ourCtx.newXmlParser().encodeResourceToString(patient); + assertThat(enc, containsString("")); + + Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, new StringReader(enc)); + assertEquals(1, parsed.getNameFirstRep().getFamilyFirstRep().getUndeclaredExtensionsByUrl("http://examples.com#givenext").size()); + ExtensionDt ext = parsed.getNameFirstRep().getFamilyFirstRep().getUndeclaredExtensionsByUrl("http://examples.com#givenext").get(0); + assertEquals("Hello", ext.getValueAsPrimitive().getValue()); + + } + + + + @Test public void testExtensions() throws DataFormatException { @@ -630,6 +540,7 @@ public class XmlParserTest { assertTrue(d.toString(), d.identical()); } + @Test public void testLoadAndEncodeUndeclaredExtensions() throws ConfigurationException, DataFormatException, SAXException, IOException { IParser p = ourCtx.newXmlParser(); @@ -683,25 +594,6 @@ public class XmlParserTest { assertTrue(d.toString(), d.identical()); } - - @Test - public void testParseWithXmlHeader() throws ConfigurationException, DataFormatException { - IParser p = ourCtx.newXmlParser(); - - //@formatter:off - String msg = "" + - "\n" + - " \n" + - " \n" + - ""; - //@formatter:on - - Patient resource = (Patient) p.parseResource(msg); - assertEquals("IdentifierLabel", resource.getIdentifier().get(0).getLabel().getValue()); - } - - @Test public void testLoadObservation() throws ConfigurationException, DataFormatException, IOException { @@ -767,6 +659,52 @@ public class XmlParserTest { } + + @Test + public void testMoreExtensions() throws Exception { + + Patient patient = new Patient(); + patient.addIdentifier(IdentifierUseEnum.OFFICIAL, "urn:example", "7000135", null); + + ExtensionDt ext = new ExtensionDt(); + ext.setModifier(false); + ext.setUrl("http://example.com/extensions#someext"); + ext.setValue(new DateTimeDt("2011-01-02T11:13:15")); + + // Add the extension to the resource + patient.addUndeclaredExtension(ext); + // END SNIPPET: resourceExtension + + // START SNIPPET: resourceStringExtension + HumanNameDt name = patient.addName(); + name.addFamily().setValue("Shmoe"); + StringDt given = name.addGiven(); + given.setValue("Joe"); + ExtensionDt ext2 = new ExtensionDt(false, "http://examples.com#givenext", new StringDt("given")); + given.addUndeclaredExtension(ext2); + // END SNIPPET: resourceStringExtension + + // START SNIPPET: subExtension + ExtensionDt parent = new ExtensionDt(false, "http://example.com#parent"); + patient.addUndeclaredExtension(parent); + + ExtensionDt child1 = new ExtensionDt(false, "http://example.com#child", new StringDt("value1")); + parent.addUndeclaredExtension(child1); + + ExtensionDt child2 = new ExtensionDt(false, "http://example.com#child", new StringDt("value1")); + parent.addUndeclaredExtension(child2); + // END SNIPPET: subExtension + + String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient); + ourLog.info(output); + + String enc = ourCtx.newXmlParser().encodeResourceToString(patient); + assertThat(enc, containsString("")); + assertThat(enc, containsString("")); + assertThat(enc, containsString("")); + } + + @Test public void testNarrativeGeneration() throws DataFormatException { @@ -791,14 +729,52 @@ public class XmlParserTest { } @Test - public void testParseBundleWithMixedReturnTypes() { - InputStreamReader str = new InputStreamReader(getClass().getResourceAsStream("/mixed-return-bundle.xml")); - Bundle b = ourCtx.newXmlParser().parseBundle(Patient.class, str); - assertEquals(Patient.class, b.getEntries().get(0).getResource().getClass()); - assertEquals(Patient.class, b.getEntries().get(1).getResource().getClass()); - assertEquals(Organization.class, b.getEntries().get(2).getResource().getClass()); + public void testNestedContainedResources() { + + Observation A = new Observation(); + A.getName().setText("A"); + + Observation B = new Observation(); + B.getName().setText("B"); + A.addRelated().setTarget(new ResourceReferenceDt(B)); + + Observation C = new Observation(); + C.getName().setText("C"); + B.addRelated().setTarget(new ResourceReferenceDt(C)); + + String str = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(A); + ourLog.info(str); + + assertThat(str, stringContainsInOrder(Arrays.asList("", "", ""))); + assertThat(str, stringContainsInOrder(Arrays.asList("", ""))); + + // Only one (outer) contained block + int idx0 = str.indexOf(""); + int idx1 = str.indexOf("",idx0+1); + assertNotEquals(-1, idx0); + assertEquals(-1, idx1); + + Observation obs = ourCtx.newXmlParser().parseResource(Observation.class, str); + assertEquals("A",obs.getName().getText().getValue()); + + Observation obsB = (Observation) obs.getRelatedFirstRep().getTarget().getResource(); + assertEquals("B",obsB.getName().getText().getValue()); + + Observation obsC = (Observation) obsB.getRelatedFirstRep().getTarget().getResource(); + assertEquals("C",obsC.getName().getText().getValue()); + + } - + + @Test + public void testParseBinaryResource() { + + Binary val = ourCtx.newXmlParser().parseResource(Binary.class, "AQIDBA=="); + assertEquals("foo", val.getContentType()); + assertArrayEquals(new byte[] {1,2,3,4}, val.getContent()); + + } + @SuppressWarnings("deprecation") @Test public void testParseBundle() { @@ -813,7 +789,8 @@ public class XmlParserTest { String msg = "\n" + " FHIR Core Valuesets\n" + " http://hl7.org/fhir/profile/valuesets\n" + - " \n" + + " \n" + + " \n" + " 2014-02-10T04:11:24.435-00:00\n" + " \n" + " Valueset "256a5231-a2bb-49bd-9fea-f349d428b70d" to support automated processing\n" + @@ -867,6 +844,9 @@ public class XmlParserTest { IParser p = new FhirContext(ValueSet.class).newXmlParser(); Bundle bundle = p.parseBundle(msg); + assertEquals(1, bundle.getCategories().size()); + assertEquals("http://hl7.org/fhir/tag", bundle.getCategories().get(0).getScheme()); + assertEquals("FHIR Core Valuesets", bundle.getTitle().getValue()); assertEquals("http://hl7.org/implement/standards/fhir/valuesets.xml", bundle.getLinkSelf().getValue()); assertEquals("2014-02-10T04:11:24.435+00:00", bundle.getUpdated().getValueAsString()); @@ -946,7 +926,6 @@ public class XmlParserTest { } - @Test public void testParseBundleLarge() throws IOException { @@ -960,6 +939,15 @@ public class XmlParserTest { assertEquals("3216379", bundle.getEntries().get(0).getResource().getId().getIdPart()); } + + @Test + public void testParseBundleWithMixedReturnTypes() { + InputStreamReader str = new InputStreamReader(getClass().getResourceAsStream("/mixed-return-bundle.xml")); + Bundle b = ourCtx.newXmlParser().parseBundle(Patient.class, str); + assertEquals(Patient.class, b.getEntries().get(0).getResource().getClass()); + assertEquals(Patient.class, b.getEntries().get(1).getResource().getClass()); + assertEquals(Organization.class, b.getEntries().get(2).getResource().getClass()); + } @Test public void testParseContainedResources() throws IOException { @@ -976,20 +964,7 @@ public class XmlParserTest { } - /** - * This sample has extra elements in that are not actually a - * part of the spec any more.. - */ - @Test - public void testParseFuroreMetadataWithExtraElements() throws IOException { - String msg = IOUtils.toString(XmlParserTest.class.getResourceAsStream("/furore-conformance.xml")); - - IParser p = new FhirContext(ValueSet.class).newXmlParser(); - Conformance conf = p.parseResource(Conformance.class, msg); - RestResource res = conf.getRestFirstRep().getResourceFirstRep(); - assertEquals("_id", res.getSearchParam().get(1).getName().getValue()); - } - + @Test public void testParseEncodeNarrative() { @@ -1009,104 +984,67 @@ public class XmlParserTest { assertThat(output, not(StringContainsInOrder.stringContainsInOrder(Arrays.asList("b xmlns")))); } + + /** + * This sample has extra elements in that are not actually a + * part of the spec any more.. + */ + @Test + public void testParseFuroreMetadataWithExtraElements() throws IOException { + String msg = IOUtils.toString(XmlParserTest.class.getResourceAsStream("/furore-conformance.xml")); + + IParser p = new FhirContext(ValueSet.class).newXmlParser(); + Conformance conf = p.parseResource(Conformance.class, msg); + RestResource res = conf.getRestFirstRep().getResourceFirstRep(); + assertEquals("_id", res.getSearchParam().get(1).getName().getValue()); + } + + @Test + public void testParseLanguage() { + String input = "

海生
IdentifierURNo
Address99 Houston Road
BENTLEIGH Victoria
Date of birth01 January 1997
"; + Patient pt = ourCtx.newXmlParser().parseResource(Patient.class, input); + + assertEquals("zh-CN", pt.getLanguage().getValue()); + } + + @Test + public void testParseQuery() { + String msg = "\n" + + " \n" + + " \n" + + "
[Put rendering here]
\n" + + "
\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
"; + Query query = ourCtx.newXmlParser().parseResource(Query.class, msg); + + assertEquals("urn:uuid:42b253f5-fa17-40d0-8da5-44aeb4230376", query.getIdentifier().getValueAsString()); + assertEquals("http://hl7.org/fhir/query#_query", query.getParameterFirstRep().getUrlAsString()); + assertEquals("example", query.getParameterFirstRep().getValueAsPrimitive().getValueAsString()); + + } - @BeforeClass - public static void beforeClass() { - XMLUnit.setIgnoreAttributeOrder(true); - XMLUnit.setIgnoreComments(true); - XMLUnit.setIgnoreWhitespace(true); - ourCtx = new FhirContext(); - } - @Test - public void testMoreExtensions() throws Exception { + public void testParseWithXmlHeader() throws ConfigurationException, DataFormatException { + IParser p = ourCtx.newXmlParser(); - Patient patient = new Patient(); - patient.addIdentifier(IdentifierUseEnum.OFFICIAL, "urn:example", "7000135", null); - - ExtensionDt ext = new ExtensionDt(); - ext.setModifier(false); - ext.setUrl("http://example.com/extensions#someext"); - ext.setValue(new DateTimeDt("2011-01-02T11:13:15")); - - // Add the extension to the resource - patient.addUndeclaredExtension(ext); - // END SNIPPET: resourceExtension - - // START SNIPPET: resourceStringExtension - HumanNameDt name = patient.addName(); - name.addFamily().setValue("Shmoe"); - StringDt given = name.addGiven(); - given.setValue("Joe"); - ExtensionDt ext2 = new ExtensionDt(false, "http://examples.com#givenext", new StringDt("given")); - given.addUndeclaredExtension(ext2); - // END SNIPPET: resourceStringExtension - - // START SNIPPET: subExtension - ExtensionDt parent = new ExtensionDt(false, "http://example.com#parent"); - patient.addUndeclaredExtension(parent); - - ExtensionDt child1 = new ExtensionDt(false, "http://example.com#child", new StringDt("value1")); - parent.addUndeclaredExtension(child1); - - ExtensionDt child2 = new ExtensionDt(false, "http://example.com#child", new StringDt("value1")); - parent.addUndeclaredExtension(child2); - // END SNIPPET: subExtension - - String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient); - ourLog.info(output); - - String enc = ourCtx.newXmlParser().encodeResourceToString(patient); - assertThat(enc, containsString("")); - assertThat(enc, containsString("")); - assertThat(enc, containsString("")); - } - - @Test - public void testExtensionOnComposite() throws Exception { - - Patient patient = new Patient(); - - HumanNameDt name = patient.addName(); - name.addFamily().setValue("Shmoe"); - HumanNameDt given = name.addGiven("Joe"); - ExtensionDt ext2 = new ExtensionDt(false, "http://examples.com#givenext", new StringDt("Hello")); - given.addUndeclaredExtension(ext2); - String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient); - ourLog.info(output); - - String enc = ourCtx.newXmlParser().encodeResourceToString(patient); - assertThat(enc, containsString("")); - - Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, new StringReader(enc)); - assertEquals(1, parsed.getNameFirstRep().getUndeclaredExtensionsByUrl("http://examples.com#givenext").size()); - ExtensionDt ext = parsed.getNameFirstRep().getUndeclaredExtensionsByUrl("http://examples.com#givenext").get(0); - assertEquals("Hello", ext.getValueAsPrimitive().getValue()); - - } - - @Test - public void testExtensionOnPrimitive() throws Exception { - - Patient patient = new Patient(); - - HumanNameDt name = patient.addName(); - StringDt family = name.addFamily(); - family.setValue("Shmoe"); - - ExtensionDt ext2 = new ExtensionDt(false, "http://examples.com#givenext", new StringDt("Hello")); - family.addUndeclaredExtension(ext2); - String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient); - ourLog.info(output); - - String enc = ourCtx.newXmlParser().encodeResourceToString(patient); - assertThat(enc, containsString("")); - - Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, new StringReader(enc)); - assertEquals(1, parsed.getNameFirstRep().getFamilyFirstRep().getUndeclaredExtensionsByUrl("http://examples.com#givenext").size()); - ExtensionDt ext = parsed.getNameFirstRep().getFamilyFirstRep().getUndeclaredExtensionsByUrl("http://examples.com#givenext").get(0); - assertEquals("Hello", ext.getValueAsPrimitive().getValue()); + //@formatter:off + String msg = "" + + "\n" + + " \n" + + " \n" + + ""; + //@formatter:on + Patient resource = (Patient) p.parseResource(msg); + assertEquals("IdentifierLabel", resource.getIdentifier().get(0).getLabel().getValue()); } @Test @@ -1167,4 +1105,71 @@ public class XmlParserTest { } + @Test + public void testTagList() { + + //@formatter:off + String tagListStr = " \n" + + " \n" + + " \n" + + " \n" + + ""; + //@formatter:on + + TagList tagList = ourCtx.newXmlParser().parseTagList(tagListStr); + assertEquals(3, tagList.size()); + assertEquals("term0", tagList.get(0).getTerm()); + assertEquals("label0", tagList.get(0).getLabel()); + assertEquals("scheme0", tagList.get(0).getScheme()); + assertEquals("term1", tagList.get(1).getTerm()); + assertEquals("label1", tagList.get(1).getLabel()); + assertEquals(null, tagList.get(1).getScheme()); + assertEquals("term2", tagList.get(2).getTerm()); + assertEquals("label2", tagList.get(2).getLabel()); + assertEquals(null, tagList.get(2).getScheme()); + + /* + * Encode + */ + + //@formatter:off + String expected = "" + + "" + + "" + + "" + + ""; + //@formatter:on + + String encoded = ourCtx.newXmlParser().encodeTagListToString(tagList); + assertEquals(expected,encoded); + + } + + @Test + public void testTotalResultsUsingOldNamespace() { + + //@formatter:off + String bundle = "\n" + + " Search results for Patient\n" + + " urn:uuid:374f2876-0da7-4441-87da-526e2fc624f8\n" + + " 15\n" + + " 2014-05-04T13:19:47.027-04:00\n" + + " \n" + + " AEGIS Wildfhir Server\n" + + " " + + ""; + //@formatter:off + + Bundle bundleR = ourCtx.newXmlParser().parseBundle(bundle); + assertEquals(15, bundleR.getTotalResults().getValue().intValue()); + } + + @BeforeClass + public static void beforeClass() { + XMLUnit.setIgnoreAttributeOrder(true); + XMLUnit.setIgnoreComments(true); + XMLUnit.setIgnoreWhitespace(true); + ourCtx = new FhirContext(); + } + } diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/client/ClientTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/client/ClientTest.java index eb1724112c9..cb19614e268 100644 --- a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/client/ClientTest.java +++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/client/ClientTest.java @@ -1,9 +1,7 @@ package ca.uhn.fhir.rest.client; import static org.hamcrest.Matchers.containsString; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -581,9 +579,11 @@ public class ClientTest { ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); when(httpClient.execute(capt.capture())).thenReturn(httpResponse); when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); - Header[] headers = new Header[2]; - headers[0] = new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Wed, 15 Nov 1995 04:58:08 GMT"); - headers[1] = new BasicHeader(Constants.HEADER_CONTENT_LOCATION, "http://foo.com/Patient/123/_history/2333"); + Header[] headers = new Header[] { + new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Wed, 15 Nov 1995 04:58:08 GMT"), + new BasicHeader(Constants.HEADER_CONTENT_LOCATION, "http://foo.com/Patient/123/_history/2333"), + new BasicHeader(Constants.HEADER_CATEGORY, "http://foo/tagdefinition.html; scheme=\"http://hl7.org/fhir/tag\"; label=\"Some tag\"") + }; when(httpResponse.getAllHeaders()).thenReturn(headers); when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); @@ -603,6 +603,13 @@ public class ClientTest { lm.setTimeZoneZulu(true); assertEquals("1995-11-15T04:58:08.000Z", lm.getValueAsString()); + TagList tags = ResourceMetadataKeyEnum.TAG_LIST.get(response); + assertNotNull(tags); + assertEquals(1,tags.size()); + assertEquals("http://foo/tagdefinition.html", tags.get(0).getTerm()); + assertEquals("http://hl7.org/fhir/tag",tags.get(0).getScheme()); + assertEquals("Some tag",tags.get(0).getLabel()); + } @Test diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/client/GenericClientTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/client/GenericClientTest.java index 47e60bf8d24..64f147e0d58 100644 --- a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/client/GenericClientTest.java +++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/client/GenericClientTest.java @@ -270,9 +270,11 @@ public class GenericClientTest { when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); - Header[] headers = new Header[2]; - headers[0] = new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Wed, 15 Nov 1995 04:58:08 GMT"); - headers[1] = new BasicHeader(Constants.HEADER_CONTENT_LOCATION, "http://foo.com/Patient/123/_history/2333"); + Header[] headers = new Header[] { + new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Wed, 15 Nov 1995 04:58:08 GMT"), + new BasicHeader(Constants.HEADER_CONTENT_LOCATION, "http://foo.com/Patient/123/_history/2333"), + new BasicHeader(Constants.HEADER_CATEGORY, "http://foo/tagdefinition.html; scheme=\"http://hl7.org/fhir/tag\"; label=\"Some tag\"") + }; when(myHttpResponse.getAllHeaders()).thenReturn(headers); IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); @@ -289,6 +291,13 @@ public class GenericClientTest { lm.setTimeZoneZulu(true); assertEquals("1995-11-15T04:58:08.000Z", lm.getValueAsString()); + TagList tags = ResourceMetadataKeyEnum.TAG_LIST.get(response); + assertNotNull(tags); + assertEquals(1,tags.size()); + assertEquals("http://foo/tagdefinition.html", tags.get(0).getTerm()); + assertEquals("http://hl7.org/fhir/tag",tags.get(0).getScheme()); + assertEquals("Some tag",tags.get(0).getLabel()); + } @SuppressWarnings("unused") diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/client/TransactionClientTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/client/TransactionClientTest.java index 6d9e877893c..857d5657880 100644 --- a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/client/TransactionClientTest.java +++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/client/TransactionClientTest.java @@ -75,7 +75,7 @@ public class TransactionClientTest { when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_ATOM_XML + "; charset=UTF-8")); when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(createBundle()), Charset.forName("UTF-8"))); - client.searchWithParam(resources); + client.transaction(resources); assertEquals(HttpPost.class, capt.getValue().getClass()); HttpPost post = (HttpPost) capt.getValue(); @@ -92,6 +92,47 @@ public class TransactionClientTest { assertTrue(bundle.getEntries().get(1).getId().isEmpty()); } + + + @Test + public void testSimpleTransactionWithBundleParam() throws Exception { + Patient patient = new Patient(); + patient.setId(new IdDt("Patient/testPersistWithSimpleLinkP01")); + patient.addIdentifier("urn:system", "testPersistWithSimpleLinkP01"); + patient.addName().addFamily("Tester").addGiven("Joe"); + + Observation obs = new Observation(); + obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO01"); + obs.setSubject(new ResourceReferenceDt("Patient/testPersistWithSimpleLinkP01")); + + Bundle transactionBundle = Bundle.withResources(Arrays.asList((IResource)patient, obs), ctx, "http://foo"); + + IBundleClient client = ctx.newRestfulClient(IBundleClient.class, "http://foo"); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_ATOM_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(createBundle()), Charset.forName("UTF-8"))); + + client.transaction(transactionBundle); + + assertEquals(HttpPost.class, capt.getValue().getClass()); + HttpPost post = (HttpPost) capt.getValue(); + assertEquals("http://foo/", post.getURI().toString()); + + Bundle bundle = ctx.newXmlParser().parseBundle(new InputStreamReader(post.getEntity().getContent())); + ourLog.info(ctx.newXmlParser().setPrettyPrint(true).encodeBundleToString(bundle)); + + assertEquals(2, bundle.size()); + assertEquals("http://foo/Patient/testPersistWithSimpleLinkP01", bundle.getEntries().get(0).getId().getValue()); + assertEquals("http://foo/Patient/testPersistWithSimpleLinkP01", bundle.getEntries().get(0).getLinkSelf().getValue()); + assertEquals(null, bundle.getEntries().get(0).getLinkAlternate().getValue()); + + assertTrue(bundle.getEntries().get(1).getId().isEmpty()); + + } + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TransactionClientTest.class); private String createBundle() { return ctx.newXmlParser().encodeBundleToString(new Bundle()); @@ -100,7 +141,15 @@ public class TransactionClientTest { private interface IClient extends IBasicClient { @Transaction - public List searchWithParam(@TransactionParam List theResources); + public List transaction(@TransactionParam List theResources); + + + } + + private interface IBundleClient extends IBasicClient { + + @Transaction + public List transaction(@TransactionParam Bundle theResources); } diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBindingTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBindingTest.java index e07825421c8..025886ab5c3 100644 --- a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBindingTest.java +++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBindingTest.java @@ -14,7 +14,7 @@ public class BaseOutcomeReturningMethodBindingTest { String headerString = "http://britsystems.com/fhir/tag/4567; scheme=\"http://britsystems.com/fhir\"; label=\"Tag-4567\",http://client/scheme/tag/123; scheme=\"http://client/scheme\"; label=\"tag 123\",http://client/scheme/tag/456; scheme=\"http://client/scheme\"; label=\"tag 456\",http://fhir.healthintersections.com.au/open/Patient/1; scheme=\"http://hl7.org/fhir/tag\"; label=\"GET //\",http://hl7.fhir/example; scheme=\"http://hl7.org/fhir/tag\"; label=\"FHIR example\",http://hl7.org/fhir/sid/us-ssn; scheme=\"http://hl7.org/fhir/tag\"; label=\"POST /\",http://hl7.org/fhir/tools/tag/test; scheme=\"http://hl7.org/fhir/tag\"; label=\"Test Tag\",http://hl7.org/implement/standards/fhir/v3/ActCode/InformationSensitivityPolicy#GDIS; scheme=\"http://hl7.org/fhir/tag\"; label=\"GDIS\",http://hl7.org/implement/standards/fhir/v3/Confidentiality#N; scheme=\"http://hl7.org/fhir/tag\"; label=\"N (Normal)\",http://hl7.org/implement/standards/fhir/v3/Confidentiality#R; scheme=\"http://hl7.org/fhir/tag\"; label=\"restricted\",http://nu.nl/testname; scheme=\"http://hl7.org/fhir/tag\"; label=\"TestCreateEditDelete\",http://readtag.nu.nl; scheme=\"http://hl7.org/fhir/tag\"; label=\"readTagTest\",http://spark.furore.com/fhir; scheme=\"http://hl7.org/fhir/tag\"; label=\"GET //\",http://www.healthintersections.com.au/fhir/tags/invalid; scheme=\"http://hl7.org/fhir/tag\"; label=\"Non-conformant Resource\",urn:happytag; scheme=\"http://hl7.org/fhir/tag\"; label=\"This is a happy resource\",condition; scheme=\"http://hl7.org/fhir/tag/profile\"; label=\"Profile condition\",device; scheme=\"http://hl7.org/fhir/tag/profile\"; label=\"Profile device\",http://fhir.healthintersections.com.au/open/Profile/condition; scheme=\"http://hl7.org/fhir/tag/profile\"; label=\"Profile condition\",http://fhir.healthintersections.com.au/open/Profile/device; scheme=\"http://hl7.org/fhir/tag/profile\"; label=\"Profile device\",http://hl7.org/fhir/v3/ActCode#CEL; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Celebrity / VIP\",http://hl7.org/fhir/v3/ActCode#DEMO; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Contact/Employment Confidential\",http://hl7.org/fhir/v3/ActCode#DIA; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Diagnosis is/would be Confidential\",http://hl7.org/fhir/v3/ActCode#EMP; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Employee / Staff member\",http://hl7.org/fhir/v3/ActCode#ORCON; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Author only\",http://hl7.org/fhir/v3/ActCode#TABOO; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Patient/Carer Only\",http://hl7.org/fhir/v3/Confidentiality#L; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Confidentiality = Low\",http://hl7.org/fhir/v3/Confidentiality#M; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Confidentiality = Moderate\",http://hl7.org/fhir/v3/Confidentiality#N; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Confidentiality = Normal\",http://hl7.org/fhir/v3/Confidentiality#R; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Confidentiality = Restricted\",http://hl7.org/fhir/v3/Confidentiality#U; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Confidentiality = none\",http://hl7.org/fhir/v3/Confidentiality#V; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Confidentiality = Very Restricted\",http://term.com; scheme=\"http://scheme.com\"; label=\"Some good ole term\""; TagList parsedFromHeader = new TagList(); - BaseOutcomeReturningMethodBinding.parseTagValue(parsedFromHeader, headerString); + MethodUtil.parseTagValue(parsedFromHeader, headerString); //@formatter:off String resourceString = "{\n" + diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/server/CustomTypeTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/server/CustomTypeTest.java index 63a450ff89e..e37a11e15d5 100644 --- a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/server/CustomTypeTest.java +++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/server/CustomTypeTest.java @@ -63,7 +63,7 @@ public class CustomTypeTest { assertEquals(1, bundle.getEntries().size()); BundleEntry entry = bundle.getEntries().get(0); - ArrayList profileTags = entry.getCategories().getTagsWithScheme(Constants.TAG_SCHEME_PROFILE); + List profileTags = entry.getCategories().getTagsWithScheme(Tag.HL7_ORG_PROFILE_TAG); assertEquals(1, profileTags.size()); assertEquals("http://foo/profiles/Profile", profileTags.get(0).getTerm()); diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/server/SearchTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/server/SearchTest.java index bf1592ecec0..10600966d63 100644 --- a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/server/SearchTest.java +++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/server/SearchTest.java @@ -10,6 +10,7 @@ import org.apache.commons.io.IOUtils; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.CloseableHttpClient; @@ -26,9 +27,11 @@ import org.junit.Test; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.model.api.Bundle; import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; import ca.uhn.fhir.model.dstu.composite.CodingDt; import ca.uhn.fhir.model.dstu.resource.Observation; import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator; import ca.uhn.fhir.rest.annotation.OptionalParam; import ca.uhn.fhir.rest.annotation.RequiredParam; @@ -149,6 +152,29 @@ public class SearchTest { assertEquals("AAANamed", p.getIdentifierFirstRep().getValue().getValue()); } + @Test + public void testReturnLinks() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort+"/Patient?_query=findWithLinks"); + + CloseableHttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.getEntries().size()); + + Patient p = bundle.getResources(Patient.class).get(0); + assertEquals("AAANamed", p.getIdentifierFirstRep().getValue().getValue()); + assertEquals("http://foo/Patient?_id=1", bundle.getEntries().get(0).getLinkSearch().getValue()); + assertEquals("http://localhost:" + ourPort+"/Patient/9988", bundle.getEntries().get(0).getLinkAlternate().getValue()); + + assertEquals("http://foo/Patient?_id=1", ResourceMetadataKeyEnum.LINK_SEARCH.get(p)); + assertEquals("http://localhost:" + ourPort+"/Patient/9988", ResourceMetadataKeyEnum.LINK_ALTERNATE.get(p)); + + + } + + @AfterClass public static void afterClass() throws Exception { ourServer.stop(); @@ -206,7 +232,7 @@ public class SearchTest { public static class DummyPatientResourceProvider implements IResourceProvider { @Search - public List findPatient(@OptionalParam(name = "_id") StringParam theParam) { + public List findPatient(@RequiredParam(name = "_id") StringParam theParam) { ArrayList retVal = new ArrayList(); Patient patient = new Patient(); @@ -220,7 +246,7 @@ public class SearchTest { } @Search - public List findPatientByAAA01(@OptionalParam(name = "AAA") StringParam theParam) { + public List findPatientByAAA01(@RequiredParam(name = "AAA") StringParam theParam) { ArrayList retVal = new ArrayList(); Patient patient = new Patient(); @@ -241,6 +267,19 @@ public class SearchTest { return retVal; } + @Search(queryName="findWithLinks") + public List findWithLinks() { + ArrayList retVal = new ArrayList(); + + Patient patient = new Patient(); + patient.setId("1"); + patient.addIdentifier("system", "AAANamed"); + ResourceMetadataKeyEnum.LINK_SEARCH.put(patient, ("http://foo/Patient?_id=1")); + ResourceMetadataKeyEnum.LINK_ALTERNATE.put(patient, ("Patient/9988")); + retVal.add(patient); + return retVal; + } + @Override public Class getResourceType() { return Patient.class; diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/server/TransactionTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/server/TransactionTest.java index bae1c49484e..665535cb0f1 100644 --- a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/server/TransactionTest.java +++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/server/TransactionTest.java @@ -41,24 +41,23 @@ public class TransactionTest { private static CloseableHttpClient ourClient; private static FhirContext ourCtx = new FhirContext(); + private static boolean ourDropFirstResource; private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TransactionTest.class); private static int ourPort; private static boolean ourReturnOperationOutcome; - private static Server ourServer; - - - + @Before public void before() { ourReturnOperationOutcome = false; + ourDropFirstResource = false; } - + @Test public void testTransaction() throws Exception { Bundle b = new Bundle(); InstantDt nowInstant = InstantDt.withCurrentTime(); - + Patient p1 = new Patient(); p1.addName().addFamily("Family1"); BundleEntry entry = b.addEntry(); @@ -70,24 +69,25 @@ public class TransactionTest { entry = b.addEntry(); entry.getId().setValue("2"); entry.setResource(p2); - + BundleEntry deletedEntry = b.addEntry(); deletedEntry.setId(new IdDt("Patient/3")); deletedEntry.setDeleted(nowInstant); - + String bundleString = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(b); ourLog.info(bundleString); - + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/"); - httpPost.addHeader("Accept", Constants.CT_ATOM_XML + "; pretty=true"); + httpPost.addHeader("Accept", Constants.CT_ATOM_XML + "; pretty=true"); httpPost.setEntity(new StringEntity(bundleString, ContentType.create(Constants.CT_ATOM_XML, "UTF-8"))); HttpResponse status = ourClient.execute(httpPost); - String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); assertEquals(200, status.getStatusLine().getStatusCode()); - + ourLog.info(responseContent); - + Bundle bundle = new FhirContext().newXmlParser().parseBundle(responseContent); assertEquals(3, bundle.size()); @@ -95,7 +95,7 @@ public class TransactionTest { assertEquals("http://localhost:" + ourPort + "/Patient/81", entry0.getId().getValue()); assertEquals("http://localhost:" + ourPort + "/Patient/81/_history/91", entry0.getLinkSelf().getValue()); assertEquals("http://localhost:" + ourPort + "/Patient/1", entry0.getLinkAlternate().getValue()); - + BundleEntry entry1 = bundle.getEntries().get(1); assertEquals("http://localhost:" + ourPort + "/Patient/82", entry1.getId().getValue()); assertEquals("http://localhost:" + ourPort + "/Patient/82/_history/92", entry1.getLinkSelf().getValue()); @@ -105,16 +105,15 @@ public class TransactionTest { assertEquals("http://localhost:" + ourPort + "/Patient/3", entry2.getId().getValue()); assertEquals("http://localhost:" + ourPort + "/Patient/3/_history/93", entry2.getLinkSelf().getValue()); assertEquals(nowInstant.getValueAsString(), entry2.getDeletedAt().getValueAsString()); -} - - + } + @Test - public void testTransactionWithOperationOutcome() throws Exception { - ourReturnOperationOutcome = true; + public void testTransactionWithFewerResponseElements() throws Exception { + ourDropFirstResource =true; Bundle b = new Bundle(); InstantDt nowInstant = InstantDt.withCurrentTime(); - + Patient p1 = new Patient(); p1.addName().addFamily("Family1"); BundleEntry entry = b.addEntry(); @@ -126,35 +125,87 @@ public class TransactionTest { entry = b.addEntry(); entry.getId().setValue("2"); entry.setResource(p2); - + BundleEntry deletedEntry = b.addEntry(); deletedEntry.setId(new IdDt("Patient/3")); deletedEntry.setDeleted(nowInstant); - + String bundleString = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(b); ourLog.info(bundleString); - + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/"); - httpPost.addHeader("Accept", Constants.CT_ATOM_XML + "; pretty=true"); + httpPost.addHeader("Accept", Constants.CT_ATOM_XML + "; pretty=true"); httpPost.setEntity(new StringEntity(bundleString, ContentType.create(Constants.CT_ATOM_XML, "UTF-8"))); HttpResponse status = ourClient.execute(httpPost); - String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); assertEquals(200, status.getStatusLine().getStatusCode()); - + ourLog.info(responseContent); - + + Bundle bundle = new FhirContext().newXmlParser().parseBundle(responseContent); + assertEquals(2, bundle.size()); + + BundleEntry entry1 = bundle.getEntries().get(0); + assertEquals("http://localhost:" + ourPort + "/Patient/82", entry1.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/82/_history/92", entry1.getLinkSelf().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/2", entry1.getLinkAlternate().getValue()); + + BundleEntry entry2 = bundle.getEntries().get(1); + assertEquals("http://localhost:" + ourPort + "/Patient/3", entry2.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/3/_history/93", entry2.getLinkSelf().getValue()); + assertEquals(nowInstant.getValueAsString(), entry2.getDeletedAt().getValueAsString()); + } + + @Test + public void testTransactionWithOperationOutcome() throws Exception { + ourReturnOperationOutcome = true; + + Bundle b = new Bundle(); + InstantDt nowInstant = InstantDt.withCurrentTime(); + + Patient p1 = new Patient(); + p1.addName().addFamily("Family1"); + BundleEntry entry = b.addEntry(); + entry.getId().setValue("1"); + entry.setResource(p1); + + Patient p2 = new Patient(); + p2.addName().addFamily("Family2"); + entry = b.addEntry(); + entry.getId().setValue("2"); + entry.setResource(p2); + + BundleEntry deletedEntry = b.addEntry(); + deletedEntry.setId(new IdDt("Patient/3")); + deletedEntry.setDeleted(nowInstant); + + String bundleString = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(b); + ourLog.info(bundleString); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/"); + httpPost.addHeader("Accept", Constants.CT_ATOM_XML + "; pretty=true"); + httpPost.setEntity(new StringEntity(bundleString, ContentType.create(Constants.CT_ATOM_XML, "UTF-8"))); + HttpResponse status = ourClient.execute(httpPost); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + + ourLog.info(responseContent); + Bundle bundle = new FhirContext().newXmlParser().parseBundle(responseContent); assertEquals(4, bundle.size()); assertEquals(OperationOutcome.class, bundle.getEntries().get(0).getResource().getClass()); assertEquals("OperationOutcome (no ID)", bundle.getEntries().get(0).getTitle().getValue()); - + BundleEntry entry0 = bundle.getEntries().get(1); assertEquals("http://localhost:" + ourPort + "/Patient/81", entry0.getId().getValue()); assertEquals("http://localhost:" + ourPort + "/Patient/81/_history/91", entry0.getLinkSelf().getValue()); assertEquals("http://localhost:" + ourPort + "/Patient/1", entry0.getLinkAlternate().getValue()); - + BundleEntry entry1 = bundle.getEntries().get(2); assertEquals("http://localhost:" + ourPort + "/Patient/82", entry1.getId().getValue()); assertEquals("http://localhost:" + ourPort + "/Patient/82/_history/92", entry1.getLinkSelf().getValue()); @@ -164,7 +215,7 @@ public class TransactionTest { assertEquals("http://localhost:" + ourPort + "/Patient/3", entry2.getId().getValue()); assertEquals("http://localhost:" + ourPort + "/Patient/3/_history/93", entry2.getLinkSelf().getValue()); assertEquals(nowInstant.getValueAsString(), entry2.getDeletedAt().getValueAsString()); -} + } @AfterClass public static void afterClass() throws Exception { @@ -179,7 +230,7 @@ public class TransactionTest { DummyProvider patientProvider = new DummyProvider(); RestfulServer server = new RestfulServer(); server.setProviders(patientProvider); - + org.eclipse.jetty.servlet.ServletContextHandler proxyHandler = new org.eclipse.jetty.servlet.ServletContextHandler(); proxyHandler.setContextPath("/"); @@ -189,44 +240,46 @@ public class TransactionTest { ourServer.setHandler(proxyHandler); ourServer.start(); - + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); HttpClientBuilder builder = HttpClientBuilder.create(); builder.setConnectionManager(connectionManager); ourClient = builder.build(); } - + /** * Created by dsotnikov on 2/25/2014. */ - public static class DummyProvider { + public static class DummyProvider { @Transaction public List transaction(@TransactionParam List theResources) { - int index=1; + int index = 1; for (IResource next : theResources) { - String newId = "8"+Integer.toString(index); + String newId = "8" + Integer.toString(index); if (next.getResourceMetadata().containsKey(ResourceMetadataKeyEnum.DELETED_AT)) { newId = next.getId().getIdPart(); } - next.setId(new IdDt("Patient", newId, "9"+Integer.toString(index))); + next.setId(new IdDt("Patient", newId, "9" + Integer.toString(index))); index++; } - - List retVal = theResources; + + List retVal = new ArrayList(theResources); + + if (ourDropFirstResource) { + retVal.remove(0); + } + if (ourReturnOperationOutcome) { - retVal = new ArrayList(); OperationOutcome oo = new OperationOutcome(); oo.addIssue().setDetails("AAAAA"); - retVal.add(oo); - retVal.addAll(theResources); + retVal.add(0, oo); } - + return retVal; } - } } diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/server/TransactionWithBundleParamTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/server/TransactionWithBundleParamTest.java new file mode 100644 index 00000000000..a9e966301f9 --- /dev/null +++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/server/TransactionWithBundleParamTest.java @@ -0,0 +1,234 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.BundleEntry; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; +import ca.uhn.fhir.model.dstu.resource.OperationOutcome; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.InstantDt; +import ca.uhn.fhir.rest.annotation.Transaction; +import ca.uhn.fhir.rest.annotation.TransactionParam; +import ca.uhn.fhir.testutil.RandomServerPortProvider; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class TransactionWithBundleParamTest { + + private static CloseableHttpClient ourClient; + private static FhirContext ourCtx = new FhirContext(); + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TransactionWithBundleParamTest.class); + private static int ourPort; + private static boolean ourReturnOperationOutcome; + + private static Server ourServer; + + + + @Before + public void before() { + ourReturnOperationOutcome = false; + } + + @Test + public void testTransaction() throws Exception { + Bundle b = new Bundle(); + InstantDt nowInstant = InstantDt.withCurrentTime(); + + Patient p1 = new Patient(); + p1.addName().addFamily("Family1"); + BundleEntry entry = b.addEntry(); + entry.getId().setValue("1"); + entry.setResource(p1); + + Patient p2 = new Patient(); + p2.addName().addFamily("Family2"); + entry = b.addEntry(); + entry.getId().setValue("2"); + entry.setResource(p2); + + BundleEntry deletedEntry = b.addEntry(); + deletedEntry.setId(new IdDt("Patient/3")); + deletedEntry.setDeleted(nowInstant); + + String bundleString = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(b); + ourLog.info(bundleString); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/"); + httpPost.addHeader("Accept", Constants.CT_ATOM_XML + "; pretty=true"); + httpPost.setEntity(new StringEntity(bundleString, ContentType.create(Constants.CT_ATOM_XML, "UTF-8"))); + HttpResponse status = ourClient.execute(httpPost); + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + + ourLog.info(responseContent); + + Bundle bundle = new FhirContext().newXmlParser().parseBundle(responseContent); + assertEquals(3, bundle.size()); + + BundleEntry entry0 = bundle.getEntries().get(0); + assertEquals("http://localhost:" + ourPort + "/Patient/81", entry0.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/81/_history/91", entry0.getLinkSelf().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/1", entry0.getLinkAlternate().getValue()); + + BundleEntry entry1 = bundle.getEntries().get(1); + assertEquals("http://localhost:" + ourPort + "/Patient/82", entry1.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/82/_history/92", entry1.getLinkSelf().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/2", entry1.getLinkAlternate().getValue()); + + BundleEntry entry2 = bundle.getEntries().get(2); + assertEquals("http://localhost:" + ourPort + "/Patient/3", entry2.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/3/_history/93", entry2.getLinkSelf().getValue()); + assertEquals(nowInstant.getValueAsString(), entry2.getDeletedAt().getValueAsString()); +} + + + @Test + public void testTransactionWithOperationOutcome() throws Exception { + ourReturnOperationOutcome = true; + + Bundle b = new Bundle(); + InstantDt nowInstant = InstantDt.withCurrentTime(); + + Patient p1 = new Patient(); + p1.addName().addFamily("Family1"); + BundleEntry entry = b.addEntry(); + entry.getId().setValue("1"); + entry.setResource(p1); + + Patient p2 = new Patient(); + p2.addName().addFamily("Family2"); + entry = b.addEntry(); + entry.getId().setValue("2"); + entry.setResource(p2); + + BundleEntry deletedEntry = b.addEntry(); + deletedEntry.setId(new IdDt("Patient/3")); + deletedEntry.setDeleted(nowInstant); + + String bundleString = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(b); + ourLog.info(bundleString); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/"); + httpPost.addHeader("Accept", Constants.CT_ATOM_XML + "; pretty=true"); + httpPost.setEntity(new StringEntity(bundleString, ContentType.create(Constants.CT_ATOM_XML, "UTF-8"))); + HttpResponse status = ourClient.execute(httpPost); + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + + ourLog.info(responseContent); + + Bundle bundle = new FhirContext().newXmlParser().parseBundle(responseContent); + assertEquals(4, bundle.size()); + + assertEquals(OperationOutcome.class, bundle.getEntries().get(0).getResource().getClass()); + assertEquals("OperationOutcome (no ID)", bundle.getEntries().get(0).getTitle().getValue()); + + BundleEntry entry0 = bundle.getEntries().get(1); + assertEquals("http://localhost:" + ourPort + "/Patient/81", entry0.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/81/_history/91", entry0.getLinkSelf().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/1", entry0.getLinkAlternate().getValue()); + + BundleEntry entry1 = bundle.getEntries().get(2); + assertEquals("http://localhost:" + ourPort + "/Patient/82", entry1.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/82/_history/92", entry1.getLinkSelf().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/2", entry1.getLinkAlternate().getValue()); + + BundleEntry entry2 = bundle.getEntries().get(3); + assertEquals("http://localhost:" + ourPort + "/Patient/3", entry2.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/3/_history/93", entry2.getLinkSelf().getValue()); + assertEquals(nowInstant.getValueAsString(), entry2.getDeletedAt().getValueAsString()); +} + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = RandomServerPortProvider.findFreePort(); + ourServer = new Server(ourPort); + + DummyProvider patientProvider = new DummyProvider(); + RestfulServer server = new RestfulServer(); + server.setProviders(patientProvider); + + org.eclipse.jetty.servlet.ServletContextHandler proxyHandler = new org.eclipse.jetty.servlet.ServletContextHandler(); + proxyHandler.setContextPath("/"); + + ServletHolder handler = new ServletHolder(); + handler.setServlet(server); + proxyHandler.addServlet(handler, "/*"); + + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + + + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyProvider { + + @Transaction + public List transaction(@TransactionParam Bundle theResources) { + int index=1; + for (IResource next : theResources.toListOfResources()) { + String newId = "8"+Integer.toString(index); + if (next.getResourceMetadata().containsKey(ResourceMetadataKeyEnum.DELETED_AT)) { + newId = next.getId().getIdPart(); + } + next.setId(new IdDt("Patient", newId, "9"+Integer.toString(index))); + index++; + } + + List retVal = theResources.toListOfResources(); + if (ourReturnOperationOutcome) { + retVal = new ArrayList(); + OperationOutcome oo = new OperationOutcome(); + oo.addIssue().setDetails("AAAAA"); + retVal.add(oo); + retVal.addAll(theResources.toListOfResources()); + } + + return retVal; + } + + + } + +} diff --git a/hapi-fhir-base/src/test/resources/atom-document-large.json b/hapi-fhir-base/src/test/resources/atom-document-large.json index 59ca6cca251..e1fbe3a9a38 100644 --- a/hapi-fhir-base/src/test/resources/atom-document-large.json +++ b/hapi-fhir-base/src/test/resources/atom-document-large.json @@ -25,6 +25,11 @@ } ], "updated" : "2014-03-22T15:37:12Z", + "category" : [{ + "term" : "http://term", + "label" : "label", + "scheme" : "http://scheme" + }], "totalResults" : "356", "entry" : [ { diff --git a/hapi-fhir-jpaserver-uhnfhirtest/.settings/org.eclipse.wst.common.component b/hapi-fhir-jpaserver-uhnfhirtest/.settings/org.eclipse.wst.common.component index c94187882b4..ee477891317 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/.settings/org.eclipse.wst.common.component +++ b/hapi-fhir-jpaserver-uhnfhirtest/.settings/org.eclipse.wst.common.component @@ -12,7 +12,7 @@ uses - + consumes diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderStructuresMojo.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderStructuresMojo.java index c7e03cb3f0b..8766db5587b 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderStructuresMojo.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderStructuresMojo.java @@ -110,6 +110,7 @@ public class TinderStructuresMojo extends AbstractMojo { ourLog.info("Loading profiles..."); ProfileParser pp = new ProfileParser(); for (ProfileFileDefinition next : resourceProfileFiles) { + ourLog.info("Parsing file: {}", next.profileFile); pp.parseSingleProfile(new File(next.profileFile), next.profileSourceUrl); } @@ -182,6 +183,10 @@ public class TinderStructuresMojo extends AbstractMojo { public static void main(String[] args) throws Exception { + ProfileParser pp = new ProfileParser(); + pp.parseSingleProfile(new File("../hapi-tinder-test/src/test/resources/profile/patient.xml"), "http://foo"); + + ValueSetGenerator vsp = new ValueSetGenerator(); // vsp.setDirectory("src/test/resources/vs/"); vsp.parse(); @@ -194,8 +199,9 @@ public class TinderStructuresMojo extends AbstractMojo { dtp.writeAll(new File(dtOutputDir), "ca.uhn.fhir.model.dstu"); ResourceGeneratorUsingSpreadsheet rp = new ResourceGeneratorUsingSpreadsheet(); - rp.setBaseResourceNames(Arrays.asList("observation")); + rp.setBaseResourceNames(Arrays.asList("patient")); rp.parse(); + // rp.bindValueSets(vsp); String rpOutputDir = "target/generated/valuesets/ca/uhn/fhir/model/dstu/resource"; diff --git a/pom.xml b/pom.xml index 60769b184db..4036cfbfd49 100644 --- a/pom.xml +++ b/pom.xml @@ -57,6 +57,7 @@ hapi-fhir-base + hapi-fhir-base/examples hapi-tinder-plugin hapi-tinder-test hapi-fhir-structures-dstu