From 92c2aa7cfbe4cfd0aafc8ef8caf0b96386d52423 Mon Sep 17 00:00:00 2001 From: "Dr. Christoph \"Schorsch\" Jung" Date: Wed, 27 Sep 2023 15:59:12 +0200 Subject: [PATCH 1/7] style: add tractusx settings for various editors/tools. --- .editorconfig | 1168 ++++++++++++++++++++++++++++ resources/tx-checkstyle-config.xml | 436 +++++++++++ resources/tx-codestyle.xml | 337 ++++++++ 3 files changed, 1941 insertions(+) create mode 100644 .editorconfig create mode 100644 resources/tx-checkstyle-config.xml create mode 100644 resources/tx-codestyle.xml diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..9654ee2 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,1168 @@ +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = false +max_line_length = 120 +tab_width = 4 +ij_continuation_indent_size = 8 +ij_formatter_off_tag = @formatter:off +ij_formatter_on_tag = @formatter:on +ij_formatter_tags_enabled = false +ij_smart_tabs = false +ij_visual_guides = none +ij_wrap_on_typing = false + +[*.css] +ij_css_align_closing_brace_with_properties = false +ij_css_blank_lines_around_nested_selector = 1 +ij_css_blank_lines_between_blocks = 1 +ij_css_block_comment_add_space = false +ij_css_brace_placement = end_of_line +ij_css_enforce_quotes_on_format = false +ij_css_hex_color_long_format = false +ij_css_hex_color_lower_case = false +ij_css_hex_color_short_format = false +ij_css_hex_color_upper_case = false +ij_css_keep_blank_lines_in_code = 2 +ij_css_keep_indents_on_empty_lines = false +ij_css_keep_single_line_blocks = false +ij_css_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_css_space_after_colon = true +ij_css_space_before_opening_brace = true +ij_css_use_double_quotes = true +ij_css_value_alignment = do_not_align + +[*.feature] +indent_size = 2 +ij_gherkin_keep_indents_on_empty_lines = false + +[*.gsp] +ij_gsp_keep_indents_on_empty_lines = false + +[*.haml] +indent_size = 2 +ij_haml_keep_indents_on_empty_lines = false + +[*.java] +ij_java_align_consecutive_assignments = false +ij_java_align_consecutive_variable_declarations = false +ij_java_align_group_field_declarations = false +ij_java_align_multiline_annotation_parameters = false +ij_java_align_multiline_array_initializer_expression = false +ij_java_align_multiline_assignment = false +ij_java_align_multiline_binary_operation = false +ij_java_align_multiline_chained_methods = false +ij_java_align_multiline_extends_list = false +ij_java_align_multiline_for = true +ij_java_align_multiline_method_parentheses = false +ij_java_align_multiline_parameters = true +ij_java_align_multiline_parameters_in_calls = false +ij_java_align_multiline_parenthesized_expression = false +ij_java_align_multiline_records = true +ij_java_align_multiline_resources = true +ij_java_align_multiline_ternary_operation = false +ij_java_align_multiline_text_blocks = false +ij_java_align_multiline_throws_list = false +ij_java_align_subsequent_simple_methods = false +ij_java_align_throws_keyword = false +ij_java_annotation_parameter_wrap = off +ij_java_array_initializer_new_line_after_left_brace = false +ij_java_array_initializer_right_brace_on_new_line = false +ij_java_array_initializer_wrap = off +ij_java_assert_statement_colon_on_next_line = false +ij_java_assert_statement_wrap = off +ij_java_assignment_wrap = off +ij_java_binary_operation_sign_on_next_line = false +ij_java_binary_operation_wrap = off +ij_java_blank_lines_after_anonymous_class_header = 0 +ij_java_blank_lines_after_class_header = 0 +ij_java_blank_lines_after_imports = 1 +ij_java_blank_lines_after_package = 1 +ij_java_blank_lines_around_class = 1 +ij_java_blank_lines_around_field = 0 +ij_java_blank_lines_around_field_in_interface = 0 +ij_java_blank_lines_around_initializer = 1 +ij_java_blank_lines_around_method = 1 +ij_java_blank_lines_around_method_in_interface = 1 +ij_java_blank_lines_before_class_end = 0 +ij_java_blank_lines_before_imports = 1 +ij_java_blank_lines_before_method_body = 0 +ij_java_blank_lines_before_package = 0 +ij_java_block_brace_style = end_of_line +ij_java_block_comment_add_space = false +ij_java_block_comment_at_first_column = true +ij_java_builder_methods = none +ij_java_call_parameters_new_line_after_left_paren = false +ij_java_call_parameters_right_paren_on_new_line = false +ij_java_call_parameters_wrap = off +ij_java_case_statement_on_separate_line = true +ij_java_catch_on_new_line = false +ij_java_class_annotation_wrap = split_into_lines +ij_java_class_brace_style = end_of_line +ij_java_class_count_to_use_import_on_demand = 99 +ij_java_class_names_in_javadoc = 1 +ij_java_do_not_indent_top_level_class_members = false +ij_java_do_not_wrap_after_single_annotation = false +ij_java_do_while_brace_force = never +ij_java_doc_add_blank_line_after_description = true +ij_java_doc_add_blank_line_after_param_comments = false +ij_java_doc_add_blank_line_after_return = false +ij_java_doc_add_p_tag_on_empty_lines = true +ij_java_doc_align_exception_comments = true +ij_java_doc_align_param_comments = true +ij_java_doc_do_not_wrap_if_one_line = false +ij_java_doc_enable_formatting = true +ij_java_doc_enable_leading_asterisks = true +ij_java_doc_indent_on_continuation = false +ij_java_doc_keep_empty_lines = true +ij_java_doc_keep_empty_parameter_tag = true +ij_java_doc_keep_empty_return_tag = true +ij_java_doc_keep_empty_throws_tag = true +ij_java_doc_keep_invalid_tags = true +ij_java_doc_param_description_on_new_line = false +ij_java_doc_preserve_line_breaks = false +ij_java_doc_use_throws_not_exception_tag = true +ij_java_else_on_new_line = false +ij_java_entity_dd_suffix = EJB +ij_java_entity_eb_suffix = Bean +ij_java_entity_hi_suffix = Home +ij_java_entity_lhi_prefix = Local +ij_java_entity_lhi_suffix = Home +ij_java_entity_li_prefix = Local +ij_java_entity_pk_class = java.lang.String +ij_java_entity_vo_suffix = VO +ij_java_enum_constants_wrap = off +ij_java_extends_keyword_wrap = off +ij_java_extends_list_wrap = off +ij_java_field_annotation_wrap = split_into_lines +ij_java_finally_on_new_line = false +ij_java_for_brace_force = never +ij_java_for_statement_new_line_after_left_paren = false +ij_java_for_statement_right_paren_on_new_line = false +ij_java_for_statement_wrap = off +ij_java_generate_final_locals = false +ij_java_generate_final_parameters = false +ij_java_if_brace_force = never +ij_java_imports_layout = *,|,java.**,javax.**,|,$* +ij_java_indent_case_from_switch = true +ij_java_insert_inner_class_imports = false +ij_java_insert_override_annotation = true +ij_java_keep_blank_lines_before_right_brace = 2 +ij_java_keep_blank_lines_between_package_declaration_and_header = 2 +ij_java_keep_blank_lines_in_code = 2 +ij_java_keep_blank_lines_in_declarations = 2 +ij_java_keep_builder_methods_indents = false +ij_java_keep_control_statement_in_one_line = true +ij_java_keep_first_column_comment = false +ij_java_keep_indents_on_empty_lines = false +ij_java_keep_line_breaks = true +ij_java_keep_multiple_expressions_in_one_line = false +ij_java_keep_simple_blocks_in_one_line = false +ij_java_keep_simple_classes_in_one_line = false +ij_java_keep_simple_lambdas_in_one_line = false +ij_java_keep_simple_methods_in_one_line = false +ij_java_label_indent_absolute = false +ij_java_label_indent_size = 0 +ij_java_lambda_brace_style = end_of_line +ij_java_layout_static_imports_separately = true +ij_java_line_comment_add_space = true +ij_java_line_comment_at_first_column = false +ij_java_message_dd_suffix = EJB +ij_java_message_eb_suffix = Bean +ij_java_method_annotation_wrap = split_into_lines +ij_java_method_brace_style = end_of_line +ij_java_method_call_chain_wrap = off +ij_java_method_parameters_new_line_after_left_paren = false +ij_java_method_parameters_right_paren_on_new_line = false +ij_java_method_parameters_wrap = off +ij_java_modifier_list_wrap = false +ij_java_names_count_to_use_import_on_demand = 99 +ij_java_new_line_after_lparen_in_record_header = false +ij_java_packages_to_use_import_on_demand = java.awt.*,javax.swing.* +ij_java_parameter_annotation_wrap = off +ij_java_parentheses_expression_new_line_after_left_paren = false +ij_java_parentheses_expression_right_paren_on_new_line = false +ij_java_place_assignment_sign_on_next_line = false +ij_java_prefer_longer_names = true +ij_java_prefer_parameters_wrap = false +ij_java_record_components_wrap = normal +ij_java_repeat_synchronized = true +ij_java_replace_instanceof_and_cast = false +ij_java_replace_null_check = true +ij_java_replace_sum_lambda_with_method_ref = true +ij_java_resource_list_new_line_after_left_paren = false +ij_java_resource_list_right_paren_on_new_line = false +ij_java_resource_list_wrap = off +ij_java_rparen_on_new_line_in_record_header = false +ij_java_session_dd_suffix = EJB +ij_java_session_eb_suffix = Bean +ij_java_session_hi_suffix = Home +ij_java_session_lhi_prefix = Local +ij_java_session_lhi_suffix = Home +ij_java_session_li_prefix = Local +ij_java_session_si_suffix = Service +ij_java_space_after_closing_angle_bracket_in_type_argument = false +ij_java_space_after_colon = true +ij_java_space_after_comma = true +ij_java_space_after_comma_in_type_arguments = true +ij_java_space_after_for_semicolon = true +ij_java_space_after_quest = true +ij_java_space_after_type_cast = true +ij_java_space_before_annotation_array_initializer_left_brace = false +ij_java_space_before_annotation_parameter_list = false +ij_java_space_before_array_initializer_left_brace = false +ij_java_space_before_catch_keyword = true +ij_java_space_before_catch_left_brace = true +ij_java_space_before_catch_parentheses = true +ij_java_space_before_class_left_brace = true +ij_java_space_before_colon = true +ij_java_space_before_colon_in_foreach = true +ij_java_space_before_comma = false +ij_java_space_before_do_left_brace = true +ij_java_space_before_else_keyword = true +ij_java_space_before_else_left_brace = true +ij_java_space_before_finally_keyword = true +ij_java_space_before_finally_left_brace = true +ij_java_space_before_for_left_brace = true +ij_java_space_before_for_parentheses = true +ij_java_space_before_for_semicolon = false +ij_java_space_before_if_left_brace = true +ij_java_space_before_if_parentheses = true +ij_java_space_before_method_call_parentheses = false +ij_java_space_before_method_left_brace = true +ij_java_space_before_method_parentheses = false +ij_java_space_before_opening_angle_bracket_in_type_parameter = false +ij_java_space_before_quest = true +ij_java_space_before_switch_left_brace = true +ij_java_space_before_switch_parentheses = true +ij_java_space_before_synchronized_left_brace = true +ij_java_space_before_synchronized_parentheses = true +ij_java_space_before_try_left_brace = true +ij_java_space_before_try_parentheses = true +ij_java_space_before_type_parameter_list = false +ij_java_space_before_while_keyword = true +ij_java_space_before_while_left_brace = true +ij_java_space_before_while_parentheses = true +ij_java_space_inside_one_line_enum_braces = false +ij_java_space_within_empty_array_initializer_braces = false +ij_java_space_within_empty_method_call_parentheses = false +ij_java_space_within_empty_method_parentheses = false +ij_java_spaces_around_additive_operators = true +ij_java_spaces_around_assignment_operators = true +ij_java_spaces_around_bitwise_operators = true +ij_java_spaces_around_equality_operators = true +ij_java_spaces_around_lambda_arrow = true +ij_java_spaces_around_logical_operators = true +ij_java_spaces_around_method_ref_dbl_colon = false +ij_java_spaces_around_multiplicative_operators = true +ij_java_spaces_around_relational_operators = true +ij_java_spaces_around_shift_operators = true +ij_java_spaces_around_type_bounds_in_type_parameters = true +ij_java_spaces_around_unary_operator = false +ij_java_spaces_within_angle_brackets = false +ij_java_spaces_within_annotation_parentheses = false +ij_java_spaces_within_array_initializer_braces = true +ij_java_spaces_within_braces = false +ij_java_spaces_within_brackets = false +ij_java_spaces_within_cast_parentheses = false +ij_java_spaces_within_catch_parentheses = false +ij_java_spaces_within_for_parentheses = false +ij_java_spaces_within_if_parentheses = false +ij_java_spaces_within_method_call_parentheses = false +ij_java_spaces_within_method_parentheses = false +ij_java_spaces_within_parentheses = false +ij_java_spaces_within_record_header = false +ij_java_spaces_within_switch_parentheses = false +ij_java_spaces_within_synchronized_parentheses = false +ij_java_spaces_within_try_parentheses = false +ij_java_spaces_within_while_parentheses = false +ij_java_special_else_if_treatment = true +ij_java_subclass_name_suffix = Impl +ij_java_ternary_operation_signs_on_next_line = false +ij_java_ternary_operation_wrap = off +ij_java_test_name_suffix = Test +ij_java_throws_keyword_wrap = off +ij_java_throws_list_wrap = off +ij_java_use_external_annotations = false +ij_java_use_fq_class_names = false +ij_java_use_relative_indents = false +ij_java_use_single_class_imports = true +ij_java_variable_annotation_wrap = off +ij_java_visibility = public +ij_java_while_brace_force = never +ij_java_while_on_new_line = false +ij_java_wrap_comments = false +ij_java_wrap_first_method_in_call_chain = false +ij_java_wrap_long_lines = false + +[*.less] +indent_size = 2 +ij_less_align_closing_brace_with_properties = false +ij_less_blank_lines_around_nested_selector = 1 +ij_less_blank_lines_between_blocks = 1 +ij_less_block_comment_add_space = false +ij_less_brace_placement = 0 +ij_less_enforce_quotes_on_format = false +ij_less_hex_color_long_format = false +ij_less_hex_color_lower_case = false +ij_less_hex_color_short_format = false +ij_less_hex_color_upper_case = false +ij_less_keep_blank_lines_in_code = 2 +ij_less_keep_indents_on_empty_lines = false +ij_less_keep_single_line_blocks = false +ij_less_line_comment_add_space = false +ij_less_line_comment_at_first_column = false +ij_less_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_less_space_after_colon = true +ij_less_space_before_opening_brace = true +ij_less_use_double_quotes = true +ij_less_value_alignment = 0 + +[*.proto] +indent_size = 2 +tab_width = 2 +ij_continuation_indent_size = 4 +ij_protobuf_keep_blank_lines_in_code = 2 +ij_protobuf_keep_indents_on_empty_lines = false +ij_protobuf_keep_line_breaks = true +ij_protobuf_space_after_comma = true +ij_protobuf_space_before_comma = false +ij_protobuf_spaces_around_assignment_operators = true +ij_protobuf_spaces_within_braces = false +ij_protobuf_spaces_within_brackets = false + +[*.sass] +indent_size = 2 +ij_sass_align_closing_brace_with_properties = false +ij_sass_blank_lines_around_nested_selector = 1 +ij_sass_blank_lines_between_blocks = 1 +ij_sass_brace_placement = 0 +ij_sass_enforce_quotes_on_format = false +ij_sass_hex_color_long_format = false +ij_sass_hex_color_lower_case = false +ij_sass_hex_color_short_format = false +ij_sass_hex_color_upper_case = false +ij_sass_keep_blank_lines_in_code = 2 +ij_sass_keep_indents_on_empty_lines = false +ij_sass_keep_single_line_blocks = false +ij_sass_line_comment_add_space = false +ij_sass_line_comment_at_first_column = false +ij_sass_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_sass_space_after_colon = true +ij_sass_space_before_opening_brace = true +ij_sass_use_double_quotes = true +ij_sass_value_alignment = 0 + +[*.scss] +indent_size = 2 +ij_scss_align_closing_brace_with_properties = false +ij_scss_blank_lines_around_nested_selector = 1 +ij_scss_blank_lines_between_blocks = 1 +ij_scss_block_comment_add_space = false +ij_scss_brace_placement = 0 +ij_scss_enforce_quotes_on_format = false +ij_scss_hex_color_long_format = false +ij_scss_hex_color_lower_case = false +ij_scss_hex_color_short_format = false +ij_scss_hex_color_upper_case = false +ij_scss_keep_blank_lines_in_code = 2 +ij_scss_keep_indents_on_empty_lines = false +ij_scss_keep_single_line_blocks = false +ij_scss_line_comment_add_space = false +ij_scss_line_comment_at_first_column = false +ij_scss_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_scss_space_after_colon = true +ij_scss_space_before_opening_brace = true +ij_scss_use_double_quotes = true +ij_scss_value_alignment = 0 + +[*.styl] +indent_size = 2 +ij_stylus_align_closing_brace_with_properties = false +ij_stylus_blank_lines_around_nested_selector = 1 +ij_stylus_blank_lines_between_blocks = 1 +ij_stylus_brace_placement = 0 +ij_stylus_enforce_quotes_on_format = false +ij_stylus_hex_color_long_format = false +ij_stylus_hex_color_lower_case = false +ij_stylus_hex_color_short_format = false +ij_stylus_hex_color_upper_case = false +ij_stylus_keep_blank_lines_in_code = 2 +ij_stylus_keep_indents_on_empty_lines = false +ij_stylus_keep_single_line_blocks = false +ij_stylus_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_stylus_space_after_colon = true +ij_stylus_space_before_opening_brace = true +ij_stylus_use_double_quotes = true +ij_stylus_value_alignment = 0 + +[.editorconfig] +ij_editorconfig_align_group_field_declarations = false +ij_editorconfig_space_after_colon = false +ij_editorconfig_space_after_comma = true +ij_editorconfig_space_before_colon = false +ij_editorconfig_space_before_comma = false +ij_editorconfig_spaces_around_assignment_operators = true + +[{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.pom,*.rng,*.tld,*.wadl,*.wsdd,*.wsdl,*.xjb,*.xml,*.xsd,*.xsl,*.xslt,*.xul}] +ij_xml_align_attributes = true +ij_xml_align_text = false +ij_xml_attribute_wrap = normal +ij_xml_block_comment_add_space = false +ij_xml_block_comment_at_first_column = true +ij_xml_keep_blank_lines = 2 +ij_xml_keep_indents_on_empty_lines = false +ij_xml_keep_line_breaks = true +ij_xml_keep_line_breaks_in_text = true +ij_xml_keep_whitespaces = false +ij_xml_keep_whitespaces_around_cdata = preserve +ij_xml_keep_whitespaces_inside_cdata = false +ij_xml_line_comment_at_first_column = true +ij_xml_space_after_tag_name = false +ij_xml_space_around_equals_in_attribute = false +ij_xml_space_inside_empty_tag = false +ij_xml_text_wrap = normal +ij_xml_use_custom_settings = false + +[{*.ats,*.cts,*.mts,*.ts}] +ij_continuation_indent_size = 4 +ij_typescript_align_imports = false +ij_typescript_align_multiline_array_initializer_expression = false +ij_typescript_align_multiline_binary_operation = false +ij_typescript_align_multiline_chained_methods = false +ij_typescript_align_multiline_extends_list = false +ij_typescript_align_multiline_for = true +ij_typescript_align_multiline_parameters = true +ij_typescript_align_multiline_parameters_in_calls = false +ij_typescript_align_multiline_ternary_operation = false +ij_typescript_align_object_properties = 0 +ij_typescript_align_union_types = false +ij_typescript_align_var_statements = 0 +ij_typescript_array_initializer_new_line_after_left_brace = false +ij_typescript_array_initializer_right_brace_on_new_line = false +ij_typescript_array_initializer_wrap = off +ij_typescript_assignment_wrap = off +ij_typescript_binary_operation_sign_on_next_line = false +ij_typescript_binary_operation_wrap = off +ij_typescript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/** +ij_typescript_blank_lines_after_imports = 1 +ij_typescript_blank_lines_around_class = 1 +ij_typescript_blank_lines_around_field = 0 +ij_typescript_blank_lines_around_field_in_interface = 0 +ij_typescript_blank_lines_around_function = 1 +ij_typescript_blank_lines_around_method = 1 +ij_typescript_blank_lines_around_method_in_interface = 1 +ij_typescript_block_brace_style = end_of_line +ij_typescript_block_comment_add_space = false +ij_typescript_block_comment_at_first_column = true +ij_typescript_call_parameters_new_line_after_left_paren = false +ij_typescript_call_parameters_right_paren_on_new_line = false +ij_typescript_call_parameters_wrap = off +ij_typescript_catch_on_new_line = false +ij_typescript_chained_call_dot_on_new_line = true +ij_typescript_class_brace_style = end_of_line +ij_typescript_comma_on_new_line = false +ij_typescript_do_while_brace_force = never +ij_typescript_else_on_new_line = false +ij_typescript_enforce_trailing_comma = keep +ij_typescript_extends_keyword_wrap = off +ij_typescript_extends_list_wrap = off +ij_typescript_field_prefix = _ +ij_typescript_file_name_style = relaxed +ij_typescript_finally_on_new_line = false +ij_typescript_for_brace_force = never +ij_typescript_for_statement_new_line_after_left_paren = false +ij_typescript_for_statement_right_paren_on_new_line = false +ij_typescript_for_statement_wrap = off +ij_typescript_force_quote_style = false +ij_typescript_force_semicolon_style = false +ij_typescript_function_expression_brace_style = end_of_line +ij_typescript_if_brace_force = never +ij_typescript_import_merge_members = global +ij_typescript_import_prefer_absolute_path = global +ij_typescript_import_sort_members = true +ij_typescript_import_sort_module_name = false +ij_typescript_import_use_node_resolution = true +ij_typescript_imports_wrap = on_every_item +ij_typescript_indent_case_from_switch = true +ij_typescript_indent_chained_calls = true +ij_typescript_indent_package_children = 0 +ij_typescript_jsdoc_include_types = false +ij_typescript_jsx_attribute_value = braces +ij_typescript_keep_blank_lines_in_code = 2 +ij_typescript_keep_first_column_comment = true +ij_typescript_keep_indents_on_empty_lines = false +ij_typescript_keep_line_breaks = true +ij_typescript_keep_simple_blocks_in_one_line = false +ij_typescript_keep_simple_methods_in_one_line = false +ij_typescript_line_comment_add_space = true +ij_typescript_line_comment_at_first_column = false +ij_typescript_method_brace_style = end_of_line +ij_typescript_method_call_chain_wrap = off +ij_typescript_method_parameters_new_line_after_left_paren = false +ij_typescript_method_parameters_right_paren_on_new_line = false +ij_typescript_method_parameters_wrap = off +ij_typescript_object_literal_wrap = on_every_item +ij_typescript_parentheses_expression_new_line_after_left_paren = false +ij_typescript_parentheses_expression_right_paren_on_new_line = false +ij_typescript_place_assignment_sign_on_next_line = false +ij_typescript_prefer_as_type_cast = false +ij_typescript_prefer_explicit_types_function_expression_returns = false +ij_typescript_prefer_explicit_types_function_returns = false +ij_typescript_prefer_explicit_types_vars_fields = false +ij_typescript_prefer_parameters_wrap = false +ij_typescript_reformat_c_style_comments = false +ij_typescript_space_after_colon = true +ij_typescript_space_after_comma = true +ij_typescript_space_after_dots_in_rest_parameter = false +ij_typescript_space_after_generator_mult = true +ij_typescript_space_after_property_colon = true +ij_typescript_space_after_quest = true +ij_typescript_space_after_type_colon = true +ij_typescript_space_after_unary_not = false +ij_typescript_space_before_async_arrow_lparen = true +ij_typescript_space_before_catch_keyword = true +ij_typescript_space_before_catch_left_brace = true +ij_typescript_space_before_catch_parentheses = true +ij_typescript_space_before_class_lbrace = true +ij_typescript_space_before_class_left_brace = true +ij_typescript_space_before_colon = true +ij_typescript_space_before_comma = false +ij_typescript_space_before_do_left_brace = true +ij_typescript_space_before_else_keyword = true +ij_typescript_space_before_else_left_brace = true +ij_typescript_space_before_finally_keyword = true +ij_typescript_space_before_finally_left_brace = true +ij_typescript_space_before_for_left_brace = true +ij_typescript_space_before_for_parentheses = true +ij_typescript_space_before_for_semicolon = false +ij_typescript_space_before_function_left_parenth = true +ij_typescript_space_before_generator_mult = false +ij_typescript_space_before_if_left_brace = true +ij_typescript_space_before_if_parentheses = true +ij_typescript_space_before_method_call_parentheses = false +ij_typescript_space_before_method_left_brace = true +ij_typescript_space_before_method_parentheses = false +ij_typescript_space_before_property_colon = false +ij_typescript_space_before_quest = true +ij_typescript_space_before_switch_left_brace = true +ij_typescript_space_before_switch_parentheses = true +ij_typescript_space_before_try_left_brace = true +ij_typescript_space_before_type_colon = false +ij_typescript_space_before_unary_not = false +ij_typescript_space_before_while_keyword = true +ij_typescript_space_before_while_left_brace = true +ij_typescript_space_before_while_parentheses = true +ij_typescript_spaces_around_additive_operators = true +ij_typescript_spaces_around_arrow_function_operator = true +ij_typescript_spaces_around_assignment_operators = true +ij_typescript_spaces_around_bitwise_operators = true +ij_typescript_spaces_around_equality_operators = true +ij_typescript_spaces_around_logical_operators = true +ij_typescript_spaces_around_multiplicative_operators = true +ij_typescript_spaces_around_relational_operators = true +ij_typescript_spaces_around_shift_operators = true +ij_typescript_spaces_around_unary_operator = false +ij_typescript_spaces_within_array_initializer_brackets = false +ij_typescript_spaces_within_brackets = false +ij_typescript_spaces_within_catch_parentheses = false +ij_typescript_spaces_within_for_parentheses = false +ij_typescript_spaces_within_if_parentheses = false +ij_typescript_spaces_within_imports = false +ij_typescript_spaces_within_interpolation_expressions = false +ij_typescript_spaces_within_method_call_parentheses = false +ij_typescript_spaces_within_method_parentheses = false +ij_typescript_spaces_within_object_literal_braces = false +ij_typescript_spaces_within_object_type_braces = true +ij_typescript_spaces_within_parentheses = false +ij_typescript_spaces_within_switch_parentheses = false +ij_typescript_spaces_within_type_assertion = false +ij_typescript_spaces_within_union_types = true +ij_typescript_spaces_within_while_parentheses = false +ij_typescript_special_else_if_treatment = true +ij_typescript_ternary_operation_signs_on_next_line = false +ij_typescript_ternary_operation_wrap = off +ij_typescript_union_types_wrap = on_every_item +ij_typescript_use_chained_calls_group_indents = false +ij_typescript_use_double_quotes = true +ij_typescript_use_explicit_js_extension = global +ij_typescript_use_path_mapping = always +ij_typescript_use_public_modifier = false +ij_typescript_use_semicolon_after_statement = true +ij_typescript_var_declaration_wrap = normal +ij_typescript_while_brace_force = never +ij_typescript_while_on_new_line = false +ij_typescript_wrap_comments = false + +[{*.bash,*.sh,*.zsh}] +indent_size = 2 +tab_width = 2 +ij_shell_binary_ops_start_line = false +ij_shell_keep_column_alignment_padding = false +ij_shell_minify_program = false +ij_shell_redirect_followed_by_space = false +ij_shell_switch_cases_indented = false +ij_shell_use_unix_line_separator = true + +[{*.cjs,*.js}] +ij_continuation_indent_size = 4 +ij_javascript_align_imports = false +ij_javascript_align_multiline_array_initializer_expression = false +ij_javascript_align_multiline_binary_operation = false +ij_javascript_align_multiline_chained_methods = false +ij_javascript_align_multiline_extends_list = false +ij_javascript_align_multiline_for = true +ij_javascript_align_multiline_parameters = true +ij_javascript_align_multiline_parameters_in_calls = false +ij_javascript_align_multiline_ternary_operation = false +ij_javascript_align_object_properties = 0 +ij_javascript_align_union_types = false +ij_javascript_align_var_statements = 0 +ij_javascript_array_initializer_new_line_after_left_brace = false +ij_javascript_array_initializer_right_brace_on_new_line = false +ij_javascript_array_initializer_wrap = off +ij_javascript_assignment_wrap = off +ij_javascript_binary_operation_sign_on_next_line = false +ij_javascript_binary_operation_wrap = off +ij_javascript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/** +ij_javascript_blank_lines_after_imports = 1 +ij_javascript_blank_lines_around_class = 1 +ij_javascript_blank_lines_around_field = 0 +ij_javascript_blank_lines_around_function = 1 +ij_javascript_blank_lines_around_method = 1 +ij_javascript_block_brace_style = end_of_line +ij_javascript_block_comment_add_space = false +ij_javascript_block_comment_at_first_column = true +ij_javascript_call_parameters_new_line_after_left_paren = false +ij_javascript_call_parameters_right_paren_on_new_line = false +ij_javascript_call_parameters_wrap = off +ij_javascript_catch_on_new_line = false +ij_javascript_chained_call_dot_on_new_line = true +ij_javascript_class_brace_style = end_of_line +ij_javascript_comma_on_new_line = false +ij_javascript_do_while_brace_force = never +ij_javascript_else_on_new_line = false +ij_javascript_enforce_trailing_comma = keep +ij_javascript_extends_keyword_wrap = off +ij_javascript_extends_list_wrap = off +ij_javascript_field_prefix = _ +ij_javascript_file_name_style = relaxed +ij_javascript_finally_on_new_line = false +ij_javascript_for_brace_force = never +ij_javascript_for_statement_new_line_after_left_paren = false +ij_javascript_for_statement_right_paren_on_new_line = false +ij_javascript_for_statement_wrap = off +ij_javascript_force_quote_style = false +ij_javascript_force_semicolon_style = false +ij_javascript_function_expression_brace_style = end_of_line +ij_javascript_if_brace_force = never +ij_javascript_import_merge_members = global +ij_javascript_import_prefer_absolute_path = global +ij_javascript_import_sort_members = true +ij_javascript_import_sort_module_name = false +ij_javascript_import_use_node_resolution = true +ij_javascript_imports_wrap = on_every_item +ij_javascript_indent_case_from_switch = true +ij_javascript_indent_chained_calls = true +ij_javascript_indent_package_children = 0 +ij_javascript_jsx_attribute_value = braces +ij_javascript_keep_blank_lines_in_code = 2 +ij_javascript_keep_first_column_comment = true +ij_javascript_keep_indents_on_empty_lines = false +ij_javascript_keep_line_breaks = true +ij_javascript_keep_simple_blocks_in_one_line = false +ij_javascript_keep_simple_methods_in_one_line = false +ij_javascript_line_comment_add_space = true +ij_javascript_line_comment_at_first_column = false +ij_javascript_method_brace_style = end_of_line +ij_javascript_method_call_chain_wrap = off +ij_javascript_method_parameters_new_line_after_left_paren = false +ij_javascript_method_parameters_right_paren_on_new_line = false +ij_javascript_method_parameters_wrap = off +ij_javascript_object_literal_wrap = on_every_item +ij_javascript_parentheses_expression_new_line_after_left_paren = false +ij_javascript_parentheses_expression_right_paren_on_new_line = false +ij_javascript_place_assignment_sign_on_next_line = false +ij_javascript_prefer_as_type_cast = false +ij_javascript_prefer_explicit_types_function_expression_returns = false +ij_javascript_prefer_explicit_types_function_returns = false +ij_javascript_prefer_explicit_types_vars_fields = false +ij_javascript_prefer_parameters_wrap = false +ij_javascript_reformat_c_style_comments = false +ij_javascript_space_after_colon = true +ij_javascript_space_after_comma = true +ij_javascript_space_after_dots_in_rest_parameter = false +ij_javascript_space_after_generator_mult = true +ij_javascript_space_after_property_colon = true +ij_javascript_space_after_quest = true +ij_javascript_space_after_type_colon = true +ij_javascript_space_after_unary_not = false +ij_javascript_space_before_async_arrow_lparen = true +ij_javascript_space_before_catch_keyword = true +ij_javascript_space_before_catch_left_brace = true +ij_javascript_space_before_catch_parentheses = true +ij_javascript_space_before_class_lbrace = true +ij_javascript_space_before_class_left_brace = true +ij_javascript_space_before_colon = true +ij_javascript_space_before_comma = false +ij_javascript_space_before_do_left_brace = true +ij_javascript_space_before_else_keyword = true +ij_javascript_space_before_else_left_brace = true +ij_javascript_space_before_finally_keyword = true +ij_javascript_space_before_finally_left_brace = true +ij_javascript_space_before_for_left_brace = true +ij_javascript_space_before_for_parentheses = true +ij_javascript_space_before_for_semicolon = false +ij_javascript_space_before_function_left_parenth = true +ij_javascript_space_before_generator_mult = false +ij_javascript_space_before_if_left_brace = true +ij_javascript_space_before_if_parentheses = true +ij_javascript_space_before_method_call_parentheses = false +ij_javascript_space_before_method_left_brace = true +ij_javascript_space_before_method_parentheses = false +ij_javascript_space_before_property_colon = false +ij_javascript_space_before_quest = true +ij_javascript_space_before_switch_left_brace = true +ij_javascript_space_before_switch_parentheses = true +ij_javascript_space_before_try_left_brace = true +ij_javascript_space_before_type_colon = false +ij_javascript_space_before_unary_not = false +ij_javascript_space_before_while_keyword = true +ij_javascript_space_before_while_left_brace = true +ij_javascript_space_before_while_parentheses = true +ij_javascript_spaces_around_additive_operators = true +ij_javascript_spaces_around_arrow_function_operator = true +ij_javascript_spaces_around_assignment_operators = true +ij_javascript_spaces_around_bitwise_operators = true +ij_javascript_spaces_around_equality_operators = true +ij_javascript_spaces_around_logical_operators = true +ij_javascript_spaces_around_multiplicative_operators = true +ij_javascript_spaces_around_relational_operators = true +ij_javascript_spaces_around_shift_operators = true +ij_javascript_spaces_around_unary_operator = false +ij_javascript_spaces_within_array_initializer_brackets = false +ij_javascript_spaces_within_brackets = false +ij_javascript_spaces_within_catch_parentheses = false +ij_javascript_spaces_within_for_parentheses = false +ij_javascript_spaces_within_if_parentheses = false +ij_javascript_spaces_within_imports = false +ij_javascript_spaces_within_interpolation_expressions = false +ij_javascript_spaces_within_method_call_parentheses = false +ij_javascript_spaces_within_method_parentheses = false +ij_javascript_spaces_within_object_literal_braces = false +ij_javascript_spaces_within_object_type_braces = true +ij_javascript_spaces_within_parentheses = false +ij_javascript_spaces_within_switch_parentheses = false +ij_javascript_spaces_within_type_assertion = false +ij_javascript_spaces_within_union_types = true +ij_javascript_spaces_within_while_parentheses = false +ij_javascript_special_else_if_treatment = true +ij_javascript_ternary_operation_signs_on_next_line = false +ij_javascript_ternary_operation_wrap = off +ij_javascript_union_types_wrap = on_every_item +ij_javascript_use_chained_calls_group_indents = false +ij_javascript_use_double_quotes = true +ij_javascript_use_explicit_js_extension = global +ij_javascript_use_path_mapping = always +ij_javascript_use_public_modifier = false +ij_javascript_use_semicolon_after_statement = true +ij_javascript_var_declaration_wrap = normal +ij_javascript_while_brace_force = never +ij_javascript_while_on_new_line = false +ij_javascript_wrap_comments = false + +[{*.ft,*.vm,*.vsl}] +ij_vtl_keep_indents_on_empty_lines = false + +[{*.gant,*.gradle,*.groovy,*.gson,*.gy}] +ij_groovy_align_group_field_declarations = false +ij_groovy_align_multiline_array_initializer_expression = false +ij_groovy_align_multiline_assignment = false +ij_groovy_align_multiline_binary_operation = false +ij_groovy_align_multiline_chained_methods = false +ij_groovy_align_multiline_extends_list = false +ij_groovy_align_multiline_for = true +ij_groovy_align_multiline_list_or_map = true +ij_groovy_align_multiline_method_parentheses = false +ij_groovy_align_multiline_parameters = true +ij_groovy_align_multiline_parameters_in_calls = false +ij_groovy_align_multiline_resources = true +ij_groovy_align_multiline_ternary_operation = false +ij_groovy_align_multiline_throws_list = false +ij_groovy_align_named_args_in_map = true +ij_groovy_align_throws_keyword = false +ij_groovy_array_initializer_new_line_after_left_brace = false +ij_groovy_array_initializer_right_brace_on_new_line = false +ij_groovy_array_initializer_wrap = off +ij_groovy_assert_statement_wrap = off +ij_groovy_assignment_wrap = off +ij_groovy_binary_operation_wrap = off +ij_groovy_blank_lines_after_class_header = 0 +ij_groovy_blank_lines_after_imports = 1 +ij_groovy_blank_lines_after_package = 1 +ij_groovy_blank_lines_around_class = 1 +ij_groovy_blank_lines_around_field = 0 +ij_groovy_blank_lines_around_field_in_interface = 0 +ij_groovy_blank_lines_around_method = 1 +ij_groovy_blank_lines_around_method_in_interface = 1 +ij_groovy_blank_lines_before_imports = 1 +ij_groovy_blank_lines_before_method_body = 0 +ij_groovy_blank_lines_before_package = 0 +ij_groovy_block_brace_style = end_of_line +ij_groovy_block_comment_add_space = false +ij_groovy_block_comment_at_first_column = true +ij_groovy_call_parameters_new_line_after_left_paren = false +ij_groovy_call_parameters_right_paren_on_new_line = false +ij_groovy_call_parameters_wrap = off +ij_groovy_catch_on_new_line = false +ij_groovy_class_annotation_wrap = split_into_lines +ij_groovy_class_brace_style = end_of_line +ij_groovy_class_count_to_use_import_on_demand = 5 +ij_groovy_do_while_brace_force = never +ij_groovy_else_on_new_line = false +ij_groovy_enum_constants_wrap = off +ij_groovy_extends_keyword_wrap = off +ij_groovy_extends_list_wrap = off +ij_groovy_field_annotation_wrap = split_into_lines +ij_groovy_finally_on_new_line = false +ij_groovy_for_brace_force = never +ij_groovy_for_statement_new_line_after_left_paren = false +ij_groovy_for_statement_right_paren_on_new_line = false +ij_groovy_for_statement_wrap = off +ij_groovy_if_brace_force = never +ij_groovy_import_annotation_wrap = 2 +ij_groovy_imports_layout = *,|,javax.**,java.**,|,$* +ij_groovy_indent_case_from_switch = true +ij_groovy_indent_label_blocks = true +ij_groovy_insert_inner_class_imports = false +ij_groovy_keep_blank_lines_before_right_brace = 2 +ij_groovy_keep_blank_lines_in_code = 2 +ij_groovy_keep_blank_lines_in_declarations = 2 +ij_groovy_keep_control_statement_in_one_line = true +ij_groovy_keep_first_column_comment = true +ij_groovy_keep_indents_on_empty_lines = false +ij_groovy_keep_line_breaks = true +ij_groovy_keep_multiple_expressions_in_one_line = false +ij_groovy_keep_simple_blocks_in_one_line = false +ij_groovy_keep_simple_classes_in_one_line = true +ij_groovy_keep_simple_lambdas_in_one_line = true +ij_groovy_keep_simple_methods_in_one_line = true +ij_groovy_label_indent_absolute = false +ij_groovy_label_indent_size = 0 +ij_groovy_lambda_brace_style = end_of_line +ij_groovy_layout_static_imports_separately = true +ij_groovy_line_comment_add_space = false +ij_groovy_line_comment_at_first_column = true +ij_groovy_method_annotation_wrap = split_into_lines +ij_groovy_method_brace_style = end_of_line +ij_groovy_method_call_chain_wrap = off +ij_groovy_method_parameters_new_line_after_left_paren = false +ij_groovy_method_parameters_right_paren_on_new_line = false +ij_groovy_method_parameters_wrap = off +ij_groovy_modifier_list_wrap = false +ij_groovy_names_count_to_use_import_on_demand = 3 +ij_groovy_parameter_annotation_wrap = off +ij_groovy_parentheses_expression_new_line_after_left_paren = false +ij_groovy_parentheses_expression_right_paren_on_new_line = false +ij_groovy_prefer_parameters_wrap = false +ij_groovy_resource_list_new_line_after_left_paren = false +ij_groovy_resource_list_right_paren_on_new_line = false +ij_groovy_resource_list_wrap = off +ij_groovy_space_after_assert_separator = true +ij_groovy_space_after_colon = true +ij_groovy_space_after_comma = true +ij_groovy_space_after_comma_in_type_arguments = true +ij_groovy_space_after_for_semicolon = true +ij_groovy_space_after_quest = true +ij_groovy_space_after_type_cast = true +ij_groovy_space_before_annotation_parameter_list = false +ij_groovy_space_before_array_initializer_left_brace = false +ij_groovy_space_before_assert_separator = false +ij_groovy_space_before_catch_keyword = true +ij_groovy_space_before_catch_left_brace = true +ij_groovy_space_before_catch_parentheses = true +ij_groovy_space_before_class_left_brace = true +ij_groovy_space_before_closure_left_brace = true +ij_groovy_space_before_colon = true +ij_groovy_space_before_comma = false +ij_groovy_space_before_do_left_brace = true +ij_groovy_space_before_else_keyword = true +ij_groovy_space_before_else_left_brace = true +ij_groovy_space_before_finally_keyword = true +ij_groovy_space_before_finally_left_brace = true +ij_groovy_space_before_for_left_brace = true +ij_groovy_space_before_for_parentheses = true +ij_groovy_space_before_for_semicolon = false +ij_groovy_space_before_if_left_brace = true +ij_groovy_space_before_if_parentheses = true +ij_groovy_space_before_method_call_parentheses = false +ij_groovy_space_before_method_left_brace = true +ij_groovy_space_before_method_parentheses = false +ij_groovy_space_before_quest = true +ij_groovy_space_before_record_parentheses = false +ij_groovy_space_before_switch_left_brace = true +ij_groovy_space_before_switch_parentheses = true +ij_groovy_space_before_synchronized_left_brace = true +ij_groovy_space_before_synchronized_parentheses = true +ij_groovy_space_before_try_left_brace = true +ij_groovy_space_before_try_parentheses = true +ij_groovy_space_before_while_keyword = true +ij_groovy_space_before_while_left_brace = true +ij_groovy_space_before_while_parentheses = true +ij_groovy_space_in_named_argument = true +ij_groovy_space_in_named_argument_before_colon = false +ij_groovy_space_within_empty_array_initializer_braces = false +ij_groovy_space_within_empty_method_call_parentheses = false +ij_groovy_spaces_around_additive_operators = true +ij_groovy_spaces_around_assignment_operators = true +ij_groovy_spaces_around_bitwise_operators = true +ij_groovy_spaces_around_equality_operators = true +ij_groovy_spaces_around_lambda_arrow = true +ij_groovy_spaces_around_logical_operators = true +ij_groovy_spaces_around_multiplicative_operators = true +ij_groovy_spaces_around_regex_operators = true +ij_groovy_spaces_around_relational_operators = true +ij_groovy_spaces_around_shift_operators = true +ij_groovy_spaces_within_annotation_parentheses = false +ij_groovy_spaces_within_array_initializer_braces = false +ij_groovy_spaces_within_braces = true +ij_groovy_spaces_within_brackets = false +ij_groovy_spaces_within_cast_parentheses = false +ij_groovy_spaces_within_catch_parentheses = false +ij_groovy_spaces_within_for_parentheses = false +ij_groovy_spaces_within_gstring_injection_braces = false +ij_groovy_spaces_within_if_parentheses = false +ij_groovy_spaces_within_list_or_map = false +ij_groovy_spaces_within_method_call_parentheses = false +ij_groovy_spaces_within_method_parentheses = false +ij_groovy_spaces_within_parentheses = false +ij_groovy_spaces_within_switch_parentheses = false +ij_groovy_spaces_within_synchronized_parentheses = false +ij_groovy_spaces_within_try_parentheses = false +ij_groovy_spaces_within_tuple_expression = false +ij_groovy_spaces_within_while_parentheses = false +ij_groovy_special_else_if_treatment = true +ij_groovy_ternary_operation_wrap = off +ij_groovy_throws_keyword_wrap = off +ij_groovy_throws_list_wrap = off +ij_groovy_use_flying_geese_braces = false +ij_groovy_use_fq_class_names = false +ij_groovy_use_fq_class_names_in_javadoc = true +ij_groovy_use_relative_indents = false +ij_groovy_use_single_class_imports = true +ij_groovy_variable_annotation_wrap = off +ij_groovy_while_brace_force = never +ij_groovy_while_on_new_line = false +ij_groovy_wrap_chain_calls_after_dot = false +ij_groovy_wrap_long_lines = false + +[{*.gradle.kts,*.kt,*.kts,*.main.kts,*.space.kts}] +ij_kotlin_align_in_columns_case_branch = false +ij_kotlin_align_multiline_binary_operation = false +ij_kotlin_align_multiline_extends_list = false +ij_kotlin_align_multiline_method_parentheses = false +ij_kotlin_align_multiline_parameters = true +ij_kotlin_align_multiline_parameters_in_calls = false +ij_kotlin_allow_trailing_comma = false +ij_kotlin_allow_trailing_comma_on_call_site = false +ij_kotlin_assignment_wrap = normal +ij_kotlin_blank_lines_after_class_header = 0 +ij_kotlin_blank_lines_around_block_when_branches = 0 +ij_kotlin_blank_lines_before_declaration_with_comment_or_annotation_on_separate_line = 1 +ij_kotlin_block_comment_add_space = false +ij_kotlin_block_comment_at_first_column = true +ij_kotlin_call_parameters_new_line_after_left_paren = true +ij_kotlin_call_parameters_right_paren_on_new_line = true +ij_kotlin_call_parameters_wrap = on_every_item +ij_kotlin_catch_on_new_line = false +ij_kotlin_class_annotation_wrap = split_into_lines +ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL +ij_kotlin_continuation_indent_for_chained_calls = false +ij_kotlin_continuation_indent_for_expression_bodies = false +ij_kotlin_continuation_indent_in_argument_lists = false +ij_kotlin_continuation_indent_in_elvis = false +ij_kotlin_continuation_indent_in_if_conditions = false +ij_kotlin_continuation_indent_in_parameter_lists = false +ij_kotlin_continuation_indent_in_supertype_lists = false +ij_kotlin_else_on_new_line = false +ij_kotlin_enum_constants_wrap = off +ij_kotlin_extends_list_wrap = normal +ij_kotlin_field_annotation_wrap = split_into_lines +ij_kotlin_finally_on_new_line = false +ij_kotlin_if_rparen_on_new_line = true +ij_kotlin_import_nested_classes = false +ij_kotlin_imports_layout = *,java.**,javax.**,kotlin.**,^ +ij_kotlin_insert_whitespaces_in_simple_one_line_method = true +ij_kotlin_keep_blank_lines_before_right_brace = 2 +ij_kotlin_keep_blank_lines_in_code = 2 +ij_kotlin_keep_blank_lines_in_declarations = 2 +ij_kotlin_keep_first_column_comment = true +ij_kotlin_keep_indents_on_empty_lines = false +ij_kotlin_keep_line_breaks = true +ij_kotlin_lbrace_on_next_line = false +ij_kotlin_line_comment_add_space = false +ij_kotlin_line_comment_at_first_column = true +ij_kotlin_method_annotation_wrap = split_into_lines +ij_kotlin_method_call_chain_wrap = normal +ij_kotlin_method_parameters_new_line_after_left_paren = true +ij_kotlin_method_parameters_right_paren_on_new_line = true +ij_kotlin_method_parameters_wrap = on_every_item +ij_kotlin_name_count_to_use_star_import = 5 +ij_kotlin_name_count_to_use_star_import_for_members = 3 +ij_kotlin_packages_to_use_import_on_demand = java.util.*,kotlinx.android.synthetic.**,io.ktor.** +ij_kotlin_parameter_annotation_wrap = off +ij_kotlin_space_after_comma = true +ij_kotlin_space_after_extend_colon = true +ij_kotlin_space_after_type_colon = true +ij_kotlin_space_before_catch_parentheses = true +ij_kotlin_space_before_comma = false +ij_kotlin_space_before_extend_colon = true +ij_kotlin_space_before_for_parentheses = true +ij_kotlin_space_before_if_parentheses = true +ij_kotlin_space_before_lambda_arrow = true +ij_kotlin_space_before_type_colon = false +ij_kotlin_space_before_when_parentheses = true +ij_kotlin_space_before_while_parentheses = true +ij_kotlin_spaces_around_additive_operators = true +ij_kotlin_spaces_around_assignment_operators = true +ij_kotlin_spaces_around_equality_operators = true +ij_kotlin_spaces_around_function_type_arrow = true +ij_kotlin_spaces_around_logical_operators = true +ij_kotlin_spaces_around_multiplicative_operators = true +ij_kotlin_spaces_around_range = false +ij_kotlin_spaces_around_relational_operators = true +ij_kotlin_spaces_around_unary_operator = false +ij_kotlin_spaces_around_when_arrow = true +ij_kotlin_variable_annotation_wrap = off +ij_kotlin_while_on_new_line = false +ij_kotlin_wrap_elvis_expressions = 1 +ij_kotlin_wrap_expression_body_functions = 1 +ij_kotlin_wrap_first_method_in_call_chain = false + +[{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.stylelintrc,bowerrc,jest.config}] +indent_size = 2 +ij_json_keep_blank_lines_in_code = 0 +ij_json_keep_indents_on_empty_lines = false +ij_json_keep_line_breaks = true +ij_json_space_after_colon = true +ij_json_space_after_comma = true +ij_json_space_before_colon = true +ij_json_space_before_comma = false +ij_json_spaces_within_braces = false +ij_json_spaces_within_brackets = false +ij_json_wrap_long_lines = false + +[{*.hcl,*.nomad}] +indent_size = 2 +ij_hcl_array_wrapping = 2 +ij_hcl_keep_blank_lines_in_code = 2 +ij_hcl_keep_indents_on_empty_lines = false +ij_hcl_keep_line_breaks = true +ij_hcl_object_wrapping = 2 +ij_hcl_property_alignment = 0 +ij_hcl_property_line_commenter_character = 0 +ij_hcl_space_after_comma = true +ij_hcl_space_before_comma = false +ij_hcl_spaces_around_assignment_operators = true +ij_hcl_spaces_within_braces = false +ij_hcl_spaces_within_brackets = false +ij_hcl_wrap_long_lines = false + +[{*.htm,*.html,*.ng,*.sht,*.shtm,*.shtml}] +ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3 +ij_html_align_attributes = true +ij_html_align_text = false +ij_html_attribute_wrap = normal +ij_html_block_comment_add_space = false +ij_html_block_comment_at_first_column = true +ij_html_do_not_align_children_of_min_lines = 0 +ij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p +ij_html_do_not_indent_children_of_tags = html,body,thead,tbody,tfoot +ij_html_enforce_quotes = false +ij_html_inline_tags = a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var +ij_html_keep_blank_lines = 2 +ij_html_keep_indents_on_empty_lines = false +ij_html_keep_line_breaks = true +ij_html_keep_line_breaks_in_text = true +ij_html_keep_whitespaces = false +ij_html_keep_whitespaces_inside = span,pre,textarea +ij_html_line_comment_at_first_column = true +ij_html_new_line_after_last_attribute = never +ij_html_new_line_before_first_attribute = never +ij_html_quote_style = double +ij_html_remove_new_line_before_tags = br +ij_html_space_after_tag_name = false +ij_html_space_around_equality_in_attribute = false +ij_html_space_inside_empty_tag = false +ij_html_text_wrap = normal + +[{*.jsf,*.jsp,*.jspf,*.tag,*.tagf,*.xjsp}] +ij_jsp_jsp_prefer_comma_separated_import_list = false +ij_jsp_keep_indents_on_empty_lines = false + +[{*.jspx,*.tagx}] +ij_jspx_keep_indents_on_empty_lines = false + +[{*.markdown,*.md}] +ij_markdown_force_one_space_after_blockquote_symbol = true +ij_markdown_force_one_space_after_header_symbol = true +ij_markdown_force_one_space_after_list_bullet = true +ij_markdown_force_one_space_between_words = true +ij_markdown_keep_indents_on_empty_lines = false +ij_markdown_max_lines_around_block_elements = 1 +ij_markdown_max_lines_around_header = 1 +ij_markdown_max_lines_between_paragraphs = 1 +ij_markdown_min_lines_around_block_elements = 1 +ij_markdown_min_lines_around_header = 1 +ij_markdown_min_lines_between_paragraphs = 1 + +[{*.pb,*.textproto}] +indent_size = 2 +tab_width = 2 +ij_continuation_indent_size = 4 +ij_prototext_keep_blank_lines_in_code = 2 +ij_prototext_keep_indents_on_empty_lines = false +ij_prototext_keep_line_breaks = true +ij_prototext_space_after_colon = true +ij_prototext_space_after_comma = true +ij_prototext_space_before_colon = false +ij_prototext_space_before_comma = false +ij_prototext_spaces_within_braces = true +ij_prototext_spaces_within_brackets = false + +[{*.properties,spring.handlers,spring.schemas}] +ij_properties_align_group_field_declarations = false +ij_properties_keep_blank_lines = false +ij_properties_key_value_delimiter = equals +ij_properties_spaces_around_key_value_delimiter = false + +[{*.tf,*.tfvars}] +indent_size = 2 +ij_hcl-terraform_array_wrapping = 2 +ij_hcl-terraform_keep_blank_lines_in_code = 2 +ij_hcl-terraform_keep_indents_on_empty_lines = false +ij_hcl-terraform_keep_line_breaks = true +ij_hcl-terraform_object_wrapping = 2 +ij_hcl-terraform_property_alignment = 0 +ij_hcl-terraform_property_line_commenter_character = 0 +ij_hcl-terraform_space_after_comma = true +ij_hcl-terraform_space_before_comma = false +ij_hcl-terraform_spaces_around_assignment_operators = true +ij_hcl-terraform_spaces_within_braces = false +ij_hcl-terraform_spaces_within_brackets = false +ij_hcl-terraform_wrap_long_lines = false + +[{*.yaml,*.yml}] +indent_size = 2 +ij_yaml_align_values_properties = do_not_align +ij_yaml_autoinsert_sequence_marker = true +ij_yaml_block_mapping_on_new_line = false +ij_yaml_indent_sequence_value = true +ij_yaml_keep_indents_on_empty_lines = false +ij_yaml_keep_line_breaks = true +ij_yaml_sequence_on_new_line = false +ij_yaml_space_before_colon = false +ij_yaml_spaces_within_braces = true +ij_yaml_spaces_within_brackets = true diff --git a/resources/tx-checkstyle-config.xml b/resources/tx-checkstyle-config.xml new file mode 100644 index 0000000..cdce348 --- /dev/null +++ b/resources/tx-checkstyle-config.xml @@ -0,0 +1,436 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/tx-codestyle.xml b/resources/tx-codestyle.xml new file mode 100644 index 0000000..9297f6b --- /dev/null +++ b/resources/tx-codestyle.xml @@ -0,0 +1,337 @@ + + + + + + + + + + + + + + \ No newline at end of file From 7b9e274be389675de0b5dd356ce88e9aed6c3dfb Mon Sep 17 00:00:00 2001 From: "Dr. Christoph \"Schorsch\" Jung" Date: Thu, 28 Sep 2023 16:41:55 +0200 Subject: [PATCH 2/7] style: reformat code according to tx styleguide. --- .editorconfig | 34 +- agent-plane/agent-plane-protocol/pom.xml | 60 +- .../tractusx/agents/edc/AgentConfig.java | 181 +++-- .../tractusx/agents/edc/AgentExtension.java | 88 +-- .../tractusx/agents/edc/AgentProtocol.java | 2 +- .../agents/edc/AgreementController.java | 391 +---------- .../agents/edc/AgreementControllerImpl.java | 433 ++++++++++++ .../agents/edc/IAgreementController.java | 41 -- .../tractusx/agents/edc/MonitorWrapper.java | 4 +- .../agents/edc/SkillDistribution.java | 17 +- .../edc/{ISkillStore.java => SkillStore.java} | 21 +- .../eclipse/tractusx/agents/edc/Tuple.java | 31 +- .../eclipse/tractusx/agents/edc/TupleSet.java | 67 +- .../agents/edc/http/AgentController.java | 252 ++++--- .../agents/edc/http/AgentHttpAction.java | 53 +- .../agents/edc/http/DelegationResponse.java | 84 +-- .../agents/edc/http/DelegationService.java | 341 +--------- .../edc/http/DelegationServiceImpl.java | 367 ++++++++++ .../agents/edc/http/HttpClientAdapter.java | 38 +- .../agents/edc/http/HttpClientFactory.java | 33 +- .../agents/edc/http/HttpResponseAdapter.java | 14 +- .../edc/http/HttpServletContextAdapter.java | 24 +- .../edc/http/HttpServletRequestAdapter.java | 60 +- .../edc/http/HttpServletResponseAdapter.java | 42 +- .../tractusx/agents/edc/http/HttpUtils.java | 69 +- .../agents/edc/http/IDelegationService.java | 43 -- .../agents/edc/http/IJakartaAdapter.java | 86 --- .../agents/edc/http/JakartaAdapter.java | 89 ++- .../agents/edc/http/JakartaAdapterImpl.java | 62 ++ .../JakartaServletInputStreamAdapter.java | 15 +- .../JakartaServletOutputStreamAdapter.java | 15 +- .../edc/http/ServletInputStreamDelegator.java | 6 +- .../http/ServletOutputStreamDelegator.java | 6 +- .../agents/edc/http/transfer/AgentSource.java | 95 +-- .../edc/http/transfer/AgentSourceFactory.java | 29 +- .../AgentSourceHttpParamsDecorator.java | 129 ++-- .../AgentSourceRequestParamsSupplier.java | 9 +- .../tractusx/agents/edc/jsonld/JsonLd.java | 41 +- .../agents/edc/jsonld/JsonLdObject.java | 2 +- .../tractusx/agents/edc/model/Asset.java | 4 +- .../agents/edc/model/ContractNegotiation.java | 4 +- .../edc/model/ContractNegotiationRequest.java | 4 +- .../agents/edc/model/DcatCatalog.java | 10 +- .../agents/edc/model/DcatDataset.java | 2 +- .../edc/rdf/{RDFStore.java => RdfStore.java} | 43 +- .../agents/edc/service/DataManagement.java | 98 +-- .../edc/service/DataspaceSynchronizer.java | 167 ++--- .../agents/edc/service/EdcSkillStore.java | 60 +- .../edc/service/InMemorySkillStore.java | 12 +- .../agents/edc/sparql/CatenaxWarning.java | 23 +- .../edc/sparql/DataspaceServiceExecutor.java | 324 ++++----- .../agents/edc/sparql/GraphRewrite.java | 36 +- .../edc/sparql/GraphRewriteVisitor.java | 4 +- .../edc/sparql/OptimizeJoinStrategy.java | 17 +- .../tractusx/agents/edc/sparql/Optimizer.java | 2 + .../agents/edc/sparql/QueryExecutor.java | 339 ++++++---- .../edc/sparql/QueryExecutorBuilder.java | 26 +- .../agents/edc/sparql/QueryIterFutures.java | 77 ++- .../agents/edc/sparql/QueryIterJoin.java | 28 +- .../edc/sparql/SkillVariableDetector.java | 12 +- .../edc/sparql/SparqlQueryProcessor.java | 306 +++++---- .../edc/sparql/SparqlQuerySerializer.java | 25 +- .../sparql/SparqlQuerySerializerFactory.java | 5 +- .../sparql/StratifiedFormatterElement.java | 8 +- .../agents/edc/sparql/VariableDetector.java | 19 +- ...hingDataPlaneTokenValidatorController.java | 23 +- .../agents/edc/MockAgreementController.java | 2 +- .../tractusx/agents/edc/TestConfig.java | 2 +- .../agents/edc/http/TestAgentController.java | 16 +- .../service/TestDataspaceSynchronizer.java | 4 +- .../edc/sparql/TestSparqlProcessor.java | 24 +- agent-plane/agentplane-azure-vault/pom.xml | 36 +- agent-plane/agentplane-hashicorp/pom.xml | 40 +- agent-plane/pom.xml | 2 +- common/auth-jwt/pom.xml | 27 +- .../edc/auth/ApiKeyAuthenticationService.java | 14 +- .../edc/auth/AuthenticationExtension.java | 70 +- .../auth/CompositeAuthenticationService.java | 17 +- .../edc/auth/CompositeJwsVerifier.java | 66 +- .../edc/auth/JwtAuthenticationService.java | 44 +- .../auth/ApiKeyAuthenticationServiceTest.java | 20 +- .../CompositeAuthenticationServiceTest.java | 42 +- .../auth/JwtAuthenticationServiceTest.java | 40 +- pom.xml | 37 +- resources/suppressions.xml | 22 + resources/tx-codestyle.xml | 634 +++++++++--------- 86 files changed, 3344 insertions(+), 2867 deletions(-) create mode 100644 agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgreementControllerImpl.java delete mode 100644 agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/IAgreementController.java rename agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/{ISkillStore.java => SkillStore.java} (83%) create mode 100644 agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationServiceImpl.java delete mode 100644 agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/IDelegationService.java delete mode 100644 agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/IJakartaAdapter.java create mode 100644 agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaAdapterImpl.java rename agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/rdf/{RDFStore.java => RdfStore.java} (82%) create mode 100644 resources/suppressions.xml diff --git a/.editorconfig b/.editorconfig index 9654ee2..8e01c3c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -28,7 +28,7 @@ ij_css_hex_color_upper_case = false ij_css_keep_blank_lines_in_code = 2 ij_css_keep_indents_on_empty_lines = false ij_css_keep_single_line_blocks = false -ij_css_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_css_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow ij_css_space_after_colon = true ij_css_space_before_opening_brace = true ij_css_use_double_quotes = true @@ -145,7 +145,7 @@ ij_java_for_statement_wrap = off ij_java_generate_final_locals = false ij_java_generate_final_parameters = false ij_java_if_brace_force = never -ij_java_imports_layout = *,|,java.**,javax.**,|,$* +ij_java_imports_layout = *, |, java.**, javax.**, |, $* ij_java_indent_case_from_switch = true ij_java_insert_inner_class_imports = false ij_java_insert_override_annotation = true @@ -180,7 +180,7 @@ ij_java_method_parameters_wrap = off ij_java_modifier_list_wrap = false ij_java_names_count_to_use_import_on_demand = 99 ij_java_new_line_after_lparen_in_record_header = false -ij_java_packages_to_use_import_on_demand = java.awt.*,javax.swing.* +ij_java_packages_to_use_import_on_demand = java.awt.*, javax.swing.* ij_java_parameter_annotation_wrap = off ij_java_parentheses_expression_new_line_after_left_paren = false ij_java_parentheses_expression_right_paren_on_new_line = false @@ -314,7 +314,7 @@ ij_less_keep_indents_on_empty_lines = false ij_less_keep_single_line_blocks = false ij_less_line_comment_add_space = false ij_less_line_comment_at_first_column = false -ij_less_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_less_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow ij_less_space_after_colon = true ij_less_space_before_opening_brace = true ij_less_use_double_quotes = true @@ -349,7 +349,7 @@ ij_sass_keep_indents_on_empty_lines = false ij_sass_keep_single_line_blocks = false ij_sass_line_comment_add_space = false ij_sass_line_comment_at_first_column = false -ij_sass_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_sass_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow ij_sass_space_after_colon = true ij_sass_space_before_opening_brace = true ij_sass_use_double_quotes = true @@ -372,7 +372,7 @@ ij_scss_keep_indents_on_empty_lines = false ij_scss_keep_single_line_blocks = false ij_scss_line_comment_add_space = false ij_scss_line_comment_at_first_column = false -ij_scss_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_scss_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow ij_scss_space_after_colon = true ij_scss_space_before_opening_brace = true ij_scss_use_double_quotes = true @@ -392,7 +392,7 @@ ij_stylus_hex_color_upper_case = false ij_stylus_keep_blank_lines_in_code = 2 ij_stylus_keep_indents_on_empty_lines = false ij_stylus_keep_single_line_blocks = false -ij_stylus_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_stylus_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow ij_stylus_space_after_colon = true ij_stylus_space_before_opening_brace = true ij_stylus_use_double_quotes = true @@ -446,7 +446,7 @@ ij_typescript_array_initializer_wrap = off ij_typescript_assignment_wrap = off ij_typescript_binary_operation_sign_on_next_line = false ij_typescript_binary_operation_wrap = off -ij_typescript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/** +ij_typescript_blacklist_imports = rxjs/Rx, node_modules/**, **/node_modules/**, @angular/material, @angular/material/typings/** ij_typescript_blank_lines_after_imports = 1 ij_typescript_blank_lines_around_class = 1 ij_typescript_blank_lines_around_field = 0 @@ -626,7 +626,7 @@ ij_javascript_array_initializer_wrap = off ij_javascript_assignment_wrap = off ij_javascript_binary_operation_sign_on_next_line = false ij_javascript_binary_operation_wrap = off -ij_javascript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/** +ij_javascript_blacklist_imports = rxjs/Rx, node_modules/**, **/node_modules/**, @angular/material, @angular/material/typings/** ij_javascript_blank_lines_after_imports = 1 ij_javascript_blank_lines_around_class = 1 ij_javascript_blank_lines_around_field = 0 @@ -833,7 +833,7 @@ ij_groovy_for_statement_right_paren_on_new_line = false ij_groovy_for_statement_wrap = off ij_groovy_if_brace_force = never ij_groovy_import_annotation_wrap = 2 -ij_groovy_imports_layout = *,|,javax.**,java.**,|,$* +ij_groovy_imports_layout = *, |, javax.**, java.**, |, $* ij_groovy_indent_case_from_switch = true ij_groovy_indent_label_blocks = true ij_groovy_insert_inner_class_imports = false @@ -993,7 +993,7 @@ ij_kotlin_field_annotation_wrap = split_into_lines ij_kotlin_finally_on_new_line = false ij_kotlin_if_rparen_on_new_line = true ij_kotlin_import_nested_classes = false -ij_kotlin_imports_layout = *,java.**,javax.**,kotlin.**,^ +ij_kotlin_imports_layout = *, java.**, javax.**, kotlin.**, ^ ij_kotlin_insert_whitespaces_in_simple_one_line_method = true ij_kotlin_keep_blank_lines_before_right_brace = 2 ij_kotlin_keep_blank_lines_in_code = 2 @@ -1011,7 +1011,7 @@ ij_kotlin_method_parameters_right_paren_on_new_line = true ij_kotlin_method_parameters_wrap = on_every_item ij_kotlin_name_count_to_use_star_import = 5 ij_kotlin_name_count_to_use_star_import_for_members = 3 -ij_kotlin_packages_to_use_import_on_demand = java.util.*,kotlinx.android.synthetic.**,io.ktor.** +ij_kotlin_packages_to_use_import_on_demand = java.util.*, kotlinx.android.synthetic.**, io.ktor.** ij_kotlin_parameter_annotation_wrap = off ij_kotlin_space_after_comma = true ij_kotlin_space_after_extend_colon = true @@ -1071,23 +1071,23 @@ ij_hcl_spaces_within_brackets = false ij_hcl_wrap_long_lines = false [{*.htm,*.html,*.ng,*.sht,*.shtm,*.shtml}] -ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3 +ij_html_add_new_line_before_tags = body, div, p, form, h1, h2, h3 ij_html_align_attributes = true ij_html_align_text = false ij_html_attribute_wrap = normal ij_html_block_comment_add_space = false ij_html_block_comment_at_first_column = true ij_html_do_not_align_children_of_min_lines = 0 -ij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p -ij_html_do_not_indent_children_of_tags = html,body,thead,tbody,tfoot +ij_html_do_not_break_if_inline_tags = title, h1, h2, h3, h4, h5, h6, p +ij_html_do_not_indent_children_of_tags = html, body, thead, tbody, tfoot ij_html_enforce_quotes = false -ij_html_inline_tags = a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var +ij_html_inline_tags = a, abbr, acronym, b, basefont, bdo, big, br, cite, cite, code, dfn, em, font, i, img, input, kbd, label, q, s, samp, select, small, span, strike, strong, sub, sup, textarea, tt, u, var ij_html_keep_blank_lines = 2 ij_html_keep_indents_on_empty_lines = false ij_html_keep_line_breaks = true ij_html_keep_line_breaks_in_text = true ij_html_keep_whitespaces = false -ij_html_keep_whitespaces_inside = span,pre,textarea +ij_html_keep_whitespaces_inside = span, pre, textarea ij_html_line_comment_at_first_column = true ij_html_new_line_after_last_attribute = never ij_html_new_line_before_first_attribute = never diff --git a/agent-plane/agent-plane-protocol/pom.xml b/agent-plane/agent-plane-protocol/pom.xml index 5e6f466..ac99925 100644 --- a/agent-plane/agent-plane-protocol/pom.xml +++ b/agent-plane/agent-plane-protocol/pom.xml @@ -20,7 +20,7 @@ - org.eclipse.tractusx.agents.edc @@ -36,7 +36,9 @@ jar Tractus-X Agent-Related Transfer Protocols - A Dataplane Extension with SparQL-Over-Http Endpoint, Delegation Capabilities and a Federated Graph-Based Data Catalogue. + A Dataplane Extension with SparQL-Over-Http Endpoint, Delegation Capabilities and a Federated + Graph-Based Data Catalogue. + http://catena-x.net/ @@ -89,7 +91,7 @@ - + org.apache.maven.plugins maven-dependency-plugin @@ -104,13 +106,13 @@ - + org.apache.maven.plugins maven-surefire-plugin - com.diffplug.spotless - spotless-maven-plugin + org.apache.maven.plugins + maven-checkstyle-plugin - org.apache.jena - jena-fuseki-core - ${org.apache.jena.version} - + org.apache.jena + jena-fuseki-core + ${org.apache.jena.version} + org.slf4j slf4j-api - + - org.slf4j - jcl-over-slf4j + org.slf4j + jcl-over-slf4j org.eclipse.jetty jetty-server - + org.eclipse.jetty jetty-http - + org.eclipse.jetty jetty-io - + org.eclipse.jetty jetty-security - + org.eclipse.jetty jetty-servlets - + org.eclipse.jetty jetty-servlet - + org.eclipse.jetty jetty-servlet - - + + - org.junit.jupiter - junit-jupiter-engine - test - + org.junit.jupiter + junit-jupiter-engine + test + - org.mockito - mockito-core - test - + org.mockito + mockito-core + test + jakarta.validation jakarta.validation-api diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgentConfig.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgentConfig.java index 416e092..8588b1f 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgentConfig.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgentConfig.java @@ -28,65 +28,65 @@ */ public class AgentConfig { - public static String DEFAULT_ASSET_PROPERTY = "cx.agent.asset.default"; - public static String DEFAULT_ASSET_NAME = "urn:x-arq:DefaultGraph"; + public static final String DEFAULT_ASSET_PROPERTY = "cx.agent.asset.default"; + public static final String DEFAULT_ASSET_NAME = "urn:x-arq:DefaultGraph"; - public static String ASSET_FILE_PROPERTY = "cx.agent.asset.file"; + public static final String ASSET_FILE_PROPERTY = "cx.agent.asset.file"; - public static String ACCESS_POINT_PROPERTY = "cx.agent.accesspoint.name"; - public static String DEFAULT_ACCESS_POINT = "api"; + public static final String ACCESS_POINT_PROPERTY = "cx.agent.accesspoint.name"; + public static final String DEFAULT_ACCESS_POINT = "api"; - public static String VERBOSE_PROPERTY = "cx.agent.sparql.verbose"; - public static boolean DEFAULT_VERBOSE_PROPERTY = false; + public static final String VERBOSE_PROPERTY = "cx.agent.sparql.verbose"; + public static final boolean DEFAULT_VERBOSE_PROPERTY = false; - public static String CONTROL_PLANE_MANAGEMENT_PROVIDER = "cx.agent.controlplane.management.provider"; - public static String CONTROL_PLANE_MANAGEMENT = "cx.agent.controlplane.management"; - public static String CONTROL_PLANE_IDS = "cx.agent.controlplane.protocol"; + public static final String CONTROL_PLANE_MANAGEMENT_PROVIDER = "cx.agent.controlplane.management.provider"; + public static final String CONTROL_PLANE_MANAGEMENT = "cx.agent.controlplane.management"; + public static final String CONTROL_PLANE_IDS = "cx.agent.controlplane.protocol"; - public static String BUSINESS_PARTNER_NUMBER = "edc.participant.id"; - public static String CONTROL_PLANE_AUTH_HEADER = "edc.api.auth.header"; - public static String CONTROL_PLANE_AUTH_VALUE = "edc.api.auth.key"; + public static final String BUSINESS_PARTNER_NUMBER = "edc.participant.id"; + public static final String CONTROL_PLANE_AUTH_HEADER = "edc.api.auth.header"; + public static final String CONTROL_PLANE_AUTH_VALUE = "edc.api.auth.key"; - public static String NEGOTIATION_TIMEOUT_PROPERTY = "cx.agent.negotiation.timeout"; - public static long DEFAULT_NEGOTIATION_TIMEOUT = 30000; + public static final String NEGOTIATION_TIMEOUT_PROPERTY = "cx.agent.negotiation.timeout"; + public static final long DEFAULT_NEGOTIATION_TIMEOUT = 30000; - public static String NEGOTIATION_POLLINTERVAL_PROPERTY = "cx.agent.negotiation.poll"; - public static long DEFAULT_NEGOTIATION_POLLINTERVAL = 1000; + public static final String NEGOTIATION_POLLINTERVAL_PROPERTY = "cx.agent.negotiation.poll"; + public static final long DEFAULT_NEGOTIATION_POLLINTERVAL = 1000; - public static String DATASPACE_SYNCINTERVAL_PROPERTY = "cx.agent.dataspace.synchronization"; - public static long DEFAULT_DATASPACE_SYNCINTERVAL = -1; + public static final String DATASPACE_SYNCINTERVAL_PROPERTY = "cx.agent.dataspace.synchronization"; + public static final long DEFAULT_DATASPACE_SYNCINTERVAL = -1; - public static String DATASPACE_SYNCCONNECTORS_PROPERTY = "cx.agent.dataspace.remotes"; + public static final String DATASPACE_SYNCCONNECTORS_PROPERTY = "cx.agent.dataspace.remotes"; - public static String VALIDATION_ENDPOINTS = "edc.dataplane.token.validation.endpoints"; + public static final String VALIDATION_ENDPOINTS = "edc.dataplane.token.validation.endpoints"; - public static String FEDERATION_SERVICE_BATCH_SIZE = "cx.agent.federation.batch.max"; - public static long DEFAULT_FEDERATION_SERVICE_BATCH_SIZE = Long.MAX_VALUE; + public static final String FEDERATION_SERVICE_BATCH_SIZE = "cx.agent.federation.batch.max"; + public static final long DEFAULT_FEDERATION_SERVICE_BATCH_SIZE = Long.MAX_VALUE; - public static String THREAD_POOL_SIZE = "cx.agent.threadpool.size"; - public static int DEFAULT_THREAD_POOL_SIZE = 4; + public static final String THREAD_POOL_SIZE = "cx.agent.threadpool.size"; + public static final int DEFAULT_THREAD_POOL_SIZE = 4; - public static String CONNECT_TIMEOUT_PROPERTY = "cx.agent.connect.timeout"; - public static String WRITE_TIMEOUT_PROPERTY = "cx.agent.write.timeout"; - public static String CALL_TIMEOUT_PROPERTY = "cx.agent.call.timeout"; - public static String READ_TIMEOUT_PROPERTY = "cx.agent.read.timeout"; - public static int DEFAULT_READ_TIMEOUT=1080000; + public static final String CONNECT_TIMEOUT_PROPERTY = "cx.agent.connect.timeout"; + public static final String WRITE_TIMEOUT_PROPERTY = "cx.agent.write.timeout"; + public static final String CALL_TIMEOUT_PROPERTY = "cx.agent.call.timeout"; + public static final String READ_TIMEOUT_PROPERTY = "cx.agent.read.timeout"; + public static final int DEFAULT_READ_TIMEOUT = 1080000; - public static String CALLBACK_ENDPOINT="cx.agent.callback"; + public static final String CALLBACK_ENDPOINT = "cx.agent.callback"; - public static String DEFAULT_SKILL_CONTRACT_PROPERTY = "cx.agent.skill.contract.default"; + public static final String DEFAULT_SKILL_CONTRACT_PROPERTY = "cx.agent.skill.contract.default"; - public static String SERVICE_ALLOW_PROPERTY = "cx.agent.service.allow"; - public static String DEFAULT_SERVICE_ALLOW_PATTERN = "(http|edc)s?://.*"; + public static final String SERVICE_ALLOW_PROPERTY = "cx.agent.service.allow"; + public static final String DEFAULT_SERVICE_ALLOW_PATTERN = "(http|edc)s?://.*"; - public static String SERVICE_DENY_PROPERTY = "cx.agent.service.deny"; - public static String DEFAULT_SERVICE_DENY_PATTERN = "^$"; + public static final String SERVICE_DENY_PROPERTY = "cx.agent.service.deny"; + public static final String DEFAULT_SERVICE_DENY_PATTERN = "^$"; - public static String SERVICE_ALLOW_ASSET_PROPERTY = "cx.agent.service.asset.allow"; - public static String DEFAULT_SERVICE_ALLOW_ASSET_PATTERN = "(http|edc)s://.*"; + public static final String SERVICE_ALLOW_ASSET_PROPERTY = "cx.agent.service.asset.allow"; + public static final String DEFAULT_SERVICE_ALLOW_ASSET_PATTERN = "(http|edc)s://.*"; - public static String SERVICE_DENY_ASSET_PROPERTY = "cx.agent.service.asset.deny"; - public static String DEFAULT_SERVICE_DENY_ASSET_PATTERN = "^$"; + public static final String SERVICE_DENY_ASSET_PROPERTY = "cx.agent.service.asset.deny"; + public static final String DEFAULT_SERVICE_DENY_ASSET_PATTERN = "^$"; /** * precompiled stuff @@ -104,19 +104,22 @@ public class AgentConfig { /** * creates the typed config + * * @param monitor logger * @param config untyped config */ public AgentConfig(Monitor monitor, Config config) { this.monitor = monitor; this.config = config; - serviceAllowPattern=Pattern.compile(config.getString(SERVICE_ALLOW_PROPERTY,DEFAULT_SERVICE_ALLOW_PATTERN)); - serviceDenyPattern=Pattern.compile(config.getString(SERVICE_DENY_PROPERTY,DEFAULT_SERVICE_DENY_PATTERN)); - serviceAssetAllowPattern=Pattern.compile(config.getString(SERVICE_ALLOW_ASSET_PROPERTY,DEFAULT_SERVICE_ALLOW_ASSET_PATTERN)); - serviceAssetDenyPattern=Pattern.compile(config.getString(SERVICE_DENY_ASSET_PROPERTY,DEFAULT_SERVICE_DENY_ASSET_PATTERN)); + serviceAllowPattern = Pattern.compile(config.getString(SERVICE_ALLOW_PROPERTY, DEFAULT_SERVICE_ALLOW_PATTERN)); + serviceDenyPattern = Pattern.compile(config.getString(SERVICE_DENY_PROPERTY, DEFAULT_SERVICE_DENY_PATTERN)); + serviceAssetAllowPattern = Pattern.compile(config.getString(SERVICE_ALLOW_ASSET_PROPERTY, DEFAULT_SERVICE_ALLOW_ASSET_PATTERN)); + serviceAssetDenyPattern = Pattern.compile(config.getString(SERVICE_DENY_ASSET_PROPERTY, DEFAULT_SERVICE_DENY_ASSET_PATTERN)); } /** + * access + * * @return callback endpoint */ public String getCallbackEndpoint() { @@ -124,6 +127,8 @@ public String getCallbackEndpoint() { } /** + * access + * * @return the name of the default asset/graph */ public String getDefaultAsset() { @@ -135,17 +140,21 @@ public String getBusinessPartnerNumber() { } /** + * access + * * @return initial file to load */ public String[] getAssetFiles() { - String[] files= config.getString(ASSET_FILE_PROPERTY,"").split(","); - if(files.length==1 && (files[0]==null || files[0].length()==0)) { + String[] files = config.getString(ASSET_FILE_PROPERTY, "").split(","); + if (files.length == 1 && (files[0] == null || files[0].length() == 0)) { return null; } return files; } /** + * access + * * @return name of the sparql access point */ public String getAccessPoint() { @@ -153,32 +162,40 @@ public String getAccessPoint() { } /** + * access + * * @return uri of the control plane management endpoint (without concrete api) */ public String getControlPlaneManagementUrl() { - return config.getString(CONTROL_PLANE_MANAGEMENT,null); + return config.getString(CONTROL_PLANE_MANAGEMENT, null); } /** + * access + * * @return uri of the control plane management endpoint (without concrete api) */ public String getControlPlaneManagementProviderUrl() { - return config.getString(CONTROL_PLANE_MANAGEMENT_PROVIDER,config.getString(CONTROL_PLANE_MANAGEMENT,null)); + return config.getString(CONTROL_PLANE_MANAGEMENT_PROVIDER, config.getString(CONTROL_PLANE_MANAGEMENT, null)); } /** + * access + * * @return uri of the control plane ids endpoint (without concrete api) */ public String getControlPlaneIdsUrl() { - return config.getString(CONTROL_PLANE_IDS,null); + return config.getString(CONTROL_PLANE_IDS, null); } /** + * access + * * @return a map of key/value paris to be used when interacting with the control plane management endpoint */ public Map getControlPlaneManagementHeaders() { - String key = config.getString(CONTROL_PLANE_AUTH_HEADER,"X-Api-Key"); - String value = config.getString(CONTROL_PLANE_AUTH_VALUE,null); + String key = config.getString(CONTROL_PLANE_AUTH_HEADER, "X-Api-Key"); + String value = config.getString(CONTROL_PLANE_AUTH_VALUE, null); if (key != null && value != null) { return Map.of(key, value); } @@ -186,45 +203,57 @@ public Map getControlPlaneManagementHeaders() { } /** + * access + * * @return the default overall timeout when waiting for a negotation result */ public long getNegotiationTimeout() { - return config.getLong(NEGOTIATION_TIMEOUT_PROPERTY,DEFAULT_NEGOTIATION_TIMEOUT); + return config.getLong(NEGOTIATION_TIMEOUT_PROPERTY, DEFAULT_NEGOTIATION_TIMEOUT); } /** + * access + * * @return the thread pool size of the agent executors */ public int getThreadPoolSize() { - return config.getInteger(THREAD_POOL_SIZE,DEFAULT_THREAD_POOL_SIZE); + return config.getInteger(THREAD_POOL_SIZE, DEFAULT_THREAD_POOL_SIZE); } /** + * access + * * @return the default overall timeout when waiting for a negotation result */ public long getNegotiationPollInterval() { - return config.getLong(NEGOTIATION_POLLINTERVAL_PROPERTY,DEFAULT_NEGOTIATION_POLLINTERVAL); + return config.getLong(NEGOTIATION_POLLINTERVAL_PROPERTY, DEFAULT_NEGOTIATION_POLLINTERVAL); } /** + * access + * * @return the synchronization interval between individual sync calls, -1 if no sync */ public long getDataspaceSynchronizationInterval() { - return config.getLong(DATASPACE_SYNCINTERVAL_PROPERTY,DEFAULT_DATASPACE_SYNCINTERVAL); + return config.getLong(DATASPACE_SYNCINTERVAL_PROPERTY, DEFAULT_DATASPACE_SYNCINTERVAL); } /** + * access + * * @return array of connector urls to synchronize, null if no sync */ public String[] getDataspaceSynchronizationConnectors() { - String[] connectors= config.getString(DATASPACE_SYNCCONNECTORS_PROPERTY,"").split(","); - if(connectors.length==1 && (connectors[0]==null || connectors[0].length()==0)) { + String[] connectors = config.getString(DATASPACE_SYNCCONNECTORS_PROPERTY, "").split(","); + if (connectors.length == 1 && (connectors[0] == null || connectors[0].length() == 0)) { return null; } return connectors; } /** + * access + * * @return array of validation endpoints */ public String[] getValidatorEndpoints() { @@ -232,55 +261,71 @@ public String[] getValidatorEndpoints() { } /** + * access + * * @return whether sparql engine is set to verbose */ public boolean isSparqlVerbose() { - return config.getBoolean(VERBOSE_PROPERTY,DEFAULT_VERBOSE_PROPERTY); + return config.getBoolean(VERBOSE_PROPERTY, DEFAULT_VERBOSE_PROPERTY); } /** + * access + * * @return maximal batch size for remote service calls */ public long getFederationServiceBatchSize() { - return config.getLong(FEDERATION_SERVICE_BATCH_SIZE,DEFAULT_FEDERATION_SERVICE_BATCH_SIZE); + return config.getLong(FEDERATION_SERVICE_BATCH_SIZE, DEFAULT_FEDERATION_SERVICE_BATCH_SIZE); } /** + * access + * * @return outgoing socket connect timeout */ public Integer getConnectTimeout() { - return config.getInteger(CONNECT_TIMEOUT_PROPERTY,null); + return config.getInteger(CONNECT_TIMEOUT_PROPERTY, null); } /** + * access + * * @return outgoing socket read timeout */ public Integer getReadTimeout() { - return config.getInteger(READ_TIMEOUT_PROPERTY,DEFAULT_READ_TIMEOUT); + return config.getInteger(READ_TIMEOUT_PROPERTY, DEFAULT_READ_TIMEOUT); } /** + * access + * * @return outgoing socket write timeout */ public Integer getWriteTimeout() { - return config.getInteger(WRITE_TIMEOUT_PROPERTY,null); + return config.getInteger(WRITE_TIMEOUT_PROPERTY, null); } /** + * access + * * @return outgoing socket write timeout */ public Integer getCallTimeout() { - return config.getInteger(CALL_TIMEOUT_PROPERTY,null); + return config.getInteger(CALL_TIMEOUT_PROPERTY, null); } /** + * access + * * @return default skill contract */ public String getDefaultSkillContract() { - return config.getString(DEFAULT_SKILL_CONTRACT_PROPERTY,null); + return config.getString(DEFAULT_SKILL_CONTRACT_PROPERTY, null); } /** + * access + * * @return regular expression for allowed service URLs */ public Pattern getServiceAllowPattern() { @@ -288,13 +333,17 @@ public Pattern getServiceAllowPattern() { } /** + * access + * * @return regular expression for denied service URLs */ public Pattern getServiceDenyPattern() { return serviceDenyPattern; } - /** + /** + * access + * * @return regular expression for allowed service URLs in assets */ public Pattern getServiceAssetAllowPattern() { @@ -302,6 +351,8 @@ public Pattern getServiceAssetAllowPattern() { } /** + * access + * * @return regular expression for denied service URLs in assets */ public Pattern getServiceAssetDenyPattern() { diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgentExtension.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgentExtension.java index 7814e31..806357e 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgentExtension.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgentExtension.java @@ -16,36 +16,35 @@ // SPDX-License-Identifier: Apache-2.0 package org.eclipse.tractusx.agents.edc; +import okhttp3.OkHttpClient; +import org.apache.jena.query.Syntax; +import org.apache.jena.sparql.serializer.SerializerRegistry; +import org.apache.jena.sparql.service.ServiceExecutorRegistry; +import org.eclipse.edc.connector.dataplane.http.params.HttpRequestFactory; import org.eclipse.edc.connector.dataplane.http.spi.HttpRequestParamsProvider; +import org.eclipse.edc.connector.dataplane.spi.pipeline.PipelineService; +import org.eclipse.edc.runtime.metamodel.annotation.Inject; import org.eclipse.edc.runtime.metamodel.annotation.Requires; +import org.eclipse.edc.spi.http.EdcHttpClient; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.security.Vault; +import org.eclipse.edc.spi.system.ServiceExtension; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.eclipse.edc.spi.types.TypeManager; +import org.eclipse.edc.web.spi.WebService; import org.eclipse.tractusx.agents.edc.http.AgentController; -import org.eclipse.tractusx.agents.edc.http.DelegationService; +import org.eclipse.tractusx.agents.edc.http.DelegationServiceImpl; import org.eclipse.tractusx.agents.edc.http.HttpClientFactory; import org.eclipse.tractusx.agents.edc.http.transfer.AgentSourceFactory; import org.eclipse.tractusx.agents.edc.http.transfer.AgentSourceRequestParamsSupplier; -import org.eclipse.tractusx.agents.edc.rdf.RDFStore; +import org.eclipse.tractusx.agents.edc.rdf.RdfStore; +import org.eclipse.tractusx.agents.edc.service.DataManagement; import org.eclipse.tractusx.agents.edc.service.DataspaceSynchronizer; import org.eclipse.tractusx.agents.edc.service.EdcSkillStore; import org.eclipse.tractusx.agents.edc.sparql.DataspaceServiceExecutor; import org.eclipse.tractusx.agents.edc.sparql.SparqlQueryProcessor; import org.eclipse.tractusx.agents.edc.sparql.SparqlQuerySerializerFactory; import org.eclipse.tractusx.agents.edc.validation.SwitchingDataPlaneTokenValidatorController; -import org.apache.jena.query.Syntax; -import org.apache.jena.sparql.serializer.*; -import org.apache.jena.sparql.service.ServiceExecutorRegistry; -import org.eclipse.edc.connector.dataplane.http.params.HttpRequestFactory; -import org.eclipse.edc.spi.http.EdcHttpClient; -import org.eclipse.edc.web.spi.WebService; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.security.Vault; -import org.eclipse.edc.runtime.metamodel.annotation.Inject; -import org.eclipse.edc.spi.system.ServiceExtension; -import org.eclipse.edc.spi.system.ServiceExtensionContext; -import okhttp3.OkHttpClient; -import org.eclipse.tractusx.agents.edc.service.DataManagement; - -import org.eclipse.edc.connector.dataplane.spi.pipeline.PipelineService; -import org.eclipse.edc.spi.types.TypeManager; import java.util.Map; import java.util.concurrent.Executors; @@ -63,8 +62,8 @@ public class AgentExtension implements ServiceExtension { */ protected static final String DEFAULT_CONTEXT_ALIAS = "default"; protected static final String CALLBACK_CONTEXT_ALIAS = "callback"; - public static Pattern GRAPH_PATTERN=Pattern.compile("((?[^#]+)#)?(?.*Graph(Asset)?.*)"); - public static Pattern SKILL_PATTERN=Pattern.compile("((?[^#]+)#)?(?.*Skill(Asset)?.*)"); + public static final Pattern GRAPH_PATTERN = Pattern.compile("((?[^#]+)#)?(?.*Graph(Asset)?.*)"); + public static final Pattern SKILL_PATTERN = Pattern.compile("((?[^#]+)#)?(?.*Skill(Asset)?.*)"); /** @@ -101,6 +100,8 @@ public class AgentExtension implements ServiceExtension { protected DataspaceSynchronizer synchronizer; /** + * access + * * @return name of the extension */ @Override @@ -110,39 +111,40 @@ public String name() { /** * runs on extension initialization + * * @param context EDC bootstrap context */ @Override public void initialize(ServiceExtensionContext context) { Monitor monitor = context.getMonitor(); - monitor.debug(String.format("Initializing %s",name())); + monitor.debug(String.format("Initializing %s", name())); - AgentConfig config = new AgentConfig(monitor,context.getConfig()); - Map.Entry instance = HttpClientFactory.create(edcHttpClient,httpClient,pipelineService,config); - edcHttpClient=instance.getKey(); - httpClient=instance.getValue(); + AgentConfig config = new AgentConfig(monitor, context.getConfig()); + Map.Entry instance = HttpClientFactory.create(edcHttpClient, httpClient, pipelineService, config); + edcHttpClient = instance.getKey(); + httpClient = instance.getValue(); - DataManagement catalogService=new DataManagement(monitor,typeManager,httpClient,config); + DataManagement catalogService = new DataManagement(monitor, typeManager, httpClient, config); - AgreementController agreementController=new AgreementController(monitor,config,catalogService); - monitor.debug(String.format("Registering agreement controller %s",agreementController)); + AgreementControllerImpl agreementController = new AgreementControllerImpl(monitor, config, catalogService); + monitor.debug(String.format("Registering agreement controller %s", agreementController)); webService.registerResource(CALLBACK_CONTEXT_ALIAS, agreementController); - RDFStore rdfStore=new RDFStore(config,monitor); + RdfStore rdfStore = new RdfStore(config, monitor); - executorService= Executors.newScheduledThreadPool(config.getThreadPoolSize()); - synchronizer=new DataspaceSynchronizer(executorService,config,catalogService,rdfStore,monitor); + executorService = Executors.newScheduledThreadPool(config.getThreadPoolSize()); + synchronizer = new DataspaceSynchronizer(executorService, config, catalogService, rdfStore, monitor); - SwitchingDataPlaneTokenValidatorController validatorController=new SwitchingDataPlaneTokenValidatorController(httpClient,config,monitor); - if(validatorController.isEnabled()) { - monitor.debug(String.format("Registering switching validator controller %s",validatorController)); - webService.registerResource(DEFAULT_CONTEXT_ALIAS,validatorController); + SwitchingDataPlaneTokenValidatorController validatorController = new SwitchingDataPlaneTokenValidatorController(httpClient, config, monitor); + if (validatorController.isEnabled()) { + monitor.debug(String.format("Registering switching validator controller %s", validatorController)); + webService.registerResource(DEFAULT_CONTEXT_ALIAS, validatorController); } // EDC Remoting Support ServiceExecutorRegistry reg = new ServiceExecutorRegistry(); - reg.addBulkLink(new DataspaceServiceExecutor(monitor,agreementController,config,httpClient,executorService,typeManager)); + reg.addBulkLink(new DataspaceServiceExecutor(monitor, agreementController, config, httpClient, executorService, typeManager)); //reg.add(new DataspaceServiceExecutor(monitor,agreementController,config,httpClient)); // Ontop and other deep nesting-afraid providers/optimizers @@ -153,19 +155,19 @@ public void initialize(ServiceExtensionContext context) { SerializerRegistry.get().addQuerySerializer(Syntax.syntaxSPARQL_11, arqQuerySerializerFactory); // the actual sparql engine inside the EDC - SparqlQueryProcessor processor=new SparqlQueryProcessor(reg,monitor,config,rdfStore, typeManager); + SparqlQueryProcessor processor = new SparqlQueryProcessor(reg, monitor, config, rdfStore, typeManager); // stored procedure store and transport endpoint - ISkillStore skillStore=new EdcSkillStore(catalogService,typeManager,config); - DelegationService delegationService=new DelegationService(agreementController,monitor,httpClient,typeManager,config); - AgentController agentController=new AgentController(monitor,agreementController,config,processor,skillStore,delegationService); - monitor.debug(String.format("Registering agent controller %s",agentController)); + SkillStore skillStore = new EdcSkillStore(catalogService, typeManager, config); + DelegationServiceImpl delegationService = new DelegationServiceImpl(agreementController, monitor, httpClient, typeManager, config); + AgentController agentController = new AgentController(monitor, agreementController, config, processor, skillStore, delegationService); + monitor.debug(String.format("Registering agent controller %s", agentController)); webService.registerResource(DEFAULT_CONTEXT_ALIAS, agentController); - monitor.debug(String.format("Initialized %s",name())); + monitor.debug(String.format("Initialized %s", name())); HttpRequestFactory httpRequestFactory = new HttpRequestFactory(); - AgentSourceFactory sourceFactory = new AgentSourceFactory(edcHttpClient, new AgentSourceRequestParamsSupplier(vault,typeManager,config,monitor),monitor,httpRequestFactory, processor, skillStore); + AgentSourceFactory sourceFactory = new AgentSourceFactory(edcHttpClient, new AgentSourceRequestParamsSupplier(vault, typeManager, config, monitor), monitor, httpRequestFactory, processor, skillStore); pipelineService.registerFactory(sourceFactory); } diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgentProtocol.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgentProtocol.java index 54027a4..00c8447 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgentProtocol.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgentProtocol.java @@ -27,7 +27,7 @@ public enum AgentProtocol { private final String protocolId; AgentProtocol(String protocolId) { - this.protocolId=protocolId; + this.protocolId = protocolId; } public String getProtocolId() { diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgreementController.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgreementController.java index 5bbc4ec..1254e36 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgreementController.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgreementController.java @@ -16,394 +16,29 @@ // SPDX-License-Identifier: Apache-2.0 package org.eclipse.tractusx.agents.edc; -import com.nimbusds.jose.JWSObject; -import jakarta.json.JsonValue; -import jakarta.ws.rs.*; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.types.domain.DataAddress; -import org.eclipse.edc.spi.types.domain.callback.CallbackAddress; +import jakarta.ws.rs.WebApplicationException; import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; -import org.eclipse.tractusx.agents.edc.jsonld.JsonLd; -import org.eclipse.tractusx.agents.edc.model.*; -import org.eclipse.tractusx.agents.edc.service.*; - -import java.io.IOException; -import java.text.ParseException; -import java.util.*; - /** - * An endpoint/service that receives information from the control plane + * Interface to any agreement controller */ -@Consumes({MediaType.APPLICATION_JSON}) -@Path("/endpoint-data-reference") -public class AgreementController implements IAgreementController { - - /** - * which transfer to use - */ - public static String TRANSFER_TYPE="HttpProxy"; - - /** - * EDC service references - */ - protected final Monitor monitor; - protected final DataManagement dataManagement; - protected final AgentConfig config; - - /** - * memory store for links from assets to the actual transfer addresses - * TODO make this a distributed cache - * TODO let this cache evict invalidate references automatically - */ - // hosts all pending processes - protected final Set activeAssets = new HashSet<>(); - // any contract agreements indexed by asset - protected final Map agreementStore = new HashMap<>(); - // any transfer processes indexed by asset, the current process should - // always adhere to the above agreement - protected final Map processStore = new HashMap<>(); - // at the end of provisioning and endpoint reference will be set - // that fits to the current transfer process - protected final Map endpointStore = new HashMap<>(); - - /** - * creates an agreement controller - * - * @param monitor logger - * @param config typed config - * @param dataManagement data management service wrapper - */ - public AgreementController(Monitor monitor, AgentConfig config, DataManagement dataManagement) { - this.monitor = monitor; - this.dataManagement = dataManagement; - this.config = config; - } - - /** - * render nicely - */ - @Override - public String toString() { - return super.toString() + "/endpoint-data-reference"; - } - - /** - * this is called by the control plane when an agreement has been made - * - * @param dataReference contains the actual call token - */ - @POST - public void receiveEdcCallback(EndpointDataReference dataReference) { - var agreementId = dataReference.getId(); - monitor.debug(String.format("An endpoint data reference for agreement %s has been posted.", agreementId)); - synchronized (agreementStore) { - for (Map.Entry process : processStore.entrySet()) { - if (process.getValue().getId().equals(agreementId)) { - synchronized (endpointStore) { - monitor.debug(String.format("Agreement %s belongs to asset %s.", agreementId, process.getKey())); - endpointStore.put(process.getKey(), dataReference); - return; - } - } - } - } - monitor.debug(String.format("Agreement %s has no active asset. Guess that came for another plane. Ignoring.", agreementId)); - } +public interface AgreementController { /** - * accesses an active endpoint for the given asset + * check whether an agreement for the asset already exists * - * @param assetId id of the agreed asset - * @return endpoint found, null if not found or invalid - */ - @Override - public EndpointDataReference get(String assetId) { - synchronized (activeAssets) { - if (!activeAssets.contains(assetId)) { - monitor.debug(String.format("Asset %s is not active", assetId)); - return null; - } - synchronized (endpointStore) { - EndpointDataReference result = endpointStore.get(assetId); - if (result != null) { - String token = result.getAuthCode(); - if (token != null) { - try { - JWSObject jwt = JWSObject.parse(token); - Object expiryObject=jwt.getPayload().toJSONObject().get("exp"); - if(expiryObject instanceof Long) { - // token times are in seconds - if(!new Date((Long) expiryObject*1000).before(new Date(System.currentTimeMillis() + 30 * 1000))) { - return result; - } - } - } catch(ParseException | NumberFormatException e) { - monitor.debug(String.format("Active asset %s has invalid agreement token.", assetId)); - } - } - endpointStore.remove(assetId); - } - monitor.debug(String.format("Active asset %s has timed out or was not installed.", assetId)); - synchronized (processStore) { - processStore.remove(assetId); - synchronized (agreementStore) { - ContractAgreement agreement = agreementStore.get(assetId); - if (agreement != null && agreement.getContractSigningDate()+600000L <= System.currentTimeMillis()) { - agreementStore.remove(assetId); - } - activeAssets.remove(assetId); - } - } - } - } - return null; - } - - /** - * sets active - * @param asset name - */ - protected void activate(String asset) { - synchronized (activeAssets) { - if (activeAssets.contains(asset)) { - throw new ClientErrorException("Cannot agree on an already active asset.", Response.Status.CONFLICT); - } - activeAssets.add(asset); - } - } - - /** - * sets active - * @param asset name - */ - protected void deactivate(String asset) { - synchronized (activeAssets) { - activeAssets.remove(asset); - } - synchronized (agreementStore) { - agreementStore.remove(asset); - } - synchronized (processStore) { - processStore.remove(asset); - } - } - - /** - * register an agreement - * @param asset name - * @param agreement object - */ - protected void registerAgreement(String asset, ContractAgreement agreement) { - synchronized (agreementStore) { - agreementStore.put(asset, agreement); - } - } - - /** - * register a process - * @param asset name - * @param process object + * @param asset id of the asset + * @return endpoint data reference, null if non-existant */ - protected void registerProcess(String asset, TransferProcess process) { - synchronized (processStore) { - processStore.put(asset, process); - } - } + EndpointDataReference get(String asset); /** - * creates a new agreement (asynchronously) - * and waits for the result + * negotiates an endpoint for the given asset * - * @param remoteUrl ids endpoint url of the remote connector - * @param asset name of the asset to agree upon - * TODO make this federation aware: multiple assets, different policies + * @param remoteUrl the connector + * @param asset id of the asset + * @return endpoint data reference + * @throws WebApplicationException in case agreement could not be made (in time) */ - @Override - public EndpointDataReference createAgreement(String remoteUrl, String asset) throws WebApplicationException { - monitor.debug(String.format("About to create an agreement for asset %s at connector %s",asset,remoteUrl)); - - activate(asset); - - DcatCatalog contractOffers; - - try { - contractOffers=dataManagement.findContractOffers(remoteUrl, asset); - } catch(IOException io) { - deactivate(asset); - throw new InternalServerErrorException(String.format("Error when resolving contract offers from %s for asset %s through data management api.",remoteUrl,asset),io); - } - - if (contractOffers.getDatasets().isEmpty()) { - deactivate(asset); - throw new BadRequestException(String.format("There is no contract offer in remote connector %s related to asset %s.", remoteUrl, asset)); - } - - // TODO implement a cost-based offer choice - DcatDataset contractOffer = contractOffers.getDatasets().get(0); - Map assetProperties = DataspaceSynchronizer.getProperties(contractOffer); - OdrlPolicy policy=contractOffer.hasPolicy(); - String offerId= policy.getId(); - JsonValue offerType=assetProperties.get("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"); - monitor.debug(String.format("About to create an agreement for contract offer %s (for asset %s of type %s at connector %s)",offerId,asset, - offerType,remoteUrl)); - - var contractOfferDescription = new ContractOfferDescription( - offerId, - asset, - policy - ); - var contractNegotiationRequest = ContractNegotiationRequest.Builder.newInstance() - .offerId(contractOfferDescription) - .connectorId("provider") - .connectorAddress(String.format(DataManagement.DSP_PATH, remoteUrl)) - .protocol("dataspace-protocol-http") - .localBusinessPartnerNumber(config.getBusinessPartnerNumber()) - .remoteBusinessPartnerNumber(contractOffers.getParticipantId()) - .build(); - String negotiationId; - - try { - negotiationId=dataManagement.initiateNegotiation(contractNegotiationRequest); - } catch(IOException ioe) { - deactivate(asset); - throw new InternalServerErrorException(String.format("Error when initiating negotation for offer %s through data management api.",offerId),ioe); - } - - monitor.debug(String.format("About to check negotiation %s for contract offer %s (for asset %s at connector %s)",negotiationId,offerId,asset,remoteUrl)); - - // Check negotiation state - ContractNegotiation negotiation = null; - - long startTime = System.currentTimeMillis(); - - try { - while ((System.currentTimeMillis() - startTime < config.getNegotiationTimeout()) - && (negotiation == null || - (!negotiation.getState().equals("FINALIZED") && !negotiation.getState().equals("TERMINATED")))) { - Thread.sleep(config.getNegotiationPollInterval()); - negotiation = dataManagement.getNegotiation( - negotiationId - ); - } - } catch (InterruptedException e) { - monitor.info(String.format("Negotiation thread for asset %s negotiation %s has been interrupted. Giving up.", asset, negotiationId),e); - } catch(IOException e) { - monitor.warning(String.format("Negotiation thread for asset %s negotiation %s run into problem. Giving up.", asset, negotiationId),e); - } - - if (negotiation == null || !negotiation.getState().equals("FINALIZED")) { - deactivate(asset); - if(negotiation!=null) { - String errorDetail=negotiation.getErrorDetail(); - if(errorDetail!=null) { - monitor.severe(String.format("Contract Negotiation %s failed because of %s",negotiationId,errorDetail)); - } - } - throw new InternalServerErrorException(String.format("Contract Negotiation %s for asset %s was not successful.", negotiationId, asset)); - } - - monitor.debug(String.format("About to check agreement %s for contract offer %s (for asset %s at connector %s)",negotiation.getContractAgreementId(),offerId,asset,remoteUrl)); - - ContractAgreement agreement; - - try { - agreement=dataManagement.getAgreement(negotiation.getContractAgreementId()); - } catch(IOException ioe) { - deactivate(asset); - throw new InternalServerErrorException(String.format("Error when retrieving agreement %s for negotiation %s.",negotiation.getContractAgreementId(),negotiationId),ioe); - } - - if (agreement == null || !agreement.getAssetId().endsWith(asset)) { - deactivate(asset); - throw new InternalServerErrorException(String.format("Agreement %s does not refer to asset %s.", negotiation.getContractAgreementId(), asset)); - } - - registerAgreement(asset,agreement); - - DataAddress dataDestination = DataAddress.Builder.newInstance() - .type(TRANSFER_TYPE) - .build(); - - CallbackAddress address= - CallbackAddress.Builder.newInstance().uri(config.getCallbackEndpoint()).build(); - - TransferRequest transferRequest = TransferRequest.Builder.newInstance() - .assetId(asset) - .contractId(agreement.getId()) - .connectorId(config.getBusinessPartnerNumber()) - .connectorAddress(String.format(DataManagement.DSP_PATH, remoteUrl)) - .protocol("dataspace-protocol-http") - .dataDestination(dataDestination) - .managedResources(false) - .callbackAddresses(List.of(address)) - .build(); - - monitor.debug(String.format("About to initiate transfer for agreement %s (for asset %s at connector %s)",negotiation.getContractAgreementId(),asset,remoteUrl)); - - String transferId; - - try { - transferId=dataManagement.initiateHttpProxyTransferProcess(transferRequest); - } catch(IOException ioe) { - deactivate(asset); - throw new InternalServerErrorException(String.format("HttpProxy transfer for agreement %s could not be initiated.", agreement.getId()),ioe); - } - - monitor.debug(String.format("About to check transfer %s (for asset %s at connector %s)",transferId,asset,remoteUrl)); - - // Check negotiation state - TransferProcess process = null; - - startTime = System.currentTimeMillis(); - - try { - while ((System.currentTimeMillis() - startTime < config.getNegotiationTimeout()) && (process == null || !process.getState().equals("COMPLETED"))) { - Thread.sleep(config.getNegotiationPollInterval()); - process = dataManagement.getTransfer( - transferId - ); - registerProcess(asset, process); - } - } catch (InterruptedException e) { - monitor.info(String.format("Process thread for asset %s transfer %s has been interrupted. Giving up.", asset, transferId),e); - } catch(IOException e) { - monitor.warning(String.format("Process thread for asset %s transfer %s run into problem. Giving up.", asset, transferId),e); - } - - if (process == null || !process.getState().equals("COMPLETED")) { - deactivate(asset); - throw new InternalServerErrorException(String.format("Transfer process %s for agreement %s and asset %s could not be provisioned.", transferId, agreement.getId(), asset)); - } - - // finally wait a bit for the endpoint data reference in case - // that the process was signalled earlier than the callbacks - startTime = System.currentTimeMillis(); - - EndpointDataReference reference=null; - - try { - while ((System.currentTimeMillis() - startTime < config.getNegotiationTimeout()) && (reference == null)) { - Thread.sleep(config.getNegotiationPollInterval()); - synchronized(endpointStore) { - reference=endpointStore.get(asset); - } - } - } catch (InterruptedException e) { - monitor.info(String.format("Wait thread for reference to asset %s has been interrupted. Giving up.", asset),e); - } - - // mark the type in the endpoint - if(reference!=null) { - for(Map.Entry prop : assetProperties.entrySet()) { - reference.getProperties().put(prop.getKey(), JsonLd.asString(prop.getValue())); - } - } - - // now delegate to the original getter - return get(asset); - } - + EndpointDataReference createAgreement(String remoteUrl, String asset) throws WebApplicationException; } diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgreementControllerImpl.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgreementControllerImpl.java new file mode 100644 index 0000000..974dfdc --- /dev/null +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgreementControllerImpl.java @@ -0,0 +1,433 @@ +// Copyright (c) 2022,2023 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc; + +import com.nimbusds.jose.JWSObject; +import jakarta.json.JsonValue; +import jakarta.ws.rs.BadRequestException; +import jakarta.ws.rs.ClientErrorException; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.InternalServerErrorException; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.types.domain.DataAddress; +import org.eclipse.edc.spi.types.domain.callback.CallbackAddress; +import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; +import org.eclipse.tractusx.agents.edc.jsonld.JsonLd; +import org.eclipse.tractusx.agents.edc.model.ContractAgreement; +import org.eclipse.tractusx.agents.edc.model.ContractNegotiation; +import org.eclipse.tractusx.agents.edc.model.ContractNegotiationRequest; +import org.eclipse.tractusx.agents.edc.model.ContractOfferDescription; +import org.eclipse.tractusx.agents.edc.model.DcatCatalog; +import org.eclipse.tractusx.agents.edc.model.DcatDataset; +import org.eclipse.tractusx.agents.edc.model.OdrlPolicy; +import org.eclipse.tractusx.agents.edc.model.TransferProcess; +import org.eclipse.tractusx.agents.edc.model.TransferRequest; +import org.eclipse.tractusx.agents.edc.service.DataManagement; +import org.eclipse.tractusx.agents.edc.service.DataspaceSynchronizer; + +import java.io.IOException; +import java.text.ParseException; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + + +/** + * An endpoint/service that receives information from the control plane + */ +@Consumes({MediaType.APPLICATION_JSON}) +@Path("/endpoint-data-reference") +public class AgreementControllerImpl implements AgreementController { + + /** + * which transfer to use + */ + public static final String TRANSFER_TYPE = "HttpProxy"; + + /** + * EDC service references + */ + protected final Monitor monitor; + protected final DataManagement dataManagement; + protected final AgentConfig config; + + /** + * memory store for links from assets to the actual transfer addresses + * TODO make this a distributed cache + * TODO let this cache evict invalidate references automatically + */ + // hosts all pending processes + protected final Set activeAssets = new HashSet<>(); + // any contract agreements indexed by asset + protected final Map agreementStore = new HashMap<>(); + // any transfer processes indexed by asset, the current process should + // always adhere to the above agreement + protected final Map processStore = new HashMap<>(); + // at the end of provisioning and endpoint reference will be set + // that fits to the current transfer process + protected final Map endpointStore = new HashMap<>(); + + /** + * creates an agreement controller + * + * @param monitor logger + * @param config typed config + * @param dataManagement data management service wrapper + */ + public AgreementControllerImpl(Monitor monitor, AgentConfig config, DataManagement dataManagement) { + this.monitor = monitor; + this.dataManagement = dataManagement; + this.config = config; + } + + /** + * render nicely + */ + @Override + public String toString() { + return super.toString() + "/endpoint-data-reference"; + } + + /** + * this is called by the control plane when an agreement has been made + * + * @param dataReference contains the actual call token + */ + @POST + public void receiveEdcCallback(EndpointDataReference dataReference) { + var agreementId = dataReference.getId(); + monitor.debug(String.format("An endpoint data reference for agreement %s has been posted.", agreementId)); + synchronized (agreementStore) { + for (Map.Entry process : processStore.entrySet()) { + if (process.getValue().getId().equals(agreementId)) { + synchronized (endpointStore) { + monitor.debug(String.format("Agreement %s belongs to asset %s.", agreementId, process.getKey())); + endpointStore.put(process.getKey(), dataReference); + return; + } + } + } + } + monitor.debug(String.format("Agreement %s has no active asset. Guess that came for another plane. Ignoring.", agreementId)); + } + + /** + * accesses an active endpoint for the given asset + * + * @param assetId id of the agreed asset + * @return endpoint found, null if not found or invalid + */ + @Override + public EndpointDataReference get(String assetId) { + synchronized (activeAssets) { + if (!activeAssets.contains(assetId)) { + monitor.debug(String.format("Asset %s is not active", assetId)); + return null; + } + synchronized (endpointStore) { + EndpointDataReference result = endpointStore.get(assetId); + if (result != null) { + String token = result.getAuthCode(); + if (token != null) { + try { + JWSObject jwt = JWSObject.parse(token); + Object expiryObject = jwt.getPayload().toJSONObject().get("exp"); + if (expiryObject instanceof Long) { + // token times are in seconds + if (!new Date((Long) expiryObject * 1000).before(new Date(System.currentTimeMillis() + 30 * 1000))) { + return result; + } + } + } catch (ParseException | NumberFormatException e) { + monitor.debug(String.format("Active asset %s has invalid agreement token.", assetId)); + } + } + endpointStore.remove(assetId); + } + monitor.debug(String.format("Active asset %s has timed out or was not installed.", assetId)); + synchronized (processStore) { + processStore.remove(assetId); + synchronized (agreementStore) { + ContractAgreement agreement = agreementStore.get(assetId); + if (agreement != null && agreement.getContractSigningDate() + 600000L <= System.currentTimeMillis()) { + agreementStore.remove(assetId); + } + activeAssets.remove(assetId); + } + } + } + } + return null; + } + + /** + * sets active + * + * @param asset name + */ + protected void activate(String asset) { + synchronized (activeAssets) { + if (activeAssets.contains(asset)) { + throw new ClientErrorException("Cannot agree on an already active asset.", Response.Status.CONFLICT); + } + activeAssets.add(asset); + } + } + + /** + * sets active + * + * @param asset name + */ + protected void deactivate(String asset) { + synchronized (activeAssets) { + activeAssets.remove(asset); + } + synchronized (agreementStore) { + agreementStore.remove(asset); + } + synchronized (processStore) { + processStore.remove(asset); + } + } + + /** + * register an agreement + * + * @param asset name + * @param agreement object + */ + protected void registerAgreement(String asset, ContractAgreement agreement) { + synchronized (agreementStore) { + agreementStore.put(asset, agreement); + } + } + + /** + * register a process + * + * @param asset name + * @param process object + */ + protected void registerProcess(String asset, TransferProcess process) { + synchronized (processStore) { + processStore.put(asset, process); + } + } + + /** + * creates a new agreement (asynchronously) + * and waits for the result + * TODO make this federation aware: multiple assets, different policies + * + * @param remoteUrl ids endpoint url of the remote connector + * @param asset name of the asset to agree upon + */ + @Override + public EndpointDataReference createAgreement(String remoteUrl, String asset) throws WebApplicationException { + monitor.debug(String.format("About to create an agreement for asset %s at connector %s", asset, remoteUrl)); + + activate(asset); + + DcatCatalog contractOffers; + + try { + contractOffers = dataManagement.findContractOffers(remoteUrl, asset); + } catch (IOException io) { + deactivate(asset); + throw new InternalServerErrorException(String.format("Error when resolving contract offers from %s for asset %s through data management api.", remoteUrl, asset), io); + } + + if (contractOffers.getDatasets().isEmpty()) { + deactivate(asset); + throw new BadRequestException(String.format("There is no contract offer in remote connector %s related to asset %s.", remoteUrl, asset)); + } + + // TODO implement a cost-based offer choice + DcatDataset contractOffer = contractOffers.getDatasets().get(0); + Map assetProperties = DataspaceSynchronizer.getProperties(contractOffer); + OdrlPolicy policy = contractOffer.hasPolicy(); + String offerId = policy.getId(); + JsonValue offerType = assetProperties.get("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"); + monitor.debug(String.format("About to create an agreement for contract offer %s (for asset %s of type %s at connector %s)", offerId, asset, + offerType, remoteUrl)); + + var contractOfferDescription = new ContractOfferDescription( + offerId, + asset, + policy + ); + var contractNegotiationRequest = ContractNegotiationRequest.Builder.newInstance() + .offerId(contractOfferDescription) + .connectorId("provider") + .connectorAddress(String.format(DataManagement.DSP_PATH, remoteUrl)) + .protocol("dataspace-protocol-http") + .localBusinessPartnerNumber(config.getBusinessPartnerNumber()) + .remoteBusinessPartnerNumber(contractOffers.getParticipantId()) + .build(); + String negotiationId; + + try { + negotiationId = dataManagement.initiateNegotiation(contractNegotiationRequest); + } catch (IOException ioe) { + deactivate(asset); + throw new InternalServerErrorException(String.format("Error when initiating negotation for offer %s through data management api.", offerId), ioe); + } + + monitor.debug(String.format("About to check negotiation %s for contract offer %s (for asset %s at connector %s)", negotiationId, offerId, asset, remoteUrl)); + + // Check negotiation state + ContractNegotiation negotiation = null; + + long startTime = System.currentTimeMillis(); + + try { + while ((System.currentTimeMillis() - startTime < config.getNegotiationTimeout()) && + (negotiation == null || + (!negotiation.getState().equals("FINALIZED") && !negotiation.getState().equals("TERMINATED")))) { + Thread.sleep(config.getNegotiationPollInterval()); + negotiation = dataManagement.getNegotiation( + negotiationId + ); + } + } catch (InterruptedException e) { + monitor.info(String.format("Negotiation thread for asset %s negotiation %s has been interrupted. Giving up.", asset, negotiationId), e); + } catch (IOException e) { + monitor.warning(String.format("Negotiation thread for asset %s negotiation %s run into problem. Giving up.", asset, negotiationId), e); + } + + if (negotiation == null || !negotiation.getState().equals("FINALIZED")) { + deactivate(asset); + if (negotiation != null) { + String errorDetail = negotiation.getErrorDetail(); + if (errorDetail != null) { + monitor.severe(String.format("Contract Negotiation %s failed because of %s", negotiationId, errorDetail)); + } + } + throw new InternalServerErrorException(String.format("Contract Negotiation %s for asset %s was not successful.", negotiationId, asset)); + } + + monitor.debug(String.format("About to check agreement %s for contract offer %s (for asset %s at connector %s)", negotiation.getContractAgreementId(), offerId, asset, remoteUrl)); + + ContractAgreement agreement; + + try { + agreement = dataManagement.getAgreement(negotiation.getContractAgreementId()); + } catch (IOException ioe) { + deactivate(asset); + throw new InternalServerErrorException(String.format("Error when retrieving agreement %s for negotiation %s.", negotiation.getContractAgreementId(), negotiationId), ioe); + } + + if (agreement == null || !agreement.getAssetId().endsWith(asset)) { + deactivate(asset); + throw new InternalServerErrorException(String.format("Agreement %s does not refer to asset %s.", negotiation.getContractAgreementId(), asset)); + } + + registerAgreement(asset, agreement); + + DataAddress dataDestination = DataAddress.Builder.newInstance() + .type(TRANSFER_TYPE) + .build(); + + CallbackAddress address = + CallbackAddress.Builder.newInstance().uri(config.getCallbackEndpoint()).build(); + + TransferRequest transferRequest = TransferRequest.Builder.newInstance() + .assetId(asset) + .contractId(agreement.getId()) + .connectorId(config.getBusinessPartnerNumber()) + .connectorAddress(String.format(DataManagement.DSP_PATH, remoteUrl)) + .protocol("dataspace-protocol-http") + .dataDestination(dataDestination) + .managedResources(false) + .callbackAddresses(List.of(address)) + .build(); + + monitor.debug(String.format("About to initiate transfer for agreement %s (for asset %s at connector %s)", negotiation.getContractAgreementId(), asset, remoteUrl)); + + String transferId; + + try { + transferId = dataManagement.initiateHttpProxyTransferProcess(transferRequest); + } catch (IOException ioe) { + deactivate(asset); + throw new InternalServerErrorException(String.format("HttpProxy transfer for agreement %s could not be initiated.", agreement.getId()), ioe); + } + + monitor.debug(String.format("About to check transfer %s (for asset %s at connector %s)", transferId, asset, remoteUrl)); + + // Check negotiation state + TransferProcess process = null; + + startTime = System.currentTimeMillis(); + + try { + while ((System.currentTimeMillis() - startTime < config.getNegotiationTimeout()) && (process == null || !process.getState().equals("COMPLETED"))) { + Thread.sleep(config.getNegotiationPollInterval()); + process = dataManagement.getTransfer( + transferId + ); + registerProcess(asset, process); + } + } catch (InterruptedException e) { + monitor.info(String.format("Process thread for asset %s transfer %s has been interrupted. Giving up.", asset, transferId), e); + } catch (IOException e) { + monitor.warning(String.format("Process thread for asset %s transfer %s run into problem. Giving up.", asset, transferId), e); + } + + if (process == null || !process.getState().equals("COMPLETED")) { + deactivate(asset); + throw new InternalServerErrorException(String.format("Transfer process %s for agreement %s and asset %s could not be provisioned.", transferId, agreement.getId(), asset)); + } + + // finally wait a bit for the endpoint data reference in case + // that the process was signalled earlier than the callbacks + startTime = System.currentTimeMillis(); + + EndpointDataReference reference = null; + + try { + while ((System.currentTimeMillis() - startTime < config.getNegotiationTimeout()) && (reference == null)) { + Thread.sleep(config.getNegotiationPollInterval()); + synchronized (endpointStore) { + reference = endpointStore.get(asset); + } + } + } catch (InterruptedException e) { + monitor.info(String.format("Wait thread for reference to asset %s has been interrupted. Giving up.", asset), e); + } + + // mark the type in the endpoint + if (reference != null) { + for (Map.Entry prop : assetProperties.entrySet()) { + reference.getProperties().put(prop.getKey(), JsonLd.asString(prop.getValue())); + } + } + + // now delegate to the original getter + return get(asset); + } + +} diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/IAgreementController.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/IAgreementController.java deleted file mode 100644 index 9982c47..0000000 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/IAgreementController.java +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2022,2023 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc; - -import jakarta.ws.rs.WebApplicationException; -import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; - -/** - * Interface to any agreement controller - */ -public interface IAgreementController { - - /** - * check whether an agreement for the asset already exists - * @param asset id of the asset - * @return endpoint data reference, null if non-existant - */ - EndpointDataReference get(String asset); - /** - * negotiates an endpoint for the given asset - * @param remoteUrl the connector - * @param asset id of the asset - * @return endpoint data reference - * @throws WebApplicationException in case agreement could not be made (in time) - */ - EndpointDataReference createAgreement(String remoteUrl, String asset) throws WebApplicationException; -} diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/MonitorWrapper.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/MonitorWrapper.java index 3dce1af..2d5228b 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/MonitorWrapper.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/MonitorWrapper.java @@ -25,12 +25,12 @@ * A (better) adapter to bridge slf4j to EDC logging */ public class MonitorWrapper extends AbstractLogger { - + final Monitor instance; public MonitorWrapper(String name, Monitor monitor) { this.name = name; - this.instance=monitor; + this.instance = monitor; } @Override diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/SkillDistribution.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/SkillDistribution.java index 2f01a97..34f173b 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/SkillDistribution.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/SkillDistribution.java @@ -27,6 +27,8 @@ public enum SkillDistribution { private final String mode; /** + * access + * * @param mode the textual mode */ SkillDistribution(final String mode) { @@ -34,13 +36,17 @@ public enum SkillDistribution { } /** + * access + * * @return mode a semantic value */ public String getDistributionMode() { - return "cx-common:SkillDistribution?run="+this.mode; + return "cx-common:SkillDistribution?run=" + this.mode; } /** + * access + * * @return mode as argument */ public String getMode() { @@ -48,15 +54,18 @@ public String getMode() { } /** + * access + * * @param mode as argument * @return respective enum (or ALL if it does not fir) */ public static SkillDistribution valueOfMode(String mode) { - if(mode!=null) { - if (mode.endsWith("consumer")) + if (mode != null) { + if (mode.endsWith("consumer")) { return CONSUMER; - if (mode.endsWith("provider")) + } else if (mode.endsWith("provider")) { return PROVIDER; + } } return ALL; } diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/ISkillStore.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/SkillStore.java similarity index 83% rename from agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/ISkillStore.java rename to agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/SkillStore.java index 7e32711..0fc32e5 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/ISkillStore.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/SkillStore.java @@ -22,10 +22,11 @@ /** * interface to a skill store */ -public interface ISkillStore { +public interface SkillStore { /** * match a given asset + * * @param key asset name * @return matcher */ @@ -35,6 +36,7 @@ static Matcher matchSkill(String key) { /** * check a given asset for being a skill + * * @param key asset name * @return whether the asset encodes a skill */ @@ -42,21 +44,23 @@ static Matcher matchSkill(String key) { /** * register a skill - * @param key asset name required - * @param skill query text required - * @param name of skill optional + * + * @param key asset name required + * @param skill query text required + * @param name of skill optional * @param description of skill optional - * @param version of skill optional - * @param contract of skill optional - * @param dist of skill required + * @param version of skill optional + * @param contract of skill optional + * @param dist of skill required * @param isFederated whether skill maybe synchronized in catalogue - * @param ontologies a set of ontologies + * @param ontologies a set of ontologies * @return skill id */ String put(String key, String skill, String name, String description, String version, String contract, SkillDistribution dist, boolean isFederated, String... ontologies); /** * return the skill distribution + * * @param key asset name * @return skill distribution mode */ @@ -64,6 +68,7 @@ static Matcher matchSkill(String key) { /** * return the stored skill text + * * @param key asset name * @return optional skill text if registered */ diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/Tuple.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/Tuple.java index 6ba6ebb..bbad6f1 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/Tuple.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/Tuple.java @@ -21,42 +21,45 @@ import java.util.Set; /** - * A tuple contains a binding of variables to a single value. + * A tuple contains a binding of variables to a single value. */ public class Tuple { - Map bindings; - + Map bindings; + /** * create a fresh tuple */ public Tuple() { - bindings=new HashMap<>(); + bindings = new HashMap<>(); } /** * create a tuple with existing bindings + * * @param bindings map of variable names to string values */ - public Tuple(Map bindings) { - this.bindings=bindings; + public Tuple(Map bindings) { + this.bindings = bindings; } /** * adds a binding - * @param key variable name + * + * @param key variable name * @param value string-based value * @throws Exception in case the variable is already bound */ public void add(String key, String value) throws Exception { - if(bindings.containsKey(key)) { - throw new Exception(String.format("Cannot host several values for key %s in simple binding.",key)); + if (bindings.containsKey(key)) { + throw new Exception(String.format("Cannot host several values for key %s in simple binding.", key)); } - bindings.put(key,value); + bindings.put(key, value); } /** * access a binding + * * @param key variable name * @return bound value (null of not bound) */ @@ -65,6 +68,8 @@ public String get(String key) { } /** + * access + * * @return the set of bound variables */ public Set getVariables() { @@ -73,6 +78,7 @@ public Set getVariables() { /** * clone this tuple + * * @return a detached tuple with the same bindings */ @Override @@ -82,11 +88,12 @@ public Tuple clone() { /** * merges this tuple with another + * * @param other other tuple * @return a detached tuple with the combined bindings of this an the other tuple */ public Tuple merge(Tuple other) { - Map newTuple=new HashMap<>(bindings); + Map newTuple = new HashMap<>(bindings); newTuple.putAll(other.bindings); return new Tuple(newTuple); } @@ -96,6 +103,6 @@ public Tuple merge(Tuple other) { */ @Override public String toString() { - return "Tuple("+bindings.toString()+")"; + return "Tuple(" + bindings.toString() + ")"; } } diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/TupleSet.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/TupleSet.java index 1994da6..00c1f30 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/TupleSet.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/TupleSet.java @@ -16,6 +16,8 @@ // SPDX-License-Identifier: Apache-2.0 package org.eclipse.tractusx.agents.edc; +import org.apache.jena.ext.com.google.common.collect.ArrayListMultimap; + import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -23,71 +25,71 @@ import java.util.List; import java.util.Set; -import org.apache.jena.ext.com.google.common.collect.ArrayListMultimap; - /** * Implementation of a compact representation of - * a tuple set that is the explosion of + * a tuple set that is the explosion of * - multivalue bindings of individual variables * - logical combination of several tuple sets */ public class TupleSet { - - ArrayListMultimap bindings=ArrayListMultimap.create(); - List explodes=new ArrayList<>(); + + ArrayListMultimap bindings = ArrayListMultimap.create(); + List explodes = new ArrayList<>(); /** * add a binding to the tuple set - * @param key variable + * + * @param key variable * @param value string value * @throws Exception in case that the variable is already bound in the combined tuple sets */ public void add(String key, String value) throws Exception { - if(explodes.stream().anyMatch( explode -> explode.hasVariable(key))) { - throw new Exception(String.format("Could not bind variable %s on higher level as it is already bound in an embedded binding.",key)); + if (explodes.stream().anyMatch(explode -> explode.hasVariable(key))) { + throw new Exception(String.format("Could not bind variable %s on higher level as it is already bound in an embedded binding.", key)); } bindings.put(key, value); } /** - * flattens the representation + * flattens the representation + * * @param variables a set of variables * @return set of flat tuples. * @throws Exception in case that the representation has unintended intersections */ public Collection getTuples(String... variables) throws Exception { - List ownVars=new ArrayList<>(); - List explodedVars=new ArrayList<>(); - for(String var : variables) { - if(bindings.containsKey(var)) { + List ownVars = new ArrayList<>(); + List explodedVars = new ArrayList<>(); + for (String var : variables) { + if (bindings.containsKey(var)) { ownVars.add(var); } else { explodedVars.add(var); } } - Collection explosion=new ArrayList<>(); + Collection explosion = new ArrayList<>(); for (TupleSet explode : explodes) { explosion.addAll(explode.getTuples(explodedVars.toArray(new String[0]))); } - if(ownVars.size()>0) { - for(String key : ownVars) { - if(explosion.size()==0) { - for(String value : bindings.get(key)) { - Tuple tuple=new Tuple(); - tuple.add(key,value); + if (ownVars.size() > 0) { + for (String key : ownVars) { + if (explosion.size() == 0) { + for (String value : bindings.get(key)) { + Tuple tuple = new Tuple(); + tuple.add(key, value); explosion.add(tuple); - } + } } else { - Collection nextExplosion= new ArrayList<>(); - for(String value : bindings.get(key)) { - for(Tuple yetTuple : explosion) { - Tuple tuple=yetTuple.clone(); - tuple.add(key,value); + Collection nextExplosion = new ArrayList<>(); + for (String value : bindings.get(key)) { + for (Tuple yetTuple : explosion) { + Tuple tuple = yetTuple.clone(); + tuple.add(key, value); nextExplosion.add(tuple); } } - explosion=nextExplosion; + explosion = nextExplosion; } } } @@ -96,19 +98,21 @@ public Collection getTuples(String... variables) throws Exception { /** * checks whether a particular variable is bound + * * @param key variable name * @return existance flag */ public boolean hasVariable(String key) { - return bindings.containsKey(key) || explodes.stream().anyMatch( explode -> explode.hasVariable(key)); + return bindings.containsKey(key) || explodes.stream().anyMatch(explode -> explode.hasVariable(key)); } /** * compute the set of bound variables + * * @return set of bound variables */ public Set getVariables() { - Set myVars=new HashSet<>(bindings.keySet()); + Set myVars = new HashSet<>(bindings.keySet()); for (TupleSet explode : explodes) { myVars.addAll(explode.getVariables()); } @@ -117,6 +121,7 @@ public Set getVariables() { /** * merge another tupleset into this one + * * @param other tupleset */ public void merge(TupleSet other) { @@ -128,6 +133,6 @@ public void merge(TupleSet other) { */ @Override public String toString() { - return "Tuple("+bindings.toString()+ "+"+Arrays.toString(explodes.toArray()) + ")"; + return "Tuple(" + bindings.toString() + "+" + Arrays.toString(explodes.toArray()) + ")"; } } diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/AgentController.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/AgentController.java index ac2d2fb..627c5b1 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/AgentController.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/AgentController.java @@ -16,20 +16,27 @@ // SPDX-License-Identifier: Apache-2.0 package org.eclipse.tractusx.agents.edc.http; -import org.eclipse.tractusx.agents.edc.ISkillStore; -import org.eclipse.tractusx.agents.edc.SkillDistribution; -import org.eclipse.tractusx.agents.edc.sparql.SparqlQueryProcessor; -import jakarta.ws.rs.*; -import jakarta.ws.rs.core.*; - import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; - +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.UriInfo; import org.apache.http.HttpStatus; import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.tractusx.agents.edc.AgentConfig; import org.eclipse.tractusx.agents.edc.AgentExtension; -import org.eclipse.tractusx.agents.edc.IAgreementController; +import org.eclipse.tractusx.agents.edc.AgreementController; +import org.eclipse.tractusx.agents.edc.SkillDistribution; +import org.eclipse.tractusx.agents.edc.SkillStore; +import org.eclipse.tractusx.agents.edc.sparql.SparqlQueryProcessor; import java.util.Optional; import java.util.regex.Matcher; @@ -48,28 +55,29 @@ public class AgentController { // EDC services protected final Monitor monitor; - protected final IAgreementController agreementController; + protected final AgreementController agreementController; protected final AgentConfig config; - protected final ISkillStore skillStore; + protected final SkillStore skillStore; // the actual Matchmaking Agent is a Fuseki engine protected final SparqlQueryProcessor processor; - protected final IDelegationService delegationService; + protected final DelegationService delegationService; /** - * creates a new agent controller + * creates a new agent controller + * * @param monitor logging subsystem * @param agreementController agreement controller for remote skill/queries * @param config configuration * @param processor sparql processor */ - public AgentController(Monitor monitor, IAgreementController agreementController, AgentConfig config, SparqlQueryProcessor processor, ISkillStore skillStore, IDelegationService delegationService) { + public AgentController(Monitor monitor, AgreementController agreementController, AgentConfig config, SparqlQueryProcessor processor, SkillStore skillStore, DelegationService delegationService) { this.monitor = monitor; this.agreementController = agreementController; - this.config=config; - this.processor=processor; - this.skillStore=skillStore; - this.delegationService=delegationService; + this.config = config; + this.processor = processor; + this.skillStore = skillStore; + this.delegationService = delegationService; } /** @@ -77,23 +85,24 @@ public AgentController(Monitor monitor, IAgreementController agreementController */ @Override public String toString() { - return super.toString()+"/agent"; + return super.toString() + "/agent"; } /** * endpoint for posting a sparql query (maybe as a stored skill with a bindingset) + * * @param asset can be a named graph for executing a query or a skill asset * @return response */ @POST - @Consumes({"application/sparql-query","application/sparql-results+json"}) + @Consumes({"application/sparql-query", "application/sparql-results+json"}) public Response postSparqlQuery(@QueryParam("asset") String asset, @Context HttpHeaders headers, @Context HttpServletRequest request, @Context HttpServletResponse response, @Context UriInfo uri ) { - monitor.debug(String.format("Received a SparQL POST request %s for asset %s",request,asset)); + monitor.debug(String.format("Received a SparQL POST request %s for asset %s", request, asset)); return executeQuery(asset, headers, request, response, uri); } @@ -104,6 +113,7 @@ public Response postSparqlQuery(@QueryParam("asset") String asset, * with the query text in the body and expects a * special content disposition in the response header which * marks the body as a kind of file attachement. + * * @param asset can be a named graph for executing a query or a skill asset * @return response compatible with graphdb convention */ @@ -114,9 +124,9 @@ public Response postFormQuery(@QueryParam("asset") String asset, @Context HttpServletRequest request, @Context HttpServletResponse response, @Context UriInfo uri) { - monitor.debug(String.format("Received a Form-based POST request %s for asset %s",request,asset)); - Response result= executeQuery(asset, headers, request, response, uri); - response.addHeader("Content-Disposition","attachement; filename=query-result.srjs"); + monitor.debug(String.format("Received a Form-based POST request %s for asset %s", request, asset)); + Response result = executeQuery(asset, headers, request, response, uri); + response.addHeader("Content-Disposition", "attachement; filename=query-result.srjs"); return result; } @@ -127,6 +137,7 @@ public Response postFormQuery(@QueryParam("asset") String asset, * with the query text in the body and expects a * special content disposition in the response header which * marks the body as a kind of file attachement. + * * @param asset can be a named graph for executing a query or a skill asset * @return response compatible with graphdb convention */ @@ -138,14 +149,15 @@ public Response postFormRepositoryQuery(@QueryParam("asset") String asset, @Context HttpServletRequest request, @Context HttpServletResponse response, @Context UriInfo uri) { - monitor.debug(String.format("Received a Form-based POST repository request %s for asset %s",request,asset)); - Response result= executeQuery(asset, headers, request, response, uri); - response.addHeader("Content-Disposition","attachement; filename=query-result.srjs"); + monitor.debug(String.format("Received a Form-based POST repository request %s for asset %s", request, asset)); + Response result = executeQuery(asset, headers, request, response, uri); + response.addHeader("Content-Disposition", "attachement; filename=query-result.srjs"); return result; } /** * endpoint for getting a query + * * @param asset can be a named graph for executing a query or a skill asset * @return response */ @@ -155,12 +167,13 @@ public Response getQuery(@QueryParam("asset") String asset, @Context HttpServletRequest request, @Context HttpServletResponse response, @Context UriInfo uri) { - monitor.debug(String.format("Received a GET request %s for asset %s",request,asset)); + monitor.debug(String.format("Received a GET request %s for asset %s", request, asset)); return executeQuery(asset, headers, request, response, uri); } /** * 2nd endpoint for getting a query + * * @param asset can be a named graph for executing a query or a skill asset * @return response */ @@ -171,39 +184,35 @@ public Response getRepositoryQuery(@QueryParam("asset") String asset, @Context HttpServletRequest request, @Context HttpServletResponse response, @Context UriInfo uri) { - monitor.debug(String.format("Received a GET repository request %s for asset %s",request,asset)); + monitor.debug(String.format("Received a GET repository request %s for asset %s", request, asset)); return executeQuery(asset, headers, request, response, uri); } /** * check import status + * * @return response */ @GET @Path("/repositories/AGENT/import/active") public Response getRepositoryImportQuery( - //@Context HttpHeaders headers, @Context HttpServletRequest request - //,@Context HttpServletResponse response, - //@Context UriInfo uri ) { - monitor.debug(String.format("Received a GET repository import active request %s",request)); - return Response.status(406,"Not Acceptable (HTTP status 406)").build(); + monitor.debug(String.format("Received a GET repository import active request %s", request)); + return Response.status(406, "Not Acceptable (HTTP status 406)").build(); } /** * check size + * * @return response */ @GET @Path("/rest/repositories/AGENT/size") public Response getRestRepositorySizeQuery( - //@Context HttpHeaders headers, @Context HttpServletRequest request - //,@Context HttpServletResponse response, - //@Context UriInfo uri ) { - monitor.debug(String.format("Received a GET rest repository size request %s",request)); + monitor.debug(String.format("Received a GET rest repository size request %s", request)); return Response.ok("{\n" + " \"inferred\": 70,\n" + " \"total\": 70,\n" + @@ -213,106 +222,95 @@ public Response getRestRepositorySizeQuery( /** * check size + * * @return response */ @GET @Path("/repositories/AGENT/size") public Response getRepositorySizeQuery( - //@Context HttpHeaders headers, @Context HttpServletRequest request - //,@Context HttpServletResponse response, - //@Context UriInfo uri ) { - monitor.debug(String.format("Received a GET repository size request %s",request)); - return Response.ok("0" ).type(jakarta.ws.rs.core.MediaType.APPLICATION_JSON_TYPE).build(); + monitor.debug(String.format("Received a GET repository size request %s", request)); + return Response.ok("0").type(jakarta.ws.rs.core.MediaType.APPLICATION_JSON_TYPE).build(); } /** * check import status + * * @return response */ @GET @Path("/rest/repositories/AGENT/import/active") public Response getRestRepositoryImportQuery( - //@Context HttpHeaders headers, @Context HttpServletRequest request - //,@Context HttpServletResponse response, - //@Context UriInfo uri ) { - monitor.debug(String.format("Received a GET rest repository import active request %s",request)); + monitor.debug(String.format("Received a GET rest repository import active request %s", request)); return Response.ok("0").type(jakarta.ws.rs.core.MediaType.APPLICATION_JSON_TYPE).build(); } /** * return version info for graphdb/fedx integration + * * @return version string */ @GET @Path("/rest/info/version") public String getVersion( - //@Context HttpHeaders headers, @Context HttpServletRequest request - //,@Context HttpServletResponse response, - //@Context UriInfo uri ) { - monitor.debug(String.format("Received a GET Version request %s",request)); + monitor.debug(String.format("Received a GET Version request %s", request)); return "0.8.4"; } /** * return protocol info for graphdb/fedx integration + * * @return protocol string */ @GET @Path("/protocol") public String getProtocol( - //@Context HttpHeaders headers, @Context HttpServletRequest request - //,@Context HttpServletResponse response, - //@Context UriInfo uri ) { - monitor.debug(String.format("Received a GET Protocol request %s",request)); + monitor.debug(String.format("Received a GET Protocol request %s", request)); return "12"; } /** * return version info for graphdb/fedx integration + * * @return version string */ @GET @Path("/rest/locations/id") public String getId( - //@Context HttpHeaders headers, @Context HttpServletRequest request - //,@Context HttpServletResponse response, - //@Context UriInfo uri ) { - monitor.debug(String.format("Received a GET Id request %s",request)); + monitor.debug(String.format("Received a GET Id request %s", request)); return "Catena-X Knowledge Agent"; } /** * return repositories for graphdb/fedx integration + * * @return single repo as json */ @GET @Path("/rest/repositories") public String getRestRepositories( - //@Context HttpHeaders headers, @Context HttpServletRequest request, - //@Context HttpServletResponse response, @Context UriInfo uri ) { - monitor.debug(String.format("Received a GET Rest Repositories request %s",request)); - String url=uri.getAbsolutePath().toString(); - url=url.substring(0,url.length()-18); - url=HttpUtils.urlEncode(url); + monitor.debug(String.format("Received a GET Rest Repositories request %s", request)); + String url = uri.getAbsolutePath().toString(); + url = url.substring(0, url.length() - 18); + url = HttpUtils.urlEncode(url); return "[\n" + " {\n" + " \"id\": \"AGENT\",\n" + " \"title\": \"Catena-X Knowledge Agent Dataspace Endpoint\",\n" + - " \"uri\": \""+url+"\",\n" + - " \"externalUrl\": \""+url+"\",\n" + + " \"uri\": \"" + url + "\",\n" + + " \"externalUrl\": \"" + url + "\",\n" + " \"local\": false,\n" + " \"type\": \"fuseki\",\n" + " \"sesameType\": \"cx:AgentController\",\n" + @@ -327,111 +325,110 @@ public String getRestRepositories( /** * return repositories for graphdb/fedx integration + * * @return single repo as csv */ @GET @Path("/repositories") public Response getRepositories( - //@Context HttpHeaders headers, @Context HttpServletRequest request, - //@Context HttpServletResponse response, @Context UriInfo uri ) { - monitor.debug(String.format("Received a GET Repositories request %s",request)); - String url=uri.getAbsolutePath().toString(); - url=url.substring(0,url.length()-13); - url=HttpUtils.urlEncode(url); - Response.ResponseBuilder builder=Response.ok("uri,id,title,readable,writable\n"+url+",AGENT,Catena-X Knowledge Agent Dataspace Endpoint,true,true\n"); + monitor.debug(String.format("Received a GET Repositories request %s", request)); + String url = uri.getAbsolutePath().toString(); + url = url.substring(0, url.length() - 13); + url = HttpUtils.urlEncode(url); + Response.ResponseBuilder builder = Response.ok("uri,id,title,readable,writable\n" + url + ",AGENT,Catena-X Knowledge Agent Dataspace Endpoint,true,true\n"); builder.type("text/csv;charset=UTF-8"); - builder.header("Content-Disposition","attachment; filename=repositories.csv"); + builder.header("Content-Disposition", "attachment; filename=repositories.csv"); return builder.build(); } /** * return repositories for graphdb/fedx integration + * * @return single repo as csv */ @GET @Path("/repositories/AGENT/namespaces") public Response getNamespaces( - //@Context HttpHeaders headers, @Context HttpServletRequest request - //,@Context HttpServletResponse response, - //@Context UriInfo uri ) { - monitor.debug(String.format("Received a GET Namespaces request %s",request)); - Response.ResponseBuilder builder=Response.ok("prefix,namespace\n" + + monitor.debug(String.format("Received a GET Namespaces request %s", request)); + Response.ResponseBuilder builder = Response.ok("prefix,namespace\n" + "rdf,http://www.w3.org/1999/02/22-rdf-syntax-ns#\n" + "owl,http://www.w3.org/2002/07/owl#\n" + "xsd,http://www.w3.org/2001/XMLSchema#\n" + "rdfs,http://www.w3.org/2000/01/rdf-schema#\n" + "cx,https://w3id.org/catenax/ontology#\n"); builder.type("text/csv;charset=UTF-8"); - builder.header("Content-Disposition","attachment; filename=namespaces.csv"); + builder.header("Content-Disposition", "attachment; filename=namespaces.csv"); return builder.build(); } /** * the actual execution is done by delegating to the Fuseki engine + * * @param asset target graph * @return a response */ public Response executeQuery(String asset, HttpHeaders headers, HttpServletRequest request, HttpServletResponse response, UriInfo uri) { - String skill=null; - String graph=null; - String remoteUrl=null; + String skill = null; + String graph = null; + String remoteUrl = null; - if(asset!=null) { - Matcher matcher= AgentExtension.GRAPH_PATTERN.matcher(asset); - if(matcher.matches()) { - remoteUrl=matcher.group("url"); - graph=matcher.group("graph"); + if (asset != null) { + Matcher matcher = AgentExtension.GRAPH_PATTERN.matcher(asset); + if (matcher.matches()) { + remoteUrl = matcher.group("url"); + graph = matcher.group("graph"); } else { - matcher=ISkillStore.matchSkill(asset); - if(!matcher.matches()) { + matcher = SkillStore.matchSkill(asset); + if (!matcher.matches()) { return Response.status(Response.Status.BAD_REQUEST).build(); } - remoteUrl=matcher.group("url"); - skill=matcher.group("skill"); + remoteUrl = matcher.group("url"); + skill = matcher.group("skill"); } } - if(remoteUrl!=null) { - // we need to delegate to the agent under remote URL - DelegationResponse intermediateResponse = delegationService.executeQueryRemote(remoteUrl,skill,graph, headers, request, response, uri); - // in case runMode = provider the response already contains the final result - if (intermediateResponse.getQueryString() == null) { - return intermediateResponse.getResponse(); - } else { - // in case runMode = consumer we set the skill text to the downloaded text and advance - skill = intermediateResponse.getQueryString(); - asset = null; - } + if (remoteUrl != null) { + // we need to delegate to the agent under remote URL + DelegationResponse intermediateResponse = delegationService.executeQueryRemote(remoteUrl, skill, graph, headers, request, response, uri); + // in case runMode = provider the response already contains the final result + if (intermediateResponse.getQueryString() == null) { + return intermediateResponse.getResponse(); + } else { + // in case runMode = consumer we set the skill text to the downloaded text and advance + skill = intermediateResponse.getQueryString(); + asset = null; + } } try { // exchange skill against text - if( asset!=null ) { - if(skillStore.isSkill(asset)) { + if (asset != null) { + if (skillStore.isSkill(asset)) { Optional skillOption = skillStore.get(asset); if (skillOption.isPresent()) { skill = skillOption.get(); } else { - return HttpUtils.respond(monitor,headers, HttpStatus.SC_NOT_FOUND, "The requested skill is not registered.", null); + return HttpUtils.respond(monitor, headers, HttpStatus.SC_NOT_FOUND, "The requested skill is not registered.", null); } } } - processor.execute(request,response,skill,graph); + processor.execute(request, response, skill, graph); // kind of redundant, but javax.ws.rs likes it this way return Response.status(response.getStatus()).build(); - } catch(WebApplicationException e) { - return HttpUtils.respond(monitor,headers,e.getResponse().getStatus(),e.getMessage(),e.getCause()); + } catch (WebApplicationException e) { + return HttpUtils.respond(monitor, headers, e.getResponse().getStatus(), e.getMessage(), e.getCause()); } } /** * endpoint for posting a skill + * * @param query mandatory query * @param asset asset key * @param name asset name @@ -445,29 +442,30 @@ public Response executeQuery(String asset, HttpHeaders headers, HttpServletReque */ @POST @Path("/skill") - @Consumes({"application/sparql-query"}) - public Response postSkill(String query, - @QueryParam("asset") String asset, - @QueryParam("assetName") String name, - @QueryParam("assetDescription") String description, - @QueryParam("assetVersion") String version, - @QueryParam("contract") String contract, - @QueryParam("distributionMode") SkillDistribution mode, - @QueryParam("isFederated") boolean isFederated, - @QueryParam("ontology") String[] ontologies - ) { - monitor.debug(String.format("Received a POST skill request %s %s %s %s %s %b %s ",asset,name,description,version,contract,mode.getMode(),isFederated,query)); + @Consumes({ "application/sparql-query" }) + public Response postSkill(String query, + @QueryParam("asset") String asset, + @QueryParam("assetName") String name, + @QueryParam("assetDescription") String description, + @QueryParam("assetVersion") String version, + @QueryParam("contract") String contract, + @QueryParam("distributionMode") SkillDistribution mode, + @QueryParam("isFederated") boolean isFederated, + @QueryParam("ontology") String[] ontologies + ) { + monitor.debug(String.format("Received a POST skill request %s %s %s %s %s %b %s ", asset, name, description, version, contract, mode.getMode(), isFederated, query)); Response.ResponseBuilder rb; - if(skillStore.put(asset,query,name,description,version,contract,mode,isFederated,ontologies)!=null) { - rb=Response.ok(); + if (skillStore.put(asset, query, name, description, version, contract, mode, isFederated, ontologies) != null) { + rb = Response.ok(); } else { - rb=Response.status(HttpStatus.SC_CREATED); + rb = Response.status(HttpStatus.SC_CREATED); } return rb.build(); } /** * endpoint for getting a skill + * * @param asset can be a named graph for executing a query or a skill asset * @return response */ @@ -475,10 +473,10 @@ public Response postSkill(String query, @Path("/skill") @Produces({"application/sparql-query"}) public Response getSkill(@QueryParam("asset") String asset) { - monitor.debug(String.format("Received a GET skill request %s",asset)); + monitor.debug(String.format("Received a GET skill request %s", asset)); Response.ResponseBuilder rb; - String query=skillStore.get(asset).orElse(null); - if(query==null) { + String query = skillStore.get(asset).orElse(null); + if (query == null) { rb = Response.status(HttpStatus.SC_NOT_FOUND); } else { rb = Response.ok(query); diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/AgentHttpAction.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/AgentHttpAction.java index 2f2914a..20e9b5b 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/AgentHttpAction.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/AgentHttpAction.java @@ -19,19 +19,19 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; -import org.eclipse.tractusx.agents.edc.TupleSet; import org.apache.http.HttpStatus; -import org.slf4j.Logger; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.apache.jena.fuseki.system.ActionCategory; import org.apache.jena.fuseki.servlets.HttpAction; +import org.apache.jena.fuseki.system.ActionCategory; +import org.eclipse.tractusx.agents.edc.TupleSet; +import org.slf4j.Logger; import java.net.URLDecoder; import java.util.Iterator; import java.util.Stack; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import static java.nio.charset.StandardCharsets.UTF_8; @@ -45,17 +45,18 @@ public class AgentHttpAction extends HttpAction { final String skill; final String graphs; - final TupleSet tupleSet=new TupleSet(); + final TupleSet tupleSet = new TupleSet(); /** * regexes to deal with url parameters */ - public static String URL_PARAM_REGEX = "(?[^=&]+)=(?[^&]+)"; - public static Pattern URL_PARAM_PATTERN=Pattern.compile(URL_PARAM_REGEX); - public static String RESULTSET_CONTENT_TYPE="application/sparql-results+json"; + public static final String URL_PARAM_REGEX = "(?[^=&]+)=(?[^&]+)"; + public static final Pattern URL_PARAM_PATTERN = Pattern.compile(URL_PARAM_REGEX); + public static final String RESULTSET_CONTENT_TYPE = "application/sparql-results+json"; /** * creates a new http action + * * @param id call id * @param logger the used logging output * @param request servlet input @@ -64,10 +65,10 @@ public class AgentHttpAction extends HttpAction { */ public AgentHttpAction(long id, Logger logger, HttpServletRequest request, HttpServletResponse response, String skill, String graphs) { super(id, logger, ActionCategory.ACTION, request, response); - this.skill=skill; - this.graphs=graphs; - parseArgs(request,response); - parseBody(request,response); + this.skill = skill; + this.graphs = graphs; + parseArgs(request, response); + parseBody(request, response); } /** @@ -118,29 +119,31 @@ protected void parseArgs(HttpServletRequest request, HttpServletResponse respons * parses the body */ protected void parseBody(HttpServletRequest request, HttpServletResponse response) { - if(RESULTSET_CONTENT_TYPE.equals(request.getContentType())) { - ObjectMapper om= new ObjectMapper(); + if (RESULTSET_CONTENT_TYPE.equals(request.getContentType())) { + ObjectMapper om = new ObjectMapper(); try { - JsonNode bindingSet=om.readTree(request.getInputStream()); - ArrayNode bindings=((ArrayNode) bindingSet.get("results").get("bindings")); - for(int count=0;count vars = binding.fieldNames(); - while(vars.hasNext()) { + while (vars.hasNext()) { String var = vars.next(); JsonNode value = binding.get(var).get("value"); - ts.add(var,value.textValue()); + ts.add(var, value.textValue()); } tupleSet.merge(ts); } - } catch(Exception e) { + } catch (Exception e) { response.setStatus(HttpStatus.SC_BAD_REQUEST); } } } /** + * access + * * @return optional skill */ public String getSkill() { @@ -148,6 +151,8 @@ public String getSkill() { } /** + * access + * * @return optional skill */ public String getGraphs() { @@ -155,6 +160,8 @@ public String getGraphs() { } /** + * access + * * @return the actual input bindings */ public TupleSet getInputBindings() { diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationResponse.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationResponse.java index 84dd4d4..117a395 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationResponse.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationResponse.java @@ -20,50 +20,54 @@ import jakarta.ws.rs.core.Response; /** - * A wrapper around the response of a + * A wrapper around the response of a * call to another agent in the dataspace - * Depending on the run mode (provider/consumer), - * this response could optionally host the text of - * a skill to be executed locally. + * Depending on the run mode (provider/consumer), + * this response could optionally host the text of + * a skill to be executed locally. */ public class DelegationResponse { - - final protected String queryString; - - final protected Response response; - - /** - * Construct a new wrapper response for runMode = consumer - * @param queryString downloaded text of the skill - * @param response the response Object to return - */ - public DelegationResponse(String queryString, Response response) { - this.queryString = queryString; - this.response = response; - } - - /** - * Construct a new wrapper response for runMode = provider - * @param response the response Object to return - */ - public DelegationResponse(Response response) { - this.response = response; - this.queryString = null; - } + protected final String queryString; + protected final Response response; - /** - * @return downloaded text of skill (should be not null if runMode = consumer) - */ - public String getQueryString() { - return queryString; - } + /** + * Construct a new wrapper response for runMode = consumer + * + * @param queryString downloaded text of the skill + * @param response the response Object to return + */ + public DelegationResponse(String queryString, Response response) { + this.queryString = queryString; + this.response = response; + } + + /** + * Construct a new wrapper response for runMode = provider + * + * @param response the response Object to return + */ + public DelegationResponse(Response response) { + this.response = response; + this.queryString = null; + } + + /** + * access + * + * @return downloaded text of skill (should be not null if runMode = consumer) + */ + public String getQueryString() { + return queryString; + } + + /** + * access + * + * @return the response Object to return (should be not null in each case) + */ + public Response getResponse() { + return response; + } - /** - * @return the response Object to return (should be not null in each case) - */ - public Response getResponse() { - return response; - } - } diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationService.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationService.java index abec631..f95b6ad 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationService.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationService.java @@ -16,341 +16,28 @@ // SPDX-License-Identifier: Apache-2.0 package org.eclipse.tractusx.agents.edc.http; -import com.fasterxml.jackson.core.type.TypeReference; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.HttpHeaders; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.UriInfo; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import org.apache.commons.io.IOUtils; -import org.apache.http.HttpStatus; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.types.TypeManager; -import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; -import org.eclipse.tractusx.agents.edc.AgentConfig; -import org.eclipse.tractusx.agents.edc.IAgreementController; -import org.eclipse.tractusx.agents.edc.sparql.CatenaxWarning; - -import java.io.*; -import java.nio.charset.Charset; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.regex.Pattern; -import java.util.stream.Collectors; /** - * A service that may delegate an incoming - * agent http request ot another agent in the + * interface to a service that may + * delegate agent http calls into the * dataspace - * deals with the special case of remote/provided (textual) - * skills which should be executed locally nevertheless */ -public class DelegationService implements IDelegationService { - - protected final IAgreementController agreementController; - protected final Monitor monitor; - protected final OkHttpClient client; - public final static TypeReference> warningTypeReference = new TypeReference<>(){}; - protected final TypeManager typeManager; - protected final AgentConfig config; - - /** - * creates a new delegation service - * @param agreementController EDC agreement helper - * @param monitor logging facility - * @param client outgoing http infrastructure - */ - public DelegationService(IAgreementController agreementController, Monitor monitor, OkHttpClient client, TypeManager typeManager, AgentConfig config) { - this.agreementController=agreementController; - this.monitor=monitor; - this.client=client; - this.typeManager=typeManager; - this.config=config; - } - - /** - * the actual execution is done by delegating to the Dataspace - * @param remoteUrl remote connector - * @param skill target skill - * @param graph target graph - * @return a wrapped response which indicates the runMode that the execution should be done - */ - public DelegationResponse executeQueryRemote(String remoteUrl, String skill, String graph, HttpHeaders headers, HttpServletRequest request, HttpServletResponse response, UriInfo uri) { - Pattern serviceAllowPattern=config.getServiceAllowPattern(); - if(!serviceAllowPattern.matcher(remoteUrl).matches()) { - return new DelegationResponse(HttpUtils.respond(monitor,headers, HttpStatus.SC_FORBIDDEN,String.format("Service %s does not match the allowed service pattern %s",remoteUrl,serviceAllowPattern.pattern()),null)); - } - Pattern serviceDenyPattern=config.getServiceDenyPattern(); - if(serviceDenyPattern.matcher(remoteUrl).matches()) { - return new DelegationResponse( HttpUtils.respond(monitor,headers, HttpStatus.SC_FORBIDDEN,String.format("Service %s matches the denied service pattern %s",remoteUrl,serviceDenyPattern.pattern()),null)); - } - String asset = skill != null ? skill : graph; - EndpointDataReference endpoint = agreementController.get(asset); - if(endpoint==null) { - try { - endpoint=agreementController.createAgreement(remoteUrl,asset); - } catch(WebApplicationException e) { - return new DelegationResponse( HttpUtils.respond(monitor,headers, e.getResponse().getStatus(),String.format("Could not get an agreement from connector %s to asset %s",remoteUrl,asset),e.getCause())); - } - } - if(endpoint==null) { - return new DelegationResponse(HttpUtils.respond(monitor,headers, HttpStatus.SC_FORBIDDEN,String.format("Could not get an agreement from connector %s to asset %s",remoteUrl,asset),null)); - } - if("GET".equals(request.getMethod())) { - try { - return sendGETRequest(endpoint, "", headers, response, uri); - } catch(IOException e) { - return new DelegationResponse(HttpUtils.respond(monitor,headers, HttpStatus.SC_INTERNAL_SERVER_ERROR,String.format("Could not delegate remote GET call to connector %s asset %s",remoteUrl,asset),e)); - } - } else if("POST".equals(request.getMethod())) { - try { - return sendPOSTRequest(endpoint, "", headers, request, response, uri); - } catch(IOException e) { - return new DelegationResponse( HttpUtils.respond(monitor,headers, HttpStatus.SC_INTERNAL_SERVER_ERROR,String.format("Could not delegate remote POST call to connector %s asset %s",remoteUrl,asset),e)); - } - } else { - return new DelegationResponse(HttpUtils.respond(monitor,headers, HttpStatus.SC_METHOD_NOT_ALLOWED,String.format("%s calls to connector %s asset %s are not allowed",request.getMethod(),remoteUrl,asset),null)); - } - - } - - /** - * route a get request - * @param dataReference the encoded call embedding - * @param subUrl protocol-specific part - * @return a wrapped response which indicates the runMode that the execution should be done - * @throws IOException in case something strange happens - */ - public DelegationResponse sendGETRequest(EndpointDataReference dataReference, String subUrl, HttpHeaders headers, HttpServletResponse response, UriInfo uri) throws IOException { - var url = getUrl(dataReference.getEndpoint(), subUrl, headers, uri); - - monitor.debug(String.format("About to delegate GET %s",url)); - - var requestBuilder = new okhttp3.Request.Builder() - .url(url); - - if(dataReference.getAuthKey()!=null) { - requestBuilder = requestBuilder.addHeader(dataReference.getAuthKey(), Objects.requireNonNull(dataReference.getAuthCode())); - } - - var newRequest = requestBuilder.build(); - - return new DelegationResponse(sendRequest(newRequest, response), Response.status(response.getStatus()).build()); - } - - /** - * route a post request - * @param dataReference the encoded call embedding - * @param subUrl protocol-specific part - * @return a wrapped response which indicates the runMode that the execution should be done - * @throws IOException in case something strange happens - */ - public DelegationResponse sendPOSTRequest(EndpointDataReference dataReference, String subUrl, HttpHeaders headers, HttpServletRequest request, HttpServletResponse response, UriInfo uri) throws IOException { - var url = getUrl(dataReference.getEndpoint(), subUrl, headers, uri); - - String contentType=request.getContentType(); - okhttp3.MediaType parsedContentType=okhttp3.MediaType.parse(contentType); - - monitor.debug(String.format("About to delegate POST %s with content type %s",url,contentType)); - - var requestBuilder = new okhttp3.Request.Builder() - .url(url) - .addHeader("Content-Type", contentType); - - if(dataReference.getAuthKey()!=null) { - requestBuilder = requestBuilder.addHeader(dataReference.getAuthKey(), Objects.requireNonNull(dataReference.getAuthCode())); - } - - requestBuilder.post(okhttp3.RequestBody.create(request.getInputStream().readAllBytes(),parsedContentType)); - - var newRequest = requestBuilder.build(); - - return new DelegationResponse(sendRequest(newRequest, response), Response.status(response.getStatus()).build()); - } - - protected static Pattern PARAMETER_KEY_ALLOW = Pattern.compile("^(?!asset$)[^&?=]+$"); - protected static Pattern PARAMETER_VALUE_ALLOW = Pattern.compile("^.+$"); - - /** - * computes the url to target the given data plane - * @param connectorUrl data plane url - * @param subUrl sub-path to use - * @param headers containing additional info that we need to wrap into a transfer request - * @return typed url - */ - protected HttpUrl getUrl(String connectorUrl, String subUrl, HttpHeaders headers, UriInfo uri) { - var url = connectorUrl; - - // EDC public api slash problem - if(!url.endsWith("/") && !url.contains("#")) { - url = url + "/"; - } - - if (subUrl != null && !subUrl.isEmpty()) { - url = url + subUrl; - } - - HttpUrl.Builder httpBuilder = Objects.requireNonNull(okhttp3.HttpUrl.parse(url)).newBuilder(); - for (Map.Entry> param : uri.getQueryParameters().entrySet()) { - String key=param.getKey(); - if(PARAMETER_KEY_ALLOW.matcher(key).matches()) { - for (String value : param.getValue()) { - if(PARAMETER_VALUE_ALLOW.matcher(value).matches()) { - String recodeKey = HttpUtils.urlEncodeParameter(key); - String recodeValue = HttpUtils.urlEncodeParameter(value); - httpBuilder = httpBuilder.addQueryParameter(recodeKey, recodeValue); - } - } - } - } - - List mediaTypes=headers.getAcceptableMediaTypes(); - if(mediaTypes.isEmpty() || mediaTypes.stream().anyMatch(MediaType.APPLICATION_JSON_TYPE::isCompatible)) { - httpBuilder = httpBuilder.addQueryParameter("cx_accept", HttpUtils.urlEncodeParameter("application/json")); - } else { - String mediaParam=mediaTypes.stream().map(MediaType::toString).collect(Collectors.joining(", ")); - mediaParam=HttpUtils.urlEncodeParameter(mediaParam); - httpBuilder.addQueryParameter("cx_accept",mediaParam); - } - return httpBuilder.build(); - } - +public interface DelegationService { /** - * generic sendRequest method which extracts the result string of textual responses - * @param request predefined request - * @param response the final response - * @return the text of a downloaded skill if runMode = consumer, null otherwise - * @throws IOException in case something goes wrong + * delegate the given call into the dataspace + * + * @param remoteUrl target EDC + * @param skill name of the remote skill (may be empty, then graph must be set) + * @param graph name of the remote graph (may be empty, then skill must be set) + * @param headers url call headers + * @param request url request + * @param response final response + * @param uri original uri + * @return an intermediate response which may contain a textual skill to be executed locally otherwise the actual result has already been put into the final response's state */ - protected String sendRequest(okhttp3.Request request, HttpServletResponse response) throws IOException { - try(var myResponse = client.newCall(request).execute()) { - - if(!myResponse.isSuccessful()) { - monitor.warning(String.format("Data plane call was not successful: %s", myResponse.code())); - } - - Optional> warnings=Optional.empty(); - - var body = myResponse.body(); - - if (body != null) { - okhttp3.MediaType contentType=body.contentType(); - InputStream inputStream=new BufferedInputStream(body.byteStream()); - - // - // Analyze whether this response contains a multipart body - // while maintaining the state of the inputstream (mark/reset approach) - // - inputStream.mark(2); - byte[] boundaryBytes=new byte[2]; - String boundary=""; - if(inputStream.read(boundaryBytes)>0) { - boundary = new String(boundaryBytes); - } - inputStream.reset(); - if("--".equals(boundary)) { - // - // Multipart Case separates the actual result (last part) from the warnings (first part) - // - if(contentType!=null) { - int boundaryIndex; - boundaryIndex=contentType.toString().indexOf(";boundary="); - if(boundaryIndex>=0) { - boundary=boundary+contentType.toString().substring(boundaryIndex+10); - } - } - StringBuilder nextPart=null; - String embeddedContentType=null; - BufferedReader reader=new BufferedReader(new InputStreamReader(inputStream)); - for(String line = reader.readLine(); line!=null; line=reader.readLine()) { - if(boundary.equals(line)) { - if(nextPart!=null && embeddedContentType!=null) { - if(embeddedContentType.equals("application/cx-warnings+json")) { - List nextWarnings=typeManager.readValue(nextPart.toString(),warningTypeReference); - if(warnings.isPresent()) { - warnings.get().addAll(nextWarnings); - } else { - warnings=Optional.of(nextWarnings); - } - } else { - inputStream=new ByteArrayInputStream(nextPart.toString().getBytes()); - contentType=okhttp3.MediaType.parse(embeddedContentType); - } - } - nextPart=new StringBuilder(); - String contentLine=reader.readLine(); - if(contentLine!=null && contentLine.startsWith("Content-Type: ")) { - embeddedContentType=contentLine.substring(14); - } else { - embeddedContentType=null; - } - } else if(nextPart!=null) { - nextPart.append(line); - nextPart.append("\n"); - } - } - reader.close(); - // multipart parsing through, now look at the actual result in the last part - if(nextPart!=null && embeddedContentType!=null) { - // is it a downloaded skill text? - if (embeddedContentType.equals("application/sparql-query")) { - // immediately return - return nextPart.toString(); - } else if(embeddedContentType.equals("application/cx-warnings+json")) { - // is it a trailing warnings structure - List nextWarnings=typeManager.readValue(nextPart.toString(), warningTypeReference); - if(warnings.isPresent()) { - warnings.get().addAll(nextWarnings); - } else { - warnings=Optional.of(nextWarnings); - } - } else { - // it is a normal "result" that we take as the actual response - inputStream=new ByteArrayInputStream(nextPart.toString().getBytes()); - contentType=okhttp3.MediaType.parse(embeddedContentType); - } - } - } - // if we got a simple skill text as answer (not multipart) - if (contentType.toString().equals("application/sparql-query")) { - // return the skill text - return IOUtils.toString(inputStream, Charset.defaultCharset()); - } - // else set the response status a - response.setStatus(myResponse.code()); - // and the response headers (including the completed warnings - for(String header : myResponse.headers().names()) { - for(String value : myResponse.headers().values(header)) { - if(header.equals("cx_warnings")) { - List nextWarnings=typeManager.getMapper().readValue(value,warningTypeReference); - if (nextWarnings != null) { - if(warnings.isPresent()) { - warnings.get().addAll(nextWarnings); - } else { - warnings=Optional.of(nextWarnings); - } - } - } else if(!header.equalsIgnoreCase("content-length")) { - response.addHeader(header, value); - } - } - } - warnings.ifPresent(catenaxWarnings -> response.addHeader("cx_warnings", typeManager.writeValueAsString(catenaxWarnings))); - if(contentType!=null) { - response.setContentType(contentType.toString()); - } - // and finally copy the body from intermediate response to final response - IOUtils.copy(inputStream, response.getOutputStream()); - inputStream.close(); - } - } - return null; - } - + DelegationResponse executeQueryRemote(String remoteUrl, String skill, String graph, HttpHeaders headers, HttpServletRequest request, HttpServletResponse response, UriInfo uri); } diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationServiceImpl.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationServiceImpl.java new file mode 100644 index 0000000..1601497 --- /dev/null +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationServiceImpl.java @@ -0,0 +1,367 @@ +// Copyright (c) 2022,2023 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http; + +import com.fasterxml.jackson.core.type.TypeReference; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.UriInfo; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpStatus; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.types.TypeManager; +import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; +import org.eclipse.tractusx.agents.edc.AgentConfig; +import org.eclipse.tractusx.agents.edc.AgreementController; +import org.eclipse.tractusx.agents.edc.sparql.CatenaxWarning; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * A service that may delegate an incoming + * agent http request ot another agent in the + * dataspace + * deals with the special case of remote/provided (textual) + * skills which should be executed locally nevertheless + */ +public class DelegationServiceImpl implements DelegationService { + + protected final AgreementController agreementController; + protected final Monitor monitor; + protected final OkHttpClient client; + public static final TypeReference> WARNING_TYPE_REFERENCE = new TypeReference<>(){}; + protected final TypeManager typeManager; + protected final AgentConfig config; + + /** + * creates a new delegation service + * + * @param agreementController EDC agreement helper + * @param monitor logging facility + * @param client outgoing http infrastructure + */ + public DelegationServiceImpl(AgreementController agreementController, Monitor monitor, OkHttpClient client, TypeManager typeManager, AgentConfig config) { + this.agreementController = agreementController; + this.monitor = monitor; + this.client = client; + this.typeManager = typeManager; + this.config = config; + } + + /** + * the actual execution is done by delegating to the Dataspace + * + * @param remoteUrl remote connector + * @param skill target skill + * @param graph target graph + * @return a wrapped response which indicates the runMode that the execution should be done + */ + public DelegationResponse executeQueryRemote(String remoteUrl, String skill, String graph, HttpHeaders headers, HttpServletRequest request, HttpServletResponse response, UriInfo uri) { + Pattern serviceAllowPattern = config.getServiceAllowPattern(); + if (!serviceAllowPattern.matcher(remoteUrl).matches()) { + return new DelegationResponse(HttpUtils.respond(monitor, headers, HttpStatus.SC_FORBIDDEN, String.format("Service %s does not match the allowed service pattern %s", remoteUrl, serviceAllowPattern.pattern()), null)); + } + Pattern serviceDenyPattern = config.getServiceDenyPattern(); + if (serviceDenyPattern.matcher(remoteUrl).matches()) { + return new DelegationResponse(HttpUtils.respond(monitor, headers, HttpStatus.SC_FORBIDDEN, String.format("Service %s matches the denied service pattern %s", remoteUrl, serviceDenyPattern.pattern()), null)); + } + String asset = skill != null ? skill : graph; + EndpointDataReference endpoint = agreementController.get(asset); + if (endpoint == null) { + try { + endpoint = agreementController.createAgreement(remoteUrl, asset); + } catch (WebApplicationException e) { + return new DelegationResponse(HttpUtils.respond(monitor, headers, e.getResponse().getStatus(), String.format("Could not get an agreement from connector %s to asset %s", remoteUrl, asset), e.getCause())); + } + } + if (endpoint == null) { + return new DelegationResponse(HttpUtils.respond(monitor, headers, HttpStatus.SC_FORBIDDEN, String.format("Could not get an agreement from connector %s to asset %s", remoteUrl, asset), null)); + } + if ("GET".equals(request.getMethod())) { + try { + return sendGetRequest(endpoint, "", headers, response, uri); + } catch (IOException e) { + return new DelegationResponse(HttpUtils.respond(monitor, headers, HttpStatus.SC_INTERNAL_SERVER_ERROR, String.format("Could not delegate remote GET call to connector %s asset %s", remoteUrl, asset), e)); + } + } else if ("POST".equals(request.getMethod())) { + try { + return sendPostRequest(endpoint, "", headers, request, response, uri); + } catch (IOException e) { + return new DelegationResponse(HttpUtils.respond(monitor, headers, HttpStatus.SC_INTERNAL_SERVER_ERROR, String.format("Could not delegate remote POST call to connector %s asset %s", remoteUrl, asset), e)); + } + } else { + return new DelegationResponse(HttpUtils.respond(monitor, headers, HttpStatus.SC_METHOD_NOT_ALLOWED, String.format("%s calls to connector %s asset %s are not allowed", request.getMethod(), remoteUrl, asset), null)); + } + + } + + /** + * route a get request + * + * @param dataReference the encoded call embedding + * @param subUrl protocol-specific part + * @return a wrapped response which indicates the runMode that the execution should be done + * @throws IOException in case something strange happens + */ + public DelegationResponse sendGetRequest(EndpointDataReference dataReference, String subUrl, HttpHeaders headers, HttpServletResponse response, UriInfo uri) throws IOException { + var url = getUrl(dataReference.getEndpoint(), subUrl, headers, uri); + + monitor.debug(String.format("About to delegate GET %s", url)); + + var requestBuilder = new okhttp3.Request.Builder() + .url(url); + + if (dataReference.getAuthKey() != null) { + requestBuilder = requestBuilder.addHeader(dataReference.getAuthKey(), Objects.requireNonNull(dataReference.getAuthCode())); + } + + var newRequest = requestBuilder.build(); + + return new DelegationResponse(sendRequest(newRequest, response), Response.status(response.getStatus()).build()); + } + + /** + * route a post request + * + * @param dataReference the encoded call embedding + * @param subUrl protocol-specific part + * @return a wrapped response which indicates the runMode that the execution should be done + * @throws IOException in case something strange happens + */ + public DelegationResponse sendPostRequest(EndpointDataReference dataReference, String subUrl, HttpHeaders headers, HttpServletRequest request, HttpServletResponse response, UriInfo uri) throws IOException { + var url = getUrl(dataReference.getEndpoint(), subUrl, headers, uri); + + String contentType = request.getContentType(); + okhttp3.MediaType parsedContentType = okhttp3.MediaType.parse(contentType); + + monitor.debug(String.format("About to delegate POST %s with content type %s", url, contentType)); + + var requestBuilder = new okhttp3.Request.Builder() + .url(url) + .addHeader("Content-Type", contentType); + + if (dataReference.getAuthKey() != null) { + requestBuilder = requestBuilder.addHeader(dataReference.getAuthKey(), Objects.requireNonNull(dataReference.getAuthCode())); + } + + requestBuilder.post(okhttp3.RequestBody.create(request.getInputStream().readAllBytes(), parsedContentType)); + + var newRequest = requestBuilder.build(); + + return new DelegationResponse(sendRequest(newRequest, response), Response.status(response.getStatus()).build()); + } + + protected static final Pattern PARAMETER_KEY_ALLOW = Pattern.compile("^(?!asset$)[^&?=]+$"); + protected static final Pattern PARAMETER_VALUE_ALLOW = Pattern.compile("^.+$"); + + /** + * computes the url to target the given data plane + * + * @param connectorUrl data plane url + * @param subUrl sub-path to use + * @param headers containing additional info that we need to wrap into a transfer request + * @return typed url + */ + protected HttpUrl getUrl(String connectorUrl, String subUrl, HttpHeaders headers, UriInfo uri) { + var url = connectorUrl; + + // EDC public api slash problem + if (!url.endsWith("/") && !url.contains("#")) { + url = url + "/"; + } + + if (subUrl != null && !subUrl.isEmpty()) { + url = url + subUrl; + } + + HttpUrl.Builder httpBuilder = Objects.requireNonNull(okhttp3.HttpUrl.parse(url)).newBuilder(); + for (Map.Entry> param : uri.getQueryParameters().entrySet()) { + String key = param.getKey(); + if (PARAMETER_KEY_ALLOW.matcher(key).matches()) { + for (String value : param.getValue()) { + if (PARAMETER_VALUE_ALLOW.matcher(value).matches()) { + String recodeKey = HttpUtils.urlEncodeParameter(key); + String recodeValue = HttpUtils.urlEncodeParameter(value); + httpBuilder = httpBuilder.addQueryParameter(recodeKey, recodeValue); + } + } + } + } + + List mediaTypes = headers.getAcceptableMediaTypes(); + if (mediaTypes.isEmpty() || mediaTypes.stream().anyMatch(MediaType.APPLICATION_JSON_TYPE::isCompatible)) { + httpBuilder = httpBuilder.addQueryParameter("cx_accept", HttpUtils.urlEncodeParameter("application/json")); + } else { + String mediaParam = mediaTypes.stream().map(MediaType::toString).collect(Collectors.joining(", ")); + mediaParam = HttpUtils.urlEncodeParameter(mediaParam); + httpBuilder.addQueryParameter("cx_accept", mediaParam); + } + return httpBuilder.build(); + } + + /** + * generic sendRequest method which extracts the result string of textual responses + * + * @param request predefined request + * @param response the final response + * @return the text of a downloaded skill if runMode = consumer, null otherwise + * @throws IOException in case something goes wrong + */ + protected String sendRequest(okhttp3.Request request, HttpServletResponse response) throws IOException { + try (var myResponse = client.newCall(request).execute()) { + + if (!myResponse.isSuccessful()) { + monitor.warning(String.format("Data plane call was not successful: %s", myResponse.code())); + } + + Optional> warnings = Optional.empty(); + + var body = myResponse.body(); + + if (body != null) { + okhttp3.MediaType contentType = body.contentType(); + InputStream inputStream = new BufferedInputStream(body.byteStream()); + + // + // Analyze whether this response contains a multipart body + // while maintaining the state of the inputstream (mark/reset approach) + // + inputStream.mark(2); + byte[] boundaryBytes = new byte[2]; + String boundary = ""; + if (inputStream.read(boundaryBytes) > 0) { + boundary = new String(boundaryBytes); + } + inputStream.reset(); + if ("--".equals(boundary)) { + // + // Multipart Case separates the actual result (last part) from the warnings (first part) + // + if (contentType != null) { + int boundaryIndex; + boundaryIndex = contentType.toString().indexOf(";boundary="); + if (boundaryIndex >= 0) { + boundary = boundary + contentType.toString().substring(boundaryIndex + 10); + } + } + StringBuilder nextPart = null; + String embeddedContentType = null; + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + for (String line = reader.readLine(); line != null; line = reader.readLine()) { + if (boundary.equals(line)) { + if (nextPart != null && embeddedContentType != null) { + if (embeddedContentType.equals("application/cx-warnings+json")) { + List nextWarnings = typeManager.readValue(nextPart.toString(), WARNING_TYPE_REFERENCE); + if (warnings.isPresent()) { + warnings.get().addAll(nextWarnings); + } else { + warnings = Optional.of(nextWarnings); + } + } else { + inputStream = new ByteArrayInputStream(nextPart.toString().getBytes()); + contentType = okhttp3.MediaType.parse(embeddedContentType); + } + } + nextPart = new StringBuilder(); + String contentLine = reader.readLine(); + if (contentLine != null && contentLine.startsWith("Content-Type: ")) { + embeddedContentType = contentLine.substring(14); + } else { + embeddedContentType = null; + } + } else if (nextPart != null) { + nextPart.append(line); + nextPart.append("\n"); + } + } + reader.close(); + // multipart parsing through, now look at the actual result in the last part + if (nextPart != null && embeddedContentType != null) { + // is it a downloaded skill text? + if (embeddedContentType.equals("application/sparql-query")) { + // immediately return + return nextPart.toString(); + } else if (embeddedContentType.equals("application/cx-warnings+json")) { + // is it a trailing warnings structure + List nextWarnings = typeManager.readValue(nextPart.toString(), WARNING_TYPE_REFERENCE); + if (warnings.isPresent()) { + warnings.get().addAll(nextWarnings); + } else { + warnings = Optional.of(nextWarnings); + } + } else { + // it is a normal "result" that we take as the actual response + inputStream = new ByteArrayInputStream(nextPart.toString().getBytes()); + contentType = okhttp3.MediaType.parse(embeddedContentType); + } + } + } + // if we got a simple skill text as answer (not multipart) + if (contentType.toString().equals("application/sparql-query")) { + // return the skill text + return IOUtils.toString(inputStream, Charset.defaultCharset()); + } + // else set the response status a + response.setStatus(myResponse.code()); + // and the response headers (including the completed warnings + for (String header : myResponse.headers().names()) { + for (String value : myResponse.headers().values(header)) { + if (header.equals("cx_warnings")) { + List nextWarnings = typeManager.getMapper().readValue(value, WARNING_TYPE_REFERENCE); + if (nextWarnings != null) { + if (warnings.isPresent()) { + warnings.get().addAll(nextWarnings); + } else { + warnings = Optional.of(nextWarnings); + } + } + } else if (!header.equalsIgnoreCase("content-length")) { + response.addHeader(header, value); + } + } + } + warnings.ifPresent(catenaxWarnings -> response.addHeader("cx_warnings", typeManager.writeValueAsString(catenaxWarnings))); + if (contentType != null) { + response.setContentType(contentType.toString()); + } + // and finally copy the body from intermediate response to final response + IOUtils.copy(inputStream, response.getOutputStream()); + inputStream.close(); + } + } + return null; + } + +} diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpClientAdapter.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpClientAdapter.java index 127b766..9f72b52 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpClientAdapter.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpClientAdapter.java @@ -16,10 +16,13 @@ // SPDX-License-Identifier: Apache-2.0 package org.eclipse.tractusx.agents.edc.http; -import okhttp3.*; +import okhttp3.Call; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLParameters; import java.io.IOException; import java.net.Authenticator; import java.net.CookieHandler; @@ -33,6 +36,8 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.Flow; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; /** * Wrapper that hides OkHttpClient behind a java.net.http.HttpClient @@ -43,10 +48,11 @@ public class HttpClientAdapter extends HttpClient { /** * creates a new wrapper + * * @param delegate the real client */ public HttpClientAdapter(OkHttpClient delegate) { - this.delegate=delegate; + this.delegate = delegate; } @@ -97,9 +103,9 @@ public Optional executor() { @Override public HttpResponse send(HttpRequest request, HttpResponse.BodyHandler responseBodyHandler) throws IOException, InterruptedException { - var builder=new Request.Builder(); - request.headers().map().forEach( (key,values) -> values.forEach( value -> builder.header(key,value))); - if(request.bodyPublisher().isPresent()) { + var builder = new Request.Builder(); + request.headers().map().forEach((key, values) -> values.forEach(value -> builder.header(key, value))); + if (request.bodyPublisher().isPresent()) { var bodyPublisher = request.bodyPublisher().get(); var subscriber = new Flow.Subscriber() { @@ -115,14 +121,14 @@ public void onSubscribe(Flow.Subscription subscription) { @Override public void onNext(ByteBuffer item) { - if(body==null) { + if (body == null) { body = item; - } else if(item!=null) { - ByteBuffer combined=ByteBuffer.allocate(body.capacity()+item.capacity()); + } else if (item != null) { + ByteBuffer combined = ByteBuffer.allocate(body.capacity() + item.capacity()); combined.put(body); combined.put(item); combined.flip(); - body=combined; + body = combined; } } @@ -146,17 +152,17 @@ public void onComplete() { throw new IOException("Could not wrap request because body cannot be read"); } if (subscriber.problem != null) { - throw new IOException("Could not wrap request because body cannot be read",subscriber.problem); + throw new IOException("Could not wrap request because body cannot be read", subscriber.problem); } - builder.method(request.method(), RequestBody.create(subscriber.body.array(),MediaType.parse(request.headers().firstValue("Content-Type").get()))); + builder.method(request.method(), RequestBody.create(subscriber.body.array(), MediaType.parse(request.headers().firstValue("Content-Type").get()))); } else { builder.method(request.method(), null); } builder.url(request.uri().toURL()); - Request okRequest=builder.build(); + Request okRequest = builder.build(); Call okCall = delegate.newCall(okRequest); - Response okResponse=okCall.execute(); - return (HttpResponse) new HttpResponseAdapter(okResponse,request); + Response okResponse = okCall.execute(); + return (HttpResponse) new HttpResponseAdapter(okResponse, request); } @Override diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpClientFactory.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpClientFactory.java index 1fd31ed..eaf6939 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpClientFactory.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpClientFactory.java @@ -16,11 +16,11 @@ // SPDX-License-Identifier: Apache-2.0 package org.eclipse.tractusx.agents.edc.http; +import okhttp3.OkHttpClient; import org.eclipse.edc.connector.dataplane.spi.pipeline.DataSourceFactory; import org.eclipse.edc.connector.dataplane.spi.pipeline.PipelineService; import org.eclipse.edc.spi.http.EdcHttpClient; import org.eclipse.tractusx.agents.edc.AgentConfig; -import okhttp3.OkHttpClient; import org.jetbrains.annotations.NotNull; import java.lang.reflect.Field; @@ -46,12 +46,12 @@ public class HttpClientFactory { static { try { - sourceFactories=HttpClientFactory.class.getClassLoader().loadClass("org.eclipse.edc.connector.dataplane.framework.pipeline.PipelineServiceImpl").getDeclaredField("sourceFactories"); + sourceFactories = HttpClientFactory.class.getClassLoader().loadClass("org.eclipse.edc.connector.dataplane.framework.pipeline.PipelineServiceImpl").getDeclaredField("sourceFactories"); sourceFactories.setAccessible(true); - httpDataSourceFactory=HttpClientFactory.class.getClassLoader().loadClass("org.eclipse.edc.connector.dataplane.http.pipeline.HttpDataSourceFactory"); - httpClient=httpDataSourceFactory.getDeclaredField("httpClient"); + httpDataSourceFactory = HttpClientFactory.class.getClassLoader().loadClass("org.eclipse.edc.connector.dataplane.http.pipeline.HttpDataSourceFactory"); + httpClient = httpDataSourceFactory.getDeclaredField("httpClient"); httpClient.setAccessible(true); - okHttpClient=HttpClientFactory.class.getClassLoader().loadClass("org.eclipse.edc.connector.core.base.EdcHttpClientImpl").getDeclaredField("okHttpClient"); + okHttpClient = HttpClientFactory.class.getClassLoader().loadClass("org.eclipse.edc.connector.core.base.EdcHttpClientImpl").getDeclaredField("okHttpClient"); okHttpClient.setAccessible(true); connectTimeoutMillis = OkHttpClient.class.getDeclaredField("connectTimeoutMillis"); connectTimeoutMillis.setAccessible(true); @@ -63,27 +63,28 @@ public class HttpClientFactory { pingIntervalMillis.setAccessible(true); callTimeoutMillis = OkHttpClient.class.getDeclaredField("pingIntervalMillis"); callTimeoutMillis.setAccessible(true); - } catch(ClassNotFoundException | NoSuchFieldException e) { + } catch (ClassNotFoundException | NoSuchFieldException e) { System.err.println("HttpClientFactory could not be initialised. Leaving default okhttp settings."); } } /** * Create an modified OkHttpClient instance + * * @param config agent config * @param client parent/blueprint instance * @return the modified OkHttpClient */ @NotNull - public static Map.Entry create(EdcHttpClient eClient, OkHttpClient client, PipelineService service, AgentConfig config) { - Integer connectTimeout=config.getConnectTimeout(); - Integer readTimeout=config.getReadTimeout(); - Integer callTimeout=config.getCallTimeout(); - Integer writeTimeout=config.getWriteTimeout(); + public static Map.Entry create(EdcHttpClient edcClient, OkHttpClient client, PipelineService service, AgentConfig config) { + Integer connectTimeout = config.getConnectTimeout(); + Integer readTimeout = config.getReadTimeout(); + Integer callTimeout = config.getCallTimeout(); + Integer writeTimeout = config.getWriteTimeout(); - if(connectTimeout!=null || readTimeout!=null || callTimeout!=null || writeTimeout!=null) { + if (connectTimeout != null || readTimeout != null || callTimeout != null || writeTimeout != null) { try { - eClient = ((Collection) sourceFactories.get(service)).stream().flatMap(factory -> { + edcClient = ((Collection) sourceFactories.get(service)).stream().flatMap(factory -> { if (httpDataSourceFactory.equals(factory.getClass())) { try { return Optional.of((EdcHttpClient) httpClient.get(factory)).stream(); @@ -93,8 +94,8 @@ public static Map.Entry create(EdcHttpClient eClient } return Optional.empty().stream(); } - ).findFirst().orElse(eClient); - client = (OkHttpClient) okHttpClient.get(eClient); + ).findFirst().orElse(edcClient); + client = (OkHttpClient) okHttpClient.get(edcClient); } catch (IllegalArgumentException | IllegalAccessException e) { System.err.println("HttpClientFactory could not reuse okhttp client."); } @@ -127,7 +128,7 @@ public static Map.Entry create(EdcHttpClient eClient } } } - return new AbstractMap.SimpleEntry(eClient,client); + return new AbstractMap.SimpleEntry(edcClient, client); } } diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpResponseAdapter.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpResponseAdapter.java index fca3005..64cd6a0 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpResponseAdapter.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpResponseAdapter.java @@ -19,7 +19,6 @@ import okhttp3.Response; import okhttp3.ResponseBody; -import javax.net.ssl.SSLSession; import java.io.InputStream; import java.net.URI; import java.net.http.HttpClient; @@ -27,6 +26,7 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.util.Optional; +import javax.net.ssl.SSLSession; /** * wraps OkHttp Response to java.net.http version @@ -38,9 +38,9 @@ public class HttpResponseAdapter implements HttpResponse { HttpRequest request; public HttpResponseAdapter(Response delegate, HttpRequest request) { - this.delegate=delegate; - this.request=request; - headers=HttpHeaders.of(delegate.headers().toMultimap(), (key,value)->true); + this.delegate = delegate; + this.request = request; + headers = HttpHeaders.of(delegate.headers().toMultimap(), (key, value) -> true); } @Override @@ -65,9 +65,9 @@ public HttpHeaders headers() { @Override public InputStream body() { - ResponseBody body=delegate.body(); - if(body!=null) { - return body.byteStream(); + ResponseBody body = delegate.body(); + if (body != null) { + return body.byteStream(); } return null; } diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletContextAdapter.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletContextAdapter.java index de46ac8..b1e58a1 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletContextAdapter.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletContextAdapter.java @@ -18,12 +18,25 @@ import okhttp3.Request; -import javax.servlet.*; -import javax.servlet.descriptor.JspConfigDescriptor; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; -import java.util.*; +import java.util.Collections; +import java.util.Enumeration; +import java.util.EventListener; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import javax.servlet.Filter; +import javax.servlet.FilterRegistration; +import javax.servlet.RequestDispatcher; +import javax.servlet.Servlet; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRegistration; +import javax.servlet.SessionCookieConfig; +import javax.servlet.SessionTrackingMode; +import javax.servlet.descriptor.JspConfigDescriptor; /** * Servlet context adapter which hides a mock okhttp request @@ -32,8 +45,9 @@ public class HttpServletContextAdapter implements ServletContext { Request request; protected final Map attributes = new HashMap<>(); + public HttpServletContextAdapter(Request request) { - this.request=request; + this.request = request; } @Override @@ -163,7 +177,7 @@ public Enumeration getAttributeNames() { @Override public void setAttribute(String name, Object object) { - attributes.put(name,object); + attributes.put(name, object); } @Override diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletRequestAdapter.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletRequestAdapter.java index f855f5e..bb14d97 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletRequestAdapter.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletRequestAdapter.java @@ -17,13 +17,35 @@ package org.eclipse.tractusx.agents.edc.http; import okhttp3.Request; -import okio.*; +import okio.Buffer; -import javax.servlet.*; -import javax.servlet.http.*; -import java.io.*; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.StringReader; +import java.io.UnsupportedEncodingException; import java.security.Principal; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import javax.servlet.AsyncContext; +import javax.servlet.DispatcherType; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpUpgradeHandler; +import javax.servlet.http.Part; /** * Wraps an ok Request into a javax servlet request @@ -34,8 +56,8 @@ public class HttpServletRequestAdapter implements HttpServletRequest { protected final ServletContext context; public HttpServletRequestAdapter(Request request, ServletContext context) { - this.request=request; - this.context=context; + this.request = request; + this.context = context; } @Override @@ -72,7 +94,7 @@ public Enumeration getHeaderNames() { public int getIntHeader(String name) { try { return Integer.parseInt(request.header(name)); - } catch(NumberFormatException nfe) { + } catch (NumberFormatException nfe) { throw new RuntimeException(nfe); } } @@ -226,7 +248,7 @@ public void setCharacterEncoding(String env) throws UnsupportedEncodingException public int getContentLength() { try { return (int) request.body().contentLength(); - } catch(IOException e) { + } catch (IOException e) { return -1; } } @@ -235,17 +257,17 @@ public int getContentLength() { public long getContentLengthLong() { try { return request.body().contentLength(); - } catch(IOException e) { + } catch (IOException e) { return -1L; } } @Override public String getContentType() { - var body=request.body(); - if(body!=null) { - var contentType=body.contentType(); - if(contentType!=null) { + var body = request.body(); + if (body != null) { + var contentType = body.contentType(); + if (contentType != null) { return contentType.toString(); } } @@ -254,9 +276,9 @@ public String getContentType() { @Override public ServletInputStream getInputStream() throws IOException { - Buffer buffer=new Buffer(); + Buffer buffer = new Buffer(); request.body().writeTo(buffer); - ByteArrayInputStream bais=new ByteArrayInputStream(buffer.readByteArray()); + ByteArrayInputStream bais = new ByteArrayInputStream(buffer.readByteArray()); return new ServletInputStreamDelegator(bais); } @@ -277,9 +299,9 @@ public String[] getParameterValues(String name) { @Override public Map getParameterMap() { - Map parameterMap=new HashMap<>(); + Map parameterMap = new HashMap<>(); for (String queryParameterName : request.url().queryParameterNames()) { - parameterMap.put(queryParameterName,getParameterValues(queryParameterName)); + parameterMap.put(queryParameterName, getParameterValues(queryParameterName)); } return parameterMap; } @@ -321,7 +343,7 @@ public String getRemoteHost() { @Override public void setAttribute(String name, Object o) { - context.setAttribute(name,o); + context.setAttribute(name, o); } @Override diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletResponseAdapter.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletResponseAdapter.java index b245c13..161700b 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletResponseAdapter.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletResponseAdapter.java @@ -16,25 +16,29 @@ // SPDX-License-Identifier: Apache-2.0 package org.eclipse.tractusx.agents.edc.http; -import okhttp3.*; +import okhttp3.MediaType; +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletResponse; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.Collection; import java.util.Locale; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; /** * builds a ok response from an in-memory servlet response implementation */ public class HttpServletResponseAdapter implements HttpServletResponse { - Response.Builder builder=new Response.Builder(); - ByteArrayOutputStream bos=new ByteArrayOutputStream(); - ServletOutputStream sos=new ServletOutputStreamDelegator(bos); + Response.Builder builder = new Response.Builder(); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ServletOutputStream sos = new ServletOutputStreamDelegator(bos); String contentType; long contentLength; @@ -90,37 +94,37 @@ public void sendRedirect(String location) throws IOException { @Override public void setDateHeader(String name, long date) { - builder.header(name,String.valueOf(date)); + builder.header(name, String.valueOf(date)); } @Override public void addDateHeader(String name, long date) { - builder.addHeader(name,String.valueOf(date)); + builder.addHeader(name, String.valueOf(date)); } @Override public void setHeader(String name, String value) { - builder.header(name,value); + builder.header(name, value); } @Override public void addHeader(String name, String value) { - builder.addHeader(name,value); + builder.addHeader(name, value); } @Override public void setIntHeader(String name, int value) { - builder.header(name,String.valueOf(value)); + builder.header(name, String.valueOf(value)); } @Override public void addIntHeader(String name, int value) { - builder.addHeader(name,String.valueOf(value)); + builder.addHeader(name, String.valueOf(value)); } @Override public void setStatus(int sc) { - builder.code(sc).message(String.format("Status %d",sc)); + builder.code(sc).message(String.format("Status %d", sc)); } @Override @@ -174,17 +178,17 @@ public void setCharacterEncoding(String charset) { @Override public void setContentLength(int len) { - contentLength=len; + contentLength = len; } @Override public void setContentLengthLong(long len) { - contentLength=len; + contentLength = len; } @Override public void setContentType(String type) { - contentType=type; + contentType = type; } @Override @@ -225,8 +229,8 @@ public Locale getLocale() { } public Response toResponse() { - if(contentType!=null) { - ResponseBody body= ResponseBody.create(bos.toByteArray(), MediaType.parse(contentType)); + if (contentType != null) { + ResponseBody body = ResponseBody.create(bos.toByteArray(), MediaType.parse(contentType)); builder.body(body); } return builder.build(); diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpUtils.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpUtils.java index 8a9feda..2137076 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpUtils.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpUtils.java @@ -29,36 +29,38 @@ */ public class HttpUtils { - public static String DEFAULT_ENCODING = System.getProperty("fis.encoding","UTF-8"); + public static final String DEFAULT_ENCODING = System.getProperty("fis.encoding", "UTF-8"); /** * ensure that the given parameter string is correctly * encoded + * * @param pattern maybe undecoded patterm - * @return a url encoded string + * @return a url encoded string */ public static String urlEncode(String pattern) { try { - return URLEncoder.encode(pattern,DEFAULT_ENCODING); - } catch(UnsupportedEncodingException e) { + return URLEncoder.encode(pattern, DEFAULT_ENCODING); + } catch (UnsupportedEncodingException e) { // this should never happen return pattern; } } - /** + /** * ensure that the given parameter string is correctly * encoded * TODO optimize + * * @param parameter maybe undecoded parameter * @return a url encoded string which additionally encodes some URL-prefix related symbols */ - public static String urlEncodeParameter(String parameter) { - if(parameter==null || parameter.length()==0) return ""; + public static String urlEncodeParameter(String parameter) { + if (parameter == null || parameter.length() == 0) return ""; try { parameter = urlDecodeParameter(parameter); return encodeParameter(urlEncode(parameter)); - } catch(UnsupportedEncodingException e) { + } catch (UnsupportedEncodingException e) { // this should never happen return parameter; } @@ -66,14 +68,15 @@ public static String urlEncodeParameter(String parameter) { /** * ensure that the given parameter string is correctly decoded + * * @param parameter maybe encoded parameter * @return a url decoded string */ - public static String urlDecodeParameter(String parameter) { - if(parameter==null || parameter.length()==0) return ""; + public static String urlDecodeParameter(String parameter) { + if (parameter == null || parameter.length() == 0) return ""; try { - return URLDecoder.decode(parameter,DEFAULT_ENCODING); - } catch(UnsupportedEncodingException e) { + return URLDecoder.decode(parameter, DEFAULT_ENCODING); + } catch (UnsupportedEncodingException e) { // this should never happen return parameter; } @@ -83,55 +86,57 @@ public static String urlDecodeParameter(String parameter) { * ensure that the given parameter string is correctly * encoded * TODO optimize + * * @param parameter maybe undecoded parameter * @return a url encoded string which additionally encodes some URL-prefix related symbols */ public static String encodeParameter(String parameter) throws UnsupportedEncodingException { - if(parameter==null || parameter.length()==0) return ""; - return parameter.replace("?","%3F") - .replace("=","%3D") - .replace("{","%7B") - .replace("}","%7D") - .replace("/","%2F"); + if (parameter == null || parameter.length() == 0) return ""; + return parameter.replace("?", "%3F") + .replace("=", "%3D") + .replace("{", "%7B") + .replace("}", "%7D") + .replace("/", "%2F"); } /** * creates a response from a given setting * depending on the accept type + * * @param monitor logging system to save the reference error * @param headers of the request * @param message error message - * @param cause error object + * @param cause error object * @return http response with the right body and reference to the logging subsystem */ public static Response respond(Monitor monitor, HttpHeaders headers, int status, String message, Throwable cause) { - int messageCode=message.hashCode(); - if(monitor!=null) { - if(cause!=null) { - monitor.warning(String.format("Response with error id %d delivered message %s under cause %s", messageCode, message, cause.getMessage()),cause); + int messageCode = message.hashCode(); + if (monitor != null) { + if (cause != null) { + monitor.warning(String.format("Response with error id %d delivered message %s under cause %s", messageCode, message, cause.getMessage()), cause); } else { monitor.warning(String.format("Response with error id %d delivered message %s", messageCode, message)); } } var builder = Response.status(status); - String accept=headers.getHeaderString("Accept"); - if(accept==null || accept.length()==0 ) { - accept="*/*"; + String accept = headers.getHeaderString("Accept"); + if (accept == null || accept.length() == 0) { + accept = "*/*"; } - if(accept.contains("*/*")) { - accept="application/json"; + if (accept.contains("*/*")) { + accept = "application/json"; } - if(accept.contains("application/json")) { + if (accept.contains("application/json")) { builder.type("application/json"); builder.entity("{ " + "\"status\":" + String.valueOf(status) + "," + "\"message\":\"" + messageCode + "\" }"); - } else if(accept.contains("text/xml") || accept.contains("application/xml")) { + } else if (accept.contains("text/xml") || accept.contains("application/xml")) { builder.type(accept.contains("text/xml") ? "text/xml" : "application/xml"); builder.entity(" " + "" + String.valueOf(status) + "" + "" + messageCode + " "); - } else if(accept.contains("text/html")) { + } else if (accept.contains("text/html")) { builder.type("text/html"); builder.entity("\n" + "\n" + @@ -151,5 +156,5 @@ public static Response respond(Monitor monitor, HttpHeaders headers, int status, builder.entity(messageCode); } return builder.build(); - } + } } diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/IDelegationService.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/IDelegationService.java deleted file mode 100644 index 703c972..0000000 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/IDelegationService.java +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2022,2023 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.ws.rs.core.HttpHeaders; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.UriInfo; - -/** - * interface to a service that may - * delegate agent http calls into the - * dataspace - */ -public interface IDelegationService { - /** - * delegate the given call into the dataspace - * @param remoteUrl target EDC - * @param skill name of the remote skill (may be empty, then graph must be set) - * @param graph name of the remote graph (may be empty, then skill must be set) - * @param headers url call headers - * @param request url request - * @param response final response - * @param uri original uri - * @return an intermediate response which may contain a textual skill to be executed locally otherwise the actual result has already been put into the final response's state - */ - DelegationResponse executeQueryRemote(String remoteUrl, String skill, String graph, HttpHeaders headers, HttpServletRequest request, HttpServletResponse response, UriInfo uri); -} diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/IJakartaAdapter.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/IJakartaAdapter.java deleted file mode 100644 index 19b207e..0000000 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/IJakartaAdapter.java +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2022,2023 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http; - -import java.lang.reflect.*; - -import org.eclipse.edc.spi.monitor.Monitor; - -/** - * An invocation handler which maps all jakarta objects - * to a javax.servlet level - */ -public interface IJakartaAdapter { - - /** - * @return the wrapper object - */ - Target getDelegate(); - - /** - * @return EDC logging support - */ - Monitor getMonitor(); - - /** - * unwrap logic - * @param types array of type annotations - * @param args array of objects - * @return unwrapped array of objects - * @throws Throwable in case something strange happens - */ - @SuppressWarnings("rawtypes") - static Object[] unwrap(Class[] types, Object[] args) throws Throwable { - if(args==null) args=new Object[0]; - for(int count=0;count wrapper; - if(args[count] instanceof IJakartaAdapter) { - wrapper=(IJakartaAdapter) args[count]; - } else { - // we assume its a proxy - wrapper=(IJakartaAdapter) Proxy.getInvocationHandler(args[count]); - } - args[count]=wrapper.getDelegate(); - Class jakartaClass= IJakartaAdapter.class.getClassLoader().loadClass(types[count].getCanonicalName().replace("javax.servlet","jakarta.servlet")); - types[count]=jakartaClass; - } - } - return args; - } - - /** - * wrap logic - * @param jakarta original object - * @param javaxClass target interfaces - * @param monitor EDC loggin subsystem - * @param target interfaces as generics - * @return wrapped object - */ - static Target javaxify(Object jakarta, Class javaxClass, Monitor monitor) { - if(javax.servlet.ServletInputStream.class.equals(javaxClass)) { - return (Target) new JakartaServletInputStreamAdapter((jakarta.servlet.ServletInputStream) jakarta,monitor); - } - if(javax.servlet.ServletOutputStream.class.equals(javaxClass)) { - return (Target) new JakartaServletOutputStreamAdapter((jakarta.servlet.ServletOutputStream) jakarta,monitor); - } - return (Target) Proxy.newProxyInstance(JakartaAdapter.class.getClassLoader(), - new Class[] { javaxClass }, - new JakartaAdapter(jakarta,monitor)); - } - -} diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaAdapter.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaAdapter.java index 001e263..a994bec 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaAdapter.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaAdapter.java @@ -16,46 +16,77 @@ // SPDX-License-Identifier: Apache-2.0 package org.eclipse.tractusx.agents.edc.http; -import java.lang.reflect.*; - import org.eclipse.edc.spi.monitor.Monitor; +import java.lang.reflect.Proxy; + /** * An invocation handler which maps all jakarta objects * to a javax.servlet level */ -public class JakartaAdapter implements InvocationHandler, IJakartaAdapter { - - Object jakartaDelegate; - Monitor monitor; - - public JakartaAdapter(Object jakartaDelegate, Monitor monitor) { - this.jakartaDelegate=jakartaDelegate; - this.monitor=monitor; - } +public interface JakartaAdapter { - @Override - public Object getDelegate() { - return jakartaDelegate; - } + /** + * access + * + * @return the wrapper object + */ + TARGET getDelegate(); - @Override - public Monitor getMonitor() { - return monitor; - } + /** + * access + * + * @return EDC logging support + */ + Monitor getMonitor(); + /** + * unwrap logic + * + * @param types array of type annotations + * @param args array of objects + * @return unwrapped array of objects + * @throws Throwable in case something strange happens + */ @SuppressWarnings("rawtypes") - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - Class[] types=method.getParameterTypes(); - args= IJakartaAdapter.unwrap(types,args); - Method targetMethod=jakartaDelegate.getClass().getMethod(method.getName(),types); - Object result=targetMethod.invoke(jakartaDelegate,args); - //monitor.debug(String.format("Jakarta wrapper mapped method %s to target method %s on args %s with result %s",method,targetMethod,Arrays.toString(args),result)); - if((!method.getReturnType().isAssignableFrom(targetMethod.getReturnType())) && result!=null) { - result= IJakartaAdapter.javaxify(result,method.getReturnType(),monitor); + static Object[] unwrap(Class[] types, Object[] args) throws Throwable { + if (args == null) args = new Object[0]; + for (int count = 0; count < args.length; count++) { + if (types[count].getCanonicalName().startsWith("javax.servlet") && args[count] != null) { + JakartaAdapter wrapper; + if (args[count] instanceof JakartaAdapter) { + wrapper = (JakartaAdapter) args[count]; + } else { + // we assume its a proxy + wrapper = (JakartaAdapter) Proxy.getInvocationHandler(args[count]); + } + args[count] = wrapper.getDelegate(); + Class jakartaClass = JakartaAdapter.class.getClassLoader().loadClass(types[count].getCanonicalName().replace("javax.servlet", "jakarta.servlet")); + types[count] = jakartaClass; + } + } + return args; + } + + /** + * wrap logic + * + * @param jakarta original object + * @param javaxClass target interfaces + * @param monitor EDC loggin subsystem + * @param target interfaces as generics + * @return wrapped object + */ + static TARGET javaxify(Object jakarta, Class javaxClass, Monitor monitor) { + if (javax.servlet.ServletInputStream.class.equals(javaxClass)) { + return (TARGET) new JakartaServletInputStreamAdapter((jakarta.servlet.ServletInputStream) jakarta, monitor); + } + if (javax.servlet.ServletOutputStream.class.equals(javaxClass)) { + return (TARGET) new JakartaServletOutputStreamAdapter((jakarta.servlet.ServletOutputStream) jakarta, monitor); } - return result; + return (TARGET) Proxy.newProxyInstance(JakartaAdapterImpl.class.getClassLoader(), + new Class[]{ javaxClass }, + new JakartaAdapterImpl(jakarta, monitor)); } } diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaAdapterImpl.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaAdapterImpl.java new file mode 100644 index 0000000..46345cf --- /dev/null +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaAdapterImpl.java @@ -0,0 +1,62 @@ +// Copyright (c) 2022,2023 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http; + +import org.eclipse.edc.spi.monitor.Monitor; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +/** + * An invocation handler which maps all jakarta objects + * to a javax.servlet level + */ +public class JakartaAdapterImpl implements InvocationHandler, JakartaAdapter { + + Object jakartaDelegate; + Monitor monitor; + + public JakartaAdapterImpl(Object jakartaDelegate, Monitor monitor) { + this.jakartaDelegate = jakartaDelegate; + this.monitor = monitor; + } + + @Override + public Object getDelegate() { + return jakartaDelegate; + } + + @Override + public Monitor getMonitor() { + return monitor; + } + + @SuppressWarnings("rawtypes") + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + Class[] types = method.getParameterTypes(); + args = JakartaAdapter.unwrap(types, args); + Method targetMethod = jakartaDelegate.getClass().getMethod(method.getName(), types); + Object result = targetMethod.invoke(jakartaDelegate, args); + //monitor.debug(String.format("Jakarta wrapper mapped method %s to target method %s on args %s with result %s",method,targetMethod,Arrays.toString(args),result)); + if ((!method.getReturnType().isAssignableFrom(targetMethod.getReturnType())) && result != null) { + result = JakartaAdapter.javaxify(result, method.getReturnType(), monitor); + } + return result; + } + +} diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaServletInputStreamAdapter.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaServletInputStreamAdapter.java index 031130a..310cc12 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaServletInputStreamAdapter.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaServletInputStreamAdapter.java @@ -16,26 +16,25 @@ // SPDX-License-Identifier: Apache-2.0 package org.eclipse.tractusx.agents.edc.http; -import java.io.IOException; - -import javax.servlet.ReadListener; - import jakarta.servlet.ServletInputStream; import org.eclipse.edc.spi.monitor.Monitor; import org.jetbrains.annotations.NotNull; +import java.io.IOException; +import javax.servlet.ReadListener; + /** * An invocation handler which maps all jakarta input stream * to a javax.servlet level */ -public class JakartaServletInputStreamAdapter extends javax.servlet.ServletInputStream implements IJakartaAdapter { - +public class JakartaServletInputStreamAdapter extends javax.servlet.ServletInputStream implements JakartaAdapter { + jakarta.servlet.ServletInputStream jakartaDelegate; Monitor monitor; public JakartaServletInputStreamAdapter(jakarta.servlet.ServletInputStream jakartaDelegate, Monitor monitor) { - this.jakartaDelegate=jakartaDelegate; - this.monitor=monitor; + this.jakartaDelegate = jakartaDelegate; + this.monitor = monitor; } @Override diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaServletOutputStreamAdapter.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaServletOutputStreamAdapter.java index d17bcc3..127bbcc 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaServletOutputStreamAdapter.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaServletOutputStreamAdapter.java @@ -16,26 +16,25 @@ // SPDX-License-Identifier: Apache-2.0 package org.eclipse.tractusx.agents.edc.http; -import java.io.IOException; - -import javax.servlet.WriteListener; - import jakarta.servlet.ServletOutputStream; import org.eclipse.edc.spi.monitor.Monitor; import org.jetbrains.annotations.NotNull; +import java.io.IOException; +import javax.servlet.WriteListener; + /** * An invocation handler which maps jakarta output stream * to a javax.servlet level */ -public class JakartaServletOutputStreamAdapter extends javax.servlet.ServletOutputStream implements IJakartaAdapter { - +public class JakartaServletOutputStreamAdapter extends javax.servlet.ServletOutputStream implements JakartaAdapter { + jakarta.servlet.ServletOutputStream jakartaDelegate; Monitor monitor; public JakartaServletOutputStreamAdapter(jakarta.servlet.ServletOutputStream jakartaDelegate, Monitor monitor) { - this.jakartaDelegate=jakartaDelegate; - this.monitor=monitor; + this.jakartaDelegate = jakartaDelegate; + this.monitor = monitor; } @Override diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/ServletInputStreamDelegator.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/ServletInputStreamDelegator.java index f2a02bf..ef638c4 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/ServletInputStreamDelegator.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/ServletInputStreamDelegator.java @@ -16,10 +16,10 @@ // SPDX-License-Identifier: Apache-2.0 package org.eclipse.tractusx.agents.edc.http; -import javax.servlet.ReadListener; -import javax.servlet.ServletInputStream; import java.io.IOException; import java.io.InputStream; +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; /** * Delegating servlet input stream into a simple input stream @@ -33,6 +33,7 @@ public class ServletInputStreamDelegator extends ServletInputStream { /** * Create a DelegatingServletInputStream for the given source stream. + * * @param sourceStream the source stream (never {@code null}) */ public ServletInputStreamDelegator(InputStream sourceStream) { @@ -41,6 +42,7 @@ public ServletInputStreamDelegator(InputStream sourceStream) { /** * Return the underlying source stream (never {@code null}). + * * @return input stream */ public final InputStream getSourceStream() { diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/ServletOutputStreamDelegator.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/ServletOutputStreamDelegator.java index 732d13c..7f67751 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/ServletOutputStreamDelegator.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/ServletOutputStreamDelegator.java @@ -16,10 +16,10 @@ // SPDX-License-Identifier: Apache-2.0 package org.eclipse.tractusx.agents.edc.http; -import javax.servlet.ServletOutputStream; -import javax.servlet.WriteListener; import java.io.IOException; import java.io.OutputStream; +import javax.servlet.ServletOutputStream; +import javax.servlet.WriteListener; /** * delegates a servlet output stream to a simple outputstream @@ -29,7 +29,7 @@ public class ServletOutputStreamDelegator extends ServletOutputStream { final OutputStream delegate; public ServletOutputStreamDelegator(OutputStream delegate) { - this.delegate=delegate; + this.delegate = delegate; } @Override diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSource.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSource.java index 2cf2848..e5d491e 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSource.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSource.java @@ -16,20 +16,22 @@ // SPDX-License-Identifier: Apache-2.0 package org.eclipse.tractusx.agents.edc.http.transfer; -import org.eclipse.edc.connector.dataplane.spi.pipeline.StreamResult; -import org.eclipse.tractusx.agents.edc.AgentExtension; -import org.eclipse.tractusx.agents.edc.ISkillStore; -import org.eclipse.tractusx.agents.edc.SkillDistribution; -import org.eclipse.tractusx.agents.edc.sparql.SparqlQueryProcessor; import okhttp3.Response; import org.eclipse.edc.connector.dataplane.http.params.HttpRequestFactory; import org.eclipse.edc.connector.dataplane.http.spi.HttpRequestParams; import org.eclipse.edc.connector.dataplane.spi.pipeline.DataSource; +import org.eclipse.edc.connector.dataplane.spi.pipeline.StreamResult; import org.eclipse.edc.spi.http.EdcHttpClient; import org.eclipse.edc.spi.types.domain.transfer.DataFlowRequest; +import org.eclipse.tractusx.agents.edc.AgentExtension; +import org.eclipse.tractusx.agents.edc.SkillDistribution; +import org.eclipse.tractusx.agents.edc.SkillStore; +import org.eclipse.tractusx.agents.edc.sparql.SparqlQueryProcessor; import org.jetbrains.annotations.NotNull; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -59,11 +61,11 @@ public class AgentSource implements DataSource { protected HttpRequestFactory requestFactory; protected EdcHttpClient httpClient; protected SparqlQueryProcessor processor; - protected ISkillStore skillStore; + protected SkillStore skillStore; protected DataFlowRequest request; - public static String AGENT_BOUNDARY="--"; + public static final String AGENT_BOUNDARY = "--"; /** * creates new agent source @@ -78,54 +80,55 @@ public StreamResult> openPartStream() { /** * executes a KA-MATCHMAKING call and pipes the results into KA-TRANSFER + * * @return multipart body containing result and warnings */ @NotNull protected StreamResult> openMatchmaking() { // Agent call, we translate from KA-MATCH to KA-TRANSFER - String skill=null; - String graph=null; - String asset= request.getSourceDataAddress().getProperties().get(AgentSourceHttpParamsDecorator.ASSET_PROP_ID); - if(asset!=null && asset.length() > 0) { - Matcher graphMatcher= AgentExtension.GRAPH_PATTERN.matcher(asset); - if(graphMatcher.matches()) { - graph=asset; + String skill = null; + String graph = null; + String asset = request.getSourceDataAddress().getProperties().get(AgentSourceHttpParamsDecorator.ASSET_PROP_ID); + if (asset != null && asset.length() > 0) { + Matcher graphMatcher = AgentExtension.GRAPH_PATTERN.matcher(asset); + if (graphMatcher.matches()) { + graph = asset; } - Matcher skillMatcher= ISkillStore.matchSkill(asset); - if(skillMatcher.matches()) { - var skillText=skillStore.get(asset); - if(skillText.isEmpty()) { + Matcher skillMatcher = SkillStore.matchSkill(asset); + if (skillMatcher.matches()) { + var skillText = skillStore.get(asset); + if (skillText.isEmpty()) { return StreamResult.error(format("Skill %s does not exist.", asset)); } - SkillDistribution distribution=skillStore.getDistribution(asset); - String params=request.getProperties().get(AgentSourceHttpParamsDecorator.QUERY_PARAMS); - SkillDistribution runMode=SkillDistribution.ALL; - if(params.contains("runMode=provider") || params.contains("runMode=PROVIDER")) { - runMode=SkillDistribution.PROVIDER; - } else if(params.contains("runMode=consumer") || params.contains("runMode=CONSUMER")) { - runMode=SkillDistribution.CONSUMER; + SkillDistribution distribution = skillStore.getDistribution(asset); + String params = request.getProperties().get(AgentSourceHttpParamsDecorator.QUERY_PARAMS); + SkillDistribution runMode = SkillDistribution.ALL; + if (params.contains("runMode=provider") || params.contains("runMode=PROVIDER")) { + runMode = SkillDistribution.PROVIDER; + } else if (params.contains("runMode=consumer") || params.contains("runMode=CONSUMER")) { + runMode = SkillDistribution.CONSUMER; } - if(runMode==SkillDistribution.CONSUMER) { - if(distribution==SkillDistribution.PROVIDER) { + if (runMode == SkillDistribution.CONSUMER) { + if (distribution == SkillDistribution.PROVIDER) { return StreamResult.error(String.format("Run distribution of skill %s should be consumer, but was set to provider only.", asset)); } - return StreamResult.success(Stream.of(new AgentPart("application/sparql-query",skillText.get().getBytes()))); - } else if(runMode==SkillDistribution.PROVIDER && distribution==SkillDistribution.CONSUMER) { + return StreamResult.success(Stream.of(new AgentPart("application/sparql-query", skillText.get().getBytes()))); + } else if (runMode == SkillDistribution.PROVIDER && distribution == SkillDistribution.CONSUMER) { return StreamResult.error(String.format("Run distribution of skill %s should be provider, but was set to consumer only.", asset)); } - skill=skillText.get(); // default execution for runMode=ALL or runMode=provider and DistributionMode is ALL or provider + skill = skillText.get(); // default execution for runMode=ALL or runMode=provider and DistributionMode is ALL or provider } } - try (Response response = processor.execute(this.requestFactory.toRequest(params),skill,graph,request.getSourceDataAddress().getProperties())) { - if(!response.isSuccessful()) { + try (Response response = processor.execute(this.requestFactory.toRequest(params), skill, graph, request.getSourceDataAddress().getProperties())) { + if (!response.isSuccessful()) { return StreamResult.error(format("Received code transferring HTTP data for request %s: %s - %s.", requestId, response.code(), response.message())); } - List results=new ArrayList<>(); - if(response.body()!=null) { - results.add(new AgentPart(response.body().contentType().toString(),response.body().bytes())); + List results = new ArrayList<>(); + if (response.body() != null) { + results.add(new AgentPart(response.body().contentType().toString(), response.body().bytes())); } - if(response.header("cx_warnings")!=null) { - results.add(new AgentPart("application/cx-warnings+json",response.header("cx_warnings").getBytes())); + if (response.header("cx_warnings") != null) { + results.add(new AgentPart("application/cx-warnings+json", response.header("cx_warnings").getBytes())); } return StreamResult.success(results.stream()); } catch (IOException e) { @@ -135,7 +138,7 @@ protected StreamResult> openMatchmaking() { @Override public String toString() { - return String.format("AgentSource(%s,%s)",requestId,name); + return String.format("AgentSource(%s,%s)", requestId, name); } /** @@ -174,17 +177,17 @@ public AgentSource.Builder httpClient(EdcHttpClient httpClient) { } public AgentSource.Builder processor(SparqlQueryProcessor processor) { - dataSource.processor=processor; + dataSource.processor = processor; return this; } - public AgentSource.Builder skillStore(ISkillStore skillStore) { - dataSource.skillStore=skillStore; + public AgentSource.Builder skillStore(SkillStore skillStore) { + dataSource.skillStore = skillStore; return this; } public AgentSource.Builder request(DataFlowRequest request) { - dataSource.request=request; + dataSource.request = request; return this; } @@ -206,15 +209,15 @@ private static class AgentPart implements Part { AgentPart(String name, byte[] content) { this.name = name; - if(this.name!=null) { - StringBuilder newContent=new StringBuilder(); + if (this.name != null) { + StringBuilder newContent = new StringBuilder(); newContent.append(AGENT_BOUNDARY); newContent.append("\n"); newContent.append("Content-Type: "); newContent.append(name); newContent.append("\n"); newContent.append(new String(content)); - this.content=newContent.toString().getBytes(); + this.content = newContent.toString().getBytes(); } else { this.content = content; } diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceFactory.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceFactory.java index 5a64acd..5cd0f20 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceFactory.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceFactory.java @@ -16,15 +16,15 @@ // SPDX-License-Identifier: Apache-2.0 package org.eclipse.tractusx.agents.edc.http.transfer; -import org.eclipse.tractusx.agents.edc.AgentProtocol; -import org.eclipse.tractusx.agents.edc.ISkillStore; -import org.eclipse.tractusx.agents.edc.sparql.SparqlQueryProcessor; import org.eclipse.edc.connector.dataplane.http.params.HttpRequestFactory; import org.eclipse.edc.connector.dataplane.spi.pipeline.DataSource; import org.eclipse.edc.spi.http.EdcHttpClient; import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.types.domain.HttpDataAddress; import org.eclipse.edc.spi.types.domain.transfer.DataFlowRequest; +import org.eclipse.tractusx.agents.edc.AgentProtocol; +import org.eclipse.tractusx.agents.edc.SkillStore; +import org.eclipse.tractusx.agents.edc.sparql.SparqlQueryProcessor; /** * A factory for Agent Sources (representing backend SparQL endpoints) @@ -35,12 +35,13 @@ public class AgentSourceFactory extends org.eclipse.edc.connector.dataplane.http final Monitor monitor; final EdcHttpClient httpClient; final SparqlQueryProcessor processor; - final ISkillStore skillStore; + final SkillStore skillStore; final HttpRequestFactory requestFactory; /** * create a new agent source factory + * * @param httpClient http outgoing system * @param supplier a parameter supplier helper * @param monitor logging facility @@ -48,18 +49,19 @@ public class AgentSourceFactory extends org.eclipse.edc.connector.dataplane.http * @param processor the query processor/sparql engine * @param skillStore store for skills */ - public AgentSourceFactory(EdcHttpClient httpClient, AgentSourceRequestParamsSupplier supplier, Monitor monitor, HttpRequestFactory requestFactory, SparqlQueryProcessor processor, ISkillStore skillStore) { - super(httpClient,supplier,monitor,requestFactory); - this.supplier=supplier; - this.monitor=monitor; - this.httpClient=httpClient; - this.skillStore=skillStore; - this.processor=processor; - this.requestFactory=requestFactory; + public AgentSourceFactory(EdcHttpClient httpClient, AgentSourceRequestParamsSupplier supplier, Monitor monitor, HttpRequestFactory requestFactory, SparqlQueryProcessor processor, SkillStore skillStore) { + super(httpClient, supplier, monitor, requestFactory); + this.supplier = supplier; + this.monitor = monitor; + this.httpClient = httpClient; + this.skillStore = skillStore; + this.processor = processor; + this.requestFactory = requestFactory; } /** * choose the agent protocol + * * @param request the request to check * @return flag */ @@ -72,6 +74,7 @@ public boolean canHandle(DataFlowRequest request) { /** * depending on the transfer mode, choose to manipulate the * target address. + * * @param request incoming agent protocol request * @return new data source */ @@ -80,7 +83,7 @@ public DataSource createSource(DataFlowRequest request) { var dataAddress = HttpDataAddress.Builder.newInstance() .copyFrom(request.getSourceDataAddress()) .build(); - AgentSource dataSource= AgentSource.Builder.newInstance() + AgentSource dataSource = AgentSource.Builder.newInstance() .httpClient(httpClient) .requestId(request.getId()) .name(dataAddress.getName()) diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceHttpParamsDecorator.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceHttpParamsDecorator.java index 9dcf7a7..b7e285c 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceHttpParamsDecorator.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceHttpParamsDecorator.java @@ -16,19 +16,23 @@ // SPDX-License-Identifier: Apache-2.0 package org.eclipse.tractusx.agents.edc.http.transfer; -import org.eclipse.tractusx.agents.edc.AgentConfig; -import org.eclipse.tractusx.agents.edc.http.HttpUtils; -import org.eclipse.tractusx.agents.edc.sparql.DataspaceServiceExecutor; import org.eclipse.edc.connector.dataplane.http.spi.HttpParamsDecorator; import org.eclipse.edc.connector.dataplane.http.spi.HttpRequestParams; import org.eclipse.edc.spi.EdcException; import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.types.domain.HttpDataAddress; import org.eclipse.edc.spi.types.domain.transfer.DataFlowRequest; +import org.eclipse.tractusx.agents.edc.AgentConfig; +import org.eclipse.tractusx.agents.edc.http.HttpUtils; +import org.eclipse.tractusx.agents.edc.sparql.DataspaceServiceExecutor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -43,54 +47,56 @@ public class AgentSourceHttpParamsDecorator implements HttpParamsDecorator { /** * static constants */ - public static String ASSET_PROP_ID="https://w3id.org/edc/v0.0.1/ns/id"; - public static String ACCEPT_HEADER="https://w3id.org/catenax/ontology/common#acceptsContentType"; - public static String QUERY_PARAMS="queryParams"; - public static String QUERY_PARAM="query"; - public static String METHOD="method"; - public static String DEFAULT_METHOD="GET"; - public static String PATH_SEGMENTS="pathSegments"; - public static String BASE_URL="https://w3id.org/edc/v0.0.1/ns/baseUrl"; - public static String BODY="body"; - public static String MEDIA_TYPE="mediaType"; - public static String SLASH="/"; - - public static String CX_ACCEPT_PARAM="cx_accept"; - - public static String DEFAULT_ACCEPT="*/*"; + public static final String ASSET_PROP_ID = "https://w3id.org/edc/v0.0.1/ns/id"; + public static final String ACCEPT_HEADER = "https://w3id.org/catenax/ontology/common#acceptsContentType"; + public static final String QUERY_PARAMS = "queryParams"; + public static final String QUERY_PARAM = "query"; + public static final String METHOD = "method"; + public static final String DEFAULT_METHOD = "GET"; + public static final String PATH_SEGMENTS = "pathSegments"; + public static final String BASE_URL = "https://w3id.org/edc/v0.0.1/ns/baseUrl"; + public static final String BODY = "body"; + public static final String MEDIA_TYPE = "mediaType"; + public static final String SLASH = "/"; + + public static final String CX_ACCEPT_PARAM = "cx_accept"; + + public static final String DEFAULT_ACCEPT = "*/*"; /** * regexes to extract url-encoded form and query parts */ - public static String PARAM_GROUP="param"; - public static String VALUE_GROUP="value"; + public static final String PARAM_GROUP = "param"; + public static final String VALUE_GROUP = "value"; - public static Pattern PARAMS = Pattern.compile(String.format("(\\?|&)(?<%s>[^=&]+)=(?<%s>[^=&]*)",PARAM_GROUP,VALUE_GROUP)); + public static final Pattern PARAMS = Pattern.compile(String.format("(\\?|&)(?<%s>[^=&]+)=(?<%s>[^=&]*)", PARAM_GROUP, VALUE_GROUP)); - public static String WWW_FORM_ENCODED="application/x-www-form-urlencoded"; + public static final String WWW_FORM_ENCODED = "application/x-www-form-urlencoded"; - public static String SPARQL_QUERY="application/sparql-query"; + public static final String SPARQL_QUERY = "application/sparql-query"; - public static String CONTENT_TYPE_DISPOSITION = "q=[0-9]+(\\.[0-9]+)?, "; + public static final String CONTENT_TYPE_DISPOSITION = "q=[0-9]+(\\.[0-9]+)?, "; /** * service references */ - final protected AgentConfig config; - final protected Monitor monitor; + protected final AgentConfig config; + protected final Monitor monitor; /** * creates a new decorator + * * @param config agent configuration * @param monitor logging facility */ public AgentSourceHttpParamsDecorator(AgentConfig config, Monitor monitor) { - this.config=config; - this.monitor=monitor; + this.config = config; + this.monitor = monitor; } /** * check whether this is a transfer or a source request + * * @param dataflowRequest the request to check * @return if this is a transfer request */ @@ -100,15 +106,16 @@ public static boolean isTransferRequest(DataFlowRequest dataflowRequest) { /** * parse the body or parameter string as a url-encoded form into a map + * * @param body url-encoded form body * @return a map of parameters */ public static Map> parseParams(String body) { - Map> parts=new HashMap<>(); - if(body!=null) { - Matcher matcher=PARAMS.matcher(body); - while(matcher.find()) { - String paramName=matcher.group(PARAM_GROUP); + Map> parts = new HashMap<>(); + if (body != null) { + Matcher matcher = PARAMS.matcher(body); + while (matcher.find()) { + String paramName = matcher.group(PARAM_GROUP); List partSet = parts.computeIfAbsent(paramName, k -> new ArrayList<>()); partSet.add(matcher.group(VALUE_GROUP)); } @@ -117,11 +124,11 @@ public static Map> parseParams(String body) { } public static Map> mergeParams(Map> param1, Map> param2) { - param2.forEach( (key,value) -> { - if(param1.containsKey(key)) { + param2.forEach((key, value) -> { + if (param1.containsKey(key)) { param1.get(key).addAll(value); } else { - param1.put(key,value); + param1.put(key, value); } }); return param1; @@ -129,6 +136,7 @@ public static Map> mergeParams(Map> pa /** * Implements the decoration + * * @param request transfer request (contains dynamic stuff) * @param address target address (contains static stuff) * @param params translated call content (up to now) @@ -136,13 +144,13 @@ public static Map> mergeParams(Map> pa */ @Override public HttpRequestParams.Builder decorate(DataFlowRequest request, HttpDataAddress address, HttpRequestParams.Builder params) { - String contentType=this.extractContentType(address, request); - String body= this.extractBody(address,request); - Map> queryParams=parseParams("?"+getRequestQueryParams(address,request)); + String contentType = this.extractContentType(address, request); + String body = this.extractBody(address, request); + Map> queryParams = parseParams("?" + getRequestQueryParams(address, request)); - if(isTransferRequest(request)) { - if(!address.getProperty(BASE_URL).endsWith(SLASH)) { - params.baseUrl(address.getProperty(BASE_URL)+SLASH); + if (isTransferRequest(request)) { + if (!address.getProperty(BASE_URL).endsWith(SLASH)) { + params.baseUrl(address.getProperty(BASE_URL) + SLASH); } } else { // we need to annotate the base url "pure" because we do not directly hit the endpoint @@ -154,33 +162,33 @@ public HttpRequestParams.Builder decorate(DataFlowRequest request, HttpDataAddre // we may get query parameters in the body // in this case we leave the query in the body (and rewriting the content type) if (contentType != null && contentType.contains(WWW_FORM_ENCODED)) { - Map> bodyParams=parseParams("&"+body); - contentType=SPARQL_QUERY; - List queries=queryParams.getOrDefault(QUERY_PARAM,bodyParams.getOrDefault(QUERY_PARAM,List.of())); - if(queries.size()!=1) { - throw new EdcException(String.format("DataFlowRequest %s: found %d queries when contentType %s is used", request.getId(),queries.size(),WWW_FORM_ENCODED)); + Map> bodyParams = parseParams("&" + body); + contentType = SPARQL_QUERY; + List queries = queryParams.getOrDefault(QUERY_PARAM, bodyParams.getOrDefault(QUERY_PARAM, List.of())); + if (queries.size() != 1) { + throw new EdcException(String.format("DataFlowRequest %s: found %d queries when contentType %s is used", request.getId(), queries.size(), WWW_FORM_ENCODED)); } - body= HttpUtils.urlDecodeParameter(queries.get(0)); + body = HttpUtils.urlDecodeParameter(queries.get(0)); bodyParams.remove(QUERY_PARAM); queryParams.remove(QUERY_PARAM); - mergeParams(queryParams,bodyParams); + mergeParams(queryParams, bodyParams); } - String accept=address.getProperty(ACCEPT_HEADER,null); - List cxAccepts=queryParams.getOrDefault(CX_ACCEPT_PARAM,List.of()); + String accept = address.getProperty(ACCEPT_HEADER, null); + List cxAccepts = queryParams.getOrDefault(CX_ACCEPT_PARAM, List.of()); queryParams.remove(CX_ACCEPT_PARAM); - if(accept==null) { - accept=cxAccepts.stream().findFirst().orElse(DEFAULT_ACCEPT); + if (accept == null) { + accept = cxAccepts.stream().findFirst().orElse(DEFAULT_ACCEPT); } accept = accept.replace(CONTENT_TYPE_DISPOSITION, "").replace("%2F", "/"); - params.header("Accept",accept); + params.header("Accept", accept); } - Map> addressParams=parseParams("?"+address.getQueryParams()); - mergeParams(queryParams,addressParams); - String paramString=queryParams.entrySet().stream().flatMap((param) -> param.getValue().stream().map( (value) -> param.getKey()+"="+value)).collect(Collectors.joining("&")); + Map> addressParams = parseParams("?" + address.getQueryParams()); + mergeParams(queryParams, addressParams); + String paramString = queryParams.entrySet().stream().flatMap((param) -> param.getValue().stream().map((value) -> param.getKey() + "=" + value)).collect(Collectors.joining("&")); params.queryParams(!paramString.isEmpty() ? paramString : null); params.method(this.extractMethod(address, request)); params.path(this.extractPath(address, request)); - if(contentType!=null) { + if (contentType != null) { params.contentType(contentType); } params.body(body); @@ -189,7 +197,7 @@ public HttpRequestParams.Builder decorate(DataFlowRequest request, HttpDataAddre } protected @NotNull String extractMethod(HttpDataAddress address, DataFlowRequest request) { - if(Boolean.parseBoolean(address.getProxyMethod())) { + if (Boolean.parseBoolean(address.getProxyMethod())) { return Optional.ofNullable(request.getProperties().get(METHOD)).orElseThrow(() -> new EdcException(String.format("DataFlowRequest %s: 'method' property is missing", request.getId()))); } else { return Optional.ofNullable(address.getMethod()).orElse(DEFAULT_METHOD); @@ -206,6 +214,7 @@ public HttpRequestParams.Builder decorate(DataFlowRequest request, HttpDataAddre /** * extract the content type + * * @param address target address * @param request data flow request * @return the content type (which would be derived from the query language part in case the original content type is a url-encoded form) diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceRequestParamsSupplier.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceRequestParamsSupplier.java index e6cc127..6cd8c27 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceRequestParamsSupplier.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceRequestParamsSupplier.java @@ -16,7 +16,6 @@ // SPDX-License-Identifier: Apache-2.0 package org.eclipse.tractusx.agents.edc.http.transfer; -import org.eclipse.tractusx.agents.edc.AgentConfig; import org.eclipse.edc.connector.dataplane.http.params.decorators.BaseCommonHttpParamsDecorator; import org.eclipse.edc.connector.dataplane.http.params.decorators.BaseSinkHttpParamsDecorator; import org.eclipse.edc.connector.dataplane.http.spi.HttpParamsDecorator; @@ -27,6 +26,7 @@ import org.eclipse.edc.spi.types.TypeManager; import org.eclipse.edc.spi.types.domain.HttpDataAddress; import org.eclipse.edc.spi.types.domain.transfer.DataFlowRequest; +import org.eclipse.tractusx.agents.edc.AgentConfig; import java.util.ArrayList; import java.util.List; @@ -55,6 +55,7 @@ public class AgentSourceRequestParamsSupplier implements HttpRequestParamsProvid /** * creates a supplier + * * @param vault secret host * @param config edc config section * @param monitor logging reference @@ -63,10 +64,10 @@ public AgentSourceRequestParamsSupplier(Vault vault, TypeManager typeManager, Ag BaseCommonHttpParamsDecorator commonHttpParamsDecorator = new BaseCommonHttpParamsDecorator(vault, typeManager); this.registerSinkDecorator(commonHttpParamsDecorator); this.registerSourceDecorator(commonHttpParamsDecorator); - this.registerSourceDecorator(new AgentSourceHttpParamsDecorator(config,monitor)); + this.registerSourceDecorator(new AgentSourceHttpParamsDecorator(config, monitor)); this.registerSinkDecorator(new BaseSinkHttpParamsDecorator()); - this.config=config; - this.monitor=monitor; + this.config = config; + this.monitor = monitor; } @Override diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/jsonld/JsonLd.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/jsonld/JsonLd.java index 297c9b1..84c6add 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/jsonld/JsonLd.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/jsonld/JsonLd.java @@ -16,8 +16,20 @@ // SPDX-License-Identifier: Apache-2.0 package org.eclipse.tractusx.agents.edc.jsonld; -import jakarta.json.*; -import org.eclipse.tractusx.agents.edc.model.*; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonArrayBuilder; +import jakarta.json.JsonNumber; +import jakarta.json.JsonObject; +import jakarta.json.JsonObjectBuilder; +import jakarta.json.JsonString; +import jakarta.json.JsonValue; +import org.eclipse.tractusx.agents.edc.model.Asset; +import org.eclipse.tractusx.agents.edc.model.ContractAgreement; +import org.eclipse.tractusx.agents.edc.model.ContractNegotiation; +import org.eclipse.tractusx.agents.edc.model.DcatCatalog; +import org.eclipse.tractusx.agents.edc.model.IdResponse; +import org.eclipse.tractusx.agents.edc.model.TransferProcess; import java.io.StringReader; import java.util.HashMap; @@ -35,7 +47,7 @@ public static DcatCatalog processCatalog(String cat) { } public static DcatCatalog processCatalog(JsonObject cat) { - return new DcatCatalog(processJsonLd(cat,null)); + return new DcatCatalog(processJsonLd(cat, null)); } public static IdResponse processIdResponse(String response) { @@ -43,7 +55,7 @@ public static IdResponse processIdResponse(String response) { } public static IdResponse processIdResponse(JsonObject response) { - return new IdResponse(processJsonLd(response,null)); + return new IdResponse(processJsonLd(response, null)); } public static ContractNegotiation processContractNegotiation(String response) { @@ -51,7 +63,7 @@ public static ContractNegotiation processContractNegotiation(String response) { } public static ContractNegotiation processContractNegotiation(JsonObject response) { - return new ContractNegotiation(processJsonLd(response,null)); + return new ContractNegotiation(processJsonLd(response, null)); } public static ContractAgreement processContractAgreement(String response) { @@ -59,7 +71,7 @@ public static ContractAgreement processContractAgreement(String response) { } public static ContractAgreement processContractAgreement(JsonObject response) { - return new ContractAgreement(processJsonLd(response,null)); + return new ContractAgreement(processJsonLd(response, null)); } public static TransferProcess processTransferProcess(String response) { @@ -67,23 +79,24 @@ public static TransferProcess processTransferProcess(String response) { } public static TransferProcess processTransferProcess(JsonObject response) { - return new TransferProcess(processJsonLd(response,null)); + return new TransferProcess(processJsonLd(response, null)); } public static List processAssetList(String response) { return processAssetList(Json.createReader(new StringReader(response)).readArray()); } + public static List processAssetList(JsonArray response) { - return response.stream().map( responseObject -> - new Asset(processJsonLd(responseObject.asJsonObject(),null)) + return response.stream().map(responseObject -> + new Asset(processJsonLd(responseObject.asJsonObject(), null)) ).collect(Collectors.toList()); } public static String asString(JsonValue value) { - if(value==null) { + if (value == null) { return "null"; } - switch(value.getValueType()) { + switch (value.getValueType()) { case STRING: return ((JsonString) value).getString(); case NUMBER: @@ -93,12 +106,12 @@ public static String asString(JsonValue value) { } } - public static JsonType processJsonLd(JsonType source, Map context) { + public static JSONTYPE processJsonLd(JSONTYPE source, Map context) { switch (source.getValueType()) { case ARRAY: final JsonArrayBuilder array = Json.createArrayBuilder(); source.asJsonArray().forEach(value -> array.add(processJsonLd(value, context))); - return (JsonType) array.build(); + return (JSONTYPE) array.build(); case OBJECT: JsonObject sourceObject = source.asJsonObject(); Map namespaces = new HashMap<>(); @@ -124,7 +137,7 @@ public static JsonType processJsonLd(JsonType sourc } object.add(prop, processJsonLd(value, namespaces)); }); - return (JsonType) object.build(); + return (JSONTYPE) object.build(); default: return source; } diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/jsonld/JsonLdObject.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/jsonld/JsonLdObject.java index e793112..c990ce6 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/jsonld/JsonLdObject.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/jsonld/JsonLdObject.java @@ -26,7 +26,7 @@ public class JsonLdObject { protected JsonObject object; public JsonLdObject(JsonObject object) { - this.object=object; + this.object = object; } public Map getProperties() { diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/model/Asset.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/model/Asset.java index bf656d7..a09ebb0 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/model/Asset.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/model/Asset.java @@ -32,8 +32,8 @@ public class Asset extends JsonLdObject { public Asset(JsonObject node) { super(node); - this.publicProperties=node.getJsonObject("https://w3id.org/edc/v0.0.1/ns/properties"); - this.privateProperties=node.getJsonObject("https://w3id.org/edc/v0.0.1/ns/privateProperties"); + this.publicProperties = node.getJsonObject("https://w3id.org/edc/v0.0.1/ns/properties"); + this.privateProperties = node.getJsonObject("https://w3id.org/edc/v0.0.1/ns/privateProperties"); } public Map getPrivateProperties() { diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractNegotiation.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractNegotiation.java index a55bc22..5e48d20 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractNegotiation.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractNegotiation.java @@ -29,7 +29,7 @@ public ContractNegotiation(JsonObject node) { } public String getContractAgreementId() { - return object.getString("https://w3id.org/edc/v0.0.1/ns/contractAgreementId",null); + return object.getString("https://w3id.org/edc/v0.0.1/ns/contractAgreementId", null); } public String getState() { @@ -37,6 +37,6 @@ public String getState() { } public String getErrorDetail() { - return object.getString("https://w3id.org/edc/v0.0.1/ns/errorDetail",null); + return object.getString("https://w3id.org/edc/v0.0.1/ns/errorDetail", null); } } diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractNegotiationRequest.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractNegotiationRequest.java index 22ecb72..b84659e 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractNegotiationRequest.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractNegotiationRequest.java @@ -87,12 +87,12 @@ public Builder offerId(ContractOfferDescription offerId) { } public Builder localBusinessPartnerNumber(String bpn) { - dto.localBusinessPartnerNumber=bpn; + dto.localBusinessPartnerNumber = bpn; return this; } public Builder remoteBusinessPartnerNumber(String bpn) { - dto.remoteBusinessPartnerNumber=bpn; + dto.remoteBusinessPartnerNumber = bpn; return this; } diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/model/DcatCatalog.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/model/DcatCatalog.java index bdf50a8..a84cf32 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/model/DcatCatalog.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/model/DcatCatalog.java @@ -28,14 +28,14 @@ */ public class DcatCatalog extends JsonLdObject { - List datasets=new ArrayList<>(); + List datasets = new ArrayList<>(); public DcatCatalog(JsonObject node) { super(node); JsonValue dataset = node.get("https://www.w3.org/ns/dcat/dataset"); - if(dataset!=null) { - if(dataset.getValueType()== JsonValue.ValueType.ARRAY) { - for(JsonValue ds : dataset.asJsonArray()) { + if (dataset != null) { + if (dataset.getValueType() == JsonValue.ValueType.ARRAY) { + for (JsonValue ds : dataset.asJsonArray()) { datasets.add(new DcatDataset(ds.asJsonObject())); } } else { @@ -45,7 +45,7 @@ public DcatCatalog(JsonObject node) { } public String getParticipantId() { - return object.getString("https://w3id.org/edc/v0.0.1/ns/participantId","anonymous"); + return object.getString("https://w3id.org/edc/v0.0.1/ns/participantId", "anonymous"); } public List getDatasets() { diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/model/DcatDataset.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/model/DcatDataset.java index 194e8cd..20711d9 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/model/DcatDataset.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/model/DcatDataset.java @@ -28,7 +28,7 @@ public class DcatDataset extends JsonLdObject { public DcatDataset(JsonObject node) { super(node); - policy=new OdrlPolicy(node.getJsonObject("http://www.w3.org/ns/odrl/2/hasPolicy")); + policy = new OdrlPolicy(node.getJsonObject("http://www.w3.org/ns/odrl/2/hasPolicy")); } public OdrlPolicy hasPolicy() { diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/rdf/RDFStore.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/rdf/RdfStore.java similarity index 82% rename from agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/rdf/RDFStore.java rename to agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/rdf/RdfStore.java index 1669939..700f0a6 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/rdf/RDFStore.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/rdf/RdfStore.java @@ -16,8 +16,6 @@ // SPDX-License-Identifier: Apache-2.0 package org.eclipse.tractusx.agents.edc.rdf; -import org.eclipse.tractusx.agents.edc.AgentConfig; -import org.eclipse.tractusx.agents.edc.MonitorWrapper; import org.apache.jena.fuseki.server.DataAccessPoint; import org.apache.jena.fuseki.server.DataService; import org.apache.jena.graph.Node; @@ -33,13 +31,15 @@ import org.apache.jena.sparql.core.DatasetGraph; import org.apache.jena.sparql.core.DatasetGraphFactory; import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.tractusx.agents.edc.AgentConfig; +import org.eclipse.tractusx.agents.edc.MonitorWrapper; /** * a service sitting on a local RDF store/graph * (which hosts the ontology and the federated dataspace * representation) */ -public class RDFStore { +public class RdfStore { // we need a single data access point (with its default graph) protected final DatasetGraph dataset; @@ -52,42 +52,45 @@ public class RDFStore { /** * create a new RDF store (and initialise with a given ttl file) - * @param config EDC config + * + * @param config EDC config * @param monitor logging subsystem */ - public RDFStore(AgentConfig config, Monitor monitor) { - this.config=config; + public RdfStore(AgentConfig config, Monitor monitor) { + this.config = config; this.dataset = DatasetGraphFactory.createTxnMem(); DataService.Builder dataService = DataService.newBuilder(dataset); - this.service=dataService.build(); - api=new DataAccessPoint(config.getAccessPoint(), service); - this.monitor=monitor; - this.monitorWrapper=new MonitorWrapper(getClass().getName(),monitor); - monitor.debug(String.format("Activating data service %s under access point %s",service,api)); + this.service = dataService.build(); + api = new DataAccessPoint(config.getAccessPoint(), service); + this.monitor = monitor; + this.monitorWrapper = new MonitorWrapper(getClass().getName(), monitor); + monitor.debug(String.format("Activating data service %s under access point %s", service, api)); service.goActive(); // read file with ontology, share this dataset with the catalogue sync procedure - if(config.getAssetFiles()!=null) { + if (config.getAssetFiles() != null) { startTx(); StreamRDF dest = StreamRDFLib.dataset(dataset); - StreamRDF graphDest = StreamRDFLib.extendTriplesToQuads(getDefaultGraph(),dest); + StreamRDF graphDest = StreamRDFLib.extendTriplesToQuads(getDefaultGraph(), dest); StreamRDFCounting countingDest = StreamRDFLib.count(graphDest); ErrorHandler errorHandler = ErrorHandlerFactory.errorHandlerStd(monitorWrapper); - for(String assetFile : config.getAssetFiles()) { + for (String assetFile : config.getAssetFiles()) { RDFParser.create() .errorHandler(errorHandler) .source(assetFile) .lang(Lang.TTL) .parse(countingDest); - monitor.debug(String.format("Initialised asset %s with file %s resulted in %d triples",config.getDefaultAsset(),assetFile,countingDest.countTriples())); + monitor.debug(String.format("Initialised asset %s with file %s resulted in %d triples", config.getDefaultAsset(), assetFile, countingDest.countTriples())); } commit(); - monitor.info(String.format("Initialised asset %s with %d triples from %d files",config.getDefaultAsset(),countingDest.countTriples(),config.getAssetFiles().length)); + monitor.info(String.format("Initialised asset %s with %d triples from %d files", config.getDefaultAsset(), countingDest.countTriples(), config.getAssetFiles().length)); } else { - monitor.info(String.format("Initialised asset %s with 0 triples.",config.getDefaultAsset())); + monitor.info(String.format("Initialised asset %s with 0 triples.", config.getDefaultAsset())); } } /** + * access + * * @return name of the default graph */ public Node getDefaultGraph() { @@ -95,6 +98,8 @@ public Node getDefaultGraph() { } /** + * access + * * @return access point to the graph */ public DataAccessPoint getDataAccessPoint() { @@ -102,6 +107,8 @@ public DataAccessPoint getDataAccessPoint() { } /** + * access + * * @return dataservice shielding the graph */ public DataService getDataService() { @@ -109,6 +116,8 @@ public DataService getDataService() { } /** + * access + * * @return the actual graph store */ public DatasetGraph getDataSet() { diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagement.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagement.java index 83c87ca..69e358a 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagement.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagement.java @@ -18,15 +18,26 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; -import okhttp3.*; -import org.eclipse.tractusx.agents.edc.AgentConfig; import jakarta.ws.rs.InternalServerErrorException; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.ResponseBody; import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.query.Criterion; import org.eclipse.edc.spi.query.QuerySpec; import org.eclipse.edc.spi.types.TypeManager; +import org.eclipse.tractusx.agents.edc.AgentConfig; import org.eclipse.tractusx.agents.edc.jsonld.JsonLd; -import org.eclipse.tractusx.agents.edc.model.*; +import org.eclipse.tractusx.agents.edc.model.Asset; +import org.eclipse.tractusx.agents.edc.model.ContractAgreement; +import org.eclipse.tractusx.agents.edc.model.ContractNegotiation; +import org.eclipse.tractusx.agents.edc.model.ContractNegotiationRequest; +import org.eclipse.tractusx.agents.edc.model.DcatCatalog; +import org.eclipse.tractusx.agents.edc.model.IdResponse; +import org.eclipse.tractusx.agents.edc.model.TransferProcess; +import org.eclipse.tractusx.agents.edc.model.TransferRequest; import java.io.IOException; import java.net.URLEncoder; @@ -44,16 +55,16 @@ public class DataManagement { /** * some constants when interacting with control plane */ - public static final String DSP_PATH="%s/api/v1/dsp"; + public static final String DSP_PATH = "%s/api/v1/dsp"; public static final String CATALOG_CALL = "%s/catalog/request"; - public static final String CATALOG_REQUEST_BODY="{" + + public static final String CATALOG_REQUEST_BODY = "{" + "\"@context\": {}," + "\"protocol\": \"dataspace-protocol-http\"," + "\"providerUrl\": \"%s\", " + "\"querySpec\": %s }"; public static final String ASSET_CREATE_CALL = "%s/assets"; - public static final String ASSET_CREATE_BODY="{\n" + + public static final String ASSET_CREATE_BODY = "{\n" + " \"@context\": {\n" + " \"rdf\": \"http://www.w3.org/1999/02/22-rdf-syntax-ns#\",\n" + " \"rdfs\": \"http://www.w3.org/2000/01/rdf-schema#\",\n" + @@ -92,7 +103,7 @@ public class DataManagement { "}\n"; public static final String ASSET_CALL = "%s/assets/request"; - public static final String NEGOTIATION_REQUEST_BODY="{\n" + + public static final String NEGOTIATION_REQUEST_BODY = "{\n" + "\"@context\": { \"odrl\": \"http://www.w3.org/ns/odrl/2/\"},\n" + "\"@type\": \"NegotiationInitiateRequestDto\",\n" + "\"connectorAddress\": \"%1$s\",\n" + @@ -110,7 +121,7 @@ public class DataManagement { public static final String NEGOTIATION_CHECK_CALL = "%s/contractnegotiations/%s"; public static final String TRANSFER_INITIATE_CALL = "%s/transferprocesses"; - public static final String TRANSFER_REQUEST_BODY="{\n" + + public static final String TRANSFER_REQUEST_BODY = "{\n" + " \"@context\": {\n" + " \"odrl\": \"http://www.w3.org/ns/odrl/2/\"\n" + " },\n" + @@ -144,6 +155,7 @@ public class DataManagement { /** * creates a service wrapper + * * @param monitor logger * @param typeManager serialization * @param httpClient remoting @@ -153,27 +165,29 @@ public DataManagement(Monitor monitor, TypeManager typeManager, OkHttpClient htt this.monitor = monitor; this.objectMapper = typeManager.getMapper(); this.httpClient = httpClient; - this.config=config; + this.config = config; } /** * Search for a dedicated asset * TODO imperformant * TODO replace by accessing the federated data catalogue + * * @param remoteControlPlaneIdsUrl url of the remote control plane ids endpoint * @param assetId (connector-unique) identifier of the asset * @return a collection of contract options to access the given asset * @throws IOException in case that the remote call did not succeed */ public DcatCatalog findContractOffers(String remoteControlPlaneIdsUrl, String assetId) throws IOException { - QuerySpec findAsset=QuerySpec.Builder.newInstance().filter( - List.of(new Criterion("https://w3id.org/edc/v0.0.1/ns/id","=",assetId)) + QuerySpec findAsset = QuerySpec.Builder.newInstance().filter( + List.of(new Criterion("https://w3id.org/edc/v0.0.1/ns/id", "=", assetId)) ).build(); - return getCatalog(remoteControlPlaneIdsUrl,findAsset); + return getCatalog(remoteControlPlaneIdsUrl, findAsset); } /** * Access the catalogue + * * @param remoteControlPlaneIdsUrl url of the remote control plane ids endpoint * @param spec query specification * @return catalog object @@ -181,10 +195,10 @@ public DcatCatalog findContractOffers(String remoteControlPlaneIdsUrl, String as */ public DcatCatalog getCatalog(String remoteControlPlaneIdsUrl, QuerySpec spec) throws IOException { - var url = String.format(CATALOG_CALL,config.getControlPlaneManagementUrl()); - var catalogSpec =String.format(CATALOG_REQUEST_BODY,String.format(DSP_PATH,remoteControlPlaneIdsUrl),objectMapper.writeValueAsString(spec)); + var url = String.format(CATALOG_CALL, config.getControlPlaneManagementUrl()); + var catalogSpec = String.format(CATALOG_REQUEST_BODY, String.format(DSP_PATH, remoteControlPlaneIdsUrl), objectMapper.writeValueAsString(spec)); - var request = new Request.Builder().url(url).post(RequestBody.create(catalogSpec,MediaType.parse("application/json"))); + var request = new Request.Builder().url(url).post(RequestBody.create(catalogSpec, MediaType.parse("application/json"))); config.getControlPlaneManagementHeaders().forEach(request::addHeader); try (var response = httpClient.newCall(request.build()).execute()) { @@ -203,18 +217,19 @@ public DcatCatalog getCatalog(String remoteControlPlaneIdsUrl, QuerySpec spec) t /** * Access the (provider control plane) catalogue + * * @param spec query specification * @return catalog object * @throws IOException in case something went wrong */ public List listAssets(QuerySpec spec) throws IOException { - var url = String.format(ASSET_CALL,config.getControlPlaneManagementProviderUrl()); - var assetObject=(ObjectNode) objectMapper.readTree(objectMapper.writeValueAsString(spec)); - assetObject.put("@context",objectMapper.createObjectNode()); + var url = String.format(ASSET_CALL, config.getControlPlaneManagementProviderUrl()); + var assetObject = (ObjectNode) objectMapper.readTree(objectMapper.writeValueAsString(spec)); + assetObject.put("@context", objectMapper.createObjectNode()); var assetSpec = objectMapper.writeValueAsString(assetObject); - var request = new Request.Builder().url(url).post(RequestBody.create(assetSpec,MediaType.parse("application/json"))); + var request = new Request.Builder().url(url).post(RequestBody.create(assetSpec, MediaType.parse("application/json"))); config.getControlPlaneManagementHeaders().forEach(request::addHeader); try (var response = httpClient.newCall(request.build()).execute()) { @@ -233,6 +248,7 @@ public List listAssets(QuerySpec spec) throws IOException { /** * creates or updates a given asset + * * @param assetId key * @param name of skill * @param description of skill @@ -247,31 +263,31 @@ public List listAssets(QuerySpec spec) throws IOException { */ public IdResponse createOrUpdateSkill(String assetId, String name, String description, String version, String contract, String ontologies, String distributionMode, boolean isFederated, String query) throws IOException { - var url = String.format(ASSET_CREATE_CALL,config.getControlPlaneManagementProviderUrl()); - if(contract!=null) { - contract=String.format(" \"cx-common:publishedUnderContract\": \"%1$s\",\n",contract); + var url = String.format(ASSET_CREATE_CALL, config.getControlPlaneManagementProviderUrl()); + if (contract != null) { + contract = String.format(" \"cx-common:publishedUnderContract\": \"%1$s\",\n", contract); } else { - contract=""; + contract = ""; } - var assetSpec = String.format(ASSET_CREATE_BODY,assetId,name,description,version,contract,ontologies,distributionMode,isFederated,query); + var assetSpec = String.format(ASSET_CREATE_BODY, assetId, name, description, version, contract, ontologies, distributionMode, isFederated, query); - var request = new Request.Builder().url(url).post(RequestBody.create(assetSpec,MediaType.parse("application/json"))); + var request = new Request.Builder().url(url).post(RequestBody.create(assetSpec, MediaType.parse("application/json"))); config.getControlPlaneManagementHeaders().forEach(request::addHeader); try (var response = httpClient.newCall(request.build()).execute()) { ResponseBody body = response.body(); if (!response.isSuccessful()) { - if(response.code()!=409 || body == null) { + if (response.code() != 409 || body == null) { throw new InternalServerErrorException(format("Control plane responded with: %s %s", response.code(), body != null ? body.string() : "")); } - var patchRequest=new Request.Builder().url(url).patch(RequestBody.create(assetSpec,MediaType.parse("application/json"))); + var patchRequest = new Request.Builder().url(url).patch(RequestBody.create(assetSpec, MediaType.parse("application/json"))); config.getControlPlaneManagementHeaders().forEach(patchRequest::addHeader); try (var patchResponse = httpClient.newCall(patchRequest.build()).execute()) { - body=patchResponse.body(); - if(!patchResponse.isSuccessful() || body==null) { + body = patchResponse.body(); + if (!patchResponse.isSuccessful() || body == null) { throw new InternalServerErrorException(format("Control plane responded with: %s %s", response.code(), body != null ? body.string() : "")); } } @@ -287,14 +303,15 @@ public IdResponse createOrUpdateSkill(String assetId, String name, String descri /** * initiates negotation + * * @param negotiationRequest outgoing request * @return negotiation id * @throws IOException in case something went wronf */ public String initiateNegotiation(ContractNegotiationRequest negotiationRequest) throws IOException { - var url = String.format(NEGOTIATION_INITIATE_CALL,config.getControlPlaneManagementUrl()); + var url = String.format(NEGOTIATION_INITIATE_CALL, config.getControlPlaneManagementUrl()); - var negotiateSpec =String.format(NEGOTIATION_REQUEST_BODY, + var negotiateSpec = String.format(NEGOTIATION_REQUEST_BODY, negotiationRequest.getConnectorAddress(), negotiationRequest.getLocalBusinessPartnerNumber(), negotiationRequest.getRemoteBusinessPartnerNumber(), @@ -302,7 +319,7 @@ public String initiateNegotiation(ContractNegotiationRequest negotiationRequest) negotiationRequest.getOffer().getAssetId(), negotiationRequest.getOffer().getPolicy().asString()); - var requestBody = RequestBody.create(negotiateSpec,MediaType.parse("application/json")); + var requestBody = RequestBody.create(negotiateSpec, MediaType.parse("application/json")); var request = new Request.Builder() .url(url) @@ -330,12 +347,13 @@ public String initiateNegotiation(ContractNegotiationRequest negotiationRequest) /** * return state of contract negotiation + * * @param negotiationId id of the negotation to inbestigate * @return status of the negotiation * @throws IOException in case something went wrong */ public ContractNegotiation getNegotiation(String negotiationId) throws IOException { - var url = String.format(NEGOTIATION_CHECK_CALL,config.getControlPlaneManagementUrl(),negotiationId); + var url = String.format(NEGOTIATION_CHECK_CALL, config.getControlPlaneManagementUrl(), negotiationId); var request = new Request.Builder() .url(url); config.getControlPlaneManagementHeaders().forEach(request::addHeader); @@ -358,12 +376,14 @@ public ContractNegotiation getNegotiation(String negotiationId) throws IOExcepti } /** + * access a pending agreement + * * @param agreementId id of the agreement * @return contract agreement * @throws IOException something wild happens */ public ContractAgreement getAgreement(String agreementId) throws IOException { - var url = String.format(AGREEMENT_CHECK_CALL,config.getControlPlaneManagementUrl(), URLEncoder.encode(agreementId, StandardCharsets.UTF_8)); + var url = String.format(AGREEMENT_CHECK_CALL, config.getControlPlaneManagementUrl(), URLEncoder.encode(agreementId, StandardCharsets.UTF_8)); var request = new Request.Builder() .url(url); config.getControlPlaneManagementHeaders().forEach(request::addHeader); @@ -387,21 +407,22 @@ public ContractAgreement getAgreement(String agreementId) throws IOException { /** * Initiates a transfer + * * @param transferRequest request * @return transfer id * @throws IOException in case something went wrong */ public String initiateHttpProxyTransferProcess(TransferRequest transferRequest) throws IOException { - var url = String.format(TRANSFER_INITIATE_CALL,config.getControlPlaneManagementUrl()); + var url = String.format(TRANSFER_INITIATE_CALL, config.getControlPlaneManagementUrl()); - var transferSpec =String.format(TRANSFER_REQUEST_BODY, + var transferSpec = String.format(TRANSFER_REQUEST_BODY, transferRequest.getAssetId(), transferRequest.getConnectorAddress(), transferRequest.getContractId(), transferRequest.getCallbackAddresses().get(0).getUri(), transferRequest.getConnectorAddress()); - var requestBody = RequestBody.create(transferSpec,MediaType.parse("application/json")); + var requestBody = RequestBody.create(transferSpec, MediaType.parse("application/json")); var request = new Request.Builder() .url(url) @@ -430,12 +451,13 @@ public String initiateHttpProxyTransferProcess(TransferRequest transferRequest) /** * return state of transfer process + * * @param transferProcessId id of the transfer process * @return state of the transfer process * @throws IOException in case something went wrong */ public TransferProcess getTransfer(String transferProcessId) throws IOException { - var url = String.format(TRANSFER_CHECK_CALL,config.getControlPlaneManagementUrl(),transferProcessId); + var url = String.format(TRANSFER_CHECK_CALL, config.getControlPlaneManagementUrl(), transferProcessId); var request = new Request.Builder() .url(url); config.getControlPlaneManagementHeaders().forEach(request::addHeader); diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/DataspaceSynchronizer.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/DataspaceSynchronizer.java index b660703..4953f16 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/DataspaceSynchronizer.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/DataspaceSynchronizer.java @@ -19,6 +19,8 @@ import jakarta.json.Json; import jakarta.json.JsonValue; import org.apache.jena.atlas.lib.Sink; +import org.apache.jena.graph.Node; +import org.apache.jena.graph.NodeFactory; import org.apache.jena.riot.Lang; import org.apache.jena.riot.RDFParser; import org.apache.jena.riot.lang.StreamRDFCounting; @@ -26,21 +28,25 @@ import org.apache.jena.riot.system.ErrorHandlerFactory; import org.apache.jena.riot.system.StreamRDF; import org.apache.jena.riot.system.StreamRDFLib; +import org.apache.jena.sparql.core.Quad; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.query.Criterion; +import org.eclipse.edc.spi.query.QuerySpec; import org.eclipse.tractusx.agents.edc.AgentConfig; import org.eclipse.tractusx.agents.edc.MonitorWrapper; import org.eclipse.tractusx.agents.edc.jsonld.JsonLd; import org.eclipse.tractusx.agents.edc.model.DcatCatalog; import org.eclipse.tractusx.agents.edc.model.DcatDataset; -import org.eclipse.tractusx.agents.edc.rdf.RDFStore; -import org.apache.jena.graph.Node; -import org.apache.jena.graph.NodeFactory; -import org.apache.jena.sparql.core.Quad; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.query.Criterion; -import org.eclipse.edc.spi.query.QuerySpec; +import org.eclipse.tractusx.agents.edc.rdf.RdfStore; import java.io.StringReader; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.UUID; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -53,26 +59,26 @@ public class DataspaceSynchronizer implements Runnable { /** * constants */ - protected final static Node CX_ASSET=NodeFactory.createURI("https://w3id.org/catenax/ontology/common#offers"); - protected final static Map assetPropertyMap=new HashMap<>(); - protected final static QuerySpec federatedAssetQuery = QuerySpec.Builder.newInstance(). - filter(List.of(new Criterion("https://w3id.org/catenax/ontology/common#isFederated","=","true^^xsd:boolean"))).build(); + protected static final Node CX_ASSET = NodeFactory.createURI("https://w3id.org/catenax/ontology/common#offers"); + protected static final Map ASSET_PROPERTY_MAP = new HashMap<>(); + protected static final QuerySpec FEDERATED_ASSET_QUERY = QuerySpec.Builder.newInstance() + .filter(List.of(new Criterion("https://w3id.org/catenax/ontology/common#isFederated", "=", "true^^xsd:boolean"))).build(); protected MonitorWrapper monitorWrapper; static { - assetPropertyMap.put("https://w3id.org/edc/v0.0.1/ns/id",NodeFactory.createURI("https://w3id.org/catenax/ontology/common#id")); - assetPropertyMap.put("https://w3id.org/edc/v0.0.1/ns/name",NodeFactory.createURI("https://w3id.org/catenax/ontology/common#name")); - assetPropertyMap.put("https://w3id.org/edc/v0.0.1/ns/description",NodeFactory.createURI("https://w3id.org/catenax/ontology/common#description")); - assetPropertyMap.put("https://w3id.org/edc/v0.0.1/ns/version",NodeFactory.createURI("https://w3id.org/catenax/ontology/common#version")); - assetPropertyMap.put("https://w3id.org/edc/v0.0.1/ns/contenttype",NodeFactory.createURI("https://w3id.org/catenax/ontology/common#contentType")); - assetPropertyMap.put("http://www.w3.org/1999/02/22-rdf-syntax-ns#type",NodeFactory.createURI("http://www.w3.org/1999/02/22-rdf-syntax-ns#type")); - assetPropertyMap.put("http://www.w3.org/2000/01/rdf-schema#isDefinedBy",NodeFactory.createURI("http://www.w3.org/2000/01/rdf-schema#isDefinedBy")); - assetPropertyMap.put("https://w3id.org/catenax/ontology/common#implementsProtocol",NodeFactory.createURI("https://w3id.org/catenax/ontology/common#implementsProtocol")); - assetPropertyMap.put("http://www.w3.org/ns/shacl#shapesGraph",NodeFactory.createURI("http://www.w3.org/ns/shacl#shapesGraph")); - assetPropertyMap.put("https://w3id.org/catenax/ontology/common#isFederated",NodeFactory.createURI("https://w3id.org/catenax/ontology/common#isFederated")); - assetPropertyMap.put("https://w3id.org/catenax/ontology/common#publishedUnderContract",NodeFactory.createURI("https://w3id.org/catenax/ontology/common#publishedUnderContract")); - assetPropertyMap.put("https://w3id.org/catenax/ontology/common#satisfiesRole",NodeFactory.createURI("https://w3id.org/catenax/ontology/common#satisfiesRole")); + ASSET_PROPERTY_MAP.put("https://w3id.org/edc/v0.0.1/ns/id", NodeFactory.createURI("https://w3id.org/catenax/ontology/common#id")); + ASSET_PROPERTY_MAP.put("https://w3id.org/edc/v0.0.1/ns/name", NodeFactory.createURI("https://w3id.org/catenax/ontology/common#name")); + ASSET_PROPERTY_MAP.put("https://w3id.org/edc/v0.0.1/ns/description", NodeFactory.createURI("https://w3id.org/catenax/ontology/common#description")); + ASSET_PROPERTY_MAP.put("https://w3id.org/edc/v0.0.1/ns/version", NodeFactory.createURI("https://w3id.org/catenax/ontology/common#version")); + ASSET_PROPERTY_MAP.put("https://w3id.org/edc/v0.0.1/ns/contenttype", NodeFactory.createURI("https://w3id.org/catenax/ontology/common#contentType")); + ASSET_PROPERTY_MAP.put("http://www.w3.org/1999/02/22-rdf-syntax-ns#type", NodeFactory.createURI("http://www.w3.org/1999/02/22-rdf-syntax-ns#type")); + ASSET_PROPERTY_MAP.put("http://www.w3.org/2000/01/rdf-schema#isDefinedBy", NodeFactory.createURI("http://www.w3.org/2000/01/rdf-schema#isDefinedBy")); + ASSET_PROPERTY_MAP.put("https://w3id.org/catenax/ontology/common#implementsProtocol", NodeFactory.createURI("https://w3id.org/catenax/ontology/common#implementsProtocol")); + ASSET_PROPERTY_MAP.put("http://www.w3.org/ns/shacl#shapesGraph", NodeFactory.createURI("http://www.w3.org/ns/shacl#shapesGraph")); + ASSET_PROPERTY_MAP.put("https://w3id.org/catenax/ontology/common#isFederated", NodeFactory.createURI("https://w3id.org/catenax/ontology/common#isFederated")); + ASSET_PROPERTY_MAP.put("https://w3id.org/catenax/ontology/common#publishedUnderContract", NodeFactory.createURI("https://w3id.org/catenax/ontology/common#publishedUnderContract")); + ASSET_PROPERTY_MAP.put("https://w3id.org/catenax/ontology/common#satisfiesRole", NodeFactory.createURI("https://w3id.org/catenax/ontology/common#satisfiesRole")); } /** @@ -81,42 +87,43 @@ public class DataspaceSynchronizer implements Runnable { protected final ScheduledExecutorService service; protected final AgentConfig config; protected final DataManagement dataManagement; - protected final RDFStore rdfStore; + protected final RdfStore rdfStore; protected final Monitor monitor; /** * internal state */ - protected boolean isStarted=false; + protected boolean isStarted = false; /** * creates the synchronizer + * * @param service scheduler * @param config edc config * @param dataManagement data management service remoting * @param rdfStore a triple store for persistance * @param monitor logging subsystem */ - public DataspaceSynchronizer(ScheduledExecutorService service, AgentConfig config, DataManagement dataManagement, RDFStore rdfStore, Monitor monitor) { - this.service=service; - this.config=config; - this.dataManagement=dataManagement; - this.rdfStore=rdfStore; - this.monitor=monitor; - this.monitorWrapper=new MonitorWrapper(getClass().getName(),monitor); + public DataspaceSynchronizer(ScheduledExecutorService service, AgentConfig config, DataManagement dataManagement, RdfStore rdfStore, Monitor monitor) { + this.service = service; + this.config = config; + this.dataManagement = dataManagement; + this.rdfStore = rdfStore; + this.monitor = monitor; + this.monitorWrapper = new MonitorWrapper(getClass().getName(), monitor); } /** * starts the synchronizer */ public synchronized void start() { - if(!isStarted) { - isStarted=true; - long interval=config.getDataspaceSynchronizationInterval(); - String[] connectors=config.getDataspaceSynchronizationConnectors(); - if(interval>0 && connectors!=null && connectors.length>0) { - monitor.info(String.format("Starting dataspace synchronization on %d connectors with interval %d milliseconds", connectors.length,interval)); - service.schedule(this,interval,TimeUnit.MILLISECONDS); + if (!isStarted) { + isStarted = true; + long interval = config.getDataspaceSynchronizationInterval(); + String[] connectors = config.getDataspaceSynchronizationConnectors(); + if (interval > 0 && connectors != null && connectors.length > 0) { + monitor.info(String.format("Starting dataspace synchronization on %d connectors with interval %d milliseconds", connectors.length, interval)); + service.schedule(this, interval, TimeUnit.MILLISECONDS); } } } @@ -125,9 +132,9 @@ public synchronized void start() { * stops the synchronizer */ public synchronized void shutdown() { - if(isStarted) { + if (isStarted) { monitor.info("Shutting down dataspace synchronization"); - isStarted=false; + isStarted = false; service.shutdown(); } } @@ -138,25 +145,25 @@ public synchronized void shutdown() { @Override public void run() { monitor.debug("Synchronization run has been started"); - if(isStarted) { + if (isStarted) { for (String remote : config.getDataspaceSynchronizationConnectors()) { - if(isStarted) { + if (isStarted) { monitor.debug(String.format("About to synchronize remote connector %s", remote)); rdfStore.startTx(); try { - DcatCatalog catalog = dataManagement.getCatalog(remote,federatedAssetQuery); + DcatCatalog catalog = dataManagement.getCatalog(remote, FEDERATED_ASSET_QUERY); Node graph = rdfStore.getDefaultGraph(); Node connector = NodeFactory.createURI(remote.replace("https", "edcs").replace("http", "edc")); - Quad findAssets = Quad.create(graph,connector,CX_ASSET,Node.ANY); - Iterator assetQuads= rdfStore.getDataSet().find(findAssets); - int tupleCount=0; - while(assetQuads.hasNext()) { - Quad quadAsset=assetQuads.next(); - Quad findAssetProps = Quad.create(graph,quadAsset.getObject(),Node.ANY,Node.ANY); - Iterator propQuads=rdfStore.getDataSet().find(findAssetProps); - while(propQuads.hasNext()) { - Quad quadProp=propQuads.next(); - if(quadProp.getPredicate().isURI() && quadProp.getPredicate().getURI().equals("http://www.w3.org/ns/shacl#shapesGraph") && quadProp.getObject().isURI()) { + Quad findAssets = Quad.create(graph, connector, CX_ASSET, Node.ANY); + Iterator assetQuads = rdfStore.getDataSet().find(findAssets); + int tupleCount = 0; + while (assetQuads.hasNext()) { + Quad quadAsset = assetQuads.next(); + Quad findAssetProps = Quad.create(graph, quadAsset.getObject(), Node.ANY, Node.ANY); + Iterator propQuads = rdfStore.getDataSet().find(findAssetProps); + while (propQuads.hasNext()) { + Quad quadProp = propQuads.next(); + if (quadProp.getPredicate().isURI() && quadProp.getPredicate().getURI().equals("http://www.w3.org/ns/shacl#shapesGraph") && quadProp.getObject().isURI()) { Quad findSubGraphsProps = Quad.create(quadProp.getObject(), Node.ANY, Node.ANY, Node.ANY); Iterator subGraphQuads = rdfStore.getDataSet().find(findSubGraphsProps); while (subGraphQuads.hasNext()) { @@ -171,12 +178,12 @@ public void run() { tupleCount++; } monitor.debug(String.format("About to delete %d old tuples.", tupleCount)); - List offers=catalog.getDatasets(); - tupleCount=0; - if(offers!=null) { + List offers = catalog.getDatasets(); + tupleCount = 0; + if (offers != null) { monitor.debug(String.format("Found a catalog with %d entries for remote connector %s", offers.size(), remote)); for (DcatDataset offer : catalog.getDatasets()) { - for(Quad quad : convertToQuads(graph,connector,offer)) { + for (Quad quad : convertToQuads(graph, connector, offer)) { tupleCount++; rdfStore.getDataSet().add(quad); } @@ -191,11 +198,11 @@ public void run() { rdfStore.abort(); } } else { - monitor.debug(String.format("Synchronization is no more active. Skipping all connectors starting from %s.",remote)); + monitor.debug(String.format("Synchronization is no more active. Skipping all connectors starting from %s.", remote)); break; } } // for - if(isStarted) { + if (isStarted) { monitor.debug("Schedule next synchronization run"); service.schedule(this, config.getDataspaceSynchronizationInterval(), TimeUnit.MILLISECONDS); } else { @@ -206,50 +213,52 @@ public void run() { /** * Workaround the castration of the IDS catalogue + * * @param offer being made * @return default props */ - public static Map getProperties(DcatDataset offer) { + public static Map getProperties(DcatDataset offer) { Map assetProperties = new HashMap<>(offer.getProperties()); - if(!assetProperties.containsKey("http://www.w3.org/1999/02/22-rdf-syntax-ns#type")) { - String assetType= JsonLd.asString(assetProperties.getOrDefault("@id", Json.createValue("cx-common:Asset"))); + if (!assetProperties.containsKey("http://www.w3.org/1999/02/22-rdf-syntax-ns#type")) { + String assetType = JsonLd.asString(assetProperties.getOrDefault("@id", Json.createValue("cx-common:Asset"))); int indexOfQuestion = assetType.indexOf("?"); if (indexOfQuestion > 0) { assetType = assetType.substring(0, indexOfQuestion - 1); } - assetProperties.put("http://www.w3.org/1999/02/22-rdf-syntax-ns#type",Json.createValue(assetType)); + assetProperties.put("http://www.w3.org/1999/02/22-rdf-syntax-ns#type", Json.createValue(assetType)); } - if(!assetProperties.containsKey("@id")) { - assetProperties.put("@id",Json.createValue(UUID.randomUUID().toString())); + if (!assetProperties.containsKey("@id")) { + assetProperties.put("@id", Json.createValue(UUID.randomUUID().toString())); } return assetProperties; } /** * convert a given contract offer into quads + * * @param graph default graph * @param connector parent connector hosting the offer * @param offer the contract offer * @return a collection of quads */ public Collection convertToQuads(Node graph, Node connector, DcatDataset offer) { - Map assetProperties=getProperties(offer); + Map assetProperties = getProperties(offer); - List quads=new ArrayList<>(); - String offerId=assetProperties.get("@id").toString(); - Node assetNode=NodeFactory.createURI(offerId); + List quads = new ArrayList<>(); + String offerId = assetProperties.get("@id").toString(); + Node assetNode = NodeFactory.createURI(offerId); quads.add(Quad.create(graph, connector, CX_ASSET, assetNode)); - for(Map.Entry assetProp : assetProperties.entrySet()) { - String key=assetProp.getKey(); - Node node=assetPropertyMap.get(key); - while(node==null && key.indexOf('.')>=0) { - key=key.substring(key.lastIndexOf(".")+1); - node=assetPropertyMap.get(key); + for (Map.Entry assetProp : assetProperties.entrySet()) { + String key = assetProp.getKey(); + Node node = ASSET_PROPERTY_MAP.get(key); + while (node == null && key.indexOf('.') >= 0) { + key = key.substring(key.lastIndexOf(".") + 1); + node = ASSET_PROPERTY_MAP.get(key); } - if(node!=null) { + if (node != null) { String pureProperty = JsonLd.asString(assetProp.getValue()); if (pureProperty != null) { try { @@ -317,7 +326,7 @@ public void flush() { quads.add(Quad.create(graph, assetNode, node, NodeFactory.createLiteral(pureProperty))); } //switch } catch (Throwable t) { - monitor.debug(String.format("Could not correctly add asset triples for predicate %s with original value %s because of %s", node, pureProperty,t.getMessage())); + monitor.debug(String.format("Could not correctly add asset triples for predicate %s with original value %s because of %s", node, pureProperty, t.getMessage())); } } // if property!=null } // if node!=null diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/EdcSkillStore.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/EdcSkillStore.java index e0f82a2..2a5f26e 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/EdcSkillStore.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/EdcSkillStore.java @@ -21,8 +21,8 @@ import org.eclipse.edc.spi.query.QuerySpec; import org.eclipse.edc.spi.types.TypeManager; import org.eclipse.tractusx.agents.edc.AgentConfig; -import org.eclipse.tractusx.agents.edc.ISkillStore; import org.eclipse.tractusx.agents.edc.SkillDistribution; +import org.eclipse.tractusx.agents.edc.SkillStore; import org.eclipse.tractusx.agents.edc.jsonld.JsonLd; import org.eclipse.tractusx.agents.edc.model.Asset; @@ -33,38 +33,38 @@ /** * Implements a skill store based on EDC assets */ -public class EdcSkillStore implements ISkillStore { +public class EdcSkillStore implements SkillStore { DataManagement management; TypeManager typeManager; AgentConfig config; public EdcSkillStore(DataManagement management, TypeManager typeManager, AgentConfig config) { - this.management=management; - this.typeManager=typeManager; - this.config=config; + this.management = management; + this.typeManager = typeManager; + this.config = config; } @Override public boolean isSkill(String key) { - return ISkillStore.matchSkill(key).matches(); + return SkillStore.matchSkill(key).matches(); } @Override public String put(String key, String skill, String name, String description, String version, String contract, SkillDistribution dist, boolean isFederated, String... ontologies) { - if(name==null) { - name="No name given"; + if (name == null) { + name = "No name given"; } - if(description==null) { - description="No description given"; + if (description == null) { + description = "No description given"; } - if(version==null) { - version="unknown version"; + if (version == null) { + version = "unknown version"; } - if(contract==null) { - contract=config.getDefaultSkillContract(); + if (contract == null) { + contract = config.getDefaultSkillContract(); } - String ontologiesString=String.join(",",ontologies); + String ontologiesString = String.join(",", ontologies); try { return management.createOrUpdateSkill( key, @@ -78,35 +78,37 @@ public String put(String key, String skill, String name, String description, Str typeManager.getMapper().writeValueAsString(TextNode.valueOf(skill)) ).getId(); } catch (IOException e) { - return null; + return null; } } @Override public SkillDistribution getDistribution(String key) { - return findAsset(key).map( asset -> SkillDistribution.valueOfMode(JsonLd.asString(asset.getPublicProperties(). - get("https://w3id.org/catenax/ontology/common#distributionMode")))).orElse(SkillDistribution.ALL); + return findAsset(key).map(asset -> SkillDistribution.valueOfMode(JsonLd.asString(asset.getPublicProperties() + .get("https://w3id.org/catenax/ontology/common#distributionMode")))).orElse(SkillDistribution.ALL); } - /** finds an asset */ + /** + * finds an asset + */ protected Optional findAsset(String key) { - QuerySpec findAsset=QuerySpec.Builder.newInstance().filter( - List.of(new Criterion("https://w3id.org/edc/v0.0.1/ns/id","=",key), - new Criterion("http://www.w3.org/1999/02/22-rdf-syntax-ns#type","=","cx-common:SkillAsset"))).build(); + QuerySpec findAsset = QuerySpec.Builder.newInstance().filter( + List.of(new Criterion("https://w3id.org/edc/v0.0.1/ns/id", "=", key), + new Criterion("http://www.w3.org/1999/02/22-rdf-syntax-ns#type", "=", "cx-common:SkillAsset"))).build(); try { // we need to filter until the criterion really works - return management. - listAssets(findAsset).stream(). - findFirst(); - } catch(IOException e) { + return management + .listAssets(findAsset).stream() + .findFirst(); + } catch (IOException e) { return Optional.empty(); } } @Override public Optional get(String key) { - return findAsset(key).map(asset-> - JsonLd.asString(asset.getPrivateProperties().get("https://w3id.org/catenax/ontology/common#query")) - ); + return findAsset(key).map(asset -> + JsonLd.asString(asset.getPrivateProperties().get("https://w3id.org/catenax/ontology/common#query")) + ); } } diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/InMemorySkillStore.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/InMemorySkillStore.java index a9e02d2..a0909f2 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/InMemorySkillStore.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/InMemorySkillStore.java @@ -16,8 +16,8 @@ // SPDX-License-Identifier: Apache-2.0 package org.eclipse.tractusx.agents.edc.service; -import org.eclipse.tractusx.agents.edc.ISkillStore; import org.eclipse.tractusx.agents.edc.SkillDistribution; +import org.eclipse.tractusx.agents.edc.SkillStore; import java.util.HashMap; import java.util.Map; @@ -26,10 +26,10 @@ /** * An in-memory store for local skills */ -public class InMemorySkillStore implements ISkillStore { +public class InMemorySkillStore implements SkillStore { // temporary local skill store - final protected Map skills=new HashMap<>(); + protected final Map skills = new HashMap<>(); /** * create the store @@ -39,12 +39,12 @@ public InMemorySkillStore() { @Override public boolean isSkill(String key) { - return ISkillStore.matchSkill(key).matches(); + return SkillStore.matchSkill(key).matches(); } @Override public String put(String key, String skill, String name, String description, String version, String contract, SkillDistribution dist, boolean isFederated, String... ontologies) { - skills.put(key,skill); + skills.put(key, skill); return key; } @@ -55,7 +55,7 @@ public SkillDistribution getDistribution(String key) { @Override public Optional get(String key) { - if(!skills.containsKey(key)) { + if (!skills.containsKey(key)) { return Optional.empty(); } else { return Optional.of(skills.get(key)); diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/CatenaxWarning.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/CatenaxWarning.java index 1fcefc8..4f8f7e4 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/CatenaxWarning.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/CatenaxWarning.java @@ -28,36 +28,39 @@ * a warning */ public class CatenaxWarning { - public static Symbol cxWarnings=Symbol.create("cx:warnings"); + public static Symbol cxWarnings = Symbol.create("cx:warnings"); /** * access the thread local + * * @return current warnings */ public static List getWarnings(Context context) { - return context.get(cxWarnings,null); + return context.get(cxWarnings, null); } /** * access the thread local + * * @return current warnings or empty list */ public static List getOrSetWarnings(Context context) { - List result=getWarnings(context); - if(result==null) { - result=new ArrayList<>(); - setWarnings(context,result); + List result = getWarnings(context); + if (result == null) { + result = new ArrayList<>(); + setWarnings(context, result); } return result; } /** * set current warnings + * * @param context to set into * @param warnings the warning list */ public static void setWarnings(Context context, List warnings) { - context.put(cxWarnings,warnings); + context.put(cxWarnings, warnings); } @JsonProperty("source-tenant") @@ -85,6 +88,7 @@ public CatenaxWarning sourceTenant(String sourceTenant) { /** * Get sourceTenant + * * @return sourceTenant **/ @JsonProperty("source-tenant") @@ -103,6 +107,7 @@ public CatenaxWarning sourceAsset(String sourceAsset) { /** * Get sourceAsset + * * @return sourceAsset **/ @JsonProperty("source-asset") @@ -121,6 +126,7 @@ public CatenaxWarning targetTenant(String targetTenant) { /** * Get targetTenant + * * @return targetTenant **/ @JsonProperty("target-tenant") @@ -139,6 +145,7 @@ public CatenaxWarning targetAsset(String targetAsset) { /** * Get targetAsset + * * @return targetAsset **/ @JsonProperty("target-asset") @@ -157,6 +164,7 @@ public CatenaxWarning problem(String problem) { /** * Get problem + * * @return problem **/ @JsonProperty("problem") @@ -175,6 +183,7 @@ public CatenaxWarning context(String context) { /** * Get context + * * @return context **/ @JsonProperty("context") diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/DataspaceServiceExecutor.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/DataspaceServiceExecutor.java index cbc34cf..d1e93d1 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/DataspaceServiceExecutor.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/DataspaceServiceExecutor.java @@ -17,9 +17,6 @@ package org.eclipse.tractusx.agents.edc.sparql; import com.fasterxml.jackson.databind.ObjectMapper; -import org.eclipse.tractusx.agents.edc.AgentConfig; -import org.eclipse.tractusx.agents.edc.IAgreementController; -import org.eclipse.tractusx.agents.edc.http.HttpClientAdapter; import okhttp3.OkHttpClient; import org.apache.jena.atlas.logging.Log; import org.apache.jena.graph.Node; @@ -33,7 +30,10 @@ import org.apache.jena.sparql.algebra.Op; import org.apache.jena.sparql.algebra.OpAsQuery; import org.apache.jena.sparql.algebra.Transformer; -import org.apache.jena.sparql.algebra.op.*; +import org.apache.jena.sparql.algebra.op.OpProject; +import org.apache.jena.sparql.algebra.op.OpSequence; +import org.apache.jena.sparql.algebra.op.OpService; +import org.apache.jena.sparql.algebra.op.OpTable; import org.apache.jena.sparql.algebra.table.TableData; import org.apache.jena.sparql.core.Var; import org.apache.jena.sparql.engine.ExecutionContext; @@ -46,7 +46,9 @@ import org.apache.jena.sparql.engine.iterator.QueryIterPlainWrapper; import org.apache.jena.sparql.exec.RowSet; import org.apache.jena.sparql.exec.RowSetAdapter; -import org.apache.jena.sparql.exec.http.*; +import org.apache.jena.sparql.exec.http.Params; +import org.apache.jena.sparql.exec.http.QuerySendMode; +import org.apache.jena.sparql.exec.http.Service; import org.apache.jena.sparql.graph.NodeTransformLib; import org.apache.jena.sparql.resultset.ResultSetMem; import org.apache.jena.sparql.service.bulk.ChainingServiceExecutorBulk; @@ -57,6 +59,9 @@ import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.types.TypeManager; import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; +import org.eclipse.tractusx.agents.edc.AgentConfig; +import org.eclipse.tractusx.agents.edc.AgreementController; +import org.eclipse.tractusx.agents.edc.http.HttpClientAdapter; import java.io.IOException; import java.io.InputStream; @@ -66,7 +71,14 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -87,7 +99,7 @@ public class DataspaceServiceExecutor implements ServiceExecutor, ChainingServic * EDC services */ final Monitor monitor; - final IAgreementController agreementController; + final AgreementController agreementController; final AgentConfig config; final HttpClient client; final ExecutorService executor; @@ -96,13 +108,13 @@ public class DataspaceServiceExecutor implements ServiceExecutor, ChainingServic /** * some constants */ - public final static Symbol AUTH_KEY_SYMBOL = Symbol.create("https://w3id.org/edc/v0.0.1/ns/authKey"); - public final static Symbol AUTH_CODE_SYMBOL = Symbol.create("https://w3id.org/edc/v0.0.1/ns/authCode"); - public final static Pattern EDC_TARGET_ADDRESS_PATTERN = Pattern.compile("((?edc|edcs)://(?[^#?]*))?(#(?[^/?]*))?(\\?(?.*))?"); - public final static Symbol TARGET_URL_SYMBOL = Symbol.create("https://w3id.org/edc/v0.0.1/ns/baseUrl"); - public final static Symbol ASSET_SYMBOL = Symbol.create("https://w3id.org/edc/v0.0.1/ns/id"); - public final static Symbol ALLOW_SYMBOL = Symbol.create("https://w3id.org/catenax/ontology/common#allowServicePattern"); - public final static Symbol DENY_SYMBOL = Symbol.create("https://w3id.org/catenax/ontology/common#denyServicePattern"); + public static final Symbol AUTH_KEY_SYMBOL = Symbol.create("https://w3id.org/edc/v0.0.1/ns/authKey"); + public static final Symbol AUTH_CODE_SYMBOL = Symbol.create("https://w3id.org/edc/v0.0.1/ns/authCode"); + public static final Pattern EDC_TARGET_ADDRESS_PATTERN = Pattern.compile("((?edc|edcs)://(?[^#?]*))?(#(?[^/?]*))?(\\?(?.*))?"); + public static final Symbol TARGET_URL_SYMBOL = Symbol.create("https://w3id.org/edc/v0.0.1/ns/baseUrl"); + public static final Symbol ASSET_SYMBOL = Symbol.create("https://w3id.org/edc/v0.0.1/ns/id"); + public static final Symbol ALLOW_SYMBOL = Symbol.create("https://w3id.org/catenax/ontology/common#allowServicePattern"); + public static final Symbol DENY_SYMBOL = Symbol.create("https://w3id.org/catenax/ontology/common#denyServicePattern"); /** * create a new executor @@ -110,18 +122,19 @@ public class DataspaceServiceExecutor implements ServiceExecutor, ChainingServic * @param monitor logging subsystem * @param controller dataspace agreement */ - public DataspaceServiceExecutor(Monitor monitor, IAgreementController controller, AgentConfig config, OkHttpClient client, ExecutorService executor, TypeManager typeManager) { + public DataspaceServiceExecutor(Monitor monitor, AgreementController controller, AgentConfig config, OkHttpClient client, ExecutorService executor, TypeManager typeManager) { this.monitor = monitor; this.agreementController = controller; this.config = config; - this.client=new HttpClientAdapter(client); - this.executor=executor; - this.objectMapper=typeManager.getMapper(); + this.client = new HttpClientAdapter(client); + this.executor = executor; + this.objectMapper = typeManager.getMapper(); } /** * bulk execution call - this is the default * TODO implement batch size per service and not globally + * * @param opService bound operator * @param queryIterator incoming bindings (may set service uri and input params) * @param executionContext context @@ -130,14 +143,14 @@ public DataspaceServiceExecutor(Monitor monitor, IAgreementController controller */ @Override public QueryIterator createExecution(OpService opService, QueryIterator queryIterator, ExecutionContext executionContext, ServiceExecutorBulk serviceExecutorBulk) { - Node serviceNode=opService.getService(); - Set boundVars=new HashSet<>(); - long batchSize=config.getFederationServiceBatchSize(); + Node serviceNode = opService.getService(); + Set boundVars = new HashSet<>(); + long batchSize = config.getFederationServiceBatchSize(); // // returns an iterator over batches // - return new QueryIter1(queryIterator,executionContext) { + return new QueryIter1(queryIterator, executionContext) { // the active iterator over the current batch private QueryIterator batchIterator; @@ -148,29 +161,31 @@ public QueryIterator createExecution(OpService opService, QueryIterator queryIte */ @Override protected boolean hasNextBinding() { - return (batchIterator!=null && batchIterator.hasNext()) || hasNextResultBinding(); + return (batchIterator != null && batchIterator.hasNext()) || hasNextResultBinding(); } /** * switch to the next batch + * * @return whether next batch exists */ public boolean hasNextResultBinding() { // do we have additional input bindings - if(this.getInput().hasNext()) { + if (this.getInput().hasNext()) { // yes then read the next batch - Map> bindings=new HashMap<>(); - long batchLength=0; - while(this.getInput().hasNext() && batchLength++> bindings = new HashMap<>(); + long batchLength = 0; + while (this.getInput().hasNext() && batchLength++ < batchSize) { Binding binding = this.getInput().next(); - Iterator vars=binding.vars(); - while(vars.hasNext()) { + Iterator vars = binding.vars(); + while (vars.hasNext()) { boundVars.add(vars.next().getVarName()); } // detect the service uri under the current binding Node keyNode = serviceNode; - if (keyNode.isVariable()) + if (keyNode.isVariable()) { keyNode = binding.get((Var) keyNode); + } if (keyNode.isURI()) { String key = keyNode.getURI(); if (!bindings.containsKey(key)) { @@ -181,12 +196,12 @@ public boolean hasNextResultBinding() { monitor.warning("Omitting a call because of lacking service binding"); } } - ExecutionContext ctx=this.getExecContext(); + ExecutionContext ctx = this.getExecContext(); - List> futureBindings=bindings.entrySet().stream().map(serviceSpec -> executor.submit(() -> + List> futureBindings = bindings.entrySet().stream().map(serviceSpec -> executor.submit(() -> createExecution(opService, serviceSpec.getKey(), boundVars, serviceSpec.getValue(), ctx))).collect(Collectors.toList()); - batchIterator=new QueryIterFutures(config,monitor,config.getControlPlaneManagementUrl(),config.getDefaultAsset(),serviceNode, ctx.getContext(),futureBindings); + batchIterator = new QueryIterFutures(config, monitor, config.getControlPlaneManagementUrl(), config.getDefaultAsset(), serviceNode, ctx.getContext(), futureBindings); return hasNextBinding(); } else { return false; @@ -223,6 +238,7 @@ protected void closeSubIterator() { /** * single execution mode - this is not used anymore - batch mode is default + * * @param opExecute the bound operator (if variable is used in service description) * @param opOriginal the unbound operator * @param binding the current binding @@ -232,61 +248,63 @@ protected void closeSubIterator() { @Override public QueryIterator createExecution(OpService opExecute, OpService opOriginal, Binding binding, ExecutionContext execCxt) { // it maybe that a subselect has "masked" some input variables - Node serviceNode=opExecute.getService(); - if(serviceNode.isVariable()) { - serviceNode=binding.get((Var) serviceNode); + Node serviceNode = opExecute.getService(); + if (serviceNode.isVariable()) { + serviceNode = binding.get((Var) serviceNode); } - if (!serviceNode.isURI()) + if (!serviceNode.isURI()) { throw new QueryExecException("Service URI not bound: " + opExecute.getService()); + } // check whether we need to route over EDC String target = serviceNode.getURI(); - Set allowedVars=new HashSet<>(); + Set allowedVars = new HashSet<>(); Iterator allAllowedVars = binding.vars(); - while(allAllowedVars.hasNext()) { + while (allAllowedVars.hasNext()) { allowedVars.add(allAllowedVars.next().getVarName()); } - return createExecution(opOriginal,target,allowedVars,List.of(binding),execCxt); + return createExecution(opOriginal, target, allowedVars, List.of(binding), execCxt); } /** * (re-) implements the remote http service execution + * * @param opOriginal the unbound operator - * @param serviceURL uri of the target service + * @param serviceUrl uri of the target service * @param boundVars a set of all bound variables * @param bindings the current bindings * @param execCxt the execution context * @return a set of query results */ - public QueryIterator createExecution(OpService opOriginal, String serviceURL, Set boundVars, List bindings, ExecutionContext execCxt) { + public QueryIterator createExecution(OpService opOriginal, String serviceUrl, Set boundVars, List bindings, ExecutionContext execCxt) { Context context = execCxt.getContext(); // check whether the service url is allowed (in the context, in the default) - Pattern allowPattern = context.get(ALLOW_SYMBOL,config.getServiceAllowPattern()); - if(!allowPattern.matcher(serviceURL).matches()) { - throw new QueryExecException(String.format("The service %s does not match the allowed pattern %s. Aborted execution.",serviceURL,allowPattern.pattern())); + Pattern allowPattern = context.get(ALLOW_SYMBOL, config.getServiceAllowPattern()); + if (!allowPattern.matcher(serviceUrl).matches()) { + throw new QueryExecException(String.format("The service %s does not match the allowed pattern %s. Aborted execution.", serviceUrl, allowPattern.pattern())); } // check whether the service url is denied (in the context, in the default) - Pattern denyPattern = context.get(DENY_SYMBOL,config.getServiceDenyPattern()); - if(denyPattern.matcher(serviceURL).matches()) { - throw new QueryExecException(String.format("The service %s matches the denied pattern %s. Aborted execution.",serviceURL,denyPattern.pattern())); + Pattern denyPattern = context.get(DENY_SYMBOL, config.getServiceDenyPattern()); + if (denyPattern.matcher(serviceUrl).matches()) { + throw new QueryExecException(String.format("The service %s matches the denied pattern %s. Aborted execution.", serviceUrl, denyPattern.pattern())); } boolean silent = opOriginal.getSilent(); // derive the asset type from the service URL, if possible // otherwise we will get it from the endpoint address after a ngotiation - String assetType= serviceURL.contains("Skill") ? "cx-common:SkillAsset" : serviceURL.contains("Graph") ? "cx-common:GraphAsset" : "cx-common:Asset"; + String assetType = serviceUrl.contains("Skill") ? "cx-common:SkillAsset" : serviceUrl.contains("Graph") ? "cx-common:GraphAsset" : "cx-common:Asset"; // in case we have an EDC target, we need to negotiate/proxy the transfer - Matcher edcMatcher = EDC_TARGET_ADDRESS_PATTERN.matcher(serviceURL); + Matcher edcMatcher = EDC_TARGET_ADDRESS_PATTERN.matcher(serviceUrl); if (edcMatcher.matches()) { // // EDC case: negotiate and proxy the transfer // - monitor.info(String.format("About to execute edc target %s via dataspace", serviceURL)); + monitor.info(String.format("About to execute edc target %s via dataspace", serviceUrl)); String remoteUrl = edcMatcher.group("connector"); if (remoteUrl == null || remoteUrl.length() == 0) { remoteUrl = config.getControlPlaneIdsUrl(); @@ -299,17 +317,17 @@ public QueryIterator createExecution(OpService opOriginal, String serviceURL, Se } String asset = edcMatcher.group("asset"); if (asset == null || asset.length() == 0) { - GraphRewriteVisitor grv=new GraphRewriteVisitor(); - GraphRewrite gr=new GraphRewrite(monitor,bindings,grv); - Op transformed=Transformer.transform(gr,opOriginal.getSubOp(),grv,null); - opOriginal=new OpService(opOriginal.getService(),transformed,opOriginal.getSilent()); - Set graphNames=gr.getGraphNames(); - if(graphNames.size()>1) { - throw new QueryExecException("There are several graph assets (currently not supported due to negotiation strategy, please rewrite your query) under EDC-based service: " + serviceURL); + GraphRewriteVisitor grv = new GraphRewriteVisitor(); + GraphRewrite gr = new GraphRewrite(monitor, bindings, grv); + Op transformed = Transformer.transform(gr, opOriginal.getSubOp(), grv, null); + opOriginal = new OpService(opOriginal.getService(), transformed, opOriginal.getSilent()); + Set graphNames = gr.getGraphNames(); + if (graphNames.size() > 1) { + throw new QueryExecException("There are several graph assets (currently not supported due to negotiation strategy, please rewrite your query) under EDC-based service: " + serviceUrl); } else { - Optional graphName=graphNames.stream().findAny(); - if(graphName.isEmpty()) { - throw new QueryExecException("There is no graph asset under EDC-based service: " + serviceURL); + Optional graphName = graphNames.stream().findAny(); + if (graphName.isEmpty()) { + throw new QueryExecException("There is no graph asset under EDC-based service: " + serviceUrl); } else { asset = graphName.get(); } @@ -318,38 +336,38 @@ public QueryIterator createExecution(OpService opOriginal, String serviceURL, Se EndpointDataReference endpoint = agreementController.get(asset); if (endpoint == null) { endpoint = agreementController.createAgreement(remoteUrl, asset); - if(endpoint == null) { + if (endpoint == null) { throw new QueryExecException(String.format("Could not get an endpoint calback from connector %s to asset %s - Most likely this was a recursive call and you forgot to setup two control planes.", remoteUrl, asset)); } } // the asset type should be annotated in the rdf type property - assetType=endpoint.getProperties().getOrDefault("http://www.w3.org/1999/02/22-rdf-syntax-ns#type",assetType); + assetType = endpoint.getProperties().getOrDefault("http://www.w3.org/1999/02/22-rdf-syntax-ns#type", assetType); // put the endpoint information into a new service operator // and cater for the EDC public api slash problem - serviceURL = endpoint.getEndpoint(); - if(!serviceURL.endsWith("/")) { - serviceURL=serviceURL+"/"; + serviceUrl = endpoint.getEndpoint(); + if (!serviceUrl.endsWith("/")) { + serviceUrl = serviceUrl + "/"; } if (edcMatcher.group("params") != null) { - serviceURL = serviceURL + "?" + edcMatcher.group("params"); + serviceUrl = serviceUrl + "?" + edcMatcher.group("params"); } Map>> allServiceParams = context.get(Service.serviceParams); if (allServiceParams == null) { allServiceParams = new HashMap<>(); context.put(Service.serviceParams, allServiceParams); } - Map> serviceParams = allServiceParams.computeIfAbsent(serviceURL, k -> new HashMap<>()); - serviceParams.put("cx_accept",List.of("application/json")); + Map> serviceParams = allServiceParams.computeIfAbsent(serviceUrl, k -> new HashMap<>()); + serviceParams.put("cx_accept", List.of("application/json")); execCxt.getContext().put(AUTH_KEY_SYMBOL, endpoint.getAuthKey()); execCxt.getContext().put(AUTH_CODE_SYMBOL, endpoint.getAuthCode()); } else { - monitor.info(String.format("About to execute http target %s without dataspace", serviceURL)); + monitor.info(String.format("About to execute http target %s without dataspace", serviceUrl)); } // Next case distinction: we could either have a query or // a direct skill call - if(!assetType.contains("Skill")) { + if (!assetType.contains("Skill")) { // http execute with headers and such try { Op opRemote = opOriginal.getSubOp(); @@ -395,33 +413,33 @@ public QueryIterator createExecution(OpService opOriginal, String serviceURL, Se Query query; // do we have a "sub-select", then we smuggle our binding into it - if(opRemote instanceof OpProject) { - OpProject opRemoteProject=(OpProject) opRemote; - Op join = OpSequence.create(opTable,opRemoteProject.getSubOp()); - List resultVars=opRemoteProject.getVars(); + if (opRemote instanceof OpProject) { + OpProject opRemoteProject = (OpProject) opRemote; + Op join = OpSequence.create(opTable, opRemoteProject.getSubOp()); + List resultVars = opRemoteProject.getVars(); resultVars.add(idVar); - query=OpAsQuery.asQuery(new OpProject(join,resultVars)); + query = OpAsQuery.asQuery(new OpProject(join, resultVars)); } else { Op join = OpSequence.create(opTable, opRemote); query = OpAsQuery.asQuery(join); } - monitor.debug(String.format("Prepared target %s for query %s", serviceURL, query)); + monitor.debug(String.format("Prepared target %s for query %s", serviceUrl, query)); // -- Setup //boolean withCompression = context.isTrueOrUndef(httpQueryCompression); long timeoutMillis = config.getReadTimeout(); // RegistryServiceModifier is applied by QueryExecHTTP - Params serviceParams = getServiceParamsFromContext(serviceURL, context); - HttpClient httpClient = chooseHttpClient(serviceURL, context); + Params serviceParams = getServiceParamsFromContext(serviceUrl, context); + HttpClient httpClient = chooseHttpClient(serviceUrl, context); - QuerySendMode querySendMode = chooseQuerySendMode(serviceURL, context, QuerySendMode.asGetWithLimitBody); + QuerySendMode querySendMode = chooseQuerySendMode(serviceUrl, context, QuerySendMode.asGetWithLimitBody); // -- End setup // Build the execution - QueryExecutorBuilder qExecBuilder = QueryExecutor.newBuilder() - .endpoint(serviceURL) + QueryExecutorBuilder queryExecutorBuilder = QueryExecutor.newBuilder() + .endpoint(serviceUrl) .timeout(timeoutMillis, TimeUnit.MILLISECONDS) .query(query) .params(serviceParams) @@ -433,21 +451,21 @@ public QueryIterator createExecution(OpService opOriginal, String serviceURL, Se if (context.isDefined(AUTH_KEY_SYMBOL)) { String authKeyProp = context.get(AUTH_KEY_SYMBOL); - monitor.debug(String.format("About to use authentication header %s on http target %s", authKeyProp, serviceURL)); + monitor.debug(String.format("About to use authentication header %s on http target %s", authKeyProp, serviceUrl)); String authCodeProp = context.get(AUTH_CODE_SYMBOL); - qExecBuilder = qExecBuilder.httpHeader(authKeyProp, authCodeProp); + queryExecutorBuilder = queryExecutorBuilder.httpHeader(authKeyProp, authCodeProp); } - try (QueryExecutor qExec = qExecBuilder.build()) { + try (QueryExecutor qExec = queryExecutorBuilder.build()) { // Detach from the network stream. RowSet rowSet = qExec.select().materialize(); - QueryIterator qIter = QueryIterPlainWrapper.create(rowSet); - qIter = QueryIter.makeTracked(qIter, execCxt); - return new QueryIterJoin(qIter, newBindings, idVar, execCxt); + QueryIterator queryIterator = QueryIterPlainWrapper.create(rowSet); + queryIterator = QueryIter.makeTracked(queryIterator, execCxt); + return new QueryIterJoin(queryIterator, newBindings, idVar, execCxt); } } catch (RuntimeException ex) { if (silent) { - Log.warn(this, "SERVICE " + serviceURL + " : " + ex.getMessage()); + Log.warn(this, "SERVICE " + serviceUrl + " : " + ex.getMessage()); // Return the input return QueryIterPlainWrapper.create(bindings.iterator(), execCxt); } @@ -458,98 +476,99 @@ public QueryIterator createExecution(OpService opOriginal, String serviceURL, Se try { // [QExec] Add getSubOpUnmodified(); Op opRemote = opOriginal.getSubOp(); - String bindingVarName="binding"; + String bindingVarName = "binding"; Var idVar = Var.alloc(bindingVarName); SkillVariableDetector vd = new SkillVariableDetector(boundVars); - opRemote=Transformer.transform(vd,opRemote); - Map neededVars=vd.getVariables(); - var parameterSet=new ResultSetMem() { + opRemote = Transformer.transform(vd, opRemote); + Map neededVars = vd.getVariables(); + var parameterSet = new ResultSetMem() { public void setVarNames(List vars) { - this.varNames=vars; + this.varNames = vars; } + public List getRows() { return this.rows; } }; - List vars=new ArrayList<>(); + List vars = new ArrayList<>(); vars.add(bindingVarName); neededVars.forEach((key1, value) -> vars.add(key1)); parameterSet.setVarNames(vars); Map resultingBindings = new HashMap<>(); Map> newBindings = new HashMap<>(); - for(Binding originalBinding : bindings) { + for (Binding originalBinding : bindings) { StringBuilder keyBuilder = new StringBuilder(); - BindingBuilder bb=BindingBuilder.create(); - for(Map.Entry neededVar : neededVars.entrySet()) { - Node node=neededVar.getValue(); - if(node.isVariable()) { - node=originalBinding.get((Var) node); + BindingBuilder bb = BindingBuilder.create(); + for (Map.Entry neededVar : neededVars.entrySet()) { + Node node = neededVar.getValue(); + if (node.isVariable()) { + node = originalBinding.get((Var) node); } - if(node!=null) { + if (node != null) { keyBuilder.append(neededVar.getKey()); keyBuilder.append("#"); keyBuilder.append(node); bb.add(Var.alloc(neededVar.getKey()), node); } } - String key=keyBuilder.toString(); + String key = keyBuilder.toString(); Node keyNode; - if(resultingBindings.containsKey(key)) { - Binding existingBinding=resultingBindings.get(key); - keyNode=existingBinding.get(idVar); + if (resultingBindings.containsKey(key)) { + Binding existingBinding = resultingBindings.get(key); + keyNode = existingBinding.get(idVar); } else { - keyNode=NodeFactory.createLiteral(String.valueOf(resultingBindings.size())); - bb.add(idVar,keyNode); - newBindings.put(keyNode,new ArrayList<>()); - Binding newBinding=bb.build(); + keyNode = NodeFactory.createLiteral(String.valueOf(resultingBindings.size())); + bb.add(idVar, keyNode); + newBindings.put(keyNode, new ArrayList<>()); + Binding newBinding = bb.build(); //bb=BindingBuilder.create(newBinding); - resultingBindings.put(key,newBinding); + resultingBindings.put(key, newBinding); } - final BindingBuilder bb2=BindingBuilder.create(originalBinding); - bb2.set(idVar,keyNode); + final BindingBuilder bb2 = BindingBuilder.create(originalBinding); + bb2.set(idVar, keyNode); newBindings.get(keyNode).add(bb2.build()); } parameterSet.getRows().addAll(resultingBindings.values()); parameterSet.reset(); long timeoutMillis = config.getReadTimeout(); - HttpClient httpClient = chooseHttpClient(serviceURL, context); + HttpClient httpClient = chooseHttpClient(serviceUrl, context); - String bindingSet=ResultSetMgr.asString(parameterSet, ResultSetLang.RS_JSON); - HttpRequest.Builder skillRequest= HttpRequest.newBuilder(). - uri(new URI(serviceURL)). - header("Content-Type", WebContent.contentTypeResultsJSON). - timeout(Duration.ofMillis(timeoutMillis)). - header("Accept",WebContent.contentTypeResultsJSON). - POST(HttpRequest.BodyPublishers.ofString(bindingSet)); + String bindingSet = ResultSetMgr.asString(parameterSet, ResultSetLang.RS_JSON); + HttpRequest.Builder skillRequest = HttpRequest.newBuilder() + .uri(new URI(serviceUrl)) + .header("Content-Type", WebContent.contentTypeResultsJSON) + .timeout(Duration.ofMillis(timeoutMillis)) + .header("Accept", WebContent.contentTypeResultsJSON) + .POST(HttpRequest.BodyPublishers.ofString(bindingSet)); if (context.isDefined(AUTH_KEY_SYMBOL)) { - String authKeyProp=context.get(AUTH_KEY_SYMBOL); - monitor.debug(String.format("About to use authentication header %s on http target %s", authKeyProp,serviceURL)); - String authCodeProp=context.get(AUTH_CODE_SYMBOL); - skillRequest=skillRequest.header(authKeyProp,authCodeProp); + String authKeyProp = context.get(AUTH_KEY_SYMBOL); + monitor.debug(String.format("About to use authentication header %s on http target %s", authKeyProp, serviceUrl)); + String authCodeProp = context.get(AUTH_CODE_SYMBOL); + skillRequest = skillRequest.header(authKeyProp, authCodeProp); } - HttpResponse remoteCall=httpClient.send(skillRequest.build(), HttpResponse.BodyHandlers.ofInputStream()); - if(remoteCall.statusCode()>=200 && remoteCall.statusCode()<300) { - ResultSet result=ResultSetMgr.read(remoteCall.body(), ResultSetLang.RS_JSON); - RowSet rowSet=new RowSetAdapter(result); - QueryIterator qIter = QueryIterPlainWrapper.create(rowSet); - qIter = QueryIter.makeTracked(qIter, execCxt); - return new QueryIterJoin(qIter, newBindings, idVar, execCxt); + HttpResponse remoteCall = httpClient.send(skillRequest.build(), HttpResponse.BodyHandlers.ofInputStream()); + if (remoteCall.statusCode() >= 200 && remoteCall.statusCode() < 300) { + ResultSet result = ResultSetMgr.read(remoteCall.body(), ResultSetLang.RS_JSON); + RowSet rowSet = new RowSetAdapter(result); + QueryIterator queryIterator = QueryIterPlainWrapper.create(rowSet); + queryIterator = QueryIter.makeTracked(queryIterator, execCxt); + return new QueryIterJoin(queryIterator, newBindings, idVar, execCxt); } else { - Log.warn(this, "SERVICE " + serviceURL + " resulted in status code " + remoteCall.statusCode()); + Log.warn(this, "SERVICE " + serviceUrl + " resulted in status code " + remoteCall.statusCode()); remoteCall.body().close(); // Return the input return QueryIterPlainWrapper.create(bindings.iterator(), execCxt); } } catch (URISyntaxException | IOException | InterruptedException | RuntimeException ex) { if (silent) { - Log.warn(this, "SERVICE " + serviceURL + " : " + ex.getMessage()); + Log.warn(this, "SERVICE " + serviceUrl + " : " + ex.getMessage()); // Return the input return QueryIterPlainWrapper.create(bindings.iterator(), execCxt); } - throw new RuntimeException("Could not invoke remote skill",ex); + throw new RuntimeException("Could not invoke remote skill", ex); } } } @@ -557,13 +576,13 @@ public List getRows() { /** * choose an appropriate client * - * @param serviceURL target url + * @param serviceUrl target url * @param context query context * @return http client */ - protected HttpClient chooseHttpClient(String serviceURL, Context context) { - if(context==null) { - monitor.warning(String.format("Context is null when obtaining http client for %s",serviceURL)); + protected HttpClient chooseHttpClient(String serviceUrl, Context context) { + if (context == null) { + monitor.warning(String.format("Context is null when obtaining http client for %s", serviceUrl)); } return client; } @@ -571,17 +590,17 @@ protected HttpClient chooseHttpClient(String serviceURL, Context context) { /** * choose an appropriate send mode * - * @param serviceURL target url + * @param serviceUrl target url * @param context query content * @param dftValue default send mode of dft * @return decided send mode */ - protected QuerySendMode chooseQuerySendMode(String serviceURL, Context context, QuerySendMode dftValue) { - if(dftValue!=QuerySendMode.asPost) { - monitor.warning(String.format("Default send mode %s for %s is not post",dftValue,serviceURL)); + protected QuerySendMode chooseQuerySendMode(String serviceUrl, Context context, QuerySendMode dftValue) { + if (dftValue != QuerySendMode.asPost) { + monitor.warning(String.format("Default send mode %s for %s is not post", dftValue, serviceUrl)); } - if(context==null) { - monitor.warning(String.format("Context is null when obtaining send mode for %s",serviceURL)); + if (context == null) { + monitor.warning(String.format("Context is null when obtaining send mode for %s", serviceUrl)); } return QuerySendMode.asPost; } @@ -589,31 +608,34 @@ protected QuerySendMode chooseQuerySendMode(String serviceURL, Context context, /** * extract http params from query * - * @param serviceURI target url + * @param serviceUrl target url * @param context query context * @return query params * @throws QueryExecException in case there is something wrong */ - protected Params getServiceParamsFromContext(String serviceURI, Context context) throws QueryExecException { + protected Params getServiceParamsFromContext(String serviceUrl, Context context) throws QueryExecException { Params params = Params.create(); Object obj = context.get(Service.serviceParams); - if (obj == null) + if (obj == null) { return params; + } // Old style. try { @SuppressWarnings("unchecked") Map>> serviceParams = (Map>>) obj; - Map> paramsMap = serviceParams.get(serviceURI); + Map> paramsMap = serviceParams.get(serviceUrl); if (paramsMap != null) { for (String param : paramsMap.keySet()) { - if (HttpParams.pQuery.equals(param)) + if (HttpParams.pQuery.equals(param)) { throw new QueryExecException("ARQ serviceParams overrides the 'query' SPARQL protocol parameter"); + } List values = paramsMap.get(param); - for (String value : values) + for (String value : values) { params.add(param, value); + } } } return params; diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/GraphRewrite.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/GraphRewrite.java index 8fa155b..92e4021 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/GraphRewrite.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/GraphRewrite.java @@ -40,35 +40,35 @@ public class GraphRewrite extends TransformCopy { protected final List bindings; - protected final Set graphNames=new HashSet<>(); + protected final Set graphNames = new HashSet<>(); protected final Monitor monitor; protected final GraphRewriteVisitor visitor; public GraphRewrite(Monitor monitor, List bindings, GraphRewriteVisitor visitor) { - this.bindings=bindings; - this.monitor=monitor; - this.visitor=visitor; + this.bindings = bindings; + this.monitor = monitor; + this.visitor = visitor; } @Override public OpGraph transform(OpGraph op, Op subOp) { - if(!visitor.inService) { + if (!visitor.inService) { Node graphNode = op.getNode(); if (graphNode.isURI()) { - String graphString=graphNode.getURI(); - if(graphString.startsWith(SparqlQueryProcessor.UNSET_BASE)) { - graphString=graphString.substring(SparqlQueryProcessor.UNSET_BASE.length()); - op=new OpGraph(NodeFactory.createURI(graphString),subOp); + String graphString = graphNode.getURI(); + if (graphString.startsWith(SparqlQueryProcessor.UNSET_BASE)) { + graphString = graphString.substring(SparqlQueryProcessor.UNSET_BASE.length()); + op = new OpGraph(NodeFactory.createURI(graphString), subOp); } graphNames.add(graphString); } else if (graphNode.isLiteral()) { - String graphString=String.valueOf(graphNode.getLiteralValue()); - if(graphString.startsWith(SparqlQueryProcessor.UNSET_BASE)) { - graphString=graphString.substring(SparqlQueryProcessor.UNSET_BASE.length()); - op=new OpGraph(NodeFactory.createURI(graphString),subOp); + String graphString = String.valueOf(graphNode.getLiteralValue()); + if (graphString.startsWith(SparqlQueryProcessor.UNSET_BASE)) { + graphString = graphString.substring(SparqlQueryProcessor.UNSET_BASE.length()); + op = new OpGraph(NodeFactory.createURI(graphString), subOp); } graphNames.add(graphString); } else if (graphNode.isVariable()) { @@ -85,20 +85,20 @@ public OpGraph transform(OpGraph op, Op subOp) { } } if (bound != null) { - if( bound.isURI()) { + if (bound.isURI()) { String graphString = bound.getURI(); if (graphString.startsWith(SparqlQueryProcessor.UNSET_BASE)) { graphString = graphString.substring(SparqlQueryProcessor.UNSET_BASE.length()); } graphNames.add(graphString); - op=new OpGraph(NodeFactory.createURI(graphString), subOp); - } else if(bound.isLiteral()) { + op = new OpGraph(NodeFactory.createURI(graphString), subOp); + } else if (bound.isLiteral()) { String graphString = String.valueOf(bound.getLiteralValue()); if (graphString.startsWith(SparqlQueryProcessor.UNSET_BASE)) { graphString = graphString.substring(SparqlQueryProcessor.UNSET_BASE.length()); } graphNames.add(graphString); - op=new OpGraph(NodeFactory.createURI(graphString), subOp); + op = new OpGraph(NodeFactory.createURI(graphString), subOp); } else { monitor.warning(String.format("Found a graph node binding %s which is no uri or literal. Ignoring.", bound)); } @@ -114,6 +114,8 @@ public OpGraph transform(OpGraph op, Op subOp) { } /** + * access + * * @return set of graph names/assets found */ public Set getGraphNames() { diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/GraphRewriteVisitor.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/GraphRewriteVisitor.java index 5d18b75..ba17262 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/GraphRewriteVisitor.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/GraphRewriteVisitor.java @@ -23,11 +23,11 @@ * A visitor that indicates stop when inside a service */ public class GraphRewriteVisitor extends OpVisitorBase { - protected boolean inService=false; + protected boolean inService = false; @Override public void visit(OpService opService) { super.visit(opService); - inService=true; + inService = true; } } diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/OptimizeJoinStrategy.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/OptimizeJoinStrategy.java index 555eb9e..a70af18 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/OptimizeJoinStrategy.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/OptimizeJoinStrategy.java @@ -17,7 +17,11 @@ package org.eclipse.tractusx.agents.edc.sparql; import org.apache.jena.sparql.algebra.Op; -import org.apache.jena.sparql.algebra.op.*; +import org.apache.jena.sparql.algebra.op.OpGraph; +import org.apache.jena.sparql.algebra.op.OpJoin; +import org.apache.jena.sparql.algebra.op.OpSequence; +import org.apache.jena.sparql.algebra.op.OpService; +import org.apache.jena.sparql.algebra.op.OpUnion; import org.apache.jena.sparql.algebra.optimize.TransformJoinStrategy; import org.apache.jena.sparql.engine.main.JoinClassifier; @@ -31,24 +35,25 @@ public class OptimizeJoinStrategy extends TransformJoinStrategy { /** * implement the federated join strategy + * * @param opJoin operator to optimize - * @param left left-part of join - * @param right right-part of join + * @param left left-part of join + * @param right right-part of join * @return transformed join operator */ @Override public Op transform(OpJoin opJoin, Op left, Op right) { boolean canDoLinear = JoinClassifier.isLinear(opJoin); if (!canDoLinear) { - if(right instanceof OpService || right instanceof OpUnion) { + if (right instanceof OpService || right instanceof OpUnion) { // join no-matter what with a service or a union return OpSequence.create(left, right); } - if(left instanceof OpService || left instanceof OpGraph) { + if (left instanceof OpService || left instanceof OpGraph) { // join no matter after service and graph calls return OpSequence.create(left, right); } - if(left instanceof OpSequence && right instanceof OpSequence) { + if (left instanceof OpSequence && right instanceof OpSequence) { // join two sequences return OpSequence.create(left, right); } diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/Optimizer.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/Optimizer.java index e49aab8..3f0f74d 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/Optimizer.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/Optimizer.java @@ -27,6 +27,7 @@ public class Optimizer extends OptimizerStd { /** * Create a new optimizer + * * @param context query context */ public Optimizer(Context context) { @@ -35,6 +36,7 @@ public Optimizer(Context context) { /** * override to choose the improved join straregy + * * @param op operator to transform * @return transformed operator */ diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryExecutor.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryExecutor.java index f3a839b..e020922 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryExecutor.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryExecutor.java @@ -16,22 +16,10 @@ // SPDX-License-Identifier: Apache-2.0 package org.eclipse.tractusx.agents.edc.sparql; -import static org.apache.jena.http.HttpLib.*; - -import java.io.*; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpRequest.BodyPublishers; -import java.net.http.HttpResponse; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.TimeUnit; - import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.nimbusds.jose.util.IOUtils; -import org.eclipse.tractusx.agents.edc.AgentConfig; import org.apache.jena.atlas.RuntimeIOException; import org.apache.jena.atlas.iterator.Iter; import org.apache.jena.atlas.json.JSON; @@ -44,8 +32,20 @@ import org.apache.jena.graph.Triple; import org.apache.jena.http.HttpEnv; import org.apache.jena.http.HttpLib; -import org.apache.jena.query.*; -import org.apache.jena.riot.*; +import org.apache.jena.query.Query; +import org.apache.jena.query.QueryException; +import org.apache.jena.query.QueryExecException; +import org.apache.jena.query.QueryFactory; +import org.apache.jena.query.QueryParseException; +import org.apache.jena.query.QueryType; +import org.apache.jena.query.ResultSet; +import org.apache.jena.query.Syntax; +import org.apache.jena.riot.Lang; +import org.apache.jena.riot.RDFDataMgr; +import org.apache.jena.riot.RDFLanguages; +import org.apache.jena.riot.ResultSetMgr; +import org.apache.jena.riot.RiotException; +import org.apache.jena.riot.WebContent; import org.apache.jena.riot.resultset.ResultSetLang; import org.apache.jena.riot.resultset.ResultSetReaderRegistry; import org.apache.jena.riot.web.HttpNames; @@ -55,11 +55,40 @@ import org.apache.jena.sparql.core.Quad; import org.apache.jena.sparql.engine.http.HttpParams; import org.apache.jena.sparql.engine.http.QueryExceptionHTTP; +import org.apache.jena.sparql.exec.QueryExec; import org.apache.jena.sparql.exec.RowSet; import org.apache.jena.sparql.exec.http.Params; import org.apache.jena.sparql.exec.http.QuerySendMode; import org.apache.jena.sparql.util.Context; -import org.apache.jena.sparql.exec.QueryExec; +import org.eclipse.tractusx.agents.edc.AgentConfig; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpRequest.BodyPublishers; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.TimeUnit; + +import static org.apache.jena.http.HttpLib.acceptHeader; +import static org.apache.jena.http.HttpLib.contentTypeHeader; +import static org.apache.jena.http.HttpLib.dft; +import static org.apache.jena.http.HttpLib.execute; +import static org.apache.jena.http.HttpLib.finish; +import static org.apache.jena.http.HttpLib.requestURL; +import static org.apache.jena.http.HttpLib.responseHeader; /** * An Exec implementation which understands KA-MATCH and KA-TRANSFER remote @@ -67,21 +96,29 @@ */ public class QueryExecutor implements QueryExec { - /** @deprecated Use {@link #newBuilder} */ + /** + * creates a builder + * + * @deprecated Use {@link #newBuilder} + */ @Deprecated - public static QueryExecutorBuilder create() { return newBuilder() ; } + public static QueryExecutorBuilder create() { + return newBuilder(); + } - public static QueryExecutorBuilder newBuilder() { return QueryExecutorBuilder.create(); } + public static QueryExecutorBuilder newBuilder() { + return QueryExecutorBuilder.create(); + } - public static QueryExecutorBuilder service(String serviceURL) { - return newBuilder().endpoint(serviceURL); + public static QueryExecutorBuilder service(String serviceUrl) { + return newBuilder().endpoint(serviceUrl); } // Blazegraph has a bug : it impacts wikidata. // Unless the charset is set, wikidata interprets a POST as ISO-8859-??? (c.f. POST as form). // https://github.com/blazegraph/database/issues/224 // Only applies to SendMode.asPost of a SPARQL query. - public static final String QUERY_MIME_TYPE = WebContent.contentTypeSPARQLQuery+";charset="+WebContent.charsetUTF8; + public static final String QUERY_MIME_TYPE = WebContent.contentTypeSPARQLQuery + ";charset=" + WebContent.charsetUTF8; private final Query query; private final String queryString; private final String service; @@ -96,8 +133,8 @@ public static QueryExecutorBuilder service(String serviceURL) { private final int urlLimit; // Protocol - private final List defaultGraphURIs; - private final List namedGraphURIs; + private final List defaultGraphUris; + private final List namedGraphUris; private boolean closed = false; @@ -106,9 +143,9 @@ public static QueryExecutorBuilder service(String serviceURL) { private final TimeUnit readTimeoutUnit; // Content Types: these list the standard formats and also include */*. - private final String selectAcceptheader = WebContent.defaultSparqlResultsHeader; - private final String askAcceptHeader = WebContent.defaultSparqlAskHeader; - private final String datasetAcceptHeader = WebContent.defaultDatasetAcceptHeader; + private final String selectAcceptheader = WebContent.defaultSparqlResultsHeader; + private final String askAcceptHeader = WebContent.defaultSparqlAskHeader; + private final String datasetAcceptHeader = WebContent.defaultDatasetAcceptHeader; // If this is non-null, it overrides the use of any Content-Type above. private String appProvidedAcceptHeader; @@ -120,25 +157,26 @@ public static QueryExecutorBuilder service(String serviceURL) { private final HttpClient httpClient; private Map httpHeaders; - public QueryExecutor(String serviceURL, Query query, String queryString, int urlLimit, + public QueryExecutor(String serviceUrl, Query query, String queryString, int urlLimit, HttpClient httpClient, Map httpHeaders, Params params, Context context, - List defaultGraphURIs, List namedGraphURIs, + List defaultGraphUris, List namedGraphUris, QuerySendMode sendMode, String explicitAcceptHeader, long timeout, TimeUnit timeoutUnit, ObjectMapper objectMapper, AgentConfig agentConfig) { this.context = context; - this.service = serviceURL; + this.service = serviceUrl; this.query = query; this.queryString = queryString; this.urlLimit = urlLimit; this.httpHeaders = httpHeaders; - this.defaultGraphURIs = defaultGraphURIs; - this.namedGraphURIs = namedGraphURIs; + this.defaultGraphUris = defaultGraphUris; + this.namedGraphUris = namedGraphUris; this.sendMode = Objects.requireNonNull(sendMode); this.appProvidedAcceptHeader = explicitAcceptHeader; // Important - handled as special case because the defaults vary by query type. - if ( httpHeaders.containsKey(HttpNames.hAccept) ) { - if ( this.appProvidedAcceptHeader != null ) + if (httpHeaders.containsKey(HttpNames.hAccept)) { + if (this.appProvidedAcceptHeader != null) { this.appProvidedAcceptHeader = httpHeaders.get(HttpNames.hAccept); + } this.httpHeaders.remove(HttpNames.hAccept); } this.httpHeaders = httpHeaders; @@ -146,8 +184,8 @@ public QueryExecutor(String serviceURL, Query query, String queryString, int url this.readTimeout = timeout; this.readTimeoutUnit = timeoutUnit; this.httpClient = HttpLib.dft(httpClient, HttpEnv.getDftHttpClient()); - this.objectMapper=objectMapper; - this.agentConfig=agentConfig; + this.objectMapper = objectMapper; + this.agentConfig = agentConfig; } @Override @@ -161,7 +199,7 @@ private RowSet execRowSet() { // Use the explicitly given header or the default selectAcceptheader String thisAcceptHeader = dft(appProvidedAcceptHeader, selectAcceptheader); - Map.Entry response = performQuery(thisAcceptHeader); + Map.Entry response = performQuery(thisAcceptHeader); InputStream in = response.getValue(); // Don't assume the endpoint actually gives back the content type we asked for String actualContentType = response.getKey(); @@ -173,10 +211,12 @@ private RowSet execRowSet() { // Map to lang, with pragmatic alternatives. Lang lang = WebContent.contentTypeToLangResultSet(actualContentType); - if ( lang == null ) + if (lang == null) { throw new QueryException("Endpoint returned Content-Type: " + actualContentType + " which is not recognized for SELECT queries"); - if ( !ResultSetReaderRegistry.isRegistered(lang) ) + } + if (!ResultSetReaderRegistry.isRegistered(lang)) { throw new QueryException("Endpoint returned Content-Type: " + actualContentType + " which is not supported for SELECT queries"); + } // This returns a streaming result set for some formats. // Do not close the InputStream at this point. ResultSet result = ResultSetMgr.read(in, lang); @@ -188,24 +228,26 @@ public boolean ask() { checkNotClosed(); check(QueryType.ASK); String thisAcceptHeader = dft(appProvidedAcceptHeader, askAcceptHeader); - Map.Entry response = performQuery(thisAcceptHeader); + Map.Entry response = performQuery(thisAcceptHeader); InputStream in = response.getValue(); String actualContentType = response.getKey(); actualContentType = removeCharset(actualContentType); Lang lang = RDFLanguages.contentTypeToLang(actualContentType); - if ( lang == null ) { + if (lang == null) { // Any specials : // application/xml for application/sparql-results+xml // application/json for application/sparql-results+json - if (actualContentType.equals(WebContent.contentTypeXML)) + if (actualContentType.equals(WebContent.contentTypeXML)) { lang = ResultSetLang.RS_XML; - else if ( actualContentType.equals(WebContent.contentTypeJSON)) + } else if (actualContentType.equals(WebContent.contentTypeJSON)) { lang = ResultSetLang.RS_JSON; + } } - if ( lang == null ) + if (lang == null) { throw new QueryException("Endpoint returned Content-Type: " + actualContentType + " which is not supported for ASK queries"); + } boolean result = ResultSetMgr.readBoolean(in, lang); finish(in); return result; @@ -213,9 +255,10 @@ else if ( actualContentType.equals(WebContent.contentTypeJSON)) private String removeCharset(String contentType) { int idx = contentType.indexOf(';'); - if ( idx < 0 ) + if (idx < 0) { return contentType; - return contentType.substring(0,idx); + } + return contentType.substring(0, idx); } @Override @@ -233,19 +276,19 @@ public Iterator constructTriples() { } @Override - public Iterator constructQuads(){ + public Iterator constructQuads() { checkNotClosed(); return execQuads(); } @Override - public DatasetGraph constructDataset(){ + public DatasetGraph constructDataset() { checkNotClosed(); return constructDataset(DatasetGraphFactory.createTxnMem()); } @Override - public DatasetGraph constructDataset(DatasetGraph dataset){ + public DatasetGraph constructDataset(DatasetGraph dataset) { checkNotClosed(); check(QueryType.CONSTRUCT); return execDataset(dataset); @@ -317,7 +360,7 @@ private Iterator execQuads() { private Pair execRdfWorker(String contentType) { checkNotClosed(); String thisAcceptHeader = dft(appProvidedAcceptHeader, contentType); - Map.Entry response = performQuery(thisAcceptHeader); + Map.Entry response = performQuery(thisAcceptHeader); InputStream in = response.getValue(); // Don't assume the endpoint actually gives back the content type we asked for @@ -325,10 +368,11 @@ private Pair execRdfWorker(String contentType) { actualContentType = removeCharset(actualContentType); Lang lang = RDFLanguages.contentTypeToLang(actualContentType); - if ( ! RDFLanguages.isQuads(lang) && ! RDFLanguages.isTriples(lang) ) - throw new QueryException("Endpoint returned Content Type: " - + actualContentType - + " which is not a valid RDF syntax"); + if (!RDFLanguages.isQuads(lang) && !RDFLanguages.isTriples(lang)) { + throw new QueryException("Endpoint returned Content Type: " + + actualContentType + + " which is not a valid RDF syntax"); + } return Pair.create(in, lang); } @@ -337,37 +381,42 @@ public JsonArray execJson() { checkNotClosed(); check(QueryType.CONSTRUCT_JSON); String thisAcceptHeader = dft(appProvidedAcceptHeader, WebContent.contentTypeJSON); - Map.Entry response = performQuery(thisAcceptHeader); + Map.Entry response = performQuery(thisAcceptHeader); InputStream in = response.getValue(); try { return JSON.parseAny(in).getAsArray(); - } finally { finish(in); } + } finally { + finish(in); + } } @Override public Iterator execJsonItems() { JsonArray array = execJson().getAsArray(); List x = new ArrayList<>(array.size()); - array.forEach(elt->{ - if ( ! elt.isObject()) + array.forEach(elt -> { + if (!elt.isObject()) { throw new QueryExecException("Item in an array from a JSON query isn't an object"); + } x.add(elt.getAsObject()); }); return x.iterator(); } private void checkNotClosed() { - if ( closed ) + if (closed) { throw new QueryExecException("HTTP QueryExecHTTP has been closed"); + } } private void check(QueryType queryType) { - if ( query == null ) { + if (query == null) { // Pass through the queryString. return; } - if ( query.queryType() != queryType ) - throw new QueryExecException("Not the right form of query. Expected "+queryType+" but got "+query.queryType()); + if (query.queryType() != queryType) { + throw new QueryExecException("Not the right form of query. Expected " + queryType + " but got " + query.queryType()); + } } @Override @@ -385,16 +434,17 @@ public DatasetGraph getDataset() { // extensions to the far end. @Override public Query getQuery() { - if ( query != null ) + if (query != null) { return query; - if ( queryString != null ) { + } + if (queryString != null) { // Object not created with a Query object, may be because there is foreign // syntax in the query or may be because the query string was available and the app // didn't want the overhead of parsing it every time. // Try to parse it else return null; try { - return QueryFactory.create(queryString, Syntax.syntaxARQ); } - catch (QueryParseException ex) { + return QueryFactory.create(queryString, Syntax.syntaxARQ); + } catch (QueryParseException ex) { return null; } } @@ -416,21 +466,23 @@ public String getQueryString() { * query execution was successful and return 200. * Use {@link HttpLib#getInputStream} to access the body. */ - private Map.Entry performQuery(String reqAcceptHeader) { - if (closed) + private Map.Entry performQuery(String reqAcceptHeader) { + if (closed) { throw new ARQException("HTTP execution already closed"); + } // SERVICE specials. - Params thisParams = Params.create(params); - if ( defaultGraphURIs != null ) { - for ( String dft : defaultGraphURIs ) - thisParams.add( HttpParams.pDefaultGraph, dft ); + if (defaultGraphUris != null) { + for (String dft : defaultGraphUris) { + thisParams.add(HttpParams.pDefaultGraph, dft); + } } - if ( namedGraphURIs != null ) { - for ( String name : namedGraphURIs ) - thisParams.add( HttpParams.pNamedGraph, name ); + if (namedGraphUris != null) { + for (String name : namedGraphUris) { + thisParams.add(HttpParams.pNamedGraph, name); + } } HttpLib.modifyByService(service, context, thisParams, httpHeaders); @@ -443,81 +495,82 @@ private Map.Entry performQuery(String reqAcceptHeader) { private HttpRequest makeRequest(Params thisParams, String reqAcceptHeader) { QuerySendMode actualSendMode = actualSendMode(); HttpRequest.Builder requestBuilder; - switch(actualSendMode) { - case asGetAlways : + switch (actualSendMode) { + case asGetAlways: requestBuilder = executeQueryGet(thisParams, reqAcceptHeader); break; - case asPostForm : + case asPostForm: requestBuilder = executeQueryPostForm(thisParams, reqAcceptHeader); break; - case asPost : + case asPost: requestBuilder = executeQueryPostBody(thisParams, reqAcceptHeader); break; - default : + default: // Should not happen! - throw new InternalErrorException("Invalid value for 'actualSendMode' "+actualSendMode); + throw new InternalErrorException("Invalid value for 'actualSendMode' " + actualSendMode); } return requestBuilder.build(); } - private Map.Entry executeQuery(HttpRequest request) { + private Map.Entry executeQuery(HttpRequest request) { try { HttpResponse response = execute(httpClient, request); - String contentType=responseHeader(response,HttpNames.hContentType); - InputStream inputStream=new BufferedInputStream(HttpLib.getInputStream(response)); + String contentType = responseHeader(response, HttpNames.hContentType); + InputStream inputStream = new BufferedInputStream(HttpLib.getInputStream(response)); inputStream.mark(2); - byte[] boundaryBytes=new byte[2]; - int all=inputStream.read(boundaryBytes); - String boundary=new String(boundaryBytes); + byte[] boundaryBytes = new byte[2]; + int all = inputStream.read(boundaryBytes); + String boundary = new String(boundaryBytes); inputStream.reset(); - Optional warnings=response.headers().firstValue("cx_warnings"); - if(all==boundaryBytes.length && contentType.startsWith("multipart/form-data") || "--".equals(boundary)) { - int boundaryIndex=contentType.indexOf(";boundary="); - if(boundaryIndex>=0) { - boundary=boundary+contentType.substring(boundaryIndex+10); + Optional warnings = response.headers().firstValue("cx_warnings"); + if (all == boundaryBytes.length && contentType.startsWith("multipart/form-data") || "--".equals(boundary)) { + int boundaryIndex = contentType.indexOf(";boundary="); + if (boundaryIndex >= 0) { + boundary = boundary + contentType.substring(boundaryIndex + 10); } - StringBuilder nextPart=null; - String embeddedContentType=null; - try (BufferedReader reader=new BufferedReader(new InputStreamReader(inputStream))) { - for(String line = reader.readLine(); line!=null; line=reader.readLine()) { - if(boundary.equals(line)) { - if(nextPart!=null && embeddedContentType!=null) { - if(embeddedContentType.equals("application/cx-warnings+json")) { - warnings=Optional.of(nextPart.toString()); + StringBuilder nextPart = null; + String embeddedContentType = null; + try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + for (String line = reader.readLine(); line != null; line = reader.readLine()) { + if (boundary.equals(line)) { + if (nextPart != null && embeddedContentType != null) { + if (embeddedContentType.equals("application/cx-warnings+json")) { + warnings = Optional.of(nextPart.toString()); } else { - inputStream=new ByteArrayInputStream(nextPart.toString().getBytes()); - contentType=embeddedContentType; + inputStream = new ByteArrayInputStream(nextPart.toString().getBytes()); + contentType = embeddedContentType; } } - nextPart=new StringBuilder(); - String contentLine=reader.readLine(); - if(contentLine!=null && contentLine.startsWith("Content-Type: ")) { - embeddedContentType=contentLine.substring(14); + nextPart = new StringBuilder(); + String contentLine = reader.readLine(); + if (contentLine != null && contentLine.startsWith("Content-Type: ")) { + embeddedContentType = contentLine.substring(14); } else { - embeddedContentType=null; + embeddedContentType = null; } - } else if(nextPart!=null) { + } else if (nextPart != null) { nextPart.append(line); nextPart.append("\n"); } } } - if(nextPart!=null && embeddedContentType!=null) { - if(embeddedContentType.equals("application/cx-warnings+json")) { - warnings=Optional.of(nextPart.toString()); + if (nextPart != null && embeddedContentType != null) { + if (embeddedContentType.equals("application/cx-warnings+json")) { + warnings = Optional.of(nextPart.toString()); } else { - inputStream=new ByteArrayInputStream(nextPart.toString().getBytes()); - contentType=embeddedContentType; + inputStream = new ByteArrayInputStream(nextPart.toString().getBytes()); + contentType = embeddedContentType; } } } - if(warnings.isPresent()) { - List yetWarnings=CatenaxWarning.getOrSetWarnings(context); + if (warnings.isPresent()) { + List yetWarnings = CatenaxWarning.getOrSetWarnings(context); try { - List newWarnings=objectMapper.readValue(warnings.get(), new TypeReference<>(){}); + List newWarnings = objectMapper.readValue(warnings.get(), new TypeReference<>() { + }); yetWarnings.addAll(newWarnings); } catch (JsonProcessingException e) { - CatenaxWarning newWarning=new CatenaxWarning(); + CatenaxWarning newWarning = new CatenaxWarning(); newWarning.setSourceTenant(agentConfig.getControlPlaneIdsUrl()); newWarning.setSourceAsset(agentConfig.getDefaultAsset()); newWarning.setTargetTenant(request.uri().toString()); @@ -528,39 +581,41 @@ private Map.Entry executeQuery(HttpRequest request) { } } int httpStatusCode = response.statusCode(); - if(httpStatusCode<200 || httpStatusCode>299) { - String msg= IOUtils.readInputStreamToString(inputStream); - throw new QueryExceptionHTTP(httpStatusCode,msg); + if (httpStatusCode < 200 || httpStatusCode > 299) { + String msg = IOUtils.readInputStreamToString(inputStream); + throw new QueryExceptionHTTP(httpStatusCode, msg); } - return new AbstractMap.SimpleEntry<>(contentType,inputStream); + return new AbstractMap.SimpleEntry<>(contentType, inputStream); } catch (IOException e) { throw new QueryException(e); } } private QuerySendMode actualSendMode() { - switch(sendMode) { - case asGetAlways : - case asPostForm : - case asPost : + switch (sendMode) { + case asGetAlways: + case asPostForm: + case asPost: return sendMode; - case asGetWithLimitBody : - case asGetWithLimitForm : + case asGetWithLimitBody: + case asGetWithLimitForm: + default: break; } // Other params (query= has not been added at this point) int paramsLength = params.httpString().length(); - int qEncodedLength = calcEncodeStringLength(queryString); + int encodeStringLength = calcEncodeStringLength(queryString); // URL Length, including service (for safety) - int length = service.length() - + /* ?query= */ 1 + HttpParams.pQuery.length() - + /* encoded query */ qEncodedLength - + /* &other params*/ 1 + paramsLength; - if ( length <= urlLimit ) + int length = service.length() + + /* ?query= */ 1 + HttpParams.pQuery.length() + + /* encoded query */ encodeStringLength + + /* &other params*/ 1 + paramsLength; + if (length <= urlLimit) { return QuerySendMode.asGetAlways; - return (sendMode==QuerySendMode.asGetWithLimitBody) ? QuerySendMode.asPost : QuerySendMode.asPostForm; + } + return (sendMode == QuerySendMode.asGetWithLimitBody) ? QuerySendMode.asPost : QuerySendMode.asPostForm; } private static int calcEncodeStringLength(String str) { @@ -571,8 +626,8 @@ private static int calcEncodeStringLength(String str) { private HttpRequest.Builder executeQueryGet(Params thisParams, String acceptHeader) { thisParams.add(HttpParams.pQuery, queryString); - String requestURL = requestURL(service, thisParams.httpString()); - HttpRequest.Builder builder = HttpLib.requestBuilder(requestURL, httpHeaders, readTimeout, readTimeoutUnit); + String requestUrl = requestURL(service, thisParams.httpString()); + HttpRequest.Builder builder = HttpLib.requestBuilder(requestUrl, httpHeaders, readTimeout, readTimeoutUnit); acceptHeader(builder, acceptHeader); return builder.GET(); } @@ -591,8 +646,8 @@ private HttpRequest.Builder executeQueryPostForm(Params thisParams, String accep // Use SPARQL query body and MIME type. private HttpRequest.Builder executeQueryPostBody(Params thisParams, String acceptHeader) { // Use thisParams (for default-graph-uri etc) - String requestURL = requestURL(service, thisParams.httpString()); - HttpRequest.Builder builder = HttpLib.requestBuilder(requestURL, httpHeaders, readTimeout, readTimeoutUnit); + String requestUrl = requestURL(service, thisParams.httpString()); + HttpRequest.Builder builder = HttpLib.requestBuilder(requestUrl, httpHeaders, readTimeout, readTimeoutUnit); contentTypeHeader(builder, QUERY_MIME_TYPE); acceptHeader(builder, acceptHeader); return builder.POST(BodyPublishers.ofString(queryString)); @@ -616,8 +671,10 @@ public void close() { // as HTTP client will consume the remaining response so it can re-use the // connection. If we're closing when we're not at the end of the stream then // issue a warning to the logs - if (retainedConnection.read() != -1) - Log.warn(this, "HTTP response not fully consumed, if HTTP Client is reusing connections (its default behaviour) then it will consume the remaining response data which may take a long time and cause this application to become unresponsive"); + if (retainedConnection.read() != -1) { + Log.warn(this, "HTTP response not fully consumed, if HTTP Client is reusing connections (its default behaviour)" + + "then it will consume the remaining response data which may take a long time and cause this application to become unresponsive"); + } retainedConnection.close(); } catch (RuntimeIOException | java.io.IOException e) { // If we are closing early and the underlying stream is chunk encoded @@ -630,5 +687,7 @@ public void close() { } @Override - public boolean isClosed() { return closed; } + public boolean isClosed() { + return closed; + } } \ No newline at end of file diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryExecutorBuilder.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryExecutorBuilder.java index 0bbd342..48a2703 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryExecutorBuilder.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryExecutorBuilder.java @@ -17,12 +17,13 @@ package org.eclipse.tractusx.agents.edc.sparql; import com.fasterxml.jackson.databind.ObjectMapper; -import org.eclipse.tractusx.agents.edc.AgentConfig; import org.apache.jena.http.sys.ExecHTTPBuilder; import org.apache.jena.query.Query; +import org.apache.jena.sparql.exec.QueryExecBuilder; import org.apache.jena.sparql.exec.QueryExecMod; import org.apache.jena.sparql.exec.http.Params; import org.apache.jena.sparql.util.Context; +import org.eclipse.tractusx.agents.edc.AgentConfig; import java.net.http.HttpClient; import java.util.HashMap; @@ -30,18 +31,21 @@ import static org.apache.jena.http.HttpLib.copyArray; -import org.apache.jena.sparql.exec.QueryExecBuilder; - /** * A builder for KA Remote Query Execs */ public class QueryExecutorBuilder extends ExecHTTPBuilder implements QueryExecMod, QueryExecBuilder { - public static QueryExecutorBuilder create() { return new QueryExecutorBuilder(); } + public static QueryExecutorBuilder create() { + return new QueryExecutorBuilder(); + } - public static QueryExecutorBuilder service(String serviceURL) { return create().endpoint(serviceURL); } + public static QueryExecutorBuilder service(String serviceUrl) { + return create().endpoint(serviceUrl); + } - private QueryExecutorBuilder() {} + private QueryExecutorBuilder() { + } @Override protected QueryExecutorBuilder thisBuilder() { @@ -52,13 +56,13 @@ protected QueryExecutorBuilder thisBuilder() { protected AgentConfig agentConfig; @Override - protected QueryExecutor buildX(HttpClient hClient, Query queryActual, String queryStringActual, Context cxt) { + protected QueryExecutor buildX(HttpClient httpClient, Query queryActual, String queryStringActual, Context cxt) { return new QueryExecutor(serviceURL, queryActual, queryStringActual, urlLimit, - hClient, new HashMap<>(httpHeaders), Params.create(params), cxt, + httpClient, new HashMap<>(httpHeaders), Params.create(params), cxt, copyArray(defaultGraphURIs), copyArray(namedGraphURIs), sendMode, appAcceptHeader, - timeout, timeoutUnit, objectMapper,agentConfig); + timeout, timeoutUnit, objectMapper, agentConfig); } @Override @@ -67,12 +71,12 @@ public QueryExecutorBuilder initialTimeout(long timeout, TimeUnit timeUnit) { } public QueryExecutorBuilder objectMapper(ObjectMapper objectMapper) { - this.objectMapper=objectMapper; + this.objectMapper = objectMapper; return this; } public QueryExecutorBuilder agentConfig(AgentConfig agentConfig) { - this.agentConfig=agentConfig; + this.agentConfig = agentConfig; return this; } diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryIterFutures.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryIterFutures.java index 5d7f0ee..a844eac 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryIterFutures.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryIterFutures.java @@ -16,7 +16,6 @@ // SPDX-License-Identifier: Apache-2.0 package org.eclipse.tractusx.agents.edc.sparql; -import org.eclipse.tractusx.agents.edc.AgentConfig; import org.apache.jena.atlas.io.IndentedWriter; import org.apache.jena.graph.Node; import org.apache.jena.sparql.core.Var; @@ -26,6 +25,7 @@ import org.apache.jena.sparql.serializer.SerializationContext; import org.apache.jena.sparql.util.Context; import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.tractusx.agents.edc.AgentConfig; import java.util.List; import java.util.Optional; @@ -52,47 +52,54 @@ public class QueryIterFutures extends QueryIteratorBase { /** * creates a new future iterator - * @param config agent config - * @param monitor logging subsystem - * @param sourceTenant the name/uri of the source tenant - * @param targetNode a node (var, the name/uri of the remote tenant - * @param sourceAsset the name of the calling/consuming graph + * + * @param config agent config + * @param monitor logging subsystem + * @param sourceTenant the name/uri of the source tenant + * @param targetNode a node (var, the name/uri of the remote tenant + * @param sourceAsset the name of the calling/consuming graph * @param executionContext description of the execution context - * @param futures list of futures to synchronize on + * @param futures list of futures to synchronize on */ public QueryIterFutures(AgentConfig config, Monitor monitor, String sourceTenant, String sourceAsset, Node targetNode, Context executionContext, List> futures) { - this.futures=futures; - this.monitor=monitor; - this.config=config; - this.sourceAsset=sourceAsset; - this.sourceTenant=sourceTenant; - this.targetNode=targetNode; - this.executionContext=executionContext; + this.futures = futures; + this.monitor = monitor; + this.config = config; + this.sourceAsset = sourceAsset; + this.sourceTenant = sourceTenant; + this.targetNode = targetNode; + this.executionContext = executionContext; } /** + * access + * * @return whether any service has/will produce any binding */ @Override protected boolean hasNextBinding() { - return (current!=null && current.hasNext()) || hasNextInternalBinding(); + return (current != null && current.hasNext()) || hasNextInternalBinding(); } /** + * access + * * @return the last service node bindings uri */ protected String getTargetTenant() { - Node resolvedNode=targetNode; - if(targetNode.isVariable() && lastBinding!=null) { - resolvedNode=lastBinding.get((Var) targetNode); + Node resolvedNode = targetNode; + if (targetNode.isVariable() && lastBinding != null) { + resolvedNode = lastBinding.get((Var) targetNode); } - if(resolvedNode!=null) { + if (resolvedNode != null) { return resolvedNode.toString(false); } return ""; } /** + * access + * * @return the last service node bindings asset */ protected String getTargetAsset() { @@ -101,22 +108,23 @@ protected String getTargetAsset() { /** * move to the next ready-made future (or sync/poll for the next ready-made one in a recursion) + * * @return whether any service has/will produce any binding */ boolean hasNextInternalBinding() { - if(!futures.isEmpty()) { - Optional> boundFuture=futures.stream().filter(Future::isDone).findFirst(); + if (!futures.isEmpty()) { + Optional> boundFuture = futures.stream().filter(Future::isDone).findFirst(); try { - if(boundFuture.isPresent()) { - Future currentFuture=boundFuture.get(); + if (boundFuture.isPresent()) { + Future currentFuture = boundFuture.get(); futures.remove(currentFuture); current = currentFuture.get(); } else { Thread.sleep(config.getNegotiationPollInterval()); } - } catch(InterruptedException e) { - List warnings=CatenaxWarning.getOrSetWarnings(executionContext); - CatenaxWarning newWarning=new CatenaxWarning(); + } catch (InterruptedException e) { + List warnings = CatenaxWarning.getOrSetWarnings(executionContext); + CatenaxWarning newWarning = new CatenaxWarning(); newWarning.setSourceAsset(sourceAsset); newWarning.setSourceTenant(sourceTenant); newWarning.setTargetAsset(getTargetAsset()); @@ -124,10 +132,10 @@ boolean hasNextInternalBinding() { newWarning.setContext(String.valueOf(executionContext.hashCode())); newWarning.setProblem("Timeout/Interruption invoking a remote batch: Result may be partial."); warnings.add(newWarning); - monitor.warning(String.format("Produced warning %s for context %s",newWarning,executionContext),e); - } catch(ExecutionException e) { - List warnings=CatenaxWarning.getOrSetWarnings(executionContext); - CatenaxWarning newWarning=new CatenaxWarning(); + monitor.warning(String.format("Produced warning %s for context %s", newWarning, executionContext), e); + } catch (ExecutionException e) { + List warnings = CatenaxWarning.getOrSetWarnings(executionContext); + CatenaxWarning newWarning = new CatenaxWarning(); newWarning.setSourceAsset(sourceAsset); newWarning.setSourceTenant(sourceTenant); newWarning.setTargetAsset(getTargetAsset()); @@ -135,7 +143,7 @@ boolean hasNextInternalBinding() { newWarning.setContext(String.valueOf(executionContext.hashCode())); newWarning.setProblem("Failure invoking a remote batch: Result may be partial."); warnings.add(newWarning); - monitor.warning(String.format("Produced warning %s for context %s",newWarning,executionContext),e); + monitor.warning(String.format("Produced warning %s for context %s", newWarning, executionContext), e); } return hasNextBinding(); } @@ -144,21 +152,22 @@ boolean hasNextInternalBinding() { @Override protected Binding moveToNextBinding() { - lastBinding=current.next(); + lastBinding = current.next(); return lastBinding; } @Override protected void closeIterator() { requestCancel(); - if(current!=null) { + if (current != null) { current.close(); current = null; } } + @Override protected void requestCancel() { - futures.forEach( future -> future.cancel(true)); + futures.forEach(future -> future.cancel(true)); futures.clear(); } diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryIterJoin.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryIterJoin.java index 1c01a56..90c6e5c 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryIterJoin.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryIterJoin.java @@ -36,14 +36,14 @@ * Prepares the given bindings with a hidden variable which is then projected */ public class QueryIterJoin extends QueryIter1 { - protected final Map> joinBindings; + protected final Map> joinBindings; protected final Var idVar; protected Iterator leftBindings; - public QueryIterJoin(QueryIterator input, Map> joinBindings, Var idVar, ExecutionContext execCxt) { + public QueryIterJoin(QueryIterator input, Map> joinBindings, Var idVar, ExecutionContext execCxt) { super(input, execCxt); - this.joinBindings=joinBindings; - this.idVar=idVar; + this.joinBindings = joinBindings; + this.idVar = idVar; } @Override @@ -56,20 +56,20 @@ protected void requestSubCancel() { @Override public boolean hasNextBinding() { - return (leftBindings!=null && leftBindings.hasNext()) || hasNextInputBinding(); + return (leftBindings != null && leftBindings.hasNext()) || hasNextInputBinding(); } protected boolean hasNextInputBinding() { - if(this.getInput().hasNext()) { + if (this.getInput().hasNext()) { Binding nextBinding = this.getInput().next(); Node idNode = nextBinding.get(idVar); - List resultBindings=joinBindings.get(idNode); - if(resultBindings!=null) { - leftBindings=resultBindings.stream().map( resultBinding -> { - BindingBuilder bb=BindingBuilder.create(resultBinding); - nextBinding.forEach( (v,n) -> { - if(!resultBinding.contains(v)) { - bb.set(v,n); + List resultBindings = joinBindings.get(idNode); + if (resultBindings != null) { + leftBindings = resultBindings.stream().map(resultBinding -> { + BindingBuilder bb = BindingBuilder.create(resultBinding); + nextBinding.forEach((v, n) -> { + if (!resultBinding.contains(v)) { + bb.set(v, n); } }); return bb.build(); @@ -85,7 +85,7 @@ protected boolean hasNextInputBinding() { @Override public Binding moveToNextBinding() { - if(leftBindings!=null && leftBindings.hasNext()) { + if (leftBindings != null && leftBindings.hasNext()) { return leftBindings.next(); } else { return null; diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SkillVariableDetector.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SkillVariableDetector.java index b73117d..f3594f3 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SkillVariableDetector.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SkillVariableDetector.java @@ -36,18 +36,18 @@ */ public class SkillVariableDetector extends TransformSingle { - HashMap variables=new HashMap<>(); + HashMap variables = new HashMap<>(); Set allowed; public SkillVariableDetector(Set allowed) { - this.allowed=allowed; + this.allowed = allowed; } @Override public Op transform(OpExtend opExtend, Op subOp) { - opExtend.getVarExprList().forEachExpr( (assignment,expr) -> { - String varName= assignment.getVarName(); - if(!variables.containsKey(varName)) { + opExtend.getVarExprList().forEachExpr((assignment, expr) -> { + String varName = assignment.getVarName(); + if (!variables.containsKey(varName)) { if (expr.isVariable()) { Var var = (Var) ((ExprVar) expr).getAsNode(); if (allowed.contains(var.getVarName())) { @@ -62,7 +62,7 @@ public Op transform(OpExtend opExtend, Op subOp) { return opExtend; } - public Map getVariables() { + public Map getVariables() { return variables; } } diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQueryProcessor.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQueryProcessor.java index bb1499e..07ccb46 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQueryProcessor.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQueryProcessor.java @@ -18,8 +18,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.eclipse.tractusx.agents.edc.http.transfer.AgentSourceHttpParamsDecorator; -import org.eclipse.tractusx.agents.edc.rdf.RDFStore; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.ws.rs.BadRequestException; @@ -27,22 +25,18 @@ import okhttp3.Request; import okhttp3.Response; import org.apache.http.HttpStatus; +import org.apache.jena.atlas.lib.Pair; import org.apache.jena.fuseki.Fuseki; import org.apache.jena.fuseki.server.DataAccessPointRegistry; import org.apache.jena.fuseki.server.OperationRegistry; -import org.apache.jena.fuseki.servlets.*; - -import java.util.*; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.jena.query.QueryExecException; +import org.apache.jena.fuseki.servlets.ActionErrorException; +import org.apache.jena.fuseki.servlets.HttpAction; +import org.apache.jena.fuseki.servlets.SPARQL_QueryGeneral; import org.apache.jena.query.Query; +import org.apache.jena.query.QueryExecException; import org.apache.jena.sparql.ARQConstants; import org.apache.jena.sparql.algebra.optimize.RewriteFactory; import org.apache.jena.sparql.core.DatasetGraph; -import org.apache.jena.atlas.lib.Pair; import org.apache.jena.sparql.engine.http.QueryExceptionHTTP; import org.apache.jena.sparql.service.ServiceExecutorRegistry; import org.eclipse.edc.spi.monitor.Monitor; @@ -51,7 +45,22 @@ import org.eclipse.tractusx.agents.edc.MonitorWrapper; import org.eclipse.tractusx.agents.edc.Tuple; import org.eclipse.tractusx.agents.edc.TupleSet; -import org.eclipse.tractusx.agents.edc.http.*; +import org.eclipse.tractusx.agents.edc.http.AgentHttpAction; +import org.eclipse.tractusx.agents.edc.http.HttpServletContextAdapter; +import org.eclipse.tractusx.agents.edc.http.HttpServletRequestAdapter; +import org.eclipse.tractusx.agents.edc.http.HttpServletResponseAdapter; +import org.eclipse.tractusx.agents.edc.http.HttpUtils; +import org.eclipse.tractusx.agents.edc.http.JakartaAdapter; +import org.eclipse.tractusx.agents.edc.http.transfer.AgentSourceHttpParamsDecorator; +import org.eclipse.tractusx.agents.edc.rdf.RdfStore; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * dedicated SparQL query processor which is skill-enabled and open for edc-based services: @@ -71,34 +80,37 @@ public class SparqlQueryProcessor extends SPARQL_QueryGeneral.SPARQL_QueryProc { /** * state */ - protected final OperationRegistry operationRegistry= OperationRegistry.createEmpty(); - protected final DataAccessPointRegistry dataAccessPointRegistry=new DataAccessPointRegistry(); - protected final RewriteFactory optimizerFactory=new OptimizerFactory(); + protected final OperationRegistry operationRegistry = OperationRegistry.createEmpty(); + protected final DataAccessPointRegistry dataAccessPointRegistry = new DataAccessPointRegistry(); + protected final RewriteFactory optimizerFactory = new OptimizerFactory(); // map EDC monitor to SLF4J (better than the builtin MonitorProvider) private final MonitorWrapper monitorWrapper; // some state to set when interacting with Fuseki - protected final RDFStore rdfStore; - private long count=-1; + protected final RdfStore rdfStore; + private long count = -1; - public static String UNSET_BASE="http://server/unset-base/"; + public static final String UNSET_BASE = "http://server/unset-base/"; /** * create a new sparql processor + * * @param registry service execution registry - * @param monitor EDC logging + * @param monitor EDC logging */ - public SparqlQueryProcessor(ServiceExecutorRegistry registry, Monitor monitor, AgentConfig config, RDFStore rdfStore, TypeManager typeManager) { - this.monitor=monitor; - this.registry=registry; - this.config=config; - this.monitorWrapper=new MonitorWrapper(getClass().getName(),monitor); - this.rdfStore=rdfStore; - this.objectMapper=typeManager.getMapper(); + public SparqlQueryProcessor(ServiceExecutorRegistry registry, Monitor monitor, AgentConfig config, RdfStore rdfStore, TypeManager typeManager) { + this.monitor = monitor; + this.registry = registry; + this.config = config; + this.monitorWrapper = new MonitorWrapper(getClass().getName(), monitor); + this.rdfStore = rdfStore; + this.objectMapper = typeManager.getMapper(); dataAccessPointRegistry.register(rdfStore.getDataAccessPoint()); } /** + * access + * * @return the operation registry */ public OperationRegistry getOperationRegistry() { @@ -106,6 +118,8 @@ public OperationRegistry getOperationRegistry() { } /** + * access + * * @return the data access point registry */ public DataAccessPointRegistry getDataAccessPointRegistry() { @@ -114,28 +128,31 @@ public DataAccessPointRegistry getDataAccessPointRegistry() { /** * wraps a response to a previous servlet API + * * @param jakartaResponse new servlet object * @return wrapped/adapted response */ public javax.servlet.http.HttpServletResponse getJavaxResponse(HttpServletResponse jakartaResponse) { - return IJakartaAdapter.javaxify(jakartaResponse,javax.servlet.http.HttpServletResponse.class,monitor); + return JakartaAdapter.javaxify(jakartaResponse, javax.servlet.http.HttpServletResponse.class, monitor); } /** * wraps a request to a previous servlet API + * * @param jakartaRequest new servlet object * @return wrapped/adapted request */ public javax.servlet.http.HttpServletRequest getJavaxRequest(HttpServletRequest jakartaRequest) { - return IJakartaAdapter.javaxify(jakartaRequest,javax.servlet.http.HttpServletRequest.class,monitor); + return JakartaAdapter.javaxify(jakartaRequest, javax.servlet.http.HttpServletRequest.class, monitor); } /** * execute sparql based on the given request and response - * @param request jakarta request + * + * @param request jakarta request * @param response jakarta response - * @param skill skill ref - * @param graph graph ref + * @param skill skill ref + * @param graph graph ref */ public void execute(HttpServletRequest request, HttpServletResponse response, String skill, String graph) { request.getServletContext().setAttribute(Fuseki.attrVerbose, config.isSparqlVerbose()); @@ -144,26 +161,26 @@ public void execute(HttpServletRequest request, HttpServletResponse response, St AgentHttpAction action = new AgentHttpAction(++count, monitorWrapper, getJavaxRequest(request), getJavaxResponse(response), skill, graph); // Should we check whether this already has been done? the context should be quite static action.setRequest(rdfStore.getDataAccessPoint(), rdfStore.getDataService()); - ServiceExecutorRegistry.set(action.getContext(),registry); - action.getContext().set(ARQConstants.sysOptimizerFactory,optimizerFactory); - List previous=CatenaxWarning.getWarnings(action.getContext()); - CatenaxWarning.setWarnings(action.getContext(),null); + ServiceExecutorRegistry.set(action.getContext(), registry); + action.getContext().set(ARQConstants.sysOptimizerFactory, optimizerFactory); + List previous = CatenaxWarning.getWarnings(action.getContext()); + CatenaxWarning.setWarnings(action.getContext(), null); try { executeAction(action); - List newWarnings=CatenaxWarning.getWarnings(action.getContext()); - if(newWarnings!=null) { - response.addHeader("cx_warnings",objectMapper.writeValueAsString(newWarnings)); - response.addHeader("Access-Control-Expose-Headers","cx_warnings, content-length, content-type"); - if(response.getStatus()==200) { + List newWarnings = CatenaxWarning.getWarnings(action.getContext()); + if (newWarnings != null) { + response.addHeader("cx_warnings", objectMapper.writeValueAsString(newWarnings)); + response.addHeader("Access-Control-Expose-Headers", "cx_warnings, content-length, content-type"); + if (response.getStatus() == 200) { response.setStatus(203); } } - } catch(ActionErrorException e) { - throw new BadRequestException(e.getMessage(),e.getCause()); - } catch(QueryExecException | JsonProcessingException e) { - throw new InternalServerErrorException(e.getMessage(),e.getCause()); + } catch (ActionErrorException e) { + throw new BadRequestException(e.getMessage(), e.getCause()); + } catch (QueryExecException | JsonProcessingException e) { + throw new InternalServerErrorException(e.getMessage(), e.getCause()); } finally { - CatenaxWarning.setWarnings(action.getContext(),previous); + CatenaxWarning.setWarnings(action.getContext(), previous); } } @@ -171,6 +188,7 @@ public void execute(HttpServletRequest request, HttpServletResponse response, St * execute the given action. Circumvents * too strict SPARQL requirements in favor * to KA-MATCH semantics. + * * @param action a jena http action */ protected void executeAction(AgentHttpAction action) { @@ -183,75 +201,77 @@ protected void executeAction(AgentHttpAction action) { /** * execute sparql based on the given internal okhttp request and response - * @param request ok request - * @param skill skill ref - * @param graph graph ref + * + * @param request ok request + * @param skill skill ref + * @param graph graph ref * @param targetProperties a set of address properties of the asset to invoke * @return simulated ok response */ - public Response execute(Request request, String skill, String graph, Map targetProperties) { + public Response execute(Request request, String skill, String graph, Map targetProperties) { // wrap jakarta into java.servlet - HttpServletContextAdapter contextAdapter=new HttpServletContextAdapter(request); - HttpServletRequestAdapter requestAdapter=new HttpServletRequestAdapter(request,contextAdapter); - HttpServletResponseAdapter responseAdapter=new HttpServletResponseAdapter(request); + HttpServletContextAdapter contextAdapter = new HttpServletContextAdapter(request); + HttpServletRequestAdapter requestAdapter = new HttpServletRequestAdapter(request, contextAdapter); + HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter(request); contextAdapter.setAttribute(Fuseki.attrVerbose, config.isSparqlVerbose()); contextAdapter.setAttribute(Fuseki.attrOperationRegistry, operationRegistry); contextAdapter.setAttribute(Fuseki.attrNameRegistry, dataAccessPointRegistry); // build and populate a SPARQL action from the wrappers - AgentHttpAction action = new AgentHttpAction(++count, monitorWrapper, requestAdapter,responseAdapter, skill, graph); + AgentHttpAction action = new AgentHttpAction(++count, monitorWrapper, requestAdapter, responseAdapter, skill, graph); action.setRequest(rdfStore.getDataAccessPoint(), rdfStore.getDataService()); - ServiceExecutorRegistry.set(action.getContext(),registry); - action.getContext().set(DataspaceServiceExecutor.TARGET_URL_SYMBOL,request.header(DataspaceServiceExecutor.TARGET_URL_SYMBOL.getSymbol())); - action.getContext().set(DataspaceServiceExecutor.AUTH_KEY_SYMBOL,targetProperties.getOrDefault(DataspaceServiceExecutor.AUTH_KEY_SYMBOL.getSymbol(),null)); - action.getContext().set(DataspaceServiceExecutor.AUTH_CODE_SYMBOL,targetProperties.getOrDefault(DataspaceServiceExecutor.AUTH_CODE_SYMBOL.getSymbol(),null)); - action.getContext().set(ARQConstants.sysOptimizerFactory,optimizerFactory); - if(targetProperties.containsKey(DataspaceServiceExecutor.ALLOW_SYMBOL.getSymbol())) { - action.getContext().set(DataspaceServiceExecutor.ALLOW_SYMBOL,Pattern.compile(targetProperties.get(DataspaceServiceExecutor.ALLOW_SYMBOL.getSymbol()))); + ServiceExecutorRegistry.set(action.getContext(), registry); + action.getContext().set(DataspaceServiceExecutor.TARGET_URL_SYMBOL, request.header(DataspaceServiceExecutor.TARGET_URL_SYMBOL.getSymbol())); + action.getContext().set(DataspaceServiceExecutor.AUTH_KEY_SYMBOL, targetProperties.getOrDefault(DataspaceServiceExecutor.AUTH_KEY_SYMBOL.getSymbol(), null)); + action.getContext().set(DataspaceServiceExecutor.AUTH_CODE_SYMBOL, targetProperties.getOrDefault(DataspaceServiceExecutor.AUTH_CODE_SYMBOL.getSymbol(), null)); + action.getContext().set(ARQConstants.sysOptimizerFactory, optimizerFactory); + if (targetProperties.containsKey(DataspaceServiceExecutor.ALLOW_SYMBOL.getSymbol())) { + action.getContext().set(DataspaceServiceExecutor.ALLOW_SYMBOL, Pattern.compile(targetProperties.get(DataspaceServiceExecutor.ALLOW_SYMBOL.getSymbol()))); } else { - action.getContext().set(DataspaceServiceExecutor.ALLOW_SYMBOL,config.getServiceAssetAllowPattern()); + action.getContext().set(DataspaceServiceExecutor.ALLOW_SYMBOL, config.getServiceAssetAllowPattern()); } - if(targetProperties.containsKey(DataspaceServiceExecutor.DENY_SYMBOL.getSymbol())) { - action.getContext().set(DataspaceServiceExecutor.DENY_SYMBOL,Pattern.compile(targetProperties.get(DataspaceServiceExecutor.DENY_SYMBOL.getSymbol()))); + if (targetProperties.containsKey(DataspaceServiceExecutor.DENY_SYMBOL.getSymbol())) { + action.getContext().set(DataspaceServiceExecutor.DENY_SYMBOL, Pattern.compile(targetProperties.get(DataspaceServiceExecutor.DENY_SYMBOL.getSymbol()))); } else { - action.getContext().set(DataspaceServiceExecutor.DENY_SYMBOL,config.getServiceAssetDenyPattern()); + action.getContext().set(DataspaceServiceExecutor.DENY_SYMBOL, config.getServiceAssetDenyPattern()); } - if(graph!=null) { - action.getContext().set(DataspaceServiceExecutor.ASSET_SYMBOL,graph); + if (graph != null) { + action.getContext().set(DataspaceServiceExecutor.ASSET_SYMBOL, graph); } - List previous=CatenaxWarning.getWarnings(action.getContext()); - CatenaxWarning.setWarnings(action.getContext(),null); + List previous = CatenaxWarning.getWarnings(action.getContext()); + CatenaxWarning.setWarnings(action.getContext(), null); // and finally execute the SPARQL action try { executeAction(action); - List newWarnings=CatenaxWarning.getWarnings(action.getContext()); - if(newWarnings!=null) { - responseAdapter.addHeader("cx_warnings",objectMapper.writeValueAsString(newWarnings)); - responseAdapter.addHeader("Access-Control-Expose-Headers","cx_warnings, content-length, content-type"); + List newWarnings = CatenaxWarning.getWarnings(action.getContext()); + if (newWarnings != null) { + responseAdapter.addHeader("cx_warnings", objectMapper.writeValueAsString(newWarnings)); + responseAdapter.addHeader("Access-Control-Expose-Headers", "cx_warnings, content-length, content-type"); } - if(responseAdapter.getStatus()==200) { + if (responseAdapter.getStatus() == 200) { responseAdapter.setStatus(203); } - } catch(ActionErrorException e) { - responseAdapter.setStatus(HttpStatus.SC_BAD_REQUEST,e.getMessage()); - } catch(QueryExecException | JsonProcessingException | QueryExceptionHTTP e) { - responseAdapter.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR,e.getMessage()); + } catch (ActionErrorException e) { + responseAdapter.setStatus(HttpStatus.SC_BAD_REQUEST, e.getMessage()); + } catch (QueryExecException | JsonProcessingException | QueryExceptionHTTP e) { + responseAdapter.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage()); } finally { - CatenaxWarning.setWarnings(action.getContext(),previous); + CatenaxWarning.setWarnings(action.getContext(), previous); } return responseAdapter.toResponse(); } /** * execute GET-style with possibility of asset=local skill + * * @param action typically a GET request */ @Override protected void executeWithParameter(HttpAction action) { String queryString = ((AgentHttpAction) action).getSkill(); - if(queryString==null) { + if (queryString == null) { super.executeWithParameter(action); } else { execute(queryString, action); @@ -260,12 +280,13 @@ protected void executeWithParameter(HttpAction action) { /** * execute POST-style with possiblity of asset=local skill + * * @param action typically a POST request */ @Override protected void executeBody(HttpAction action) { String queryString = ((AgentHttpAction) action).getSkill(); - if(queryString==null) { + if (queryString == null) { super.executeBody(action); } else { execute(queryString, action); @@ -274,106 +295,107 @@ protected void executeBody(HttpAction action) { /** * general (URL-parameterized) query execution + * * @param queryString the resolved query - * @param action the http action containing the parameters - * TODO error handling + * @param action the http action containing the parameters + * TODO error handling */ @Override protected void execute(String queryString, HttpAction action) { // make sure the query param is decoded (which Fuseki sometimes forgets) - queryString=HttpUtils.urlDecodeParameter(queryString); + queryString = HttpUtils.urlDecodeParameter(queryString); // support for the special www-forms form - if(action.getRequestContentType() != null && action.getRequestContentType().contains("application/x-www-form-urlencoded")) { - Map> parts= AgentSourceHttpParamsDecorator.parseParams(queryString); - Optional query=parts.getOrDefault("query",List.of()).stream().findFirst(); - if(query.isEmpty()) { - action.getResponse().setStatus(HttpStatus.SC_BAD_REQUEST); - return; - } else { - queryString = HttpUtils.urlDecodeParameter(query.get()); - } + if (action.getRequestContentType() != null && action.getRequestContentType().contains("application/x-www-form-urlencoded")) { + Map> parts = AgentSourceHttpParamsDecorator.parseParams(queryString); + Optional query = parts.getOrDefault("query", List.of()).stream().findFirst(); + if (query.isEmpty()) { + action.getResponse().setStatus(HttpStatus.SC_BAD_REQUEST); + return; + } else { + queryString = HttpUtils.urlDecodeParameter(query.get()); + } } TupleSet ts = ((AgentHttpAction) action).getInputBindings(); Pattern tuplePattern = Pattern.compile("\\([^()]*\\)"); Pattern variablePattern = Pattern.compile("@(?[a-zA-Z0-9]+)"); - Matcher tupleMatcher=tuplePattern.matcher(queryString); - StringBuilder replaceQuery=new StringBuilder(); - int lastStart=0; - while(tupleMatcher.find()) { - replaceQuery.append(queryString.substring(lastStart,tupleMatcher.start())); - String otuple=tupleMatcher.group(0); - Matcher variableMatcher=variablePattern.matcher(otuple); - List variables=new java.util.ArrayList<>(); - while(variableMatcher.find()) { + Matcher tupleMatcher = tuplePattern.matcher(queryString); + StringBuilder replaceQuery = new StringBuilder(); + int lastStart = 0; + while (tupleMatcher.find()) { + replaceQuery.append(queryString.substring(lastStart, tupleMatcher.start())); + String otuple = tupleMatcher.group(0); + Matcher variableMatcher = variablePattern.matcher(otuple); + List variables = new java.util.ArrayList<>(); + while (variableMatcher.find()) { variables.add(variableMatcher.group("name")); } - if(variables.size()>0) { + if (variables.size() > 0) { try { - boolean isFirst=true; + boolean isFirst = true; Collection tuples = ts.getTuples(variables.toArray(new String[0])); - for(Tuple rtuple : tuples) { - if(isFirst) { - isFirst=false; + for (Tuple rtuple : tuples) { + if (isFirst) { + isFirst = false; } else { replaceQuery.append(" "); } - String newTuple=otuple; - for(String key : rtuple.getVariables()) { - newTuple=newTuple.replace("@"+key,rtuple.get(key)); + String newTuple = otuple; + for (String key : rtuple.getVariables()) { + newTuple = newTuple.replace("@" + key, rtuple.get(key)); } replaceQuery.append(newTuple); } - } catch (Exception e) { + } catch (Exception e) { System.err.println(e.getMessage()); action.getResponse().setStatus(HttpStatus.SC_BAD_REQUEST); return; } } else { replaceQuery.append(otuple); - } - lastStart=tupleMatcher.end(); + } + lastStart = tupleMatcher.end(); } replaceQuery.append(queryString.substring(lastStart)); - queryString=replaceQuery.toString(); - Matcher variableMatcher=variablePattern.matcher(queryString); - List variables=new java.util.ArrayList<>(); - while(variableMatcher.find()) { + queryString = replaceQuery.toString(); + Matcher variableMatcher = variablePattern.matcher(queryString); + List variables = new java.util.ArrayList<>(); + while (variableMatcher.find()) { variables.add(variableMatcher.group("name")); } try { - Collection tuples=ts.getTuples(variables.toArray(new String[0])); - if(tuples.size() == 0 && variables.size()>0) { - throw new BadRequestException(String.format("Error: Got variables %s on top-level but no bindings.",Arrays.toString(variables.toArray()))); - } else if(tuples.size()>1) { - System.err.println(String.format("Warning: Got %s tuples for top-level bindings of variables %s. Using only the first one.",tuples.size(),Arrays.toString(variables.toArray()))); + Collection tuples = ts.getTuples(variables.toArray(new String[0])); + if (tuples.size() == 0 && variables.size() > 0) { + throw new BadRequestException(String.format("Error: Got variables %s on top-level but no bindings.", Arrays.toString(variables.toArray()))); + } else if (tuples.size() > 1) { + System.err.println(String.format("Warning: Got %s tuples for top-level bindings of variables %s. Using only the first one.", tuples.size(), Arrays.toString(variables.toArray()))); } - if(tuples.size()>0) { - Tuple rtuple=tuples.iterator().next(); - for(String key : rtuple.getVariables()) { - queryString=queryString.replace("@"+key,rtuple.get(key)); + if (tuples.size() > 0) { + Tuple rtuple = tuples.iterator().next(); + for (String key : rtuple.getVariables()) { + queryString = queryString.replace("@" + key, rtuple.get(key)); } } } catch (Exception e) { - throw new BadRequestException(String.format("Error: Could not bind variables"),e); + throw new BadRequestException(String.format("Error: Could not bind variables"), e); } - if(action.getContext().isDefined(DataspaceServiceExecutor.ASSET_SYMBOL)) { - String targetUrl=action.getContext().get(DataspaceServiceExecutor.TARGET_URL_SYMBOL); - String asset=action.getContext().get(DataspaceServiceExecutor.ASSET_SYMBOL); - asset=asset.replace("?","\\?"); - String graphPattern=String.format("GRAPH\\s*\\?",UNSET_BASE,asset); - Matcher graphMatcher=Pattern.compile(graphPattern).matcher(queryString); - replaceQuery=new StringBuilder(); - lastStart=0; - while(graphMatcher.find()) { - replaceQuery.append(queryString.substring(lastStart,graphMatcher.start()-1)); - replaceQuery.append(String.format("SERVICE <%s>",targetUrl)); - lastStart=graphMatcher.end(); + if (action.getContext().isDefined(DataspaceServiceExecutor.ASSET_SYMBOL)) { + String targetUrl = action.getContext().get(DataspaceServiceExecutor.TARGET_URL_SYMBOL); + String asset = action.getContext().get(DataspaceServiceExecutor.ASSET_SYMBOL); + asset = asset.replace("?", "\\?"); + String graphPattern = String.format("GRAPH\\s*\\?", UNSET_BASE, asset); + Matcher graphMatcher = Pattern.compile(graphPattern).matcher(queryString); + replaceQuery = new StringBuilder(); + lastStart = 0; + while (graphMatcher.find()) { + replaceQuery.append(queryString.substring(lastStart, graphMatcher.start() - 1)); + replaceQuery.append(String.format("SERVICE <%s>", targetUrl)); + lastStart = graphMatcher.end(); } replaceQuery.append(queryString.substring(lastStart)); - queryString=replaceQuery.toString(); + queryString = replaceQuery.toString(); } - super.execute(queryString,action); + super.execute(queryString, action); } /** @@ -382,12 +404,12 @@ protected void execute(String queryString, HttpAction action) { @Override protected Pair decideDataset(HttpAction action, Query query, String queryStringLog) { // These will have been taken care of by the "getDatasetDescription" - if ( query.hasDatasetDescription() ) { + if (query.hasDatasetDescription()) { // Don't modify input. query = query.cloneQuery(); query.getNamedGraphURIs().clear(); query.getGraphURIs().clear(); } return Pair.create(rdfStore.getDataSet(), query); - } + } } diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQuerySerializer.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQuerySerializer.java index bc3b4e3..c186268 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQuerySerializer.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQuerySerializer.java @@ -26,7 +26,10 @@ import org.apache.jena.sparql.core.VarExprList; import org.apache.jena.sparql.engine.binding.Binding; import org.apache.jena.sparql.expr.Expr; -import org.apache.jena.sparql.serializer.*; +import org.apache.jena.sparql.serializer.FmtExprSPARQL; +import org.apache.jena.sparql.serializer.FormatterTemplate; +import org.apache.jena.sparql.serializer.PrologueSerializer; +import org.apache.jena.sparql.serializer.SerializationContext; import org.apache.jena.sparql.syntax.Element; import org.apache.jena.sparql.syntax.Template; import org.apache.jena.sparql.util.FmtUtils; @@ -49,8 +52,8 @@ public class SparqlQuerySerializer implements QueryVisitor { protected IndentedWriter out; protected Prologue prologue; - public SparqlQuerySerializer(OutputStream _out, StratifiedFormatterElement formatterElement, FmtExprSPARQL formatterExpr, FormatterTemplate formatterTemplate) { - this(new IndentedWriter(_out), formatterElement, formatterExpr, formatterTemplate); + public SparqlQuerySerializer(OutputStream outStream, StratifiedFormatterElement formatterElement, FmtExprSPARQL formatterExpr, FormatterTemplate formatterTemplate) { + this(new IndentedWriter(outStream), formatterElement, formatterExpr, formatterTemplate); } public SparqlQuerySerializer(IndentedWriter iwriter, StratifiedFormatterElement formatterElement, FmtExprSPARQL formatterExpr, FormatterTemplate formatterTemplate) { @@ -122,7 +125,7 @@ public void visitDescribeResultForm(Query query) { this.out.print(" "); } - appendURIList(query, this.out, query.getResultURIs()); + appendUriList(query, this.out, query.getResultURIs()); } this.out.newline(); @@ -170,7 +173,7 @@ public void visitDatasetDecl(Query query) { if (query.getGraphURIs() != null && query.getGraphURIs().size() != 0) { var2 = query.getGraphURIs().iterator(); - while(var2.hasNext()) { + while (var2.hasNext()) { uri = var2.next(); this.out.print("FROM "); this.out.print(FmtUtils.stringForURI(uri, query)); @@ -181,7 +184,7 @@ public void visitDatasetDecl(Query query) { if (query.getNamedGraphURIs() != null && query.getNamedGraphURIs().size() != 0) { var2 = query.getNamedGraphURIs().iterator(); - while(var2.hasNext()) { + while (var2.hasNext()) { uri = var2.next(); this.out.print("FROM NAMED "); this.out.print(FmtUtils.stringForURI(uri, query)); @@ -236,7 +239,7 @@ public void visitOrderBy(Query query) { this.out.print("ORDER BY "); boolean first = true; - for(Iterator var3 = query.getOrderBy().iterator(); var3.hasNext(); first = false) { + for (Iterator var3 = query.getOrderBy().iterator(); var3.hasNext(); first = false) { SortCondition sc = var3.next(); if (!first) { this.out.print(" "); @@ -341,7 +344,7 @@ public void finishVisit(Query query) { void appendVarList(IndentedWriter sb, List vars) { boolean first = true; - for(Iterator var5 = vars.iterator(); var5.hasNext(); first = false) { + for (Iterator var5 = vars.iterator(); var5.hasNext(); first = false) { String varName = var5.next(); Var var = Var.alloc(varName); if (!first) { @@ -356,7 +359,7 @@ void appendVarList(IndentedWriter sb, List vars) { void appendNamedExprList(IndentedWriter sb, VarExprList namedExprs) { boolean first = true; - for(Iterator var5 = namedExprs.getVars().iterator(); var5.hasNext(); first = false) { + for (Iterator var5 = namedExprs.getVars().iterator(); var5.hasNext(); first = false) { Var var = var5.next(); Expr expr = namedExprs.getExpr(var); if (!first) { @@ -395,11 +398,11 @@ void appendNamedExprList(IndentedWriter sb, VarExprList namedExprs) { } - static void appendURIList(Query query, IndentedWriter sb, List vars) { + static void appendUriList(Query query, IndentedWriter sb, List vars) { SerializationContext cxt = new SerializationContext(query); boolean first = true; - for(Iterator var5 = vars.iterator(); var5.hasNext(); first = false) { + for (Iterator var5 = vars.iterator(); var5.hasNext(); first = false) { Node node = var5.next(); if (!first) { sb.print(" "); diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQuerySerializerFactory.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQuerySerializerFactory.java index 74d15f9..cce891d 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQuerySerializerFactory.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQuerySerializerFactory.java @@ -20,7 +20,10 @@ import org.apache.jena.query.QueryVisitor; import org.apache.jena.query.Syntax; import org.apache.jena.sparql.core.Prologue; -import org.apache.jena.sparql.serializer.*; +import org.apache.jena.sparql.serializer.FmtExprSPARQL; +import org.apache.jena.sparql.serializer.FmtTemplate; +import org.apache.jena.sparql.serializer.QuerySerializerFactory; +import org.apache.jena.sparql.serializer.SerializationContext; import org.apache.jena.sparql.util.NodeToLabelMapBNode; /** diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/StratifiedFormatterElement.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/StratifiedFormatterElement.java index 62dd3b8..2c718c2 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/StratifiedFormatterElement.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/StratifiedFormatterElement.java @@ -19,7 +19,10 @@ import org.apache.jena.atlas.io.IndentedWriter; import org.apache.jena.sparql.serializer.FormatterElement; import org.apache.jena.sparql.serializer.SerializationContext; -import org.apache.jena.sparql.syntax.*; +import org.apache.jena.sparql.syntax.Element; +import org.apache.jena.sparql.syntax.ElementGroup; +import org.apache.jena.sparql.syntax.ElementPathBlock; +import org.apache.jena.sparql.syntax.ElementTriplesBlock; import java.util.Iterator; import java.util.Stack; @@ -47,6 +50,7 @@ public StratifiedFormatterElement(IndentedWriter out, SerializationContext conte /** * visit a join, only produce parenthesis if we are on the top level + * * @param el group element */ @@ -100,6 +104,8 @@ public void visit(ElementGroup el) { /** + * check whether two elements need a separator + * * @param el1 first element * @param el2 second element * @return decide whether a dot is required between el1 and el2 diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/VariableDetector.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/VariableDetector.java index 354223f..19fdcfd 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/VariableDetector.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/VariableDetector.java @@ -24,7 +24,6 @@ import java.util.HashMap; import java.util.List; import java.util.Set; -import java.util.stream.Collectors; /** * a pseudo transform which visits every graph node @@ -34,23 +33,23 @@ */ public class VariableDetector implements NodeTransform { - HashMap variables=new HashMap<>(); + HashMap variables = new HashMap<>(); Set allowed; public VariableDetector(Set allowed) { - this.allowed=allowed; + this.allowed = allowed; } @Override public Node apply(Node node) { - if(node.isVariable()) { - Var var = (Var)node; - String varName= var.getVarName(); - while(Var.isRenamedVar(varName)) { - varName=varName.substring(1); - var=Var.alloc(varName); + if (node.isVariable()) { + Var var = (Var) node; + String varName = var.getVarName(); + while (Var.isRenamedVar(varName)) { + varName = varName.substring(1); + var = Var.alloc(varName); } - if(allowed.contains(varName) && !variables.containsKey(varName)) { + if (allowed.contains(varName) && !variables.containsKey(varName)) { variables.put(varName, var); } return var; diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/validation/SwitchingDataPlaneTokenValidatorController.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/validation/SwitchingDataPlaneTokenValidatorController.java index c9e9826..f5e4db7 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/validation/SwitchingDataPlaneTokenValidatorController.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/validation/SwitchingDataPlaneTokenValidatorController.java @@ -16,7 +16,6 @@ // SPDX-License-Identifier: Apache-2.0 package org.eclipse.tractusx.agents.edc.validation; -import org.eclipse.tractusx.agents.edc.AgentConfig; import jakarta.ws.rs.GET; import jakarta.ws.rs.HeaderParam; import jakarta.ws.rs.Path; @@ -27,6 +26,7 @@ import okhttp3.OkHttpClient; import okhttp3.Request; import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.tractusx.agents.edc.AgentConfig; import java.io.IOException; @@ -43,22 +43,25 @@ public class SwitchingDataPlaneTokenValidatorController implements DataPlaneToke /** * creates a new controller + * * @param httpClient to use - * @param config to obey - * @param monitor to log + * @param config to obey + * @param monitor to log */ public SwitchingDataPlaneTokenValidatorController(OkHttpClient httpClient, AgentConfig config, Monitor monitor) { - this.httpClient=httpClient; - this.config=config; - this.monitor=monitor; - this.endpoints=config.getValidatorEndpoints(); + this.httpClient = httpClient; + this.config = config; + this.monitor = monitor; + this.endpoints = config.getValidatorEndpoints(); } /** + * access + * * @return a flag indicating whether this endpoint is enabled */ public boolean isEnabled() { - return endpoints!=null && endpoints.length>0; + return endpoints != null && endpoints.length > 0; } /** @@ -71,8 +74,8 @@ public boolean isEnabled() { @Produces({ MediaType.APPLICATION_JSON }) @Override public Response validate(@HeaderParam(HttpHeaders.AUTHORIZATION) String token) { - Response result=Response.status(400,"No validation endpoint could be found to switch to.").build(); - if(isEnabled()) { + Response result = Response.status(400, "No validation endpoint could be found to switch to.").build(); + if (isEnabled()) { for (String endpoint : endpoints) { var request = new Request.Builder().url(endpoint).header(HttpHeaders.AUTHORIZATION, token).get().build(); try (var response = httpClient.newCall(request).execute()) { diff --git a/agent-plane/agent-plane-protocol/src/test/java/org/eclipse/tractusx/agents/edc/MockAgreementController.java b/agent-plane/agent-plane-protocol/src/test/java/org/eclipse/tractusx/agents/edc/MockAgreementController.java index e539cbf..13191e1 100644 --- a/agent-plane/agent-plane-protocol/src/test/java/org/eclipse/tractusx/agents/edc/MockAgreementController.java +++ b/agent-plane/agent-plane-protocol/src/test/java/org/eclipse/tractusx/agents/edc/MockAgreementController.java @@ -24,7 +24,7 @@ * It will "fake" an agreement endpoint that will finally * hit the given path/port on localhost */ -public class MockAgreementController implements IAgreementController { +public class MockAgreementController implements AgreementController { String path; int port; diff --git a/agent-plane/agent-plane-protocol/src/test/java/org/eclipse/tractusx/agents/edc/TestConfig.java b/agent-plane/agent-plane-protocol/src/test/java/org/eclipse/tractusx/agents/edc/TestConfig.java index 4e014ed..7ba1be1 100644 --- a/agent-plane/agent-plane-protocol/src/test/java/org/eclipse/tractusx/agents/edc/TestConfig.java +++ b/agent-plane/agent-plane-protocol/src/test/java/org/eclipse/tractusx/agents/edc/TestConfig.java @@ -25,7 +25,7 @@ public class TestConfig extends ConfigImpl { public TestConfig() { - super("edc", Map.of("edc.cx.agent.controlplane.ids","test-tenant")); + super("", Map.of("edc.cx.agent.controlplane.ids","test-tenant","cx.agent.service.asset.allow","(http|edc)s?://.*")); } } diff --git a/agent-plane/agent-plane-protocol/src/test/java/org/eclipse/tractusx/agents/edc/http/TestAgentController.java b/agent-plane/agent-plane-protocol/src/test/java/org/eclipse/tractusx/agents/edc/http/TestAgentController.java index acbff97..6b52444 100644 --- a/agent-plane/agent-plane-protocol/src/test/java/org/eclipse/tractusx/agents/edc/http/TestAgentController.java +++ b/agent-plane/agent-plane-protocol/src/test/java/org/eclipse/tractusx/agents/edc/http/TestAgentController.java @@ -20,7 +20,7 @@ import jakarta.ws.rs.core.MultivaluedHashMap; import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.core.UriInfo; -import org.eclipse.tractusx.agents.edc.rdf.RDFStore; +import org.eclipse.tractusx.agents.edc.rdf.RdfStore; import org.eclipse.tractusx.agents.edc.service.InMemorySkillStore; import org.eclipse.tractusx.agents.edc.sparql.DataspaceServiceExecutor; import org.eclipse.tractusx.agents.edc.sparql.SparqlQueryProcessor; @@ -71,17 +71,17 @@ public class TestAgentController extends RestControllerTestBase { AgentConfig agentConfig=new AgentConfig(monitor,config); ServiceExecutorRegistry serviceExecutorReg=new ServiceExecutorRegistry(); OkHttpClient client=new OkHttpClient(); - IAgreementController mockController = new MockAgreementController("test",port); + AgreementController mockController = new MockAgreementController("test",port); ExecutorService threadedExecutor= Executors.newSingleThreadExecutor(); TypeManager typeManager = new TypeManager(); DataspaceServiceExecutor exec=new DataspaceServiceExecutor(monitor,mockController,agentConfig,client,threadedExecutor,typeManager); - RDFStore store = new RDFStore(agentConfig,monitor); + RdfStore store = new RdfStore(agentConfig,monitor); SparqlQueryProcessor processor=new SparqlQueryProcessor(serviceExecutorReg,monitor,agentConfig,store, typeManager); InMemorySkillStore skillStore=new InMemorySkillStore(); - DelegationService delegationService=new DelegationService(mockController,monitor,client,typeManager,agentConfig); + DelegationServiceImpl delegationService=new DelegationServiceImpl(mockController,monitor,client,typeManager,agentConfig); AgentController agentController=new AgentController(monitor,mockController,agentConfig,processor,skillStore,delegationService); AutoCloseable mocks=null; @@ -397,14 +397,14 @@ public void testParameterizedSkill() throws IOException { @Test @Tag("online") public void testRemotingSkill() throws IOException { - String query="PREFIX xsd: SELECT ?what WHERE { SERVICE { VALUES (?what) { (\"@input\"^^xsd:int)} } }"; + String query="PREFIX xsd: SELECT ?subject WHERE { SERVICE { VALUES (?subject) { (<@input>)} } }"; String asset="urn:cx:Skill:cx:Test"; try(var response=agentController.postSkill(query,asset,null,null,null,null,SkillDistribution.ALL,false,null)) { assertEquals(200,response.getStatus(),"post skill successful"); - String result = testExecute("GET", null, asset, "*/*", List.of(new AbstractMap.SimpleEntry<>("input", "84"))); + String result = testExecute("GET", null, asset, "*/*", List.of(new AbstractMap.SimpleEntry<>("input", "urn:cx:AnonymousSerializedPart#GB4711"))); JsonNode root = mapper.readTree(result); - JsonNode whatBinding0 = root.get("results").get("bindings").get(0).get("what"); - assertEquals("84", whatBinding0.get("value").asText(), "Correct binding"); + JsonNode whatBinding0 = root.get("results").get("bindings").get(0).get("subject"); + assertEquals("urn:cx:AnonymousSerializedPart#GB4711", whatBinding0.get("value").asText(), "Correct binding"); } } diff --git a/agent-plane/agent-plane-protocol/src/test/java/org/eclipse/tractusx/agents/edc/service/TestDataspaceSynchronizer.java b/agent-plane/agent-plane-protocol/src/test/java/org/eclipse/tractusx/agents/edc/service/TestDataspaceSynchronizer.java index 2e07b69..dc4ca08 100644 --- a/agent-plane/agent-plane-protocol/src/test/java/org/eclipse/tractusx/agents/edc/service/TestDataspaceSynchronizer.java +++ b/agent-plane/agent-plane-protocol/src/test/java/org/eclipse/tractusx/agents/edc/service/TestDataspaceSynchronizer.java @@ -22,7 +22,7 @@ import org.eclipse.tractusx.agents.edc.jsonld.JsonLd; import org.eclipse.tractusx.agents.edc.model.DcatCatalog; import org.eclipse.tractusx.agents.edc.model.DcatDataset; -import org.eclipse.tractusx.agents.edc.rdf.RDFStore; +import org.eclipse.tractusx.agents.edc.rdf.RdfStore; import okhttp3.*; import org.apache.jena.graph.Node; import org.apache.jena.sparql.core.Quad; @@ -55,7 +55,7 @@ public class TestDataspaceSynchronizer { AgentConfig agentConfig = new AgentConfig(monitor, config); OkHttpClient client = new OkHttpClient(); ScheduledExecutorService threadedExecutor = Executors.newSingleThreadScheduledExecutor(); - RDFStore store = new RDFStore(agentConfig, monitor); + RdfStore store = new RdfStore(agentConfig, monitor); TypeManager typeManager = new TypeManager(); diff --git a/agent-plane/agent-plane-protocol/src/test/java/org/eclipse/tractusx/agents/edc/sparql/TestSparqlProcessor.java b/agent-plane/agent-plane-protocol/src/test/java/org/eclipse/tractusx/agents/edc/sparql/TestSparqlProcessor.java index 423ea12..8ce99d0 100644 --- a/agent-plane/agent-plane-protocol/src/test/java/org/eclipse/tractusx/agents/edc/sparql/TestSparqlProcessor.java +++ b/agent-plane/agent-plane-protocol/src/test/java/org/eclipse/tractusx/agents/edc/sparql/TestSparqlProcessor.java @@ -23,7 +23,7 @@ import org.eclipse.edc.spi.monitor.ConsoleMonitor; import org.eclipse.edc.spi.types.TypeManager; import org.eclipse.tractusx.agents.edc.*; -import org.eclipse.tractusx.agents.edc.rdf.RDFStore; +import org.eclipse.tractusx.agents.edc.rdf.RdfStore; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Tag; @@ -48,11 +48,11 @@ public class TestSparqlProcessor { AgentConfig agentConfig=new AgentConfig(monitor,config); ServiceExecutorRegistry serviceExecutorReg=new ServiceExecutorRegistry(); OkHttpClient client=new OkHttpClient(); - IAgreementController mockController = new MockAgreementController(); + AgreementController mockController = new MockAgreementController(); ExecutorService threadedExecutor= Executors.newSingleThreadExecutor(); TypeManager typeManager = new TypeManager(); DataspaceServiceExecutor exec=new DataspaceServiceExecutor(monitor,mockController,agentConfig,client,threadedExecutor,typeManager); - RDFStore store = new RDFStore(agentConfig,monitor); + RdfStore store = new RdfStore(agentConfig,monitor); SparqlQueryProcessor processor=new SparqlQueryProcessor(serviceExecutorReg,monitor,agentConfig,store, typeManager); @@ -84,16 +84,16 @@ public void tearDown() throws Exception { @Test @Tag("online") public void testFederatedGraph() throws IOException { - String query="PREFIX xsd: SELECT ?what WHERE { SERVICE { " + - "GRAPH { VALUES (?what) { (\"42\"^^xsd:int)} } } }"; + String query="PREFIX xsd: SELECT ?what WHERE { SERVICE { " + + "GRAPH { VALUES (?subject) { ()} } } }"; Request.Builder builder=new Request.Builder(); builder.url("http://localhost:8080"); builder.addHeader("Accept","application/json"); builder.put(RequestBody.create(query, MediaType.parse("application/sparql-query"))); try (Response response=processor.execute(builder.build(),null,null,Map.of())) { JsonNode root = mapper.readTree(Objects.requireNonNull(response.body()).string()); - JsonNode whatBinding0 = root.get("results").get("bindings").get(0).get("what"); - assertEquals("42", whatBinding0.get("value").asText(), "Correct binding"); + JsonNode whatBinding0 = root.get("results").get("bindings").get(0).get("subject"); + assertEquals("urn:cx:AnonymousSerializedPart#GB4711", whatBinding0.get("value").asText(), "Correct binding"); } } @@ -104,8 +104,8 @@ public void testFederatedGraph() throws IOException { @Test @Tag("online") public void testFederatedServiceChain() throws IOException { - String query="PREFIX xsd: SELECT ?what WHERE { VALUES (?chain1) { ()} SERVICE ?chain1 { " + - "VALUES (?chain2) { ()} SERVICE ?chain2 { VALUES (?what) { (\"42\"^^xsd:int)} } } }"; + String query="PREFIX xsd: SELECT ?subject WHERE { VALUES (?chain1) { ()} SERVICE ?chain1 { " + + "VALUES (?chain2) { ()} SERVICE ?chain2 { VALUES (?subject) { ()} } } }"; Request.Builder builder=new Request.Builder(); builder.url("http://localhost:8080"); builder.addHeader("Accept","application/sparql-results+json"); @@ -113,8 +113,8 @@ public void testFederatedServiceChain() throws IOException { try(Response response=processor.execute(builder.build(),null,null,Map.of())) { assertTrue(response.isSuccessful(), "Response was successful"); JsonNode root = mapper.readTree(Objects.requireNonNull(response.body()).string()); - JsonNode whatBinding0 = root.get("results").get("bindings").get(0).get("what"); - assertEquals("84", whatBinding0.get("value").asText(), "Correct binding"); + JsonNode whatBinding0 = root.get("results").get("bindings").get(0).get("subject"); + assertEquals("urn:cx:AnonymousSerializedPart#GB4711", whatBinding0.get("value").asText(), "Correct binding"); } } @@ -168,7 +168,7 @@ public void testRemoteWarning() throws IOException { @Test @Tag("online") public void testRemoteTransfer() throws IOException { - String query="PREFIX xsd: SELECT ?what WHERE { SERVICE { VALUES (?what) { (\"42\"^^xsd:int) } } }"; + String query="PREFIX xsd: SELECT ?what WHERE { SERVICE { VALUES (?what) { (\"42\"^^xsd:int) } } }"; Request.Builder builder=new Request.Builder(); builder.url("http://localhost:8080"); builder.addHeader("Accept","application/sparql-results+json"); diff --git a/agent-plane/agentplane-azure-vault/pom.xml b/agent-plane/agentplane-azure-vault/pom.xml index ed369ed..edef553 100644 --- a/agent-plane/agentplane-azure-vault/pom.xml +++ b/agent-plane/agentplane-azure-vault/pom.xml @@ -20,7 +20,7 @@ - org.eclipse.tractusx.agents.edc @@ -36,7 +36,9 @@ jar Tractus-X Knowledge Agents EDC Dataplane (Az-Vault) - Builds a Containerized Agent Dataplane with Agent/Triple Extensions And Accessing the Azure Vault to Store Intermediate Secrets. + Builds a Containerized Agent Dataplane with Agent/Triple Extensions And Accessing the Azure Vault to + Store Intermediate Secrets. + http://catena-x.net/ @@ -104,10 +106,14 @@ - + org.apache.maven.plugins maven-surefire-plugin + + org.apache.maven.plugins + maven-checkstyle-plugin + - org.junit.jupiter - junit-jupiter-engine - test - + org.junit.jupiter + junit-jupiter-engine + test + - org.mockito - mockito-core - test - + org.mockito + mockito-core + test + net.bytebuddy byte-buddy - - + + diff --git a/agent-plane/agentplane-hashicorp/pom.xml b/agent-plane/agentplane-hashicorp/pom.xml index 77b8390..a83067f 100644 --- a/agent-plane/agentplane-hashicorp/pom.xml +++ b/agent-plane/agentplane-hashicorp/pom.xml @@ -20,7 +20,7 @@ - org.eclipse.tractusx.agents.edc @@ -36,7 +36,9 @@ jar Tractus-X Knowledge Agents EDC Dataplane (Hashicorp) - Builds a Containerized Agent Dataplane with Agent/Triple Extensions And Accessing the Hashicorp Vault to Store Intermediate Secrets. + Builds a Containerized Agent Dataplane with Agent/Triple Extensions And Accessing the Hashicorp Vault + to Store Intermediate Secrets. + http://catena-x.net/ @@ -104,10 +106,14 @@ - + org.apache.maven.plugins maven-surefire-plugin + + org.apache.maven.plugins + maven-checkstyle-plugin + - org.junit.jupiter - junit-jupiter-engine - test - + org.junit.jupiter + junit-jupiter-engine + test + - org.mockito - mockito-core - test - - - net.bytebuddy - byte-buddy - - - + org.mockito + mockito-core + test + + + net.bytebuddy + byte-buddy + + + diff --git a/agent-plane/pom.xml b/agent-plane/pom.xml index ed8b355..09658c5 100644 --- a/agent-plane/pom.xml +++ b/agent-plane/pom.xml @@ -29,7 +29,7 @@ org.eclipse.tractusx.agents edc 1.10.2-SNAPSHOT - ../pom.xml + ../pom.xml Tractus-X EDC Agent Plane Artifacts for Agent-Enabled Data Planes diff --git a/common/auth-jwt/pom.xml b/common/auth-jwt/pom.xml index 9189529..a97b05e 100644 --- a/common/auth-jwt/pom.xml +++ b/common/auth-jwt/pom.xml @@ -22,7 +22,7 @@ - org.eclipse.tractusx.agents @@ -38,7 +38,8 @@ jar Tractus-X JWT-Based Auth - EDC Extension for authenticating against JWT-based Identity Providers (Oauth2/Open ID Connect). + EDC Extension for authenticating against JWT-based Identity Providers (Oauth2/Open ID Connect). + http://catena-x.net/ @@ -68,13 +69,13 @@ - + org.apache.maven.plugins maven-surefire-plugin - com.diffplug.spotless - spotless-maven-plugin + org.apache.maven.plugins + maven-checkstyle-plugin - org.junit.jupiter - junit-jupiter-engine - test - + org.junit.jupiter + junit-jupiter-engine + test + - org.mockito - mockito-core - test - + org.mockito + mockito-core + test + \ No newline at end of file diff --git a/common/auth-jwt/src/main/java/org/eclipse/tractusx/edc/auth/ApiKeyAuthenticationService.java b/common/auth-jwt/src/main/java/org/eclipse/tractusx/edc/auth/ApiKeyAuthenticationService.java index 9e9ea0f..bc8f230 100644 --- a/common/auth-jwt/src/main/java/org/eclipse/tractusx/edc/auth/ApiKeyAuthenticationService.java +++ b/common/auth-jwt/src/main/java/org/eclipse/tractusx/edc/auth/ApiKeyAuthenticationService.java @@ -27,19 +27,19 @@ * in clear text in memory */ public class ApiKeyAuthenticationService implements AuthenticationService { - public static String AUTHENTICATION_HEADER="x-api-key"; - final protected int reference; + public static final String AUTHENTICATIONHEADER = "x-api-key"; + protected final int reference; public ApiKeyAuthenticationService(int reference) { - this.reference=reference; + this.reference = reference; } @Override public boolean isAuthenticated(Map> map) { return map.entrySet().stream() - .filter( e->e.getKey().equalsIgnoreCase(AUTHENTICATION_HEADER)) - .flatMap( e->e.getValue().stream().map( v -> reference==v.hashCode())) - .anyMatch(b->b); + .filter(e -> e.getKey().equalsIgnoreCase(AUTHENTICATIONHEADER)) + .flatMap(e -> e.getValue().stream().map(v -> reference == v.hashCode())) + .anyMatch(b -> b); } /** @@ -52,7 +52,7 @@ public Builder() { } public Builder setReference(int reference) { - this.reference=reference; + this.reference = reference; return this; } diff --git a/common/auth-jwt/src/main/java/org/eclipse/tractusx/edc/auth/AuthenticationExtension.java b/common/auth-jwt/src/main/java/org/eclipse/tractusx/edc/auth/AuthenticationExtension.java index d41211b..aa44d04 100644 --- a/common/auth-jwt/src/main/java/org/eclipse/tractusx/edc/auth/AuthenticationExtension.java +++ b/common/auth-jwt/src/main/java/org/eclipse/tractusx/edc/auth/AuthenticationExtension.java @@ -40,56 +40,56 @@ public class AuthenticationExtension implements ServiceExtension { @Setting( value = "Defines a set/list of authentication services." ) - public static String AUTH_SETTING="tractusx.auth"; + public static final String AUTHSETTING = "tractusx.auth"; @Setting( value = "Whether the auth service should be registered.", defaultValue = "false", - type="boolean" + type = "boolean" ) - public static String REGISTER_SETTING="register"; + public static final String REGISTERSETTING = "register"; @Setting( value = "The type of authentication service to use. Maybe jwt or composite" ) - public static String TYPE_SETTING="type"; + public static final String TYPESETTING = "type"; @Setting( value = "On which paths should the corresponding filter be installed." ) - public static String PATH_SETTING="paths"; + public static final String PATHSETTING = "paths"; @Setting( value = "The BASE64 encoded public key or a url where to obtain it." ) - public static String KEY_SETTING="publickey"; + public static final String KEYSETTING = "publickey"; @Setting( value = "URL indicating where to get the public key for verifying the token.", defaultValue = "true", - type="boolean" + type = "boolean" ) - public static String EXPIRE_SETTING="checkexpiry"; + public static final String EXPIRESETTING = "checkexpiry"; @Setting( value = "embedded authentication services." ) - public static String SERVICE_SETTING="service"; + public static final String SERVICESETTING = "service"; @Setting( value = "api key in vault." ) - public static String VAULT_SETTING="vault-key"; + public static final String VAULTSETTING = "vault-key"; @Setting( value = "api key hashcode." ) - public static String API_CODE_SETTING="api-code"; + public static final String APICODESETTING = "api-code"; @Setting( value = "composite mode." ) - public static String MODE_SETTING="mode"; + public static final String MODESETTING = "mode"; /** * dependency injection part @@ -104,45 +104,45 @@ public class AuthenticationExtension implements ServiceExtension { @Override public void initialize(ServiceExtensionContext ctx) { - ctx.getConfig(AUTH_SETTING).partition().forEach( authenticationServiceConfig -> - createAuthenticationService(ctx,authenticationServiceConfig)); + ctx.getConfig(AUTHSETTING).partition().forEach(authenticationServiceConfig -> + createAuthenticationService(ctx, authenticationServiceConfig)); } public AuthenticationService createAuthenticationService(ServiceExtensionContext ctx, Config authenticationServiceConfig) { - String type=authenticationServiceConfig.getString(TYPE_SETTING); - AuthenticationService newService=null; - if("jwt".equals(type)) { - CompositeJwsVerifier.Builder jwsVerifierBuilder = new CompositeJwsVerifier.Builder(typeManager.getMapper()); - String key = authenticationServiceConfig.getString(KEY_SETTING); + String type = authenticationServiceConfig.getString(TYPESETTING); + AuthenticationService newService = null; + if ("jwt".equals(type)) { + CompositeJwsVerifier.Builder jwsVerifierBuilder = new CompositeJwsVerifier.Builder(typeManager.getMapper(), ctx.getMonitor()); + String key = authenticationServiceConfig.getString(KEYSETTING); if (key != null) { jwsVerifierBuilder.addKey(key); } - newService = new JwtAuthenticationService.Builder(). - setVerifier(jwsVerifierBuilder.build()). - setCheckExpiry(authenticationServiceConfig.getBoolean(EXPIRE_SETTING, true)). - build(); - } else if("api-key".equals(type)) { + newService = new JwtAuthenticationService.Builder() + .setVerifier(jwsVerifierBuilder.build()) + .setCheckExpiry(authenticationServiceConfig.getBoolean(EXPIRESETTING, true)) + .build(); + } else if ("api-key".equals(type)) { int reference; - if(authenticationServiceConfig.hasKey(VAULT_SETTING)) { - reference=vault.resolveSecret(authenticationServiceConfig.getString(VAULT_SETTING)).hashCode(); + if (authenticationServiceConfig.hasKey(VAULTSETTING)) { + reference = vault.resolveSecret(authenticationServiceConfig.getString(VAULTSETTING)).hashCode(); } else { - reference=authenticationServiceConfig.getInteger(API_CODE_SETTING); + reference = authenticationServiceConfig.getInteger(APICODESETTING); } newService = new ApiKeyAuthenticationService.Builder().setReference(reference).build(); - } else if("composite".equals(type)) { - CompositeAuthenticationService.Builder builder=new CompositeAuthenticationService.Builder(); - builder.setMode(Enum.valueOf(CompositeAuthenticationMode.class,authenticationServiceConfig.getString(MODE_SETTING,CompositeAuthenticationMode.ALL.name()))); - authenticationServiceConfig.getConfig(SERVICE_SETTING).partition().forEach( subServiceConfig -> + } else if ("composite".equals(type)) { + CompositeAuthenticationService.Builder builder = new CompositeAuthenticationService.Builder(); + builder.setMode(Enum.valueOf(CompositeAuthenticationMode.class, authenticationServiceConfig.getString(MODESETTING, CompositeAuthenticationMode.ALL.name()))); + authenticationServiceConfig.getConfig(SERVICESETTING).partition().forEach(subServiceConfig -> builder.addService(createAuthenticationService(ctx, subServiceConfig)) ); - newService=builder.build(); + newService = builder.build(); } - if(newService!=null) { - String[] paths = authenticationServiceConfig.getString(PATH_SETTING, "").split(","); + if (newService != null) { + String[] paths = authenticationServiceConfig.getString(PATHSETTING, "").split(","); for (String path : paths) { webService.registerResource(path, new AuthenticationRequestFilter(newService)); } - if (authenticationServiceConfig.getBoolean(REGISTER_SETTING, false)) { + if (authenticationServiceConfig.getBoolean(REGISTERSETTING, false)) { ctx.registerService(AuthenticationService.class, newService); } } diff --git a/common/auth-jwt/src/main/java/org/eclipse/tractusx/edc/auth/CompositeAuthenticationService.java b/common/auth-jwt/src/main/java/org/eclipse/tractusx/edc/auth/CompositeAuthenticationService.java index b88feb9..5e9d231 100644 --- a/common/auth-jwt/src/main/java/org/eclipse/tractusx/edc/auth/CompositeAuthenticationService.java +++ b/common/auth-jwt/src/main/java/org/eclipse/tractusx/edc/auth/CompositeAuthenticationService.java @@ -29,13 +29,13 @@ public class CompositeAuthenticationService implements AuthenticationService { protected final CompositeAuthenticationMode mode; public CompositeAuthenticationService(CompositeAuthenticationMode mode, Collection subServices) { - this.mode=mode; - this.subServices=subServices; + this.mode = mode; + this.subServices = subServices; } @Override public boolean isAuthenticated(Map> map) { - switch(mode) { + switch (mode) { case ONE: return subServices.stream().anyMatch(service -> service.isAuthenticated(map)); case ALL: @@ -45,10 +45,11 @@ public boolean isAuthenticated(Map> map) { } public static class Builder { - Collection subServices=new ArrayList<>(); - CompositeAuthenticationMode mode=CompositeAuthenticationMode.ALL; + Collection subServices = new ArrayList<>(); + CompositeAuthenticationMode mode = CompositeAuthenticationMode.ALL; - public Builder() {} + public Builder() { + } public Builder addService(AuthenticationService subService) { subServices.add(subService); @@ -56,13 +57,13 @@ public Builder addService(AuthenticationService subService) { } public Builder setMode(CompositeAuthenticationMode mode) { - this.mode=mode; + this.mode = mode; return this; } public CompositeAuthenticationService build() { - return new CompositeAuthenticationService(mode,subServices); + return new CompositeAuthenticationService(mode, subServices); } } diff --git a/common/auth-jwt/src/main/java/org/eclipse/tractusx/edc/auth/CompositeJwsVerifier.java b/common/auth-jwt/src/main/java/org/eclipse/tractusx/edc/auth/CompositeJwsVerifier.java index 870370e..d9a55b5 100644 --- a/common/auth-jwt/src/main/java/org/eclipse/tractusx/edc/auth/CompositeJwsVerifier.java +++ b/common/auth-jwt/src/main/java/org/eclipse/tractusx/edc/auth/CompositeJwsVerifier.java @@ -27,10 +27,10 @@ import com.nimbusds.jose.crypto.RSASSAVerifier; import com.nimbusds.jose.jca.JCAContext; import com.nimbusds.jose.jwk.ECKey; -import com.nimbusds.jose.jwk.OctetSequenceKey; import com.nimbusds.jose.jwk.RSAKey; import com.nimbusds.jose.util.Base64URL; import com.nimbusds.jose.util.IOUtils; +import org.eclipse.edc.spi.monitor.Monitor; import java.io.IOException; import java.io.InputStream; @@ -48,7 +48,7 @@ */ public class CompositeJwsVerifier implements JWSVerifier { - final protected Map verifierMap=new HashMap<>(); + protected final Map verifierMap = new HashMap<>(); /** * create a new verifier @@ -58,22 +58,24 @@ public CompositeJwsVerifier() { /** * implement token verification by delegating to another jws verifier depending on the used algorithm - * @param jwsHeader The JSON Web Signature (JWS) header. Must - * specify a supported JWS algorithm and must not - * be {@code null}. - * @param bytes The signing input. Must not be {@code null}. - * @param base64URL The signature part of the JWS object. Must not - * be {@code null}. * + * @param jwsHeader The JSON Web Signature (JWS) header. Must + * specify a supported JWS algorithm and must not + * be {@code null}. + * @param bytes The signing input. Must not be {@code null}. + * @param base64Url The signature part of the JWS object. Must not + * be {@code null}. * @return flag indicating verification success - * @throws JOSEException + * @throws JOSEException in case an error occured */ @Override - public boolean verify(JWSHeader jwsHeader, byte[] bytes, Base64URL base64URL) throws JOSEException { - return verifierMap.get(jwsHeader.getAlgorithm()).verify(jwsHeader,bytes,base64URL); + public boolean verify(JWSHeader jwsHeader, byte[] bytes, Base64URL base64Url) throws JOSEException { + return verifierMap.get(jwsHeader.getAlgorithm()).verify(jwsHeader, bytes, base64Url); } /** + * access list of algos + * * @return the list of supported/delegated algorithms */ @Override @@ -82,41 +84,49 @@ public Set supportedJWSAlgorithms() { } /** + * access current context + * * @return we obtain the jca context by delegating to the first existing delegation service, null if none is registered */ @Override public JCAContext getJCAContext() { - return verifierMap.entrySet().stream().findFirst().map(e->e.getValue().getJCAContext()).orElse(null); + return verifierMap.entrySet().stream().findFirst().map(e -> e.getValue().getJCAContext()).orElse(null); } /** * a builder for composite jws verifiers */ public static class Builder { + protected final ObjectMapper om; + protected final Monitor monitor; protected CompositeJwsVerifier verifier; - final protected ObjectMapper om; /** * create a new builder + * * @param om objectmapper for json parsing + * @param monitor logging facility */ - public Builder(ObjectMapper om) { - verifier=new CompositeJwsVerifier(); - this.om=om; + public Builder(ObjectMapper om, Monitor monitor) { + verifier = new CompositeJwsVerifier(); + this.om = om; + this.monitor = monitor; } /** * add a new subverifier/delegating service + * * @param subVerifier the subverifier instance * @return this */ public Builder addVerifier(JWSVerifier subVerifier) { - subVerifier.supportedJWSAlgorithms().forEach(algo -> verifier.verifierMap.put(algo,subVerifier)); + subVerifier.supportedJWSAlgorithms().forEach(algo -> verifier.verifierMap.put(algo, subVerifier)); return this; } /** * adds a key as a json node + * * @param key json representation of keys * @return this builder */ @@ -127,28 +137,32 @@ public Builder addKey(JsonNode key) { if (key.isArray()) { var keyIterator = key.elements(); while (keyIterator.hasNext()) { - JsonNode nextKey= keyIterator.next(); - if(nextKey.has("use") && nextKey.get("use").asText().equals("sig")) { + JsonNode nextKey = keyIterator.next(); + if (nextKey.has("use") && nextKey.get("use").asText().equals("sig")) { addKey(nextKey); } } return this; } - if ( key.has("kty")) { + if (key.has("kty")) { var kty = key.get("kty"); switch (kty.asText()) { case "RSA": try { var rsaKey = RSAKey.parse(om.writeValueAsString(key)); return addVerifier(new RSASSAVerifier(rsaKey)); - } catch(JOSEException | JsonProcessingException | ParseException e) { + } catch (JOSEException | JsonProcessingException | ParseException e) { + monitor.warning("Trying to parse RSA key run into error. Ignoring", e); } + break; case "EC": try { var ecKey = ECKey.parse(om.writeValueAsString(key)); return addVerifier(new ECDSAVerifier(ecKey)); - } catch(JOSEException | JsonProcessingException | ParseException e) { + } catch (JOSEException | JsonProcessingException | ParseException e) { + monitor.warning("Trying to parse EC key run into error. Ignoring", e); } + break; default: break; } @@ -158,11 +172,12 @@ public Builder addKey(JsonNode key) { /** * adds s given key + * * @param key maybe a a json definition for a single key or multiple keys, or a url to download a key * @return this instance */ public Builder addKey(String key) { - if(key!=null) { + if (key != null) { try { URL keyUrl = new URL(key); try (InputStream keyStream = keyUrl.openStream()) { @@ -171,12 +186,14 @@ public Builder addKey(String key) { key = null; } } catch (MalformedURLException e) { + monitor.warning("Trying to parse key URL run into error. Ignoring", e); } } - if(key!=null) { + if (key != null) { try { return addKey(om.readTree(key)); } catch (JsonProcessingException e) { + monitor.warning("Trying to parse key json run into error. Ignoring", e); } } return this; @@ -184,6 +201,7 @@ public Builder addKey(String key) { /** * builds the composite verfifier from the builder state + * * @return new composite verifier state */ public CompositeJwsVerifier build() { diff --git a/common/auth-jwt/src/main/java/org/eclipse/tractusx/edc/auth/JwtAuthenticationService.java b/common/auth-jwt/src/main/java/org/eclipse/tractusx/edc/auth/JwtAuthenticationService.java index 242b702..5dda75e 100644 --- a/common/auth-jwt/src/main/java/org/eclipse/tractusx/edc/auth/JwtAuthenticationService.java +++ b/common/auth-jwt/src/main/java/org/eclipse/tractusx/edc/auth/JwtAuthenticationService.java @@ -33,45 +33,45 @@ * Implements a JWT (Java Web Tokens) Based Authentication Service */ public class JwtAuthenticationService implements AuthenticationService { - public static String AUTHENTICATION_HEADER="authorization"; - public static Pattern BEARER_TOKEN_VALUE=Pattern.compile("^Bearer ([a-zA-Z0-9+/\\-_]+\\.[a-zA-Z0-9+/\\-_]+\\.[a-zA-Z0-9+/\\-_]+)$"); + public static final String AUTHENTICATIONHEADER = "authorization"; + public static final Pattern BEARERTOKENVALUE = Pattern.compile("^Bearer ([a-zA-Z0-9+/\\-_]+\\.[a-zA-Z0-9+/\\-_]+\\.[a-zA-Z0-9+/\\-_]+)$"); + + protected final JWSVerifier verifier; + protected final boolean checkExpiry; - final protected JWSVerifier verifier; - final protected boolean checkExpiry; - public JwtAuthenticationService(JWSVerifier verifier, boolean checkExpiry) { - this.verifier=verifier; - this.checkExpiry=checkExpiry; + this.verifier = verifier; + this.checkExpiry = checkExpiry; } @Override public boolean isAuthenticated(Map> map) { return map.entrySet().stream() - .filter( e->e.getKey().equalsIgnoreCase(AUTHENTICATION_HEADER)) - .flatMap( e->e.getValue().stream().map( v -> BEARER_TOKEN_VALUE.matcher(v)).filter(Matcher::matches)). - anyMatch(r->checkToken(r.group(1))); + .filter(e -> e.getKey().equalsIgnoreCase(AUTHENTICATIONHEADER)) + .flatMap(e -> e.getValue().stream().map(v -> BEARERTOKENVALUE.matcher(v)).filter(Matcher::matches)) + .anyMatch(r -> checkToken(r.group(1))); } protected boolean checkToken(String token) { try { JWSObject jwsObject = JWSObject.parse(token); - boolean isVerified=jwsObject.verify(verifier); - if(isVerified) { - if(checkExpiry) { - Object expiryObject=jwsObject.getPayload().toJSONObject().get("exp"); - if(expiryObject instanceof Long) { + boolean isVerified = jwsObject.verify(verifier); + if (isVerified) { + if (checkExpiry) { + Object expiryObject = jwsObject.getPayload().toJSONObject().get("exp"); + if (expiryObject instanceof Long) { // token times are in seconds - return !new Date((Long) expiryObject*1000).before(new Date()); + return !new Date((Long) expiryObject * 1000).before(new Date()); } else { return true; } } else { return true; } - } else { + } else { return false; } - } catch(ParseException | JOSEException e) { + } catch (ParseException | JOSEException e) { return false; } } @@ -81,24 +81,24 @@ protected boolean checkToken(String token) { */ public static class Builder { protected JWSVerifier verifier; - protected boolean checkExpiry=true; + protected boolean checkExpiry = true; public Builder() { } public Builder setVerifier(JWSVerifier verifier) { - this.verifier=verifier; + this.verifier = verifier; return this; } public Builder setCheckExpiry(boolean check) { - this.checkExpiry=check; + this.checkExpiry = check; return this; } public JwtAuthenticationService build() { assert Objects.nonNull(verifier); - return new JwtAuthenticationService(verifier,checkExpiry); + return new JwtAuthenticationService(verifier, checkExpiry); } } } diff --git a/common/auth-jwt/src/test/java/org/eclipse/tractusx/edc/auth/ApiKeyAuthenticationServiceTest.java b/common/auth-jwt/src/test/java/org/eclipse/tractusx/edc/auth/ApiKeyAuthenticationServiceTest.java index 6c025db..f0b149b 100644 --- a/common/auth-jwt/src/test/java/org/eclipse/tractusx/edc/auth/ApiKeyAuthenticationServiceTest.java +++ b/common/auth-jwt/src/test/java/org/eclipse/tractusx/edc/auth/ApiKeyAuthenticationServiceTest.java @@ -19,12 +19,14 @@ import com.nimbusds.jose.JOSEException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; import java.util.List; import java.util.Map; import java.util.UUID; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * Tests the api-key service */ @@ -36,26 +38,26 @@ public class ApiKeyAuthenticationServiceTest { @BeforeEach public void initialize() throws JOSEException { - key= UUID.randomUUID().toString(); - service=new ApiKeyAuthenticationService(key.hashCode()); + key = UUID.randomUUID().toString(); + service = new ApiKeyAuthenticationService(key.hashCode()); } @Test public void testValidKey() { - var headers=Map.of("x-api-key", List.of(key)); - assertTrue(service.isAuthenticated(headers),"Could not authenticate using valid api key"); + var headers = Map.of("x-api-key", List.of(key)); + assertTrue(service.isAuthenticated(headers), "Could not authenticate using valid api key"); } @Test public void testInvalidKey() { - var headers=Map.of("x-api-key", List.of(UUID.randomUUID().toString())); - assertFalse(service.isAuthenticated(headers),"Could authenticate using invalid key"); + var headers = Map.of("x-api-key", List.of(UUID.randomUUID().toString())); + assertFalse(service.isAuthenticated(headers), "Could authenticate using invalid key"); } @Test public void testInvalidHeader() { - var headers=Map.of("api-key", List.of(key)); - assertFalse(service.isAuthenticated(headers),"Could authenticate using invalid header"); + var headers = Map.of("api-key", List.of(key)); + assertFalse(service.isAuthenticated(headers), "Could authenticate using invalid header"); } } diff --git a/common/auth-jwt/src/test/java/org/eclipse/tractusx/edc/auth/CompositeAuthenticationServiceTest.java b/common/auth-jwt/src/test/java/org/eclipse/tractusx/edc/auth/CompositeAuthenticationServiceTest.java index c1b980b..8851676 100644 --- a/common/auth-jwt/src/test/java/org/eclipse/tractusx/edc/auth/CompositeAuthenticationServiceTest.java +++ b/common/auth-jwt/src/test/java/org/eclipse/tractusx/edc/auth/CompositeAuthenticationServiceTest.java @@ -17,7 +17,6 @@ package org.eclipse.tractusx.edc.auth; import com.nimbusds.jose.JOSEException; -import com.nimbusds.jose.JWSAlgorithm; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -25,7 +24,8 @@ import java.util.Map; import java.util.UUID; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * tests the composite service @@ -39,47 +39,47 @@ public void initialize() { @Test public void testEmptyDefault() { - CompositeAuthenticationService service=new CompositeAuthenticationService.Builder().build(); - assertTrue(service.isAuthenticated(Map.of()),"Should authenticate against empty default composite service"); + CompositeAuthenticationService service = new CompositeAuthenticationService.Builder().build(); + assertTrue(service.isAuthenticated(Map.of()), "Should authenticate against empty default composite service"); } @Test public void testEmptyAll() { - CompositeAuthenticationService service=new CompositeAuthenticationService.Builder().setMode(CompositeAuthenticationMode.ALL).build(); - assertTrue(service.isAuthenticated(Map.of()),"Should authenticate against empty ALL composite service"); + CompositeAuthenticationService service = new CompositeAuthenticationService.Builder().setMode(CompositeAuthenticationMode.ALL).build(); + assertTrue(service.isAuthenticated(Map.of()), "Should authenticate against empty ALL composite service"); } @Test public void testEmptyOne() { - CompositeAuthenticationService service=new CompositeAuthenticationService.Builder().setMode(CompositeAuthenticationMode.ONE).build(); - assertFalse(service.isAuthenticated(Map.of()),"Should not authenticate against empty ONE composite service"); + CompositeAuthenticationService service = new CompositeAuthenticationService.Builder().setMode(CompositeAuthenticationMode.ONE).build(); + assertFalse(service.isAuthenticated(Map.of()), "Should not authenticate against empty ONE composite service"); } @Test public void testOne() { - String key1= UUID.randomUUID().toString(); - String key2= UUID.randomUUID().toString(); - CompositeAuthenticationService service=new CompositeAuthenticationService.Builder().setMode(CompositeAuthenticationMode.ONE). + String key1 = UUID.randomUUID().toString(); + String key2 = UUID.randomUUID().toString(); + CompositeAuthenticationService service = new CompositeAuthenticationService.Builder().setMode(CompositeAuthenticationMode.ONE). addService(new ApiKeyAuthenticationService.Builder().setReference(key1.hashCode()).build()). addService(new ApiKeyAuthenticationService.Builder().setReference(key2.hashCode()).build()).build(); - assertTrue(service.isAuthenticated(Map.of("x-api-key", List.of(key1))),"Should authenticate against ONE composite service"); - assertTrue(service.isAuthenticated(Map.of("x-api-key", List.of(key2))),"Should authenticate against ONE composite service"); - assertFalse(service.isAuthenticated(Map.of("x-api-key", List.of(UUID.randomUUID().toString()))),"Should not authenticate against ONE composite service"); - assertFalse(service.isAuthenticated(Map.of("api-key", List.of(key1))),"Should not authenticate against ONE composite service"); + assertTrue(service.isAuthenticated(Map.of("x-api-key", List.of(key1))), "Should authenticate against ONE composite service"); + assertTrue(service.isAuthenticated(Map.of("x-api-key", List.of(key2))), "Should authenticate against ONE composite service"); + assertFalse(service.isAuthenticated(Map.of("x-api-key", List.of(UUID.randomUUID().toString()))), "Should not authenticate against ONE composite service"); + assertFalse(service.isAuthenticated(Map.of("api-key", List.of(key1))), "Should not authenticate against ONE composite service"); } @Test public void testAll() throws JOSEException { - String key1= UUID.randomUUID().toString(); + String key1 = UUID.randomUUID().toString(); JwtAuthenticationServiceTest jwsTest; - jwsTest=new JwtAuthenticationServiceTest(); + jwsTest = new JwtAuthenticationServiceTest(); jwsTest.initialize(); - CompositeAuthenticationService service=new CompositeAuthenticationService.Builder().setMode(CompositeAuthenticationMode.ALL). + CompositeAuthenticationService service = new CompositeAuthenticationService.Builder().setMode(CompositeAuthenticationMode.ALL). addService(new ApiKeyAuthenticationService.Builder().setReference(key1.hashCode()).build()). addService(jwsTest.getService()).build(); - assertTrue(service.isAuthenticated(Map.of("x-api-key", List.of(key1),"Authorization",List.of("Bearer "+jwsTest.getToken()))),"Should authenticate against ALL composite service"); - assertFalse(service.isAuthenticated(Map.of("x-api-key", List.of(key1))),"Should authenticate against ALL composite service"); - assertFalse(service.isAuthenticated(Map.of("Authorization",List.of("Bearer "+jwsTest.getToken()))),"Should authenticate against ALL composite service"); + assertTrue(service.isAuthenticated(Map.of("x-api-key", List.of(key1), "Authorization", List.of("Bearer " + jwsTest.getToken()))), "Should authenticate against ALL composite service"); + assertFalse(service.isAuthenticated(Map.of("x-api-key", List.of(key1))), "Should authenticate against ALL composite service"); + assertFalse(service.isAuthenticated(Map.of("Authorization", List.of("Bearer " + jwsTest.getToken()))), "Should authenticate against ALL composite service"); } } diff --git a/common/auth-jwt/src/test/java/org/eclipse/tractusx/edc/auth/JwtAuthenticationServiceTest.java b/common/auth-jwt/src/test/java/org/eclipse/tractusx/edc/auth/JwtAuthenticationServiceTest.java index 68e8fb5..5c8d84a 100644 --- a/common/auth-jwt/src/test/java/org/eclipse/tractusx/edc/auth/JwtAuthenticationServiceTest.java +++ b/common/auth-jwt/src/test/java/org/eclipse/tractusx/edc/auth/JwtAuthenticationServiceTest.java @@ -26,19 +26,24 @@ import com.nimbusds.jose.jwk.gen.RSAKeyGenerator; import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.jwt.SignedJWT; +import org.eclipse.edc.spi.monitor.ConsoleMonitor; +import org.eclipse.edc.spi.monitor.Monitor; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; import java.util.Date; import java.util.List; import java.util.Map; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * tests the jwt service */ public class JwtAuthenticationServiceTest { ObjectMapper om; + Monitor monitor; CompositeJwsVerifier verifier; @@ -61,7 +66,8 @@ public String getToken() { @BeforeEach public void initialize() throws JOSEException { - om=new ObjectMapper(); + monitor=new ConsoleMonitor(); + om = new ObjectMapper(); RSAKey rsaJWK = new RSAKeyGenerator(2048) .keyID("123") .generate(); @@ -87,44 +93,44 @@ public void initialize() throws JOSEException { claimsSet); signedJWT2.sign(signer2); token2 = signedJWT2.serialize(); - verifier=new CompositeJwsVerifier.Builder(om).addKey(rsaPublicJWK.toJSONString()).build(); - service=new JwtAuthenticationService(verifier,false); + verifier = new CompositeJwsVerifier.Builder(om,monitor).addKey(rsaPublicJWK.toJSONString()).build(); + service = new JwtAuthenticationService(verifier, false); } @Test public void testValidJwtToken() { - var headers=Map.of("Authorization", List.of("Bearer "+token)); - assertTrue(service.isAuthenticated(headers),"Could not authenticate using valid token"); + var headers = Map.of("Authorization", List.of("Bearer " + token)); + assertTrue(service.isAuthenticated(headers), "Could not authenticate using valid token"); } @Test public void testValidLowercaseJwtToken() { - var headers=Map.of("authorization", List.of("Bearer "+token)); - assertTrue(service.isAuthenticated(headers),"Could not authenticate using valid token"); + var headers = Map.of("authorization", List.of("Bearer " + token)); + assertTrue(service.isAuthenticated(headers), "Could not authenticate using valid token"); } @Test public void testValidOtherJwtToken() { - var headers=Map.of("Authorization", List.of("Bearer "+token2)); - assertFalse(service.isAuthenticated(headers),"Could not authenticate using valid token"); + var headers = Map.of("Authorization", List.of("Bearer " + token2)); + assertFalse(service.isAuthenticated(headers), "Could not authenticate using valid token"); } @Test public void testInvalidJwtToken() { - var headers=Map.of("Authorization", List.of("Bearer "+token.substring(10,20))); - assertFalse(service.isAuthenticated(headers),"Could authenticate using invalid token"); + var headers = Map.of("Authorization", List.of("Bearer " + token.substring(10, 20))); + assertFalse(service.isAuthenticated(headers), "Could authenticate using invalid token"); } @Test public void testInvalidHeader() { - var headers=Map.of("Authorization", List.of("bullshit")); - assertFalse(service.isAuthenticated(headers),"Could authenticate using invalid header"); + var headers = Map.of("Authorization", List.of("bullshit")); + assertFalse(service.isAuthenticated(headers), "Could authenticate using invalid header"); } @Test public void testExpiredJwtToken() { - JwtAuthenticationService secondService=new JwtAuthenticationService(verifier,true); - var headers=Map.of("Authorization", List.of("Bearer "+token)); - assertFalse(secondService.isAuthenticated(headers),"Could authenticate using expired token"); + JwtAuthenticationService secondService = new JwtAuthenticationService(verifier, true); + var headers = Map.of("Authorization", List.of("Bearer " + token)); + assertFalse(secondService.isAuthenticated(headers), "Could authenticate using expired token"); } } diff --git a/pom.xml b/pom.xml index 4a30036..3dadc34 100644 --- a/pom.xml +++ b/pom.xml @@ -62,6 +62,7 @@ tractusx/ linux/amd64 + common/auth-jwt @@ -184,16 +185,24 @@ 3.3.0 - com.diffplug.spotless - spotless-maven-plugin - 2.37.0 + org.apache.maven.plugins + maven-checkstyle-plugin + 3.3.0 + + ${session.executionRootDirectory}/resources/tx-checkstyle-config.xml + + config_loc=${session.executionRootDirectory}/resources + + true + true + false + - format - process-sources + validate + validate check - apply @@ -268,15 +277,15 @@ - - dash-licenses-snapshots - https://repo.eclipse.org/content/repositories/dash-licenses-snapshots/ - - true - - + + dash-licenses-snapshots + https://repo.eclipse.org/content/repositories/dash-licenses-snapshots/ + + true + + - + github diff --git a/resources/suppressions.xml b/resources/suppressions.xml new file mode 100644 index 0000000..6a89b01 --- /dev/null +++ b/resources/suppressions.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/resources/tx-codestyle.xml b/resources/tx-codestyle.xml index 9297f6b..43925d5 100644 --- a/resources/tx-codestyle.xml +++ b/resources/tx-codestyle.xml @@ -17,321 +17,321 @@ // SPDX-License-Identifier: Apache-2.0 --> - - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file From 511c01bba087480d0df00668dfa16f862584425c Mon Sep 17 00:00:00 2001 From: "Dr. Christoph \"Schorsch\" Jung" Date: Mon, 9 Oct 2023 12:22:05 +0200 Subject: [PATCH 3/7] chore: upgrade dash tool and recompute DEPENDENCIES after reformat. --- DEPENDENCIES | 4 ++-- pom.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DEPENDENCIES b/DEPENDENCIES index 3e5824f..65a87dd 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -216,8 +216,8 @@ maven/mavencentral/org.eclipse.jetty/jetty-servlet/11.0.15, EPL-2.0 OR Apache-2. maven/mavencentral/org.eclipse.jetty/jetty-util/11.0.15, EPL-2.0 OR Apache-2.0, approved, rt.jetty maven/mavencentral/org.eclipse.jetty/jetty-webapp/11.0.15, EPL-2.0 OR Apache-2.0, approved, rt.jetty maven/mavencentral/org.eclipse.jetty/jetty-xml/11.0.15, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.tractusx.agents.edc.agent-plane/agent-plane-protocol/1.10.2-SNAPSHOT, Apache-2.0, approved, automotive.tractusx -maven/mavencentral/org.eclipse.tractusx.edc/auth-jwt/1.10.2-SNAPSHOT, Apache-2.0, approved, automotive.tractusx +maven/mavencentral/org.eclipse.tractusx.agents.edc.agent-plane/agent-plane-protocol/1.10.2-20231006.062144-7, Apache-2.0, approved, automotive.tractusx +maven/mavencentral/org.eclipse.tractusx.edc/auth-jwt/1.10.2-20231006.062053-7, Apache-2.0, approved, automotive.tractusx maven/mavencentral/org.eclipse.tractusx.edc/core-spi/0.5.0, Apache-2.0, approved, automotive.tractusx maven/mavencentral/org.eclipse.tractusx.edc/edc-dataplane-azure-vault/0.5.0, Apache-2.0, approved, automotive.tractusx maven/mavencentral/org.eclipse.tractusx.edc/edc-dataplane-base/0.5.0, Apache-2.0, approved, automotive.tractusx diff --git a/pom.xml b/pom.xml index 3dadc34..48a5e66 100644 --- a/pom.xml +++ b/pom.xml @@ -210,7 +210,7 @@ org.eclipse.dash license-tool-plugin - 0.0.1-SNAPSHOT + 1.0.3-SNAPSHOT automotive.tractusx DEPENDENCIES From ea6c3508ed25d2de4f605f645c61068d72a0dddb Mon Sep 17 00:00:00 2001 From: "Dr. Christoph \"Schorsch\" Jung" Date: Thu, 19 Oct 2023 16:36:08 +0200 Subject: [PATCH 4/7] style: checkstyle needed being reapplied to these changes. --- .../java/org/eclipse/tractusx/agents/edc/AgentConfig.java | 4 ++++ .../tractusx/agents/edc/service/DataManagement.java | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgentConfig.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgentConfig.java index df7eb14..16a5e2c 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgentConfig.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/AgentConfig.java @@ -362,6 +362,8 @@ public Pattern getServiceAssetDenyPattern() { } /** + * access + * * @return tx edc version as a string */ public String getEdcVersion() { @@ -369,6 +371,8 @@ public String getEdcVersion() { } /** + * check + * * @return whether the edc version is less than 23.09 */ public boolean isPrerelease() { diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagement.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagement.java index 973ee32..bda93e1 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagement.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagement.java @@ -111,7 +111,7 @@ public class DataManagement { public static final String ASSET_CALL = "%s/assets/request"; // negotiation request 0.5.>=1 - public static final String NEGOTIATION_REQUEST_BODY="{\n" + + public static final String NEGOTIATION_REQUEST_BODY = "{\n" + "\"@context\": { \"odrl\": \"http://www.w3.org/ns/odrl/2/\"},\n" + "\"@type\": \"NegotiationInitiateRequestDto\",\n" + "\"connectorAddress\": \"%1$s\",\n" + @@ -126,7 +126,7 @@ public class DataManagement { "}"; // negotiation request 0.5.0 - roles of provider and connector are wrong - public static final String NEGOTIATION_REQUEST_BODY_PRERELEASE="{\n" + + public static final String NEGOTIATION_REQUEST_BODY_PRERELEASE = "{\n" + "\"@context\": { \"odrl\": \"http://www.w3.org/ns/odrl/2/\"},\n" + "\"@type\": \"NegotiationInitiateRequestDto\",\n" + "\"connectorAddress\": \"%1$s\",\n" + @@ -222,7 +222,7 @@ public DcatCatalog getCatalog(String remoteControlPlaneIdsUrl, QuerySpec spec) t // use a version specific call String template = config.isPrerelease() ? CATALOG_REQUEST_BODY_PRERELEASE : CATALOG_REQUEST_BODY; - var catalogSpec =String.format(template, + var catalogSpec = String.format(template, String.format(DSP_PATH, remoteControlPlaneIdsUrl), objectMapper.writeValueAsString(spec)); var request = new Request.Builder().url(url).post(RequestBody.create(catalogSpec, MediaType.parse("application/json"))); @@ -341,7 +341,7 @@ public String initiateNegotiation(ContractNegotiationRequest negotiationRequest) // use a version specific call String template = config.isPrerelease() ? NEGOTIATION_REQUEST_BODY_PRERELEASE : NEGOTIATION_REQUEST_BODY; - var negotiateSpec =String.format(template, + var negotiateSpec = String.format(template, negotiationRequest.getConnectorAddress(), negotiationRequest.getLocalBusinessPartnerNumber(), negotiationRequest.getRemoteBusinessPartnerNumber(), From cdb7c66a6b78386a2afc4b4d8c6ba1fc4d4d15c8 Mon Sep 17 00:00:00 2001 From: "Dr. Christoph \"Schorsch\" Jung" Date: Tue, 14 Nov 2023 16:57:14 +0100 Subject: [PATCH 5/7] style: additional style violations from merging. --- .../agents/edc/service/DataManagement.java | 16 ++++--------- .../edc/sparql/DataspaceServiceExecutor.java | 24 +++++++++---------- 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagement.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagement.java index 4d54ee4..5bea2b0 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagement.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagement.java @@ -18,11 +18,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; -import jakarta.json.JsonArray; -import jakarta.json.JsonNumber; -import jakarta.json.JsonObject; -import jakarta.json.JsonString; -import jakarta.json.JsonValue; import jakarta.ws.rs.InternalServerErrorException; import okhttp3.MediaType; import okhttp3.OkHttpClient; @@ -47,10 +42,7 @@ import java.io.IOException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; -import java.util.Collection; import java.util.List; -import java.util.Map; -import java.util.Set; import static java.lang.String.format; @@ -337,8 +329,8 @@ public IdResponse createOrUpdateSkill(String assetId, String name, String descri String apiVersion = config.isPrerelease() ? "/v2" : "/v3"; var url = String.format(ASSET_CREATE_CALL, config.getControlPlaneManagementProviderUrl(), apiVersion); - if(contract!=null) { - contract=String.format(" \"cx-common:publishedUnderContract\": \"%1$s\",\n",contract); + if (contract != null) { + contract = String.format(" \"cx-common:publishedUnderContract\": \"%1$s\",\n", contract); } else { contract = ""; } @@ -362,10 +354,10 @@ public IdResponse createOrUpdateSkill(String assetId, String name, String descri try (var putResponse = httpClient.newCall(putRequest.build()).execute()) { body = putResponse.body(); - if(!putResponse.isSuccessful() || body == null) { + if (!putResponse.isSuccessful() || body == null) { throw new InternalServerErrorException(format("Control plane responded with: %s %s", response.code(), body != null ? body.string() : "")); } - return new IdResponse(jakarta.json.Json.createObjectBuilder().add("@id","assetId").build()); + return new IdResponse(jakarta.json.Json.createObjectBuilder().add("@id", "assetId").build()); } } diff --git a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/DataspaceServiceExecutor.java b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/DataspaceServiceExecutor.java index 71b938b..e20828d 100644 --- a/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/DataspaceServiceExecutor.java +++ b/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql/DataspaceServiceExecutor.java @@ -280,18 +280,18 @@ public QueryIterator createExecution(OpService opOriginal, String serviceUrl, Se // we have to only check outgoing URLs which have not already been checked String targetUrl = context.get(DataspaceServiceExecutor.TARGET_URL_SYMBOL); - if (!serviceURL.equalsIgnoreCase(targetUrl)) { - // check whether the service url is allowed (in the context, in the default) - Pattern allowPattern = context.get(ALLOW_SYMBOL, config.getServiceAllowPattern()); - if (!allowPattern.matcher(serviceURL).matches()) { - throw new QueryExecException(String.format("The service %s does not match the allowed pattern %s. Aborted execution.", serviceURL, allowPattern.pattern())); - } - - // check whether the service url is denied (in the context, in the default) - Pattern denyPattern = context.get(DENY_SYMBOL, config.getServiceDenyPattern()); - if (denyPattern.matcher(serviceURL).matches()) { - throw new QueryExecException(String.format("The service %s matches the denied pattern %s. Aborted execution.", serviceURL, denyPattern.pattern())); - } + if (!serviceUrl.equalsIgnoreCase(targetUrl)) { + // check whether the service url is allowed (in the context, in the default) + Pattern allowPattern = context.get(ALLOW_SYMBOL, config.getServiceAllowPattern()); + if (!allowPattern.matcher(serviceUrl).matches()) { + throw new QueryExecException(String.format("The service %s does not match the allowed pattern %s. Aborted execution.", serviceUrl, allowPattern.pattern())); + } + + // check whether the service url is denied (in the context, in the default) + Pattern denyPattern = context.get(DENY_SYMBOL, config.getServiceDenyPattern()); + if (denyPattern.matcher(serviceUrl).matches()) { + throw new QueryExecException(String.format("The service %s matches the denied pattern %s. Aborted execution.", serviceUrl, denyPattern.pattern())); + } } boolean silent = opOriginal.getSilent(); From c71ecbeeadf0fc228132800a3d7babeb8544981c Mon Sep 17 00:00:00 2001 From: "Dr. Christoph \"Schorsch\" Jung" Date: Wed, 15 Nov 2023 08:28:57 +0100 Subject: [PATCH 6/7] chore: update DEPENDENCIES. --- DEPENDENCIES | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/DEPENDENCIES b/DEPENDENCIES index 65a87dd..f0d1b63 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -86,8 +86,8 @@ maven/mavencentral/io.prometheus/simpleclient_tracer_otel/0.16.0, Apache-2.0, ap maven/mavencentral/io.prometheus/simpleclient_tracer_otel_agent/0.16.0, Apache-2.0, approved, clearlydefined maven/mavencentral/io.swagger.core.v3/swagger-annotations-jakarta/2.2.2, Apache-2.0, approved, #5947 maven/mavencentral/io.swagger.core.v3/swagger-core-jakarta/2.2.2, Apache-2.0, approved, #5929 -maven/mavencentral/io.swagger.core.v3/swagger-integration-jakarta/2.2.2, Apache-2.0, approved, clearlydefined -maven/mavencentral/io.swagger.core.v3/swagger-jaxrs2-jakarta/2.2.2, Apache-2.0, approved, clearlydefined +maven/mavencentral/io.swagger.core.v3/swagger-integration-jakarta/2.2.2, Apache-2.0, approved, #11475 +maven/mavencentral/io.swagger.core.v3/swagger-jaxrs2-jakarta/2.2.2, Apache-2.0, approved, #11477 maven/mavencentral/io.swagger.core.v3/swagger-models-jakarta/2.2.2, Apache-2.0, approved, #5919 maven/mavencentral/jakarta.activation/jakarta.activation-api/2.1.0, EPL-2.0 OR BSD-3-Clause OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jaf maven/mavencentral/jakarta.annotation/jakarta.annotation-api/2.1.1, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.ca @@ -216,8 +216,8 @@ maven/mavencentral/org.eclipse.jetty/jetty-servlet/11.0.15, EPL-2.0 OR Apache-2. maven/mavencentral/org.eclipse.jetty/jetty-util/11.0.15, EPL-2.0 OR Apache-2.0, approved, rt.jetty maven/mavencentral/org.eclipse.jetty/jetty-webapp/11.0.15, EPL-2.0 OR Apache-2.0, approved, rt.jetty maven/mavencentral/org.eclipse.jetty/jetty-xml/11.0.15, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.tractusx.agents.edc.agent-plane/agent-plane-protocol/1.10.2-20231006.062144-7, Apache-2.0, approved, automotive.tractusx -maven/mavencentral/org.eclipse.tractusx.edc/auth-jwt/1.10.2-20231006.062053-7, Apache-2.0, approved, automotive.tractusx +maven/mavencentral/org.eclipse.tractusx.agents.edc.agent-plane/agent-plane-protocol/1.10.6-SNAPSHOT, Apache-2.0, approved, automotive.tractusx +maven/mavencentral/org.eclipse.tractusx.edc/auth-jwt/1.10.6-SNAPSHOT, Apache-2.0, approved, automotive.tractusx maven/mavencentral/org.eclipse.tractusx.edc/core-spi/0.5.0, Apache-2.0, approved, automotive.tractusx maven/mavencentral/org.eclipse.tractusx.edc/edc-dataplane-azure-vault/0.5.0, Apache-2.0, approved, automotive.tractusx maven/mavencentral/org.eclipse.tractusx.edc/edc-dataplane-base/0.5.0, Apache-2.0, approved, automotive.tractusx From 6929522aa65195c8c6a7792bd21d9d922778648c Mon Sep 17 00:00:00 2001 From: "Dr. Christoph \"Schorsch\" Jung" Date: Wed, 15 Nov 2023 08:35:04 +0100 Subject: [PATCH 7/7] docs: cyclone was removed --- NOTICE.md | 1 - 1 file changed, 1 deletion(-) diff --git a/NOTICE.md b/NOTICE.md index 6b62ea2..352cb37 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -63,7 +63,6 @@ The KA-EDC build and runtime platform is relying on: * [Java Development Kit (JDK >=11 - license depends on chosen provider)](https://de.wikipedia.org/wiki/Java_Development_Kit) * [Apache Maven >=3.8 (Apache License 2.0)](https://maven.apache.org) * [Eclipse Dash (Eclipse Public License 2.0)](https://github.com/eclipse/dash-licenses) -* [CycloneDX 1.4 (Apache License 2.0)](https://github.com/CycloneDX) * [Docker Engine >= 20.10.17 (Apache License 2.0)]() * [Helm (Apache License 2.0)](https://helm.sh/)