More work on JPA server

This commit is contained in:
jamesagnew 2014-05-14 08:55:27 -04:00
parent 4d0b7ba84c
commit 10dc8b39aa
19 changed files with 1349 additions and 852 deletions

View File

@ -97,3 +97,283 @@ org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=warning
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
org.eclipse.jdt.core.compiler.source=1.6 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_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=120
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=4
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_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_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_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=280
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=tab
org.eclipse.jdt.core.formatter.tabulation.size=4
org.eclipse.jdt.core.formatter.use_on_off_tags=true
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
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

View File

@ -0,0 +1,3 @@
eclipse.preferences.version=1
formatter_profile=_James
formatter_settings_version=12

View File

@ -75,6 +75,10 @@ public abstract class BaseRuntimeElementCompositeDefinition<T extends IComposite
myNameToChild = new HashMap<String, BaseRuntimeChildDefinition>(); myNameToChild = new HashMap<String, BaseRuntimeChildDefinition>();
for (BaseRuntimeChildDefinition next : myChildren) { for (BaseRuntimeChildDefinition next : myChildren) {
if (next instanceof RuntimeChildChoiceDefinition) {
String key = ((RuntimeChildChoiceDefinition) next).getElementName()+"[x]";
myNameToChild.put(key, next);
}
for (String nextName : next.getValidChildNames()) { for (String nextName : next.getValidChildNames()) {
if (myNameToChild.containsKey(nextName)) { if (myNameToChild.containsKey(nextName)) {
throw new ConfigurationException("Duplicate child name: " + nextName); throw new ConfigurationException("Duplicate child name: " + nextName);

View File

@ -36,40 +36,228 @@ public class DateRangeParam implements IQueryParameterAnd {
private QualifiedDateParam myUpperBound; private QualifiedDateParam myUpperBound;
/** /**
* Basic constructor. Values must be supplied by calling {@link #setLowerBound(QualifiedDateParam)} and {@link #setUpperBound(QualifiedDateParam)} * Basic constructor. Values must be supplied by calling {@link #setLowerBound(QualifiedDateParam)} and
* {@link #setUpperBound(QualifiedDateParam)}
*/ */
public DateRangeParam() { public DateRangeParam() {
// nothing // nothing
} }
/** /**
* Constructor which takes two strings representing the lower and upper bounds of the range * Constructor which takes two Dates representing the lower and upper bounds of the range (inclusive on both ends)
* *
* @param theLowerBound * @param theLowerBound
* A qualified date param representing the lower date bound (optionally may include time), e.g. "2011-02-22" or "2011-02-22T13:12:00" * A qualified date param representing the lower date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00". Will be treated inclusively.
* @param theLowerBound * @param theLowerBound
* A qualified date param representing the upper date bound (optionally may include time), e.g. "2011-02-22" or "2011-02-22T13:12:00" * A qualified date param representing the upper date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00". Will be treated inclusively.
*/
public DateRangeParam(Date theLowerBound, Date theUpperBound) {
setRangeFromDatesInclusive(theLowerBound, theUpperBound);
}
/**
* Sets the range from a single date param. If theDateParam has no qualifier, treats it as the lower and upper bound
* (e.g. 2011-01-02 would match any time on that day). If theDateParam has a qualifier, treats it as either the
* lower or upper bound, with no opposite bound.
*/
public DateRangeParam(QualifiedDateParam theDateParam) {
if (theDateParam == null) {
throw new NullPointerException("theDateParam can not be null");
}
if (theDateParam.isEmpty()) {
throw new IllegalArgumentException("theDateParam can not be empty");
}
if (theDateParam.getComparator() == null) {
setRangeFromDatesInclusive(theDateParam.getValueAsString(), theDateParam.getValueAsString());
} else {
switch (theDateParam.getComparator()) {
case GREATERTHAN:
case GREATERTHAN_OR_EQUALS:
myLowerBound = theDateParam;
myUpperBound = null;
break;
case LESSTHAN:
case LESSTHAN_OR_EQUALS:
myLowerBound = null;
myUpperBound = theDateParam;
break;
default:
// Should not happen
throw new IllegalStateException("Unknown comparator:" + theDateParam.getComparator() + ". This is a bug.");
}
}
validateAndThrowDataFormatExceptionIfInvalid();
}
/**
* Constructor which takes two strings representing the lower and upper bounds of the range (inclusive on both ends)
*
* @param theLowerBound
* A qualified date param representing the lower date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00"
* @param theLowerBound
* A qualified date param representing the upper date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00"
*/ */
public DateRangeParam(String theLowerBound, String theUpperBound) { public DateRangeParam(String theLowerBound, String theUpperBound) {
setRangeFromDatesInclusive(theLowerBound, theUpperBound);
}
public QualifiedDateParam getLowerBound() {
return myLowerBound;
}
public Date getLowerBoundAsInstant() {
if (myLowerBound == null) {
return null;
}
Date retVal = myLowerBound.getValue();
if (myLowerBound.getComparator() != null) {
switch (myLowerBound.getComparator()) {
case GREATERTHAN:
retVal = myLowerBound.getPrecision().add(retVal, 1);
break;
case GREATERTHAN_OR_EQUALS:
break;
case LESSTHAN:
case LESSTHAN_OR_EQUALS:
throw new IllegalStateException("Unvalid lower bound comparator: " + myLowerBound.getComparator());
}
}
return retVal;
}
public QualifiedDateParam getUpperBound() {
return myUpperBound;
}
public Date getUpperBoundAsInstant() {
if (myUpperBound == null) {
return null;
}
Date retVal = myUpperBound.getValue();
if (myUpperBound.getComparator() != null) {
switch (myUpperBound.getComparator()) {
case LESSTHAN:
retVal = new Date(retVal.getTime() - 1L);
break;
case LESSTHAN_OR_EQUALS:
retVal = myUpperBound.getPrecision().add(retVal, 1);
retVal = new Date(retVal.getTime() - 1L);
break;
case GREATERTHAN_OR_EQUALS:
case GREATERTHAN:
throw new IllegalStateException("Unvalid upper bound comparator: " + myUpperBound.getComparator());
}
}
return retVal;
}
@Override
public List<List<String>> getValuesAsQueryTokens() {
ArrayList<List<String>> retVal = new ArrayList<List<String>>();
if (myLowerBound != null) {
retVal.add(Collections.singletonList(myLowerBound.getValueAsQueryToken()));
}
if (myUpperBound != null) {
retVal.add(Collections.singletonList(myUpperBound.getValueAsQueryToken()));
}
return retVal;
}
public void setLowerBound(QualifiedDateParam theLowerBound) {
myLowerBound = theLowerBound;
validateAndThrowDataFormatExceptionIfInvalid();
}
/**
* Sets the range from a pair of dates, inclusive on both ends
*
* @param theLowerBound
* A qualified date param representing the lower date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00". Will be treated inclusively.
* @param theLowerBound
* A qualified date param representing the upper date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00". Will be treated inclusively.
*/
public void setRangeFromDatesInclusive(Date theLowerBound, Date theUpperBound) {
myLowerBound = new QualifiedDateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, theLowerBound); myLowerBound = new QualifiedDateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, theLowerBound);
myUpperBound = new QualifiedDateParam(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS, theUpperBound); myUpperBound = new QualifiedDateParam(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS, theUpperBound);
validateAndThrowDataFormatExceptionIfInvalid(); validateAndThrowDataFormatExceptionIfInvalid();
} }
/** /**
* Constructor which takes two Dates representing the lower and upper bounds of the range * Sets the range from a pair of dates, inclusive on both ends
* *
* @param theLowerBound * @param theLowerBound
* A qualified date param representing the lower date bound (optionally may include time), e.g. "2011-02-22" or "2011-02-22T13:12:00" * A qualified date param representing the lower date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00". Will be treated inclusively.
* @param theLowerBound * @param theLowerBound
* A qualified date param representing the upper date bound (optionally may include time), e.g. "2011-02-22" or "2011-02-22T13:12:00" * A qualified date param representing the upper date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00". Will be treated inclusively.
*/ */
public DateRangeParam(Date theLowerBound, Date theUpperBound) { public void setRangeFromDatesInclusive(String theLowerBound, String theUpperBound) {
myLowerBound = new QualifiedDateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, theLowerBound); myLowerBound = new QualifiedDateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, theLowerBound);
myUpperBound = new QualifiedDateParam(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS, theUpperBound); myUpperBound = new QualifiedDateParam(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS, theUpperBound);
validateAndThrowDataFormatExceptionIfInvalid(); validateAndThrowDataFormatExceptionIfInvalid();
} }
public void setUpperBound(QualifiedDateParam theUpperBound) {
myUpperBound = theUpperBound;
validateAndThrowDataFormatExceptionIfInvalid();
}
@Override
public void setValuesAsQueryTokens(List<List<String>> theParameters) throws InvalidRequestException {
for (List<String> paramList : theParameters) {
if (paramList.size() == 0) {
continue;
}
if (paramList.size() > 1) {
throw new InvalidRequestException("DateRange parameter does not suppport OR queries");
}
String param = paramList.get(0);
QualifiedDateParam parsed = new QualifiedDateParam();
parsed.setValueAsQueryToken(param);
addParam(parsed);
}
}
private void addParam(QualifiedDateParam theParsed) throws InvalidRequestException {
if (theParsed.getComparator() == null) {
if (myLowerBound != null || myUpperBound != null) {
throw new InvalidRequestException("Can not have multiple date range parameters for the same param without a qualifier");
}
myLowerBound = theParsed;
myUpperBound = theParsed;
// TODO: in this case, should set lower and upper to exact moments
// using specified precision
} else {
switch (theParsed.getComparator()) {
case GREATERTHAN:
case GREATERTHAN_OR_EQUALS:
if (myLowerBound != null) {
throw new InvalidRequestException("Can not have multiple date range parameters for the same param that specify a lower bound");
}
myLowerBound = theParsed;
break;
case LESSTHAN:
case LESSTHAN_OR_EQUALS:
if (myUpperBound != null) {
throw new InvalidRequestException("Can not have multiple date range parameters for the same param that specify an upper bound");
}
myUpperBound = theParsed;
break;
default:
throw new InvalidRequestException("Unknown comparator: " + theParsed.getComparator());
}
}
}
private void validateAndThrowDataFormatExceptionIfInvalid() { private void validateAndThrowDataFormatExceptionIfInvalid() {
boolean haveLowerBound = myLowerBound != null && myLowerBound.isEmpty() == false; boolean haveLowerBound = myLowerBound != null && myLowerBound.isEmpty() == false;
@ -112,119 +300,4 @@ public class DateRangeParam implements IQueryParameterAnd {
} }
private void addParam(QualifiedDateParam theParsed) throws InvalidRequestException {
if (theParsed.getComparator() == null) {
if (myLowerBound != null || myUpperBound != null) {
throw new InvalidRequestException("Can not have multiple date range parameters for the same param without a qualifier");
}
myLowerBound = theParsed;
myUpperBound = theParsed;
// TODO: in this case, should set lower and upper to exact moments using specified precision
} else {
switch (theParsed.getComparator()) {
case GREATERTHAN:
case GREATERTHAN_OR_EQUALS:
if (myLowerBound != null) {
throw new InvalidRequestException("Can not have multiple date range parameters for the same param that specify a lower bound");
}
myLowerBound = theParsed;
break;
case LESSTHAN:
case LESSTHAN_OR_EQUALS:
if (myUpperBound != null) {
throw new InvalidRequestException("Can not have multiple date range parameters for the same param that specify an upper bound");
}
myUpperBound = theParsed;
break;
default:
throw new InvalidRequestException("Unknown comparator: " + theParsed.getComparator());
}
}
}
public QualifiedDateParam getLowerBound() {
return myLowerBound;
}
public QualifiedDateParam getUpperBound() {
return myUpperBound;
}
@Override
public List<List<String>> getValuesAsQueryTokens() {
ArrayList<List<String>> retVal = new ArrayList<List<String>>();
if (myLowerBound != null) {
retVal.add(Collections.singletonList(myLowerBound.getValueAsQueryToken()));
}
if (myUpperBound != null) {
retVal.add(Collections.singletonList(myUpperBound.getValueAsQueryToken()));
}
return retVal;
}
public void setLowerBound(QualifiedDateParam theLowerBound) {
myLowerBound = theLowerBound;
validateAndThrowDataFormatExceptionIfInvalid();
}
public void setUpperBound(QualifiedDateParam theUpperBound) {
myUpperBound = theUpperBound;
validateAndThrowDataFormatExceptionIfInvalid();
}
@Override
public void setValuesAsQueryTokens(List<List<String>> theParameters) throws InvalidRequestException {
for (List<String> paramList : theParameters) {
if (paramList.size() == 0) {
continue;
}
if (paramList.size() > 1) {
throw new InvalidRequestException("DateRange parameter does not suppport OR queries");
}
String param = paramList.get(0);
QualifiedDateParam parsed = new QualifiedDateParam();
parsed.setValueAsQueryToken(param);
addParam(parsed);
}
}
public Date getLowerBoundAsInstant() {
Date retVal = myLowerBound.getValue();
if (myLowerBound.getComparator() != null) {
switch (myLowerBound.getComparator()) {
case GREATERTHAN:
retVal = myLowerBound.getPrecision().add(retVal, 1);
break;
case GREATERTHAN_OR_EQUALS:
break;
case LESSTHAN:
case LESSTHAN_OR_EQUALS:
throw new IllegalStateException("Unvalid lower bound comparator: " + myLowerBound.getComparator());
}
}
return retVal;
}
public Date getUpperBoundAsInstant() {
Date retVal = myUpperBound.getValue();
if (myUpperBound.getComparator() != null) {
switch (myUpperBound.getComparator()) {
case LESSTHAN:
retVal = new Date(retVal.getTime() - 1L);
break;
case LESSTHAN_OR_EQUALS:
retVal = myUpperBound.getPrecision().add(retVal, 1);
retVal = new Date(retVal.getTime() - 1L);
break;
case GREATERTHAN_OR_EQUALS:
case GREATERTHAN:
throw new IllegalStateException("Unvalid upper bound comparator: " + myUpperBound.getComparator());
}
}
return retVal;
}
} }

View File

@ -53,6 +53,15 @@ public class QualifiedDateParam extends DateTimeDt implements IQueryParameterTyp
setValueAsString(theDate); setValueAsString(theDate);
} }
/**
* Constructor which takes a complete [qualifier]{date} string.
*
* @param theString The string
*/
public QualifiedDateParam(String theString) {
setValueAsQueryToken(theString);
}
/** /**
* Returns the comparator, or <code>null</code> if none has been set * Returns the comparator, or <code>null</code> if none has been set
*/ */
@ -70,6 +79,17 @@ public class QualifiedDateParam extends DateTimeDt implements IQueryParameterTyp
return ""; return "";
} }
/**
* Returns <code>true</code> if no date/time is specified. Note that this method
* does not check the comparator, so a QualifiedDateParam with only a comparator
* and no date/time is considered empty.
*/
@Override
public boolean isEmpty() {
// Just here to provide a javadoc
return super.isEmpty();
}
public void setComparator(QuantityCompararatorEnum theComparator) { public void setComparator(QuantityCompararatorEnum theComparator) {
myComparator = theComparator; myComparator = theComparator;
} }

View File

@ -41,6 +41,32 @@ public class FhirTerser {
private FhirContext myContext; private FhirContext myContext;
public BaseRuntimeChildDefinition getDefinition(Class<? extends IResource> theResourceType, String thePath) {
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResourceType);
BaseRuntimeElementCompositeDefinition<?> currentDef = def;
List<String> parts = Arrays.asList(thePath.split("\\."));
List<String> subList = parts.subList(1, parts.size() );
if (subList.size()< 1) {
throw new ConfigurationException("Invalid path: " + thePath);
}
return getDefinition(currentDef, subList);
}
private BaseRuntimeChildDefinition getDefinition(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, List<String> theSubList) {
BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(theSubList.get(0));
if (theSubList.size() == 1) {
return nextDef;
} else {
BaseRuntimeElementCompositeDefinition<?> cmp=(BaseRuntimeElementCompositeDefinition<?>) nextDef.getChildByName(theSubList.get(0));
return getDefinition(cmp, theSubList.subList(1, theSubList.size() ));
}
}
public List<Object> getValues(IResource theResource, String thePath) { public List<Object> getValues(IResource theResource, String thePath) {
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource); RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
@ -57,7 +83,8 @@ public class FhirTerser {
} }
private List<Object> getValues(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, Object theCurrentObj, List<String> theSubList) { private List<Object> getValues(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, Object theCurrentObj, List<String> theSubList) {
BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(theSubList.get(0)); String name = theSubList.get(0);
BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(name);
List<? extends IElement> values = nextDef.getAccessor().getValues(theCurrentObj); List<? extends IElement> values = nextDef.getAccessor().getValues(theCurrentObj);
List<Object> retVal = new ArrayList<Object>(); List<Object> retVal = new ArrayList<Object>();

View File

@ -18,18 +18,25 @@ public class DateRangeParamTest {
private static SimpleDateFormat ourFmt; private static SimpleDateFormat ourFmt;
@BeforeClass @Test
public static void beforeClass() { public void testDay() throws Exception {
ourFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSS"); assertEquals(parse("2011-01-01 00:00:00.0000"), create(">=2011-01-01", "<2011-01-02").getLowerBoundAsInstant());
assertEquals(parseM1("2011-01-02 00:00:00.0000"), create(">=2011-01-01", "<2011-01-02").getUpperBoundAsInstant());
assertEquals(parse("2011-01-02 00:00:00.0000"), create(">2011-01-01", "<=2011-01-02").getLowerBoundAsInstant());
assertEquals(parseM1("2011-01-03 00:00:00.0000"), create(">2011-01-01", "<=2011-01-02").getUpperBoundAsInstant());
} }
@Test @Test
public void testYear() throws Exception { public void testFromQualifiedDateParam() throws Exception {
assertEquals(parse("2011-01-01 00:00:00.0000"), create(">=2011", "<2012").getLowerBoundAsInstant()); assertEquals(parse("2011-01-01 00:00:00.0000"), create("2011-01-01").getLowerBoundAsInstant());
assertEquals(parseM1("2012-01-01 00:00:00.0000"), create(">=2011", "<2012").getUpperBoundAsInstant()); assertEquals(parseM1("2011-01-02 00:00:00.0000"), create("2011-01-01").getUpperBoundAsInstant());
assertEquals(parse("2012-01-01 00:00:00.0000"), create(">2011", "<=2012").getLowerBoundAsInstant()); assertEquals(parse("2011-01-01 00:00:00.0000"), create(">=2011-01-01").getLowerBoundAsInstant());
assertEquals(parseM1("2014-01-01 00:00:00.0000"), create(">2011", "<=2013").getUpperBoundAsInstant()); assertEquals(null, create(">=2011-01-01").getUpperBoundAsInstant());
assertEquals(null, create("<=2011-01-01").getLowerBoundAsInstant());
assertEquals(parseM1("2011-01-02 00:00:00.0000"), create("<=2011-01-01").getUpperBoundAsInstant());
} }
@Test @Test
@ -41,15 +48,6 @@ public class DateRangeParamTest {
assertEquals(parseM1("2011-03-01 00:00:00.0000"), create(">2011-01", "<=2011-02").getUpperBoundAsInstant()); assertEquals(parseM1("2011-03-01 00:00:00.0000"), create(">2011-01", "<=2011-02").getUpperBoundAsInstant());
} }
@Test
public void testDay() throws Exception {
assertEquals(parse("2011-01-01 00:00:00.0000"), create(">=2011-01-01", "<2011-01-02").getLowerBoundAsInstant());
assertEquals(parseM1("2011-01-02 00:00:00.0000"), create(">=2011-01-01", "<2011-01-02").getUpperBoundAsInstant());
assertEquals(parse("2011-01-02 00:00:00.0000"), create(">2011-01-01", "<=2011-01-02").getLowerBoundAsInstant());
assertEquals(parseM1("2011-01-03 00:00:00.0000"), create(">2011-01-01", "<=2011-01-02").getUpperBoundAsInstant());
}
@Test @Test
public void testSecond() throws Exception { public void testSecond() throws Exception {
assertEquals(parse("2011-01-01 00:00:00.0000"), create(">=2011-01-01T00:00:00", "<2011-01-01T01:00:00").getLowerBoundAsInstant()); assertEquals(parse("2011-01-01 00:00:00.0000"), create(">=2011-01-01T00:00:00", "<2011-01-01T01:00:00").getLowerBoundAsInstant());
@ -59,6 +57,19 @@ public class DateRangeParamTest {
assertEquals(parseM1("2011-01-01 02:00:01.0000"), create(">2011-01-01T00:00:00", "<=2011-01-01T02:00:00").getUpperBoundAsInstant()); assertEquals(parseM1("2011-01-01 02:00:01.0000"), create(">2011-01-01T00:00:00", "<=2011-01-01T02:00:00").getUpperBoundAsInstant());
} }
@Test
public void testYear() throws Exception {
assertEquals(parse("2011-01-01 00:00:00.0000"), create(">=2011", "<2012").getLowerBoundAsInstant());
assertEquals(parseM1("2012-01-01 00:00:00.0000"), create(">=2011", "<2012").getUpperBoundAsInstant());
assertEquals(parse("2012-01-01 00:00:00.0000"), create(">2011", "<=2012").getLowerBoundAsInstant());
assertEquals(parseM1("2014-01-01 00:00:00.0000"), create(">2011", "<=2013").getUpperBoundAsInstant());
}
private DateRangeParam create(String theString) {
return new DateRangeParam(new QualifiedDateParam(theString));
}
private Date parse(String theString) throws ParseException { private Date parse(String theString) throws ParseException {
return ourFmt.parse(theString); return ourFmt.parse(theString);
} }
@ -71,6 +82,11 @@ public class DateRangeParamTest {
return new Date(ourFmt.parse(theString).getTime() + 1L); return new Date(ourFmt.parse(theString).getTime() + 1L);
} }
@BeforeClass
public static void beforeClass() {
ourFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSS");
}
private static DateRangeParam create(String theLower, String theUpper) throws InvalidRequestException { private static DateRangeParam create(String theLower, String theUpper) throws InvalidRequestException {
DateRangeParam p = new DateRangeParam(); DateRangeParam p = new DateRangeParam();

View File

@ -1,430 +0,0 @@
package ca.uhn.fhir.jpa.dao;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.jpa.entity.BaseHasResource;
import ca.uhn.fhir.jpa.entity.BaseResourceTable;
import ca.uhn.fhir.jpa.entity.BaseTag;
import ca.uhn.fhir.jpa.entity.ResourceHistoryTable;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamToken;
import ca.uhn.fhir.model.api.IDatatype;
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
import ca.uhn.fhir.model.api.IQueryParameterType;
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.composite.CodeableConceptDt;
import ca.uhn.fhir.model.dstu.composite.CodingDt;
import ca.uhn.fhir.model.dstu.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu.valueset.SearchParamTypeEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.util.FhirTerser;
public class CopyOfFhirResourceDao<T extends IResource, X extends BaseResourceTable<T>> implements IFhirResourceDao<T> {
private FhirContext myCtx;
@PersistenceContext(name = "FHIR_UT", type = PersistenceContextType.TRANSACTION, unitName = "FHIR_UT")
private EntityManager myEntityManager;
@Autowired
private PlatformTransactionManager myPlatformTransactionManager;
private Class<T> myResourceType;
private Class<X> myTableType;
private void addTokenPredicate(CriteriaQuery<X> theCriteriaQuery, List<IQueryParameterType> theOrParams, Root<X> theFrom, CriteriaBuilder theBuilder) {
if (theOrParams == null || theOrParams.isEmpty()) {
return;
}
if (theOrParams.size() > 1) {
throw new UnsupportedOperationException("Multiple values not yet supported"); // TODO: implement
}
IQueryParameterType params = theOrParams.get(0);
String code;
String system;
if (params instanceof IdentifierDt) {
IdentifierDt id = (IdentifierDt) params;
system = id.getSystem().getValueAsString();
code = id.getValue().getValue();
} else if (params instanceof CodingDt) {
CodingDt id = (CodingDt) params;
system = id.getSystem().getValueAsString();
code = id.getCode().getValue();
} else {
throw new IllegalArgumentException("Invalid token type: " + params.getClass());
}
Join<Object, Object> join = theFrom.join("myParamsToken", JoinType.LEFT);
ArrayList<Predicate> predicates = (new ArrayList<Predicate>());
if (system != null) {
predicates.add(theBuilder.equal(join.get("mySystem"), system));
}
if (code != null) {
predicates.add(theBuilder.equal(join.get("myValue"), code));
}
theCriteriaQuery.where(predicates.toArray(new Predicate[0]));
}
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public MethodOutcome create(T theResource) {
final X entity = toEntity(theResource);
entity.setPublished(new Date());
entity.setUpdated(entity.getPublished());
final List<ResourceIndexedSearchParamString> stringParams = extractSearchParamStrings(entity, theResource);
final List<ResourceIndexedSearchParamToken> tokenParams = extractSearchParamTokens(entity, theResource);
TransactionTemplate template = new TransactionTemplate(myPlatformTransactionManager);
template.execute(new TransactionCallback<X>() {
@Override
public X doInTransaction(TransactionStatus theStatus) {
myEntityManager.persist(entity);
for (ResourceIndexedSearchParamString next : stringParams) {
myEntityManager.persist(next);
}
for (ResourceIndexedSearchParamToken next : tokenParams) {
myEntityManager.persist(next);
}
return entity;
}
});
MethodOutcome outcome = toMethodOutcome(entity);
return outcome;
}
private List<ResourceIndexedSearchParamString> extractSearchParamStrings(X theEntity, T theResource) {
ArrayList<ResourceIndexedSearchParamString> retVal = new ArrayList<ResourceIndexedSearchParamString>();
RuntimeResourceDefinition def = myCtx.getResourceDefinition(theResource);
FhirTerser t = myCtx.newTerser();
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
if (nextSpDef.getParamType() != SearchParamTypeEnum.STRING) {
continue;
}
if (nextSpDef.getPath().isEmpty()) {
continue; // TODO: implement phoenetic, and any others that have no path
}
String nextPath = nextSpDef.getPath();
List<Object> values = t.getValues(theResource, nextPath);
for (Object nextObject : values) {
if (((IDatatype) nextObject).isEmpty()) {
continue;
}
if (nextObject instanceof IPrimitiveDatatype<?>) {
IPrimitiveDatatype<?> nextValue = (IPrimitiveDatatype<?>) nextObject;
ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(nextSpDef.getName(), nextValue.getValueAsString());
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
} else if (nextObject instanceof HumanNameDt) {
for (StringDt nextName : ((HumanNameDt) nextObject).getFamily()) {
if (nextName.isEmpty()) {
continue;
}
ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(nextSpDef.getName(), nextName.getValueAsString());
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
}
} else {
throw new ConfigurationException("Search param " + nextSpDef.getName() + " is of unexpected datatype: " + nextObject.getClass());
}
}
}
return retVal;
}
private List<ResourceIndexedSearchParamToken> extractSearchParamTokens(X theEntity, T theResource) {
ArrayList<ResourceIndexedSearchParamToken> retVal = new ArrayList<ResourceIndexedSearchParamToken>();
RuntimeResourceDefinition def = myCtx.getResourceDefinition(theResource);
FhirTerser t = myCtx.newTerser();
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
if (nextSpDef.getParamType() != SearchParamTypeEnum.TOKEN) {
continue;
}
String nextPath = nextSpDef.getPath();
List<Object> values = t.getValues(theResource, nextPath);
for (Object nextObject : values) {
ResourceIndexedSearchParamToken nextEntity;
if (nextObject instanceof IdentifierDt) {
IdentifierDt nextValue = (IdentifierDt) nextObject;
if (nextValue.isEmpty()) {
continue;
}
nextEntity = new ResourceIndexedSearchParamToken(nextSpDef.getName(), nextValue.getSystem().getValueAsString(), nextValue.getValue().getValue());
} else if (nextObject instanceof IPrimitiveDatatype<?>) {
IPrimitiveDatatype<?> nextValue = (IPrimitiveDatatype<?>) nextObject;
if (nextValue.isEmpty()) {
continue;
}
nextEntity = new ResourceIndexedSearchParamToken(nextSpDef.getName(), null, nextValue.getValueAsString());
} else if (nextObject instanceof CodeableConceptDt) {
CodeableConceptDt nextCC = (CodeableConceptDt) nextObject;
for (CodingDt nextCoding : nextCC.getCoding()) {
if (nextCoding.isEmpty()) {
continue;
}
nextEntity = new ResourceIndexedSearchParamToken(nextSpDef.getName(), nextCoding.getSystem().getValueAsString(), nextCoding.getCode().getValue());
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
}
nextEntity = null;
} else {
throw new ConfigurationException("Search param " + nextSpDef.getName() + " is of unexpected datatype: " + nextObject.getClass());
}
if (nextEntity != null) {
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
}
}
}
return retVal;
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
public List<T> history(IdDt theId) {
ArrayList<T> retVal = new ArrayList<T>();
String resourceType = myCtx.getResourceDefinition(myResourceType).getName();
TypedQuery<ResourceHistoryTable> q = myEntityManager.createQuery(ResourceHistoryTable.Q_GETALL, ResourceHistoryTable.class);
q.setParameter("PID", theId.asLong());
q.setParameter("RESTYPE", resourceType);
// TypedQuery<ResourceHistoryTable> query =
// myEntityManager.createQuery(criteriaQuery);
List<ResourceHistoryTable> results = q.getResultList();
for (ResourceHistoryTable next : results) {
retVal.add(toResource(next));
}
try {
retVal.add(read(theId));
} catch (ResourceNotFoundException e) {
// ignore
}
if (retVal.isEmpty()) {
throw new ResourceNotFoundException(theId);
}
return retVal;
}
private void populateResourceIntoEntity(T theResource, X retVal) {
retVal.setResource(myCtx.newJsonParser().encodeResourceToString(theResource));
retVal.setEncoding(EncodingEnum.JSON);
TagList tagList = (TagList) theResource.getResourceMetadata().get(ResourceMetadataKeyEnum.TAG_LIST);
if (tagList != null) {
for (Tag next : tagList) {
retVal.addTag(next.getTerm(), next.getLabel(), next.getScheme());
}
}
}
@PostConstruct
public void postConstruct() throws Exception {
myResourceType = myTableType.newInstance().getResourceType();
myCtx = new FhirContext(myResourceType);
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
public T read(IdDt theId) {
X entity = readEntity(theId);
T retVal = toResource(entity);
return retVal;
}
private X readEntity(IdDt theId) {
X entity = (X) myEntityManager.find(myTableType, theId.asLong());
if (entity == null) {
throw new ResourceNotFoundException(theId);
}
return entity;
}
@Override
public List<T> search(Map<String, IQueryParameterType> theParams) {
Map<String, List<List<IQueryParameterType>>> map = new HashMap<String, List<List<IQueryParameterType>>>();
for (Entry<String, IQueryParameterType> nextEntry : theParams.entrySet()) {
map.put(nextEntry.getKey(), new ArrayList<List<IQueryParameterType>>());
map.get(nextEntry.getKey()).add(Collections.singletonList(nextEntry.getValue()));
}
return searchWithAndOr(map);
}
@Override
public List<T> search(String theSpName, IQueryParameterType theValue) {
return search(Collections.singletonMap(theSpName, theValue));
}
@Override
public List<T> searchWithAndOr(Map<String, List<List<IQueryParameterType>>> theParams) {
Map<String, List<List<IQueryParameterType>>> params = theParams;
if (params == null) {
params = Collections.emptyMap();
}
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<X> cq = builder.createQuery(myTableType);
Root<X> from = cq.from(myTableType);
RuntimeResourceDefinition resourceDef = myCtx.getResourceDefinition(myResourceType);
for (Entry<String, List<List<IQueryParameterType>>> nextParamEntry : params.entrySet()) {
String nextParamName = nextParamEntry.getKey();
RuntimeSearchParam nextParamDef = resourceDef.getSearchParam(nextParamName);
if (nextParamDef != null) {
if (nextParamDef.getParamType() == SearchParamTypeEnum.TOKEN) {
for (List<IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
addTokenPredicate(cq, nextAnd, from, builder);
}
}
}
}
// Execute the query and make sure we return distinct results
Set<Long> pids = new HashSet<Long>();
TypedQuery<X> q = myEntityManager.createQuery(cq);
List<T> retVal = new ArrayList<>();
for (X next : q.getResultList()) {
T resource = toResource(next);
if (pids.contains(next.getIdAsLong())) {
continue;
}else {
pids.add(next.getIdAsLong());
}
retVal.add(resource);
}
return retVal;
}
@Required
public void setTableType(Class<X> theTableType) {
myTableType = theTableType;
}
private X toEntity(T theResource) {
X retVal;
try {
retVal = myTableType.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new InternalErrorException(e);
}
populateResourceIntoEntity(theResource, retVal);
return retVal;
}
private MethodOutcome toMethodOutcome(final X entity) {
MethodOutcome outcome = new MethodOutcome();
outcome.setId(entity.getId());
outcome.setVersionId(entity.getVersion());
return outcome;
}
private T toResource(BaseHasResource theEntity) {
String resourceText = theEntity.getResource();
IParser parser = theEntity.getEncoding().newParser(myCtx);
T retVal = parser.parseResource(myResourceType, resourceText);
retVal.setId(theEntity.getId());
retVal.getResourceMetadata().put(ResourceMetadataKeyEnum.VERSION_ID, theEntity.getVersion());
retVal.getResourceMetadata().put(ResourceMetadataKeyEnum.PUBLISHED, theEntity.getPublished());
retVal.getResourceMetadata().put(ResourceMetadataKeyEnum.UPDATED, theEntity.getUpdated());
if (theEntity.getTags().size() > 0) {
TagList tagList = new TagList();
for (BaseTag next : theEntity.getTags()) {
tagList.add(new Tag(next.getTerm(), next.getLabel(), next.getScheme()));
}
retVal.getResourceMetadata().put(ResourceMetadataKeyEnum.TAG_LIST, tagList);
}
return retVal;
}
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public MethodOutcome update(final T theResource, final IdDt theId) {
TransactionTemplate template = new TransactionTemplate(myPlatformTransactionManager);
X savedEntity = template.execute(new TransactionCallback<X>() {
@Override
public X doInTransaction(TransactionStatus theStatus) {
final X entity = readEntity(theId);
final ResourceHistoryTable existing = entity.toHistory(myCtx);
populateResourceIntoEntity(theResource, entity);
myEntityManager.persist(existing);
entity.setUpdated(new Date());
myEntityManager.persist(entity);
return entity;
}
});
return toMethodOutcome(savedEntity);
}
}

View File

@ -17,6 +17,7 @@ import javax.persistence.PersistenceContextType;
import javax.persistence.TypedQuery; import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root; import javax.persistence.criteria.Root;
@ -37,6 +38,8 @@ import ca.uhn.fhir.jpa.entity.BaseHasResource;
import ca.uhn.fhir.jpa.entity.BaseResourceTable; import ca.uhn.fhir.jpa.entity.BaseResourceTable;
import ca.uhn.fhir.jpa.entity.BaseTag; import ca.uhn.fhir.jpa.entity.BaseTag;
import ca.uhn.fhir.jpa.entity.ResourceHistoryTable; import ca.uhn.fhir.jpa.entity.ResourceHistoryTable;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamNumber;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString; import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamToken; import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamToken;
import ca.uhn.fhir.model.api.IDatatype; import ca.uhn.fhir.model.api.IDatatype;
@ -50,12 +53,15 @@ import ca.uhn.fhir.model.dstu.composite.CodeableConceptDt;
import ca.uhn.fhir.model.dstu.composite.CodingDt; import ca.uhn.fhir.model.dstu.composite.CodingDt;
import ca.uhn.fhir.model.dstu.composite.HumanNameDt; import ca.uhn.fhir.model.dstu.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu.composite.IdentifierDt; import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu.composite.QuantityDt;
import ca.uhn.fhir.model.dstu.valueset.SearchParamTypeEnum; import ca.uhn.fhir.model.dstu.valueset.SearchParamTypeEnum;
import ca.uhn.fhir.model.primitive.BaseDateTimeDt;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.StringDt; import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.gclient.QuantityParam; import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.QualifiedDateParam;
import ca.uhn.fhir.rest.server.EncodingEnum; import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
@ -72,8 +78,387 @@ public class FhirResourceDao<T extends IResource, X extends BaseResourceTable<T>
private Class<T> myResourceType; private Class<T> myResourceType;
private Class<X> myTableType; private Class<X> myTableType;
private String myResourceName;
private Set<Long> addTokenPredicate(Set<Long> thePids, List<IQueryParameterType> theOrParams) { @Transactional(propagation = Propagation.SUPPORTS)
@Override
public MethodOutcome create(T theResource) {
final X entity = toEntity(theResource);
entity.setPublished(new Date());
entity.setUpdated(entity.getPublished());
final List<ResourceIndexedSearchParamString> stringParams = extractSearchParamStrings(entity, theResource);
final List<ResourceIndexedSearchParamToken> tokenParams = extractSearchParamTokens(entity, theResource);
final List<ResourceIndexedSearchParamNumber> numberParams = extractSearchParamNumber(entity, theResource);
final List<ResourceIndexedSearchParamDate> dateParams = extractSearchParamDates(entity, theResource);
TransactionTemplate template = new TransactionTemplate(myPlatformTransactionManager);
template.execute(new TransactionCallback<X>() {
@Override
public X doInTransaction(TransactionStatus theStatus) {
myEntityManager.persist(entity);
for (ResourceIndexedSearchParamString next : stringParams) {
myEntityManager.persist(next);
}
for (ResourceIndexedSearchParamToken next : tokenParams) {
myEntityManager.persist(next);
}
for (ResourceIndexedSearchParamNumber next : numberParams) {
myEntityManager.persist(next);
}
for (ResourceIndexedSearchParamDate next : dateParams) {
myEntityManager.persist(next);
}
return entity;
}
});
MethodOutcome outcome = toMethodOutcome(entity);
return outcome;
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
public List<T> history(IdDt theId) {
ArrayList<T> retVal = new ArrayList<T>();
String resourceType = myCtx.getResourceDefinition(myResourceType).getName();
TypedQuery<ResourceHistoryTable> q = myEntityManager.createQuery(ResourceHistoryTable.Q_GETALL, ResourceHistoryTable.class);
q.setParameter("PID", theId.asLong());
q.setParameter("RESTYPE", resourceType);
// TypedQuery<ResourceHistoryTable> query =
// myEntityManager.createQuery(criteriaQuery);
List<ResourceHistoryTable> results = q.getResultList();
for (ResourceHistoryTable next : results) {
retVal.add(toResource(next));
}
try {
retVal.add(read(theId));
} catch (ResourceNotFoundException e) {
// ignore
}
if (retVal.isEmpty()) {
throw new ResourceNotFoundException(theId);
}
return retVal;
}
@PostConstruct
public void postConstruct() throws Exception {
myResourceType = myTableType.newInstance().getResourceType();
myCtx = new FhirContext(myResourceType);
myResourceName = myCtx.getResourceDefinition(myResourceType).getName();
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
public T read(IdDt theId) {
X entity = readEntity(theId);
T retVal = toResource(entity);
return retVal;
}
@Override
public List<T> search(Map<String, IQueryParameterType> theParams) {
Map<String, List<List<IQueryParameterType>>> map = new HashMap<String, List<List<IQueryParameterType>>>();
for (Entry<String, IQueryParameterType> nextEntry : theParams.entrySet()) {
map.put(nextEntry.getKey(), new ArrayList<List<IQueryParameterType>>());
map.get(nextEntry.getKey()).add(Collections.singletonList(nextEntry.getValue()));
}
return searchWithAndOr(map);
}
@Override
public List<T> search(String theSpName, IQueryParameterType theValue) {
return search(Collections.singletonMap(theSpName, theValue));
}
@Override
public List<T> searchWithAndOr(Map<String, List<List<IQueryParameterType>>> theParams) {
Map<String, List<List<IQueryParameterType>>> params = theParams;
if (params == null) {
params = Collections.emptyMap();
}
RuntimeResourceDefinition resourceDef = myCtx.getResourceDefinition(myResourceType);
Set<Long> pids = new HashSet<Long>();
for (Entry<String, List<List<IQueryParameterType>>> nextParamEntry : params.entrySet()) {
String nextParamName = nextParamEntry.getKey();
RuntimeSearchParam nextParamDef = resourceDef.getSearchParam(nextParamName);
if (nextParamDef != null) {
if (nextParamDef.getParamType() == SearchParamTypeEnum.TOKEN) {
for (List<IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
pids = addPredicateToken(pids, nextAnd);
if (pids.isEmpty()) {
return new ArrayList<T>();
}
}
} else if (nextParamDef.getParamType() == SearchParamTypeEnum.STRING) {
for (List<IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
pids = addPredicateString(pids, nextAnd);
if (pids.isEmpty()) {
return new ArrayList<T>();
}
}
} else if (nextParamDef.getParamType() == SearchParamTypeEnum.QUANTITY) {
for (List<IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
pids = addPredicateQuantity(pids, nextAnd);
if (pids.isEmpty()) {
return new ArrayList<T>();
}
}
} else if (nextParamDef.getParamType() == SearchParamTypeEnum.DATE) {
for (List<IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
pids = addPredicateDate(pids, nextAnd);
if (pids.isEmpty()) {
return new ArrayList<T>();
}
}
} else {
throw new IllegalArgumentException("Don't know how to handle parameter of type: " + nextParamDef.getParamType());
}
}
}
// Execute the query and make sure we return distinct results
{
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<X> cq = builder.createQuery(myTableType);
Root<X> from = cq.from(myTableType);
if (!params.isEmpty()) {
cq.where(from.get("myId").in(pids));
}
TypedQuery<X> q = myEntityManager.createQuery(cq);
List<T> retVal = new ArrayList<>();
for (X next : q.getResultList()) {
T resource = toResource(next);
retVal.add(resource);
}
return retVal;
}
}
@Required
public void setTableType(Class<X> theTableType) {
myTableType = theTableType;
}
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public MethodOutcome update(final T theResource, final IdDt theId) {
TransactionTemplate template = new TransactionTemplate(myPlatformTransactionManager);
X savedEntity = template.execute(new TransactionCallback<X>() {
@Override
public X doInTransaction(TransactionStatus theStatus) {
final X entity = readEntity(theId);
final ResourceHistoryTable existing = entity.toHistory(myCtx);
populateResourceIntoEntity(theResource, entity);
myEntityManager.persist(existing);
entity.setUpdated(new Date());
myEntityManager.persist(entity);
return entity;
}
});
return toMethodOutcome(savedEntity);
}
private Set<Long> addPredicateQuantity(Set<Long> thePids, List<IQueryParameterType> theOrParams) {
if (theOrParams == null || theOrParams.isEmpty()) {
return thePids;
}
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
Root<ResourceIndexedSearchParamNumber> from = cq.from(ResourceIndexedSearchParamNumber.class);
cq.select(from.get("myResourcePid").as(Long.class));
List<Predicate> codePredicates = new ArrayList<Predicate>();
for (IQueryParameterType nextOr : theOrParams) {
IQueryParameterType params = nextOr;
if (params instanceof QuantityDt) {
QuantityDt id = (QuantityDt) params;
Predicate system;
if (id.getSystem().isEmpty()) {
system = builder.isNull(from.get("mySystem"));
} else {
system = builder.equal(from.get("mySystem"), id.getSystem().getValueAsString());
}
Predicate code;
if (id.getCode().isEmpty()) {
code = builder.isNull(from.get("myUnits"));
} else {
code = builder.equal(from.get("myUnits"), id.getUnits().getValueAsString());
}
Predicate num;
if (id.getComparator().getValueAsEnum() == null) {
num = builder.equal(from.get("myValue"), id.getValue().getValue());
} else {
switch (id.getComparator().getValueAsEnum()) {
case GREATERTHAN:
Expression<Number> path = from.get("myValue");
Number value = id.getValue().getValue();
num = builder.gt(path, value);
break;
case GREATERTHAN_OR_EQUALS:
path = from.get("myValue");
value = id.getValue().getValue();
num = builder.ge(path, value);
break;
case LESSTHAN:
path = from.get("myValue");
value = id.getValue().getValue();
num = builder.lt(path, value);
break;
case LESSTHAN_OR_EQUALS:
path = from.get("myValue");
value = id.getValue().getValue();
num = builder.le(path, value);
break;
default:
throw new IllegalStateException(id.getComparator().getValueAsString());
}
}
Predicate singleCode = builder.and(system, code, num);
codePredicates.add(singleCode);
} else {
throw new IllegalArgumentException("Invalid token type: " + params.getClass());
}
}
Predicate masterCodePredicate = builder.or(codePredicates.toArray(new Predicate[0]));
Predicate type = builder.equal(from.get("myResourceType"), myResourceName);
if (thePids.size() > 0) {
Predicate inPids = (from.get("myResourcePid").in(thePids));
cq.where(builder.and(type, inPids, masterCodePredicate));
} else {
cq.where(builder.and(type, masterCodePredicate));
}
TypedQuery<Long> q = myEntityManager.createQuery(cq);
return new HashSet<Long>(q.getResultList());
}
private Set<Long> addPredicateDate(Set<Long> thePids, List<IQueryParameterType> theOrParams) {
if (theOrParams == null || theOrParams.isEmpty()) {
return thePids;
}
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
Root<ResourceIndexedSearchParamDate> from = cq.from(ResourceIndexedSearchParamDate.class);
cq.select(from.get("myResourcePid").as(Long.class));
List<Predicate> codePredicates = new ArrayList<Predicate>();
for (IQueryParameterType nextOr : theOrParams) {
IQueryParameterType params = nextOr;
if (params instanceof QualifiedDateParam) {
QualifiedDateParam id = (QualifiedDateParam) params;
DateRangeParam range = new DateRangeParam(id);
addPredicateDateFromRange(builder, from, codePredicates, range);
} else if (params instanceof DateRangeParam) {
DateRangeParam range = (DateRangeParam) params;
addPredicateDateFromRange(builder, from, codePredicates, range);
} else {
throw new IllegalArgumentException("Invalid token type: " + params.getClass());
}
}
Predicate masterCodePredicate = builder.or(codePredicates.toArray(new Predicate[0]));
Predicate type = builder.equal(from.get("myResourceType"), myResourceName);
if (thePids.size() > 0) {
Predicate inPids = (from.get("myResourcePid").in(thePids));
cq.where(builder.and(type, inPids, masterCodePredicate));
} else {
cq.where(builder.and(type, masterCodePredicate));
}
TypedQuery<Long> q = myEntityManager.createQuery(cq);
return new HashSet<Long>(q.getResultList());
}
private void addPredicateDateFromRange(CriteriaBuilder builder, Root<ResourceIndexedSearchParamDate> from, List<Predicate> codePredicates, DateRangeParam range) {
Predicate singleCode;
Date lowerBound = range.getLowerBoundAsInstant();
Date upperBound = range.getUpperBoundAsInstant();
if (lowerBound != null && upperBound != null) {
Predicate low = builder.greaterThanOrEqualTo(from.<Date> get("myValueLow"), lowerBound);
Predicate high = builder.lessThanOrEqualTo(from.<Date> get("myValueHigh"), upperBound);
singleCode = builder.and(low, high);
} else if (lowerBound != null) {
singleCode = builder.greaterThanOrEqualTo(from.<Date> get("myValueLow"), lowerBound);
} else {
singleCode = builder.lessThanOrEqualTo(from.<Date> get("myValueHigh"), upperBound);
}
codePredicates.add(singleCode);
}
private Set<Long> addPredicateString(Set<Long> thePids, List<IQueryParameterType> theOrParams) {
if (theOrParams == null || theOrParams.isEmpty()) {
return thePids;
}
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
Root<ResourceIndexedSearchParamString> from = cq.from(ResourceIndexedSearchParamString.class);
cq.select(from.get("myResourcePid").as(Long.class));
List<Predicate> codePredicates = new ArrayList<Predicate>();
for (IQueryParameterType nextOr : theOrParams) {
IQueryParameterType params = nextOr;
String string;
if (params instanceof IPrimitiveDatatype<?>) {
IPrimitiveDatatype<?> id = (IPrimitiveDatatype<?>) params;
string = id.getValueAsString();
} else {
throw new IllegalArgumentException("Invalid token type: " + params.getClass());
}
Predicate singleCode = builder.equal(from.get("myValue"), string);
codePredicates.add(singleCode);
}
Predicate masterCodePredicate = builder.or(codePredicates.toArray(new Predicate[0]));
Predicate type = builder.equal(from.get("myResourceType"), myResourceName);
if (thePids.size() > 0) {
Predicate inPids = (from.get("myResourcePid").in(thePids));
cq.where(builder.and(type, inPids, masterCodePredicate));
} else {
cq.where(builder.and(type, masterCodePredicate));
}
TypedQuery<Long> q = myEntityManager.createQuery(cq);
return new HashSet<Long>(q.getResultList());
}
private Set<Long> addPredicateToken(Set<Long> thePids, List<IQueryParameterType> theOrParams) {
if (theOrParams == null || theOrParams.isEmpty()) { if (theOrParams == null || theOrParams.isEmpty()) {
return thePids; return thePids;
} }
@ -114,126 +499,18 @@ public class FhirResourceDao<T extends IResource, X extends BaseResourceTable<T>
Predicate masterCodePredicate = builder.or(codePredicates.toArray(new Predicate[0])); Predicate masterCodePredicate = builder.or(codePredicates.toArray(new Predicate[0]));
Predicate type = builder.equal(from.get("myResourceType"), myResourceName);
if (thePids.size() > 0) { if (thePids.size() > 0) {
Predicate inPids = (from.get("myResourcePid").in(thePids)); Predicate inPids = (from.get("myResourcePid").in(thePids));
cq.where(builder.and(inPids, masterCodePredicate)); cq.where(builder.and(type, inPids, masterCodePredicate));
} else { } else {
cq.where(masterCodePredicate); cq.where(builder.and(type, masterCodePredicate));
} }
TypedQuery<Long> q = myEntityManager.createQuery(cq); TypedQuery<Long> q = myEntityManager.createQuery(cq);
return new HashSet<Long>(q.getResultList()); return new HashSet<Long>(q.getResultList());
} }
private Set<Long> addStringPredicate(Set<Long> thePids, List<IQueryParameterType> theOrParams) {
if (theOrParams == null || theOrParams.isEmpty()) {
return thePids;
}
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
Root<ResourceIndexedSearchParamString> from = cq.from(ResourceIndexedSearchParamString.class);
cq.select(from.get("myResourcePid").as(Long.class));
List<Predicate> codePredicates = new ArrayList<Predicate>();
for (IQueryParameterType nextOr : theOrParams) {
IQueryParameterType params = nextOr;
String string;
if (params instanceof IPrimitiveDatatype<?>) {
IPrimitiveDatatype<?> id = (IPrimitiveDatatype<?>) params;
string = id.getValueAsString();
} else {
throw new IllegalArgumentException("Invalid token type: " + params.getClass());
}
Predicate singleCode = builder.equal(from.get("myValue"), string);
codePredicates.add(singleCode);
}
Predicate masterCodePredicate = builder.or(codePredicates.toArray(new Predicate[0]));
if (thePids.size() > 0) {
Predicate inPids = (from.get("myResourcePid").in(thePids));
cq.where(builder.and(inPids, masterCodePredicate));
} else {
cq.where(masterCodePredicate);
}
TypedQuery<Long> q = myEntityManager.createQuery(cq);
return new HashSet<Long>(q.getResultList());
}
private Set<Long> addQuantityPredicate(Set<Long> thePids, List<IQueryParameterType> theOrParams) {
if (theOrParams == null || theOrParams.isEmpty()) {
return thePids;
}
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
Root<ResourceIndexedSearchParamString> from = cq.from(ResourceIndexedSearchParamString.class);
cq.select(from.get("myResourcePid").as(Long.class));
List<Predicate> codePredicates = new ArrayList<Predicate>();
for (IQueryParameterType nextOr : theOrParams) {
IQueryParameterType params = nextOr;
String string;
if (params instanceof QuantityParam<?>) {
IPrimitiveDatatype<?> id = (IPrimitiveDatatype<?>) params;
string = id.getValueAsString();
} else {
throw new IllegalArgumentException("Invalid token type: " + params.getClass());
}
Predicate singleCode = builder.equal(from.get("myValue"), string);
codePredicates.add(singleCode);
}
Predicate masterCodePredicate = builder.or(codePredicates.toArray(new Predicate[0]));
if (thePids.size() > 0) {
Predicate inPids = (from.get("myResourcePid").in(thePids));
cq.where(builder.and(inPids, masterCodePredicate));
} else {
cq.where(masterCodePredicate);
}
TypedQuery<Long> q = myEntityManager.createQuery(cq);
return new HashSet<Long>(q.getResultList());
}
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public MethodOutcome create(T theResource) {
final X entity = toEntity(theResource);
entity.setPublished(new Date());
entity.setUpdated(entity.getPublished());
final List<ResourceIndexedSearchParamString> stringParams = extractSearchParamStrings(entity, theResource);
final List<ResourceIndexedSearchParamToken> tokenParams = extractSearchParamTokens(entity, theResource);
TransactionTemplate template = new TransactionTemplate(myPlatformTransactionManager);
template.execute(new TransactionCallback<X>() {
@Override
public X doInTransaction(TransactionStatus theStatus) {
myEntityManager.persist(entity);
for (ResourceIndexedSearchParamString next : stringParams) {
myEntityManager.persist(next);
}
for (ResourceIndexedSearchParamToken next : tokenParams) {
myEntityManager.persist(next);
}
return entity;
}
});
MethodOutcome outcome = toMethodOutcome(entity);
return outcome;
}
private List<ResourceIndexedSearchParamString> extractSearchParamStrings(X theEntity, T theResource) { private List<ResourceIndexedSearchParamString> extractSearchParamStrings(X theEntity, T theResource) {
ArrayList<ResourceIndexedSearchParamString> retVal = new ArrayList<ResourceIndexedSearchParamString>(); ArrayList<ResourceIndexedSearchParamString> retVal = new ArrayList<ResourceIndexedSearchParamString>();
@ -244,7 +521,8 @@ public class FhirResourceDao<T extends IResource, X extends BaseResourceTable<T>
continue; continue;
} }
if (nextSpDef.getPath().isEmpty()) { if (nextSpDef.getPath().isEmpty()) {
continue; // TODO: implement phoenetic, and any others that have no path continue; // TODO: implement phoenetic, and any others that have
// no path
} }
String nextPath = nextSpDef.getPath(); String nextPath = nextSpDef.getPath();
@ -253,22 +531,72 @@ public class FhirResourceDao<T extends IResource, X extends BaseResourceTable<T>
if (((IDatatype) nextObject).isEmpty()) { if (((IDatatype) nextObject).isEmpty()) {
continue; continue;
} }
String resourceName = nextSpDef.getName();
boolean multiType = false;
if (nextPath.endsWith("[x]")) {
multiType = true;
}
if (nextObject instanceof IPrimitiveDatatype<?>) { if (nextObject instanceof IPrimitiveDatatype<?>) {
IPrimitiveDatatype<?> nextValue = (IPrimitiveDatatype<?>) nextObject; IPrimitiveDatatype<?> nextValue = (IPrimitiveDatatype<?>) nextObject;
ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(nextSpDef.getName(), nextValue.getValueAsString()); ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(resourceName, nextValue.getValueAsString());
nextEntity.setResource(theEntity); nextEntity.setResource(theEntity, def.getName());
retVal.add(nextEntity); retVal.add(nextEntity);
} else if (nextObject instanceof HumanNameDt) { } else if (nextObject instanceof HumanNameDt) {
for (StringDt nextName : ((HumanNameDt) nextObject).getFamily()) { for (StringDt nextName : ((HumanNameDt) nextObject).getFamily()) {
if (nextName.isEmpty()) { if (nextName.isEmpty()) {
continue; continue;
} }
ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(nextSpDef.getName(), nextName.getValueAsString()); ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(resourceName, nextName.getValueAsString());
nextEntity.setResource(theEntity); nextEntity.setResource(theEntity, def.getName());
retVal.add(nextEntity); retVal.add(nextEntity);
} }
} else { } else {
throw new ConfigurationException("Search param " + nextSpDef.getName() + " is of unexpected datatype: " + nextObject.getClass()); if (!multiType) {
throw new ConfigurationException("Search param " + resourceName + " is of unexpected datatype: " + nextObject.getClass());
}
}
}
}
return retVal;
}
private ArrayList<ResourceIndexedSearchParamNumber> extractSearchParamNumber(X theEntity, T theResource) {
ArrayList<ResourceIndexedSearchParamNumber> retVal = new ArrayList<ResourceIndexedSearchParamNumber>();
RuntimeResourceDefinition def = myCtx.getResourceDefinition(theResource);
FhirTerser t = myCtx.newTerser();
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
if (nextSpDef.getParamType() != SearchParamTypeEnum.NUMBER && nextSpDef.getParamType() != SearchParamTypeEnum.QUANTITY) {
continue;
}
String nextPath = nextSpDef.getPath();
List<Object> values = t.getValues(theResource, nextPath);
for (Object nextObject : values) {
if (((IDatatype) nextObject).isEmpty()) {
continue;
}
String resourceName = nextSpDef.getName();
boolean multiType = false;
if (nextPath.endsWith("[x]")) {
multiType = true;
}
if (nextObject instanceof QuantityDt) {
QuantityDt nextValue = (QuantityDt) nextObject;
ResourceIndexedSearchParamNumber nextEntity = new ResourceIndexedSearchParamNumber(resourceName, nextValue.getValue().getValue(), nextValue.getSystem().getValueAsString(), nextValue.getUnits().getValue());
nextEntity.setResource(theEntity, def.getName());
retVal.add(nextEntity);
} else {
if (!multiType) {
throw new ConfigurationException("Search param " + resourceName + " is of unexpected datatype: " + nextObject.getClass());
} else {
continue;
}
} }
} }
} }
@ -287,6 +615,12 @@ public class FhirResourceDao<T extends IResource, X extends BaseResourceTable<T>
} }
String nextPath = nextSpDef.getPath(); String nextPath = nextSpDef.getPath();
boolean multiType = false;
if (nextPath.endsWith("[x]")) {
multiType = true;
}
List<Object> values = t.getValues(theResource, nextPath); List<Object> values = t.getValues(theResource, nextPath);
for (Object nextObject : values) { for (Object nextObject : values) {
ResourceIndexedSearchParamToken nextEntity; ResourceIndexedSearchParamToken nextEntity;
@ -309,15 +643,19 @@ public class FhirResourceDao<T extends IResource, X extends BaseResourceTable<T>
continue; continue;
} }
nextEntity = new ResourceIndexedSearchParamToken(nextSpDef.getName(), nextCoding.getSystem().getValueAsString(), nextCoding.getCode().getValue()); nextEntity = new ResourceIndexedSearchParamToken(nextSpDef.getName(), nextCoding.getSystem().getValueAsString(), nextCoding.getCode().getValue());
nextEntity.setResource(theEntity); nextEntity.setResource(theEntity, def.getName());
retVal.add(nextEntity); retVal.add(nextEntity);
} }
nextEntity = null; nextEntity = null;
} else { } else {
throw new ConfigurationException("Search param " + nextSpDef.getName() + " is of unexpected datatype: " + nextObject.getClass()); if (!multiType) {
throw new ConfigurationException("Search param " + nextSpDef.getName() + " is of unexpected datatype: " + nextObject.getClass());
} else {
continue;
}
} }
if (nextEntity != null) { if (nextEntity != null) {
nextEntity.setResource(theEntity); nextEntity.setResource(theEntity, def.getName());
retVal.add(nextEntity); retVal.add(nextEntity);
} }
} }
@ -326,31 +664,44 @@ public class FhirResourceDao<T extends IResource, X extends BaseResourceTable<T>
return retVal; return retVal;
} }
@Transactional(propagation = Propagation.REQUIRED) private List<ResourceIndexedSearchParamDate> extractSearchParamDates(X theEntity, T theResource) {
@Override ArrayList<ResourceIndexedSearchParamDate> retVal = new ArrayList<ResourceIndexedSearchParamDate>();
public List<T> history(IdDt theId) {
ArrayList<T> retVal = new ArrayList<T>();
String resourceType = myCtx.getResourceDefinition(myResourceType).getName(); RuntimeResourceDefinition def = myCtx.getResourceDefinition(theResource);
TypedQuery<ResourceHistoryTable> q = myEntityManager.createQuery(ResourceHistoryTable.Q_GETALL, ResourceHistoryTable.class); FhirTerser t = myCtx.newTerser();
q.setParameter("PID", theId.asLong()); for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
q.setParameter("RESTYPE", resourceType); if (nextSpDef.getParamType() != SearchParamTypeEnum.DATE) {
continue;
}
// TypedQuery<ResourceHistoryTable> query = String nextPath = nextSpDef.getPath();
// myEntityManager.createQuery(criteriaQuery);
List<ResourceHistoryTable> results = q.getResultList();
for (ResourceHistoryTable next : results) {
retVal.add(toResource(next));
}
try { boolean multiType = false;
retVal.add(read(theId)); if (nextPath.endsWith("[x]")) {
} catch (ResourceNotFoundException e) { multiType = true;
// ignore }
}
if (retVal.isEmpty()) { List<Object> values = t.getValues(theResource, nextPath);
throw new ResourceNotFoundException(theId); for (Object nextObject : values) {
ResourceIndexedSearchParamDate nextEntity;
if (nextObject instanceof BaseDateTimeDt) {
BaseDateTimeDt nextValue = (BaseDateTimeDt) nextObject;
if (nextValue.isEmpty()) {
continue;
}
nextEntity = new ResourceIndexedSearchParamDate(nextSpDef.getName(), nextValue.getValue(), nextValue.getValue());
} else {
if (!multiType) {
throw new ConfigurationException("Search param " + nextSpDef.getName() + " is of unexpected datatype: " + nextObject.getClass());
} else {
continue;
}
}
if (nextEntity != null) {
nextEntity.setResource(theEntity, def.getName());
retVal.add(nextEntity);
}
}
} }
return retVal; return retVal;
@ -369,21 +720,6 @@ public class FhirResourceDao<T extends IResource, X extends BaseResourceTable<T>
} }
@PostConstruct
public void postConstruct() throws Exception {
myResourceType = myTableType.newInstance().getResourceType();
myCtx = new FhirContext(myResourceType);
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
public T read(IdDt theId) {
X entity = readEntity(theId);
T retVal = toResource(entity);
return retVal;
}
private X readEntity(IdDt theId) { private X readEntity(IdDt theId) {
X entity = (X) myEntityManager.find(myTableType, theId.asLong()); X entity = (X) myEntityManager.find(myTableType, theId.asLong());
if (entity == null) { if (entity == null) {
@ -392,81 +728,6 @@ public class FhirResourceDao<T extends IResource, X extends BaseResourceTable<T>
return entity; return entity;
} }
@Override
public List<T> search(Map<String, IQueryParameterType> theParams) {
Map<String, List<List<IQueryParameterType>>> map = new HashMap<String, List<List<IQueryParameterType>>>();
for (Entry<String, IQueryParameterType> nextEntry : theParams.entrySet()) {
map.put(nextEntry.getKey(), new ArrayList<List<IQueryParameterType>>());
map.get(nextEntry.getKey()).add(Collections.singletonList(nextEntry.getValue()));
}
return searchWithAndOr(map);
}
@Override
public List<T> search(String theSpName, IQueryParameterType theValue) {
return search(Collections.singletonMap(theSpName, theValue));
}
@Override
public List<T> searchWithAndOr(Map<String, List<List<IQueryParameterType>>> theParams) {
Map<String, List<List<IQueryParameterType>>> params = theParams;
if (params == null) {
params = Collections.emptyMap();
}
RuntimeResourceDefinition resourceDef = myCtx.getResourceDefinition(myResourceType);
Set<Long> pids = new HashSet<Long>();
for (Entry<String, List<List<IQueryParameterType>>> nextParamEntry : params.entrySet()) {
String nextParamName = nextParamEntry.getKey();
RuntimeSearchParam nextParamDef = resourceDef.getSearchParam(nextParamName);
if (nextParamDef != null) {
if (nextParamDef.getParamType() == SearchParamTypeEnum.TOKEN) {
for (List<IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
pids = addTokenPredicate(pids, nextAnd);
if (pids.isEmpty()) {
return new ArrayList<T>();
}
}
} else if (nextParamDef.getParamType() == SearchParamTypeEnum.STRING) {
for (List<IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
pids = addStringPredicate(pids, nextAnd);
if (pids.isEmpty()) {
return new ArrayList<T>();
}
}
} else if (nextParamDef.getParamType() == SearchParamTypeEnum.QUANTITY) {
for (List<IQueryParameterType> nextAnd : nextParamEntry.getValue()) {
pids = addStringPredicate(pids, nextAnd);
if (pids.isEmpty()) {
return new ArrayList<T>();
}
}
}
}
}
// Execute the query and make sure we return distinct results
{
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<X> cq = builder.createQuery(myTableType);
cq.from(myTableType);
TypedQuery<X> q = myEntityManager.createQuery(cq);
List<T> retVal = new ArrayList<>();
for (X next : q.getResultList()) {
T resource = toResource(next);
retVal.add(resource);
}
return retVal;
}
}
@Required
public void setTableType(Class<X> theTableType) {
myTableType = theTableType;
}
private X toEntity(T theResource) { private X toEntity(T theResource) {
X retVal; X retVal;
try { try {
@ -505,26 +766,4 @@ public class FhirResourceDao<T extends IResource, X extends BaseResourceTable<T>
return retVal; return retVal;
} }
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public MethodOutcome update(final T theResource, final IdDt theId) {
TransactionTemplate template = new TransactionTemplate(myPlatformTransactionManager);
X savedEntity = template.execute(new TransactionCallback<X>() {
@Override
public X doInTransaction(TransactionStatus theStatus) {
final X entity = readEntity(theId);
final ResourceHistoryTable existing = entity.toHistory(myCtx);
populateResourceIntoEntity(theResource, entity);
myEntityManager.persist(existing);
entity.setUpdated(new Date());
myEntityManager.persist(entity);
return entity;
}
});
return toMethodOutcome(savedEntity);
}
} }

View File

@ -9,7 +9,7 @@ import javax.persistence.Id;
import javax.persistence.MappedSuperclass; import javax.persistence.MappedSuperclass;
@MappedSuperclass @MappedSuperclass
public abstract class BaseResourceIndexedSearchParam<T> implements Serializable { public abstract class BaseResourceIndexedSearchParam implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -21,6 +21,9 @@ public abstract class BaseResourceIndexedSearchParam<T> implements Serializable
@Column(name="SP_NAME", length=100) @Column(name="SP_NAME", length=100)
private String myName; private String myName;
@Column(name = "RES_TYPE",length=100,nullable=false)
private String myResourceType;
public String getName() { public String getName() {
return myName; return myName;
} }
@ -31,11 +34,21 @@ public abstract class BaseResourceIndexedSearchParam<T> implements Serializable
public abstract BaseResourceTable<?> getResource(); public abstract BaseResourceTable<?> getResource();
public abstract void setResource(BaseResourceTable<?> theResource); protected abstract void setResource(BaseResourceTable<?> theResource);
public abstract T getValue(); public void setResource(BaseResourceTable<?> theResource, String theResourceType) {
setResource(theResource);
setResourceType(theResourceType);
}
public String getResourceType() {
return myResourceType;
}
public void setResourceType(String theResourceType) {
myResourceType = theResourceType;
}
public abstract void setValue(T theValue);
} }

View File

@ -0,0 +1,17 @@
package ca.uhn.fhir.jpa.entity;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import ca.uhn.fhir.model.dstu.resource.Observation;
@Entity
@DiscriminatorValue("OBSERVATION")
public class ObservationResourceTable extends BaseResourceTable<Observation> {
@Override
public Class<Observation> getResourceType() {
return Observation.class;
}
}

View File

@ -12,32 +12,53 @@ import javax.persistence.TemporalType;
@Entity @Entity
@Table(name = "IDX_SP_DATE") @Table(name = "IDX_SP_DATE")
public class ResourceIndexedSearchParamDate extends BaseResourceIndexedSearchParam<Date> { public class ResourceIndexedSearchParamDate extends BaseResourceIndexedSearchParam {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Column(name = "SP_VALUE_HIGH", nullable = true)
@Temporal(TemporalType.TIMESTAMP)
public Date myValueHigh;
@Column(name = "SP_VALUE_LOW", nullable = true)
@Temporal(TemporalType.TIMESTAMP)
public Date myValueLow;
@ManyToOne(optional = false) @ManyToOne(optional = false)
@JoinColumn(name = "RESOURCE_PID", nullable = false) @JoinColumn(name = "RESOURCE_PID", nullable = false)
private BaseResourceTable<?> myResource; private BaseResourceTable<?> myResource;
@Column(name = "SP_VALUE", nullable = true) @Column(name = "RESOURCE_PID", insertable = false, updatable = false)
@Temporal(TemporalType.TIMESTAMP) private Long myResourcePid;
public Date myValue;
public ResourceIndexedSearchParamDate(String theName, Date theLow, Date theHigh) {
setName(theName);
setValueLow(theLow);
setValueHigh(theHigh);
}
public BaseResourceTable<?> getResource() { public BaseResourceTable<?> getResource() {
return myResource; return myResource;
} }
public Date getValue() { public Date getValueHigh() {
return myValue; return myValueHigh;
} }
public void setResource(BaseResourceTable<?> theResource) { public Date getValueLow() {
return myValueLow;
}
public void setValueHigh(Date theValueHigh) {
myValueHigh = theValueHigh;
}
public void setValueLow(Date theValueLow) {
myValueLow = theValueLow;
}
protected void setResource(BaseResourceTable<?> theResource) {
myResource = theResource; myResource = theResource;
} }
public void setValue(Date theValue) {
myValue = theValue;
}
} }

View File

@ -0,0 +1,72 @@
package ca.uhn.fhir.jpa.entity;
import java.math.BigDecimal;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name = "IDX_SP_NUMBER")
public class ResourceIndexedSearchParamNumber extends BaseResourceIndexedSearchParam {
private static final long serialVersionUID = 1L;
@Column(name = "SP_SYSTEM", nullable = true, length = 100)
public String mySystem;
@Column(name = "SP_UNITS", nullable = true, length = 100)
public String myUnits;
@Column(name = "SP_VALUE", nullable = true)
public BigDecimal myValue;
@ManyToOne(optional = false)
@JoinColumn(name = "RESOURCE_PID", nullable = false)
private BaseResourceTable<?> myResource;
@Column(name = "RESOURCE_PID", insertable = false, updatable = false)
private Long myResourcePid;
public ResourceIndexedSearchParamNumber(String theParamName, BigDecimal theValue, String theSystem, String theUnits) {
setName(theParamName);
setSystem(theSystem);
setValue(theValue);
setUnits(theUnits);
}
public BaseResourceTable<?> getResource() {
return myResource;
}
public String getSystem() {
return mySystem;
}
public String getUnits() {
return myUnits;
}
public BigDecimal getValue() {
return myValue;
}
protected void setResource(BaseResourceTable<?> theResource) {
myResource = theResource;
}
public void setSystem(String theSystem) {
mySystem = theSystem;
}
public void setUnits(String theUnits) {
myUnits = theUnits;
}
public void setValue(BigDecimal theValue) {
myValue = theValue;
}
}

View File

@ -9,7 +9,7 @@ import javax.persistence.Table;
@Entity @Entity
@Table(name = "IDX_SP_STRING") @Table(name = "IDX_SP_STRING")
public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchParam<String> { public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchParam {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -17,6 +17,9 @@ public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchP
@JoinColumn(name = "RESOURCE_PID", nullable = false) @JoinColumn(name = "RESOURCE_PID", nullable = false)
private BaseResourceTable<?> myResource; private BaseResourceTable<?> myResource;
@Column(name = "RESOURCE_PID", insertable=false, updatable=false)
private Long myResourcePid;
@Column(name = "SP_VALUE", length = 100, nullable = true) @Column(name = "SP_VALUE", length = 100, nullable = true)
public String myValue; public String myValue;
@ -36,7 +39,7 @@ public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchP
return myValue; return myValue;
} }
public void setResource(BaseResourceTable<?> theResource) { protected void setResource(BaseResourceTable<?> theResource) {
myResource = theResource; myResource = theResource;
} }

View File

@ -8,7 +8,7 @@ import javax.persistence.Table;
@Entity @Entity
@Table(name = "IDX_SP_TOKEN") @Table(name = "IDX_SP_TOKEN")
public class ResourceIndexedSearchParamToken extends BaseResourceIndexedSearchParam<String> { public class ResourceIndexedSearchParamToken extends BaseResourceIndexedSearchParam {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -47,7 +47,7 @@ public class ResourceIndexedSearchParamToken extends BaseResourceIndexedSearchPa
return myValue; return myValue;
} }
public void setResource(BaseResourceTable<?> theResource) { protected void setResource(BaseResourceTable<?> theResource) {
myResource = theResource; myResource = theResource;
} }

View File

@ -0,0 +1,82 @@
package ca.uhn.fhir.jpa.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.ForeignKey;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name = "RES_LINK")
public class ResourceLink implements Serializable {
private static final long serialVersionUID = 1L;
@GeneratedValue(strategy = GenerationType.AUTO)
@Id
private Long myId;
@Column(name = "SRC_PATH", length = 100, nullable = false)
private String mySourcePath;
@ManyToOne(optional = false)
@JoinColumn(name = "SRC_RESOURCE_PID", nullable = false, foreignKey = @ForeignKey(name = "FK_RES_LINK_SRC_RES"))
private BaseResourceTable<?> mySourceResource;
@Column(name = "SRC_RESOURCE_PID", insertable = false, updatable = false)
private Long mySourceResourcePid;
@ManyToOne(optional = false)
@JoinColumn(name = "TARGET_RESOURCE_PID", nullable = false, foreignKey = @ForeignKey(name = "FK_RES_LINK_TARGET_RES"))
private BaseResourceTable<?> myTargetResource;
@Column(name = "TARGET_RESOURCE_PID", insertable = false, updatable = false)
private Long myTargetResourcePid;
public String getSourcePath() {
return mySourcePath;
}
public BaseResourceTable<?> getSourceResource() {
return mySourceResource;
}
public Long getSourceResourcePid() {
return mySourceResourcePid;
}
public BaseResourceTable<?> getTargetResource() {
return myTargetResource;
}
public Long getTargetResourcePid() {
return myTargetResourcePid;
}
public void setSourcePath(String theSourcePath) {
mySourcePath = theSourcePath;
}
public void setSourceResource(BaseResourceTable<?> theSourceResource) {
mySourceResource = theSourceResource;
}
public void setSourceResourcePid(Long theSourceResourcePid) {
mySourceResourcePid = theSourceResourcePid;
}
public void setTargetResource(BaseResourceTable<?> theTargetResource) {
myTargetResource = theTargetResource;
}
public void setTargetResourcePid(Long theTargetResourcePid) {
myTargetResourcePid = theTargetResourcePid;
}
}

View File

@ -1,6 +1,5 @@
package ca.uhn.fhir.jpa.entity; package ca.uhn.fhir.jpa.entity;
import javax.annotation.Generated;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType; import javax.persistence.GenerationType;

View File

@ -21,16 +21,22 @@ import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.dstu.composite.IdentifierDt; import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu.composite.QuantityDt;
import ca.uhn.fhir.model.dstu.resource.Observation;
import ca.uhn.fhir.model.dstu.resource.Patient; import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.model.dstu.valueset.AdministrativeGenderCodesEnum; import ca.uhn.fhir.model.dstu.valueset.AdministrativeGenderCodesEnum;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.StringDt; import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.param.QualifiedDateParam;
public class FhirResourceDaoTest { public class FhirResourceDaoTest {
private static ClassPathXmlApplicationContext ourCtx; private static ClassPathXmlApplicationContext ourCtx;
private static IFhirResourceDao<Patient> ourPatientDao; private static IFhirResourceDao<Patient> ourPatientDao;
private static IFhirResourceDao<Observation> ourObservationDao;
private static Date ourTestStarted; private static Date ourTestStarted;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -39,6 +45,7 @@ public class FhirResourceDaoTest {
ourTestStarted = new Date(); ourTestStarted = new Date();
ourCtx = new ClassPathXmlApplicationContext("fhir-spring-test-config.xml"); ourCtx = new ClassPathXmlApplicationContext("fhir-spring-test-config.xml");
ourPatientDao = ourCtx.getBean("myPatientDao", IFhirResourceDao.class); ourPatientDao = ourCtx.getBean("myPatientDao", IFhirResourceDao.class);
ourObservationDao = ourCtx.getBean("myObservationDao", IFhirResourceDao.class);
} }
@AfterClass @AfterClass
@ -65,6 +72,53 @@ public class FhirResourceDaoTest {
assertTrue(updated.before(now)); assertTrue(updated.before(now));
} }
@Test
public void testPersistSearchParamObservationString() {
Observation obs = new Observation();
obs.getName().addCoding().setSystem("foo").setCode("testPersistSearchParamQuantity");
obs.setValue(new StringDt("AAAABBBB"));
ourObservationDao.create(obs);
List<Observation> found = ourObservationDao.search("value-string", new StringDt("AAAABBBB"));
assertEquals(1,found.size());
found = ourObservationDao.search("value-string", new StringDt("AAAABBBBCCC"));
assertEquals(0,found.size());
}
@Test
public void testPersistSearchParamQuantity() {
Observation obs = new Observation();
obs.getName().addCoding().setSystem("foo").setCode("testPersistSearchParamQuantity");
obs.setValue(new QuantityDt(111));
ourObservationDao.create(obs);
List<Observation> found = ourObservationDao.search("value-quantity", new QuantityDt(111));
assertEquals(1,found.size());
found = ourObservationDao.search("value-quantity", new QuantityDt(112));
assertEquals(0,found.size());
}
@Test
public void testPersistSearchParamDate() {
Patient patient = new Patient();
patient.addIdentifier("urn:system", "001");
patient.setBirthDate(new DateTimeDt("2001-01-01"));
ourPatientDao.create(patient);
List<Patient> found = ourPatientDao.search("birthdate", new QualifiedDateParam(QuantityCompararatorEnum.GREATERTHAN, "2000-01-01"));
assertEquals(1,found.size());
}
@Test @Test
public void testPersistSearchParams() { public void testPersistSearchParams() {
Patient patient = new Patient(); Patient patient = new Patient();

View File

@ -17,6 +17,10 @@
<property name="tableType" value="ca.uhn.fhir.jpa.entity.PatientResourceTable"/> <property name="tableType" value="ca.uhn.fhir.jpa.entity.PatientResourceTable"/>
</bean> </bean>
<bean id="myObservationDao" class="ca.uhn.fhir.jpa.dao.FhirResourceDao">
<property name="tableType" value="ca.uhn.fhir.jpa.entity.ObservationResourceTable"/>
</bean>
<bean id="myPersistenceDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" lazy-init="true"> <bean id="myPersistenceDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" lazy-init="true">
<property name="url" value="jdbc:derby:memory:myUnitTestDB;create=true" /> <property name="url" value="jdbc:derby:memory:myUnitTestDB;create=true" />
</bean> </bean>