├── .editorconfig ├── .github └── workflows │ ├── check.yml │ └── releaseExtension.yml ├── .gitignore ├── .idea ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml └── inspectionProfiles │ └── Project_Default.xml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── HEADER ├── LICENSE ├── NOTICE ├── README.adoc ├── build.gradle.kts ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── renovate.json5 ├── settings.gradle.kts └── src ├── hivemq-extension └── influxdb.properties ├── integrationTest ├── java │ └── com │ │ └── hivemq │ │ └── extensions │ │ └── influxdb │ │ └── InfluxDbExtensionIT.java └── resources │ ├── influxdb.properties │ └── logback-test.xml ├── main └── java │ └── com │ └── hivemq │ └── extensions │ └── influxdb │ ├── InfluxDbCloudSender.java │ ├── InfluxDbExtensionMain.java │ └── configuration │ ├── InfluxDbConfiguration.java │ └── PropertiesReader.java └── test └── java └── com └── hivemq └── extensions └── influxdb ├── InfluxDbCloudSenderTest.java ├── InfluxDbExtensionMainTest.java └── configuration ├── InfluxDbConfigurationTest.java └── PropertiesReaderTest.java /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | charset = utf-8 3 | end_of_line = lf 4 | indent_size = 4 5 | indent_style = space 6 | insert_final_newline = true 7 | max_line_length = 120 8 | tab_width = 4 9 | ij_continuation_indent_size = 8 10 | ij_formatter_off_tag = @formatter:off 11 | ij_formatter_on_tag = @formatter:on 12 | ij_formatter_tags_enabled = false 13 | ij_smart_tabs = false 14 | ij_visual_guides = none 15 | ij_wrap_on_typing = false 16 | 17 | [*.css] 18 | ij_css_align_closing_brace_with_properties = false 19 | ij_css_blank_lines_around_nested_selector = 1 20 | ij_css_blank_lines_between_blocks = 1 21 | ij_css_block_comment_add_space = false 22 | ij_css_brace_placement = end_of_line 23 | ij_css_enforce_quotes_on_format = false 24 | ij_css_hex_color_long_format = false 25 | ij_css_hex_color_lower_case = false 26 | ij_css_hex_color_short_format = false 27 | ij_css_hex_color_upper_case = false 28 | ij_css_keep_blank_lines_in_code = 2 29 | ij_css_keep_indents_on_empty_lines = false 30 | ij_css_keep_single_line_blocks = false 31 | 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 32 | ij_css_space_after_colon = true 33 | ij_css_space_before_opening_brace = true 34 | ij_css_use_double_quotes = true 35 | ij_css_value_alignment = do_not_align 36 | 37 | [*.feature] 38 | indent_size = 2 39 | ij_gherkin_keep_indents_on_empty_lines = false 40 | 41 | [*.haml] 42 | indent_size = 2 43 | ij_haml_keep_indents_on_empty_lines = false 44 | 45 | [*.java] 46 | ij_java_align_consecutive_assignments = false 47 | ij_java_align_consecutive_variable_declarations = false 48 | ij_java_align_group_field_declarations = false 49 | ij_java_align_multiline_annotation_parameters = true 50 | ij_java_align_multiline_array_initializer_expression = true 51 | ij_java_align_multiline_assignment = false 52 | ij_java_align_multiline_binary_operation = false 53 | ij_java_align_multiline_chained_methods = false 54 | ij_java_align_multiline_extends_list = false 55 | ij_java_align_multiline_for = true 56 | ij_java_align_multiline_method_parentheses = false 57 | ij_java_align_multiline_parameters = true 58 | ij_java_align_multiline_parameters_in_calls = false 59 | ij_java_align_multiline_parenthesized_expression = false 60 | ij_java_align_multiline_records = true 61 | ij_java_align_multiline_resources = true 62 | ij_java_align_multiline_ternary_operation = false 63 | ij_java_align_multiline_text_blocks = false 64 | ij_java_align_multiline_throws_list = false 65 | ij_java_align_subsequent_simple_methods = false 66 | ij_java_align_throws_keyword = false 67 | ij_java_align_types_in_multi_catch = true 68 | ij_java_annotation_parameter_wrap = on_every_item 69 | ij_java_array_initializer_new_line_after_left_brace = true 70 | ij_java_array_initializer_right_brace_on_new_line = false 71 | ij_java_array_initializer_wrap = on_every_item 72 | ij_java_assert_statement_colon_on_next_line = false 73 | ij_java_assert_statement_wrap = off 74 | ij_java_assignment_wrap = normal 75 | ij_java_binary_operation_sign_on_next_line = false 76 | ij_java_binary_operation_wrap = on_every_item 77 | ij_java_blank_lines_after_anonymous_class_header = 0 78 | ij_java_blank_lines_after_class_header = 0 79 | ij_java_blank_lines_after_imports = 1 80 | ij_java_blank_lines_after_package = 1 81 | ij_java_blank_lines_around_class = 1 82 | ij_java_blank_lines_around_field = 0 83 | ij_java_blank_lines_around_field_in_interface = 0 84 | ij_java_blank_lines_around_initializer = 1 85 | ij_java_blank_lines_around_method = 1 86 | ij_java_blank_lines_around_method_in_interface = 1 87 | ij_java_blank_lines_before_class_end = 0 88 | ij_java_blank_lines_before_imports = 1 89 | ij_java_blank_lines_before_method_body = 0 90 | ij_java_blank_lines_before_package = 0 91 | ij_java_block_brace_style = end_of_line 92 | ij_java_block_comment_add_space = false 93 | ij_java_block_comment_at_first_column = true 94 | ij_java_builder_methods = none 95 | ij_java_call_parameters_new_line_after_left_paren = false 96 | ij_java_call_parameters_right_paren_on_new_line = false 97 | ij_java_call_parameters_wrap = on_every_item 98 | ij_java_case_statement_on_separate_line = true 99 | ij_java_catch_on_new_line = false 100 | ij_java_class_annotation_wrap = split_into_lines 101 | ij_java_class_brace_style = end_of_line 102 | ij_java_class_count_to_use_import_on_demand = 50 103 | ij_java_class_names_in_javadoc = 1 104 | ij_java_do_not_indent_top_level_class_members = false 105 | ij_java_do_not_wrap_after_single_annotation = false 106 | ij_java_do_not_wrap_after_single_annotation_in_parameter = false 107 | ij_java_do_while_brace_force = always 108 | ij_java_doc_add_blank_line_after_description = true 109 | ij_java_doc_add_blank_line_after_param_comments = false 110 | ij_java_doc_add_blank_line_after_return = false 111 | ij_java_doc_add_p_tag_on_empty_lines = true 112 | ij_java_doc_align_exception_comments = true 113 | ij_java_doc_align_param_comments = true 114 | ij_java_doc_do_not_wrap_if_one_line = false 115 | ij_java_doc_enable_formatting = true 116 | ij_java_doc_enable_leading_asterisks = true 117 | ij_java_doc_indent_on_continuation = true 118 | ij_java_doc_keep_empty_lines = true 119 | ij_java_doc_keep_empty_parameter_tag = true 120 | ij_java_doc_keep_empty_return_tag = true 121 | ij_java_doc_keep_empty_throws_tag = true 122 | ij_java_doc_keep_invalid_tags = true 123 | ij_java_doc_param_description_on_new_line = false 124 | ij_java_doc_preserve_line_breaks = true 125 | ij_java_doc_use_throws_not_exception_tag = true 126 | ij_java_else_on_new_line = false 127 | ij_java_entity_dd_suffix = EJB 128 | ij_java_entity_eb_suffix = Bean 129 | ij_java_entity_hi_suffix = Home 130 | ij_java_entity_lhi_prefix = Local 131 | ij_java_entity_lhi_suffix = Home 132 | ij_java_entity_li_prefix = Local 133 | ij_java_entity_pk_class = java.lang.String 134 | ij_java_entity_vo_suffix = VO 135 | ij_java_enum_constants_wrap = split_into_lines 136 | ij_java_extends_keyword_wrap = normal 137 | ij_java_extends_list_wrap = normal 138 | ij_java_field_annotation_wrap = split_into_lines 139 | ij_java_finally_on_new_line = false 140 | ij_java_for_brace_force = always 141 | ij_java_for_statement_new_line_after_left_paren = false 142 | ij_java_for_statement_right_paren_on_new_line = false 143 | ij_java_for_statement_wrap = on_every_item 144 | ij_java_generate_final_locals = true 145 | ij_java_generate_final_parameters = true 146 | ij_java_if_brace_force = always 147 | ij_java_imports_layout = *, |, javax.**, java.**, |, $* 148 | ij_java_indent_case_from_switch = true 149 | ij_java_insert_inner_class_imports = false 150 | ij_java_insert_override_annotation = true 151 | ij_java_keep_blank_lines_before_right_brace = 2 152 | ij_java_keep_blank_lines_between_package_declaration_and_header = 2 153 | ij_java_keep_blank_lines_in_code = 2 154 | ij_java_keep_blank_lines_in_declarations = 2 155 | ij_java_keep_builder_methods_indents = false 156 | ij_java_keep_control_statement_in_one_line = true 157 | ij_java_keep_first_column_comment = true 158 | ij_java_keep_indents_on_empty_lines = false 159 | ij_java_keep_line_breaks = false 160 | ij_java_keep_multiple_expressions_in_one_line = false 161 | ij_java_keep_simple_blocks_in_one_line = false 162 | ij_java_keep_simple_classes_in_one_line = false 163 | ij_java_keep_simple_lambdas_in_one_line = true 164 | ij_java_keep_simple_methods_in_one_line = false 165 | ij_java_label_indent_absolute = false 166 | ij_java_label_indent_size = 0 167 | ij_java_lambda_brace_style = end_of_line 168 | ij_java_layout_static_imports_separately = true 169 | ij_java_line_comment_add_space = false 170 | ij_java_line_comment_add_space_on_reformat = false 171 | ij_java_line_comment_at_first_column = true 172 | ij_java_message_dd_suffix = EJB 173 | ij_java_message_eb_suffix = Bean 174 | ij_java_method_annotation_wrap = split_into_lines 175 | ij_java_method_brace_style = end_of_line 176 | ij_java_method_call_chain_wrap = on_every_item 177 | ij_java_method_parameters_new_line_after_left_paren = true 178 | ij_java_method_parameters_right_paren_on_new_line = false 179 | ij_java_method_parameters_wrap = on_every_item 180 | ij_java_modifier_list_wrap = false 181 | ij_java_multi_catch_types_wrap = normal 182 | ij_java_names_count_to_use_import_on_demand = 50 183 | ij_java_new_line_after_lparen_in_annotation = false 184 | ij_java_new_line_after_lparen_in_record_header = false 185 | ij_java_packages_to_use_import_on_demand = java.awt.*, javax.swing.* 186 | ij_java_parameter_annotation_wrap = off 187 | ij_java_parentheses_expression_new_line_after_left_paren = false 188 | ij_java_parentheses_expression_right_paren_on_new_line = false 189 | ij_java_place_assignment_sign_on_next_line = false 190 | ij_java_prefer_longer_names = true 191 | ij_java_prefer_parameters_wrap = false 192 | ij_java_record_components_wrap = normal 193 | ij_java_repeat_synchronized = true 194 | ij_java_replace_instanceof_and_cast = false 195 | ij_java_replace_null_check = true 196 | ij_java_replace_sum_lambda_with_method_ref = true 197 | ij_java_resource_list_new_line_after_left_paren = false 198 | ij_java_resource_list_right_paren_on_new_line = false 199 | ij_java_resource_list_wrap = on_every_item 200 | ij_java_rparen_on_new_line_in_annotation = false 201 | ij_java_rparen_on_new_line_in_record_header = false 202 | ij_java_session_dd_suffix = EJB 203 | ij_java_session_eb_suffix = Bean 204 | ij_java_session_hi_suffix = Home 205 | ij_java_session_lhi_prefix = Local 206 | ij_java_session_lhi_suffix = Home 207 | ij_java_session_li_prefix = Local 208 | ij_java_session_si_suffix = Service 209 | ij_java_space_after_closing_angle_bracket_in_type_argument = false 210 | ij_java_space_after_colon = true 211 | ij_java_space_after_comma = true 212 | ij_java_space_after_comma_in_type_arguments = true 213 | ij_java_space_after_for_semicolon = true 214 | ij_java_space_after_quest = true 215 | ij_java_space_after_type_cast = true 216 | ij_java_space_before_annotation_array_initializer_left_brace = false 217 | ij_java_space_before_annotation_parameter_list = false 218 | ij_java_space_before_array_initializer_left_brace = false 219 | ij_java_space_before_catch_keyword = true 220 | ij_java_space_before_catch_left_brace = true 221 | ij_java_space_before_catch_parentheses = true 222 | ij_java_space_before_class_left_brace = true 223 | ij_java_space_before_colon = true 224 | ij_java_space_before_colon_in_foreach = true 225 | ij_java_space_before_comma = false 226 | ij_java_space_before_do_left_brace = true 227 | ij_java_space_before_else_keyword = true 228 | ij_java_space_before_else_left_brace = true 229 | ij_java_space_before_finally_keyword = true 230 | ij_java_space_before_finally_left_brace = true 231 | ij_java_space_before_for_left_brace = true 232 | ij_java_space_before_for_parentheses = true 233 | ij_java_space_before_for_semicolon = false 234 | ij_java_space_before_if_left_brace = true 235 | ij_java_space_before_if_parentheses = true 236 | ij_java_space_before_method_call_parentheses = false 237 | ij_java_space_before_method_left_brace = true 238 | ij_java_space_before_method_parentheses = false 239 | ij_java_space_before_opening_angle_bracket_in_type_parameter = false 240 | ij_java_space_before_quest = true 241 | ij_java_space_before_switch_left_brace = true 242 | ij_java_space_before_switch_parentheses = true 243 | ij_java_space_before_synchronized_left_brace = true 244 | ij_java_space_before_synchronized_parentheses = true 245 | ij_java_space_before_try_left_brace = true 246 | ij_java_space_before_try_parentheses = true 247 | ij_java_space_before_type_parameter_list = false 248 | ij_java_space_before_while_keyword = true 249 | ij_java_space_before_while_left_brace = true 250 | ij_java_space_before_while_parentheses = true 251 | ij_java_space_inside_one_line_enum_braces = false 252 | ij_java_space_within_empty_array_initializer_braces = false 253 | ij_java_space_within_empty_method_call_parentheses = false 254 | ij_java_space_within_empty_method_parentheses = false 255 | ij_java_spaces_around_additive_operators = true 256 | ij_java_spaces_around_annotation_eq = true 257 | ij_java_spaces_around_assignment_operators = true 258 | ij_java_spaces_around_bitwise_operators = true 259 | ij_java_spaces_around_equality_operators = true 260 | ij_java_spaces_around_lambda_arrow = true 261 | ij_java_spaces_around_logical_operators = true 262 | ij_java_spaces_around_method_ref_dbl_colon = false 263 | ij_java_spaces_around_multiplicative_operators = true 264 | ij_java_spaces_around_relational_operators = true 265 | ij_java_spaces_around_shift_operators = true 266 | ij_java_spaces_around_type_bounds_in_type_parameters = true 267 | ij_java_spaces_around_unary_operator = false 268 | ij_java_spaces_within_angle_brackets = false 269 | ij_java_spaces_within_annotation_parentheses = false 270 | ij_java_spaces_within_array_initializer_braces = false 271 | ij_java_spaces_within_braces = false 272 | ij_java_spaces_within_brackets = false 273 | ij_java_spaces_within_cast_parentheses = false 274 | ij_java_spaces_within_catch_parentheses = false 275 | ij_java_spaces_within_for_parentheses = false 276 | ij_java_spaces_within_if_parentheses = false 277 | ij_java_spaces_within_method_call_parentheses = false 278 | ij_java_spaces_within_method_parentheses = false 279 | ij_java_spaces_within_parentheses = false 280 | ij_java_spaces_within_record_header = false 281 | ij_java_spaces_within_switch_parentheses = false 282 | ij_java_spaces_within_synchronized_parentheses = false 283 | ij_java_spaces_within_try_parentheses = false 284 | ij_java_spaces_within_while_parentheses = false 285 | ij_java_special_else_if_treatment = true 286 | ij_java_subclass_name_suffix = Impl 287 | ij_java_ternary_operation_signs_on_next_line = false 288 | ij_java_ternary_operation_wrap = on_every_item 289 | ij_java_test_name_suffix = Test 290 | ij_java_throws_keyword_wrap = normal 291 | ij_java_throws_list_wrap = normal 292 | ij_java_use_external_annotations = false 293 | ij_java_use_fq_class_names = false 294 | ij_java_use_relative_indents = false 295 | ij_java_use_single_class_imports = true 296 | ij_java_variable_annotation_wrap = off 297 | ij_java_visibility = public 298 | ij_java_while_brace_force = always 299 | ij_java_while_on_new_line = false 300 | ij_java_wrap_comments = true 301 | ij_java_wrap_first_method_in_call_chain = false 302 | ij_java_wrap_long_lines = false 303 | 304 | [*.less] 305 | indent_size = 2 306 | ij_less_align_closing_brace_with_properties = false 307 | ij_less_blank_lines_around_nested_selector = 1 308 | ij_less_blank_lines_between_blocks = 1 309 | ij_less_block_comment_add_space = false 310 | ij_less_brace_placement = 0 311 | ij_less_enforce_quotes_on_format = false 312 | ij_less_hex_color_long_format = false 313 | ij_less_hex_color_lower_case = false 314 | ij_less_hex_color_short_format = false 315 | ij_less_hex_color_upper_case = false 316 | ij_less_keep_blank_lines_in_code = 2 317 | ij_less_keep_indents_on_empty_lines = false 318 | ij_less_keep_single_line_blocks = false 319 | ij_less_line_comment_add_space = false 320 | ij_less_line_comment_at_first_column = false 321 | 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 322 | ij_less_space_after_colon = true 323 | ij_less_space_before_opening_brace = true 324 | ij_less_use_double_quotes = true 325 | ij_less_value_alignment = 0 326 | 327 | [*.proto] 328 | indent_size = 2 329 | tab_width = 2 330 | ij_continuation_indent_size = 4 331 | ij_protobuf_keep_blank_lines_in_code = 2 332 | ij_protobuf_keep_indents_on_empty_lines = false 333 | ij_protobuf_keep_line_breaks = true 334 | ij_protobuf_space_after_comma = true 335 | ij_protobuf_space_before_comma = false 336 | ij_protobuf_spaces_around_assignment_operators = true 337 | ij_protobuf_spaces_within_braces = false 338 | ij_protobuf_spaces_within_brackets = false 339 | 340 | [*.sass] 341 | indent_size = 2 342 | ij_sass_align_closing_brace_with_properties = false 343 | ij_sass_blank_lines_around_nested_selector = 1 344 | ij_sass_blank_lines_between_blocks = 1 345 | ij_sass_brace_placement = 0 346 | ij_sass_enforce_quotes_on_format = false 347 | ij_sass_hex_color_long_format = false 348 | ij_sass_hex_color_lower_case = false 349 | ij_sass_hex_color_short_format = false 350 | ij_sass_hex_color_upper_case = false 351 | ij_sass_keep_blank_lines_in_code = 2 352 | ij_sass_keep_indents_on_empty_lines = false 353 | ij_sass_keep_single_line_blocks = false 354 | ij_sass_line_comment_add_space = false 355 | ij_sass_line_comment_at_first_column = false 356 | 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 357 | ij_sass_space_after_colon = true 358 | ij_sass_space_before_opening_brace = true 359 | ij_sass_use_double_quotes = true 360 | ij_sass_value_alignment = 0 361 | 362 | [*.scss] 363 | indent_size = 2 364 | ij_scss_align_closing_brace_with_properties = false 365 | ij_scss_blank_lines_around_nested_selector = 1 366 | ij_scss_blank_lines_between_blocks = 1 367 | ij_scss_block_comment_add_space = false 368 | ij_scss_brace_placement = 0 369 | ij_scss_enforce_quotes_on_format = false 370 | ij_scss_hex_color_long_format = false 371 | ij_scss_hex_color_lower_case = false 372 | ij_scss_hex_color_short_format = false 373 | ij_scss_hex_color_upper_case = false 374 | ij_scss_keep_blank_lines_in_code = 2 375 | ij_scss_keep_indents_on_empty_lines = false 376 | ij_scss_keep_single_line_blocks = false 377 | ij_scss_line_comment_add_space = false 378 | ij_scss_line_comment_at_first_column = false 379 | 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 380 | ij_scss_space_after_colon = true 381 | ij_scss_space_before_opening_brace = true 382 | ij_scss_use_double_quotes = true 383 | ij_scss_value_alignment = 0 384 | 385 | [*.styl] 386 | indent_size = 2 387 | ij_stylus_align_closing_brace_with_properties = false 388 | ij_stylus_blank_lines_around_nested_selector = 1 389 | ij_stylus_blank_lines_between_blocks = 1 390 | ij_stylus_brace_placement = 0 391 | ij_stylus_enforce_quotes_on_format = false 392 | ij_stylus_hex_color_long_format = false 393 | ij_stylus_hex_color_lower_case = false 394 | ij_stylus_hex_color_short_format = false 395 | ij_stylus_hex_color_upper_case = false 396 | ij_stylus_keep_blank_lines_in_code = 2 397 | ij_stylus_keep_indents_on_empty_lines = false 398 | ij_stylus_keep_single_line_blocks = false 399 | 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 400 | ij_stylus_space_after_colon = true 401 | ij_stylus_space_before_opening_brace = true 402 | ij_stylus_use_double_quotes = true 403 | ij_stylus_value_alignment = 0 404 | 405 | [.editorconfig] 406 | ij_editorconfig_align_group_field_declarations = false 407 | ij_editorconfig_space_after_colon = false 408 | ij_editorconfig_space_after_comma = true 409 | ij_editorconfig_space_before_colon = false 410 | ij_editorconfig_space_before_comma = false 411 | ij_editorconfig_spaces_around_assignment_operators = true 412 | 413 | [{*.ad,*.adoc,*.asciidoc,.asciidoctorconfig}] 414 | ij_asciidoc_blank_lines_after_header = 1 415 | ij_asciidoc_blank_lines_keep_after_header = 1 416 | ij_asciidoc_formatting_enabled = true 417 | ij_asciidoc_one_sentence_per_line = true 418 | 419 | [{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.pom,*.rng,*.tld,*.wadl,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul}] 420 | ij_xml_align_attributes = true 421 | ij_xml_align_text = false 422 | ij_xml_attribute_wrap = normal 423 | ij_xml_block_comment_add_space = false 424 | ij_xml_block_comment_at_first_column = true 425 | ij_xml_keep_blank_lines = 2 426 | ij_xml_keep_indents_on_empty_lines = false 427 | ij_xml_keep_line_breaks = true 428 | ij_xml_keep_line_breaks_in_text = true 429 | ij_xml_keep_whitespaces = false 430 | ij_xml_keep_whitespaces_around_cdata = preserve 431 | ij_xml_keep_whitespaces_inside_cdata = false 432 | ij_xml_line_comment_at_first_column = true 433 | ij_xml_space_after_tag_name = false 434 | ij_xml_space_around_equals_in_attribute = false 435 | ij_xml_space_inside_empty_tag = false 436 | ij_xml_text_wrap = normal 437 | ij_xml_use_custom_settings = false 438 | 439 | [{*.ats,*.cts,*.mts,*.ts}] 440 | ij_continuation_indent_size = 4 441 | ij_typescript_align_imports = false 442 | ij_typescript_align_multiline_array_initializer_expression = false 443 | ij_typescript_align_multiline_binary_operation = false 444 | ij_typescript_align_multiline_chained_methods = false 445 | ij_typescript_align_multiline_extends_list = false 446 | ij_typescript_align_multiline_for = true 447 | ij_typescript_align_multiline_parameters = true 448 | ij_typescript_align_multiline_parameters_in_calls = false 449 | ij_typescript_align_multiline_ternary_operation = false 450 | ij_typescript_align_object_properties = 0 451 | ij_typescript_align_union_types = false 452 | ij_typescript_align_var_statements = 0 453 | ij_typescript_array_initializer_new_line_after_left_brace = false 454 | ij_typescript_array_initializer_right_brace_on_new_line = false 455 | ij_typescript_array_initializer_wrap = off 456 | ij_typescript_assignment_wrap = off 457 | ij_typescript_binary_operation_sign_on_next_line = false 458 | ij_typescript_binary_operation_wrap = off 459 | ij_typescript_blacklist_imports = rxjs/Rx, node_modules/**, **/node_modules/**, @angular/material, @angular/material/typings/** 460 | ij_typescript_blank_lines_after_imports = 1 461 | ij_typescript_blank_lines_around_class = 1 462 | ij_typescript_blank_lines_around_field = 0 463 | ij_typescript_blank_lines_around_field_in_interface = 0 464 | ij_typescript_blank_lines_around_function = 1 465 | ij_typescript_blank_lines_around_method = 1 466 | ij_typescript_blank_lines_around_method_in_interface = 1 467 | ij_typescript_block_brace_style = end_of_line 468 | ij_typescript_block_comment_add_space = false 469 | ij_typescript_block_comment_at_first_column = true 470 | ij_typescript_call_parameters_new_line_after_left_paren = false 471 | ij_typescript_call_parameters_right_paren_on_new_line = false 472 | ij_typescript_call_parameters_wrap = off 473 | ij_typescript_catch_on_new_line = false 474 | ij_typescript_chained_call_dot_on_new_line = true 475 | ij_typescript_class_brace_style = end_of_line 476 | ij_typescript_comma_on_new_line = false 477 | ij_typescript_do_while_brace_force = never 478 | ij_typescript_else_on_new_line = false 479 | ij_typescript_enforce_trailing_comma = keep 480 | ij_typescript_enum_constants_wrap = on_every_item 481 | ij_typescript_extends_keyword_wrap = off 482 | ij_typescript_extends_list_wrap = off 483 | ij_typescript_field_prefix = _ 484 | ij_typescript_file_name_style = relaxed 485 | ij_typescript_finally_on_new_line = false 486 | ij_typescript_for_brace_force = never 487 | ij_typescript_for_statement_new_line_after_left_paren = false 488 | ij_typescript_for_statement_right_paren_on_new_line = false 489 | ij_typescript_for_statement_wrap = off 490 | ij_typescript_force_quote_style = false 491 | ij_typescript_force_semicolon_style = false 492 | ij_typescript_function_expression_brace_style = end_of_line 493 | ij_typescript_if_brace_force = never 494 | ij_typescript_import_merge_members = global 495 | ij_typescript_import_prefer_absolute_path = global 496 | ij_typescript_import_sort_members = true 497 | ij_typescript_import_sort_module_name = false 498 | ij_typescript_import_use_node_resolution = true 499 | ij_typescript_imports_wrap = on_every_item 500 | ij_typescript_indent_case_from_switch = true 501 | ij_typescript_indent_chained_calls = true 502 | ij_typescript_indent_package_children = 0 503 | ij_typescript_jsdoc_include_types = false 504 | ij_typescript_jsx_attribute_value = braces 505 | ij_typescript_keep_blank_lines_in_code = 2 506 | ij_typescript_keep_first_column_comment = true 507 | ij_typescript_keep_indents_on_empty_lines = false 508 | ij_typescript_keep_line_breaks = true 509 | ij_typescript_keep_simple_blocks_in_one_line = false 510 | ij_typescript_keep_simple_methods_in_one_line = false 511 | ij_typescript_line_comment_add_space = true 512 | ij_typescript_line_comment_at_first_column = false 513 | ij_typescript_method_brace_style = end_of_line 514 | ij_typescript_method_call_chain_wrap = off 515 | ij_typescript_method_parameters_new_line_after_left_paren = false 516 | ij_typescript_method_parameters_right_paren_on_new_line = false 517 | ij_typescript_method_parameters_wrap = off 518 | ij_typescript_object_literal_wrap = on_every_item 519 | ij_typescript_parentheses_expression_new_line_after_left_paren = false 520 | ij_typescript_parentheses_expression_right_paren_on_new_line = false 521 | ij_typescript_place_assignment_sign_on_next_line = false 522 | ij_typescript_prefer_as_type_cast = false 523 | ij_typescript_prefer_explicit_types_function_expression_returns = false 524 | ij_typescript_prefer_explicit_types_function_returns = false 525 | ij_typescript_prefer_explicit_types_vars_fields = false 526 | ij_typescript_prefer_parameters_wrap = false 527 | ij_typescript_reformat_c_style_comments = false 528 | ij_typescript_space_after_colon = true 529 | ij_typescript_space_after_comma = true 530 | ij_typescript_space_after_dots_in_rest_parameter = false 531 | ij_typescript_space_after_generator_mult = true 532 | ij_typescript_space_after_property_colon = true 533 | ij_typescript_space_after_quest = true 534 | ij_typescript_space_after_type_colon = true 535 | ij_typescript_space_after_unary_not = false 536 | ij_typescript_space_before_async_arrow_lparen = true 537 | ij_typescript_space_before_catch_keyword = true 538 | ij_typescript_space_before_catch_left_brace = true 539 | ij_typescript_space_before_catch_parentheses = true 540 | ij_typescript_space_before_class_lbrace = true 541 | ij_typescript_space_before_class_left_brace = true 542 | ij_typescript_space_before_colon = true 543 | ij_typescript_space_before_comma = false 544 | ij_typescript_space_before_do_left_brace = true 545 | ij_typescript_space_before_else_keyword = true 546 | ij_typescript_space_before_else_left_brace = true 547 | ij_typescript_space_before_finally_keyword = true 548 | ij_typescript_space_before_finally_left_brace = true 549 | ij_typescript_space_before_for_left_brace = true 550 | ij_typescript_space_before_for_parentheses = true 551 | ij_typescript_space_before_for_semicolon = false 552 | ij_typescript_space_before_function_left_parenth = true 553 | ij_typescript_space_before_generator_mult = false 554 | ij_typescript_space_before_if_left_brace = true 555 | ij_typescript_space_before_if_parentheses = true 556 | ij_typescript_space_before_method_call_parentheses = false 557 | ij_typescript_space_before_method_left_brace = true 558 | ij_typescript_space_before_method_parentheses = false 559 | ij_typescript_space_before_property_colon = false 560 | ij_typescript_space_before_quest = true 561 | ij_typescript_space_before_switch_left_brace = true 562 | ij_typescript_space_before_switch_parentheses = true 563 | ij_typescript_space_before_try_left_brace = true 564 | ij_typescript_space_before_type_colon = false 565 | ij_typescript_space_before_unary_not = false 566 | ij_typescript_space_before_while_keyword = true 567 | ij_typescript_space_before_while_left_brace = true 568 | ij_typescript_space_before_while_parentheses = true 569 | ij_typescript_spaces_around_additive_operators = true 570 | ij_typescript_spaces_around_arrow_function_operator = true 571 | ij_typescript_spaces_around_assignment_operators = true 572 | ij_typescript_spaces_around_bitwise_operators = true 573 | ij_typescript_spaces_around_equality_operators = true 574 | ij_typescript_spaces_around_logical_operators = true 575 | ij_typescript_spaces_around_multiplicative_operators = true 576 | ij_typescript_spaces_around_relational_operators = true 577 | ij_typescript_spaces_around_shift_operators = true 578 | ij_typescript_spaces_around_unary_operator = false 579 | ij_typescript_spaces_within_array_initializer_brackets = false 580 | ij_typescript_spaces_within_brackets = false 581 | ij_typescript_spaces_within_catch_parentheses = false 582 | ij_typescript_spaces_within_for_parentheses = false 583 | ij_typescript_spaces_within_if_parentheses = false 584 | ij_typescript_spaces_within_imports = false 585 | ij_typescript_spaces_within_interpolation_expressions = false 586 | ij_typescript_spaces_within_method_call_parentheses = false 587 | ij_typescript_spaces_within_method_parentheses = false 588 | ij_typescript_spaces_within_object_literal_braces = false 589 | ij_typescript_spaces_within_object_type_braces = true 590 | ij_typescript_spaces_within_parentheses = false 591 | ij_typescript_spaces_within_switch_parentheses = false 592 | ij_typescript_spaces_within_type_assertion = false 593 | ij_typescript_spaces_within_union_types = true 594 | ij_typescript_spaces_within_while_parentheses = false 595 | ij_typescript_special_else_if_treatment = true 596 | ij_typescript_ternary_operation_signs_on_next_line = false 597 | ij_typescript_ternary_operation_wrap = off 598 | ij_typescript_union_types_wrap = on_every_item 599 | ij_typescript_use_chained_calls_group_indents = false 600 | ij_typescript_use_double_quotes = true 601 | ij_typescript_use_explicit_js_extension = auto 602 | ij_typescript_use_path_mapping = always 603 | ij_typescript_use_public_modifier = false 604 | ij_typescript_use_semicolon_after_statement = true 605 | ij_typescript_var_declaration_wrap = normal 606 | ij_typescript_while_brace_force = never 607 | ij_typescript_while_on_new_line = false 608 | ij_typescript_wrap_comments = false 609 | 610 | [{*.bash,*.sh,*.zsh}] 611 | indent_size = 2 612 | tab_width = 2 613 | ij_shell_binary_ops_start_line = false 614 | ij_shell_keep_column_alignment_padding = false 615 | ij_shell_minify_program = false 616 | ij_shell_redirect_followed_by_space = false 617 | ij_shell_switch_cases_indented = false 618 | ij_shell_use_unix_line_separator = true 619 | 620 | [{*.cjs,*.js}] 621 | ij_continuation_indent_size = 4 622 | ij_javascript_align_imports = false 623 | ij_javascript_align_multiline_array_initializer_expression = false 624 | ij_javascript_align_multiline_binary_operation = false 625 | ij_javascript_align_multiline_chained_methods = false 626 | ij_javascript_align_multiline_extends_list = false 627 | ij_javascript_align_multiline_for = true 628 | ij_javascript_align_multiline_parameters = true 629 | ij_javascript_align_multiline_parameters_in_calls = false 630 | ij_javascript_align_multiline_ternary_operation = false 631 | ij_javascript_align_object_properties = 0 632 | ij_javascript_align_union_types = false 633 | ij_javascript_align_var_statements = 0 634 | ij_javascript_array_initializer_new_line_after_left_brace = false 635 | ij_javascript_array_initializer_right_brace_on_new_line = false 636 | ij_javascript_array_initializer_wrap = off 637 | ij_javascript_assignment_wrap = off 638 | ij_javascript_binary_operation_sign_on_next_line = false 639 | ij_javascript_binary_operation_wrap = off 640 | ij_javascript_blacklist_imports = rxjs/Rx, node_modules/**, **/node_modules/**, @angular/material, @angular/material/typings/** 641 | ij_javascript_blank_lines_after_imports = 1 642 | ij_javascript_blank_lines_around_class = 1 643 | ij_javascript_blank_lines_around_field = 0 644 | ij_javascript_blank_lines_around_function = 1 645 | ij_javascript_blank_lines_around_method = 1 646 | ij_javascript_block_brace_style = end_of_line 647 | ij_javascript_block_comment_add_space = false 648 | ij_javascript_block_comment_at_first_column = true 649 | ij_javascript_call_parameters_new_line_after_left_paren = false 650 | ij_javascript_call_parameters_right_paren_on_new_line = false 651 | ij_javascript_call_parameters_wrap = off 652 | ij_javascript_catch_on_new_line = false 653 | ij_javascript_chained_call_dot_on_new_line = true 654 | ij_javascript_class_brace_style = end_of_line 655 | ij_javascript_comma_on_new_line = false 656 | ij_javascript_do_while_brace_force = never 657 | ij_javascript_else_on_new_line = false 658 | ij_javascript_enforce_trailing_comma = keep 659 | ij_javascript_extends_keyword_wrap = off 660 | ij_javascript_extends_list_wrap = off 661 | ij_javascript_field_prefix = _ 662 | ij_javascript_file_name_style = relaxed 663 | ij_javascript_finally_on_new_line = false 664 | ij_javascript_for_brace_force = never 665 | ij_javascript_for_statement_new_line_after_left_paren = false 666 | ij_javascript_for_statement_right_paren_on_new_line = false 667 | ij_javascript_for_statement_wrap = off 668 | ij_javascript_force_quote_style = false 669 | ij_javascript_force_semicolon_style = false 670 | ij_javascript_function_expression_brace_style = end_of_line 671 | ij_javascript_if_brace_force = never 672 | ij_javascript_import_merge_members = global 673 | ij_javascript_import_prefer_absolute_path = global 674 | ij_javascript_import_sort_members = true 675 | ij_javascript_import_sort_module_name = false 676 | ij_javascript_import_use_node_resolution = true 677 | ij_javascript_imports_wrap = on_every_item 678 | ij_javascript_indent_case_from_switch = true 679 | ij_javascript_indent_chained_calls = true 680 | ij_javascript_indent_package_children = 0 681 | ij_javascript_jsx_attribute_value = braces 682 | ij_javascript_keep_blank_lines_in_code = 2 683 | ij_javascript_keep_first_column_comment = true 684 | ij_javascript_keep_indents_on_empty_lines = false 685 | ij_javascript_keep_line_breaks = true 686 | ij_javascript_keep_simple_blocks_in_one_line = false 687 | ij_javascript_keep_simple_methods_in_one_line = false 688 | ij_javascript_line_comment_add_space = true 689 | ij_javascript_line_comment_at_first_column = false 690 | ij_javascript_method_brace_style = end_of_line 691 | ij_javascript_method_call_chain_wrap = off 692 | ij_javascript_method_parameters_new_line_after_left_paren = false 693 | ij_javascript_method_parameters_right_paren_on_new_line = false 694 | ij_javascript_method_parameters_wrap = off 695 | ij_javascript_object_literal_wrap = on_every_item 696 | ij_javascript_parentheses_expression_new_line_after_left_paren = false 697 | ij_javascript_parentheses_expression_right_paren_on_new_line = false 698 | ij_javascript_place_assignment_sign_on_next_line = false 699 | ij_javascript_prefer_as_type_cast = false 700 | ij_javascript_prefer_explicit_types_function_expression_returns = false 701 | ij_javascript_prefer_explicit_types_function_returns = false 702 | ij_javascript_prefer_explicit_types_vars_fields = false 703 | ij_javascript_prefer_parameters_wrap = false 704 | ij_javascript_reformat_c_style_comments = false 705 | ij_javascript_space_after_colon = true 706 | ij_javascript_space_after_comma = true 707 | ij_javascript_space_after_dots_in_rest_parameter = false 708 | ij_javascript_space_after_generator_mult = true 709 | ij_javascript_space_after_property_colon = true 710 | ij_javascript_space_after_quest = true 711 | ij_javascript_space_after_type_colon = true 712 | ij_javascript_space_after_unary_not = false 713 | ij_javascript_space_before_async_arrow_lparen = true 714 | ij_javascript_space_before_catch_keyword = true 715 | ij_javascript_space_before_catch_left_brace = true 716 | ij_javascript_space_before_catch_parentheses = true 717 | ij_javascript_space_before_class_lbrace = true 718 | ij_javascript_space_before_class_left_brace = true 719 | ij_javascript_space_before_colon = true 720 | ij_javascript_space_before_comma = false 721 | ij_javascript_space_before_do_left_brace = true 722 | ij_javascript_space_before_else_keyword = true 723 | ij_javascript_space_before_else_left_brace = true 724 | ij_javascript_space_before_finally_keyword = true 725 | ij_javascript_space_before_finally_left_brace = true 726 | ij_javascript_space_before_for_left_brace = true 727 | ij_javascript_space_before_for_parentheses = true 728 | ij_javascript_space_before_for_semicolon = false 729 | ij_javascript_space_before_function_left_parenth = true 730 | ij_javascript_space_before_generator_mult = false 731 | ij_javascript_space_before_if_left_brace = true 732 | ij_javascript_space_before_if_parentheses = true 733 | ij_javascript_space_before_method_call_parentheses = false 734 | ij_javascript_space_before_method_left_brace = true 735 | ij_javascript_space_before_method_parentheses = false 736 | ij_javascript_space_before_property_colon = false 737 | ij_javascript_space_before_quest = true 738 | ij_javascript_space_before_switch_left_brace = true 739 | ij_javascript_space_before_switch_parentheses = true 740 | ij_javascript_space_before_try_left_brace = true 741 | ij_javascript_space_before_type_colon = false 742 | ij_javascript_space_before_unary_not = false 743 | ij_javascript_space_before_while_keyword = true 744 | ij_javascript_space_before_while_left_brace = true 745 | ij_javascript_space_before_while_parentheses = true 746 | ij_javascript_spaces_around_additive_operators = true 747 | ij_javascript_spaces_around_arrow_function_operator = true 748 | ij_javascript_spaces_around_assignment_operators = true 749 | ij_javascript_spaces_around_bitwise_operators = true 750 | ij_javascript_spaces_around_equality_operators = true 751 | ij_javascript_spaces_around_logical_operators = true 752 | ij_javascript_spaces_around_multiplicative_operators = true 753 | ij_javascript_spaces_around_relational_operators = true 754 | ij_javascript_spaces_around_shift_operators = true 755 | ij_javascript_spaces_around_unary_operator = false 756 | ij_javascript_spaces_within_array_initializer_brackets = false 757 | ij_javascript_spaces_within_brackets = false 758 | ij_javascript_spaces_within_catch_parentheses = false 759 | ij_javascript_spaces_within_for_parentheses = false 760 | ij_javascript_spaces_within_if_parentheses = false 761 | ij_javascript_spaces_within_imports = false 762 | ij_javascript_spaces_within_interpolation_expressions = false 763 | ij_javascript_spaces_within_method_call_parentheses = false 764 | ij_javascript_spaces_within_method_parentheses = false 765 | ij_javascript_spaces_within_object_literal_braces = false 766 | ij_javascript_spaces_within_object_type_braces = true 767 | ij_javascript_spaces_within_parentheses = false 768 | ij_javascript_spaces_within_switch_parentheses = false 769 | ij_javascript_spaces_within_type_assertion = false 770 | ij_javascript_spaces_within_union_types = true 771 | ij_javascript_spaces_within_while_parentheses = false 772 | ij_javascript_special_else_if_treatment = true 773 | ij_javascript_ternary_operation_signs_on_next_line = false 774 | ij_javascript_ternary_operation_wrap = off 775 | ij_javascript_union_types_wrap = on_every_item 776 | ij_javascript_use_chained_calls_group_indents = false 777 | ij_javascript_use_double_quotes = true 778 | ij_javascript_use_explicit_js_extension = auto 779 | ij_javascript_use_path_mapping = always 780 | ij_javascript_use_public_modifier = false 781 | ij_javascript_use_semicolon_after_statement = true 782 | ij_javascript_var_declaration_wrap = normal 783 | ij_javascript_while_brace_force = never 784 | ij_javascript_while_on_new_line = false 785 | ij_javascript_wrap_comments = false 786 | 787 | [{*.ft,*.vm,*.vsl}] 788 | ij_vtl_keep_indents_on_empty_lines = false 789 | 790 | [{*.gant,*.groovy,*.gy}] 791 | ij_groovy_align_group_field_declarations = false 792 | ij_groovy_align_multiline_array_initializer_expression = false 793 | ij_groovy_align_multiline_assignment = false 794 | ij_groovy_align_multiline_binary_operation = false 795 | ij_groovy_align_multiline_chained_methods = false 796 | ij_groovy_align_multiline_extends_list = false 797 | ij_groovy_align_multiline_for = true 798 | ij_groovy_align_multiline_list_or_map = true 799 | ij_groovy_align_multiline_method_parentheses = false 800 | ij_groovy_align_multiline_parameters = true 801 | ij_groovy_align_multiline_parameters_in_calls = false 802 | ij_groovy_align_multiline_resources = true 803 | ij_groovy_align_multiline_ternary_operation = false 804 | ij_groovy_align_multiline_throws_list = false 805 | ij_groovy_align_named_args_in_map = true 806 | ij_groovy_align_throws_keyword = false 807 | ij_groovy_array_initializer_new_line_after_left_brace = false 808 | ij_groovy_array_initializer_right_brace_on_new_line = false 809 | ij_groovy_array_initializer_wrap = off 810 | ij_groovy_assert_statement_wrap = off 811 | ij_groovy_assignment_wrap = off 812 | ij_groovy_binary_operation_wrap = off 813 | ij_groovy_blank_lines_after_class_header = 0 814 | ij_groovy_blank_lines_after_imports = 1 815 | ij_groovy_blank_lines_after_package = 1 816 | ij_groovy_blank_lines_around_class = 1 817 | ij_groovy_blank_lines_around_field = 0 818 | ij_groovy_blank_lines_around_field_in_interface = 0 819 | ij_groovy_blank_lines_around_method = 1 820 | ij_groovy_blank_lines_around_method_in_interface = 1 821 | ij_groovy_blank_lines_before_imports = 1 822 | ij_groovy_blank_lines_before_method_body = 0 823 | ij_groovy_blank_lines_before_package = 0 824 | ij_groovy_block_brace_style = end_of_line 825 | ij_groovy_block_comment_add_space = false 826 | ij_groovy_block_comment_at_first_column = true 827 | ij_groovy_call_parameters_new_line_after_left_paren = false 828 | ij_groovy_call_parameters_right_paren_on_new_line = false 829 | ij_groovy_call_parameters_wrap = off 830 | ij_groovy_catch_on_new_line = false 831 | ij_groovy_class_annotation_wrap = split_into_lines 832 | ij_groovy_class_brace_style = end_of_line 833 | ij_groovy_class_count_to_use_import_on_demand = 5 834 | ij_groovy_do_while_brace_force = never 835 | ij_groovy_else_on_new_line = false 836 | ij_groovy_enable_groovydoc_formatting = true 837 | ij_groovy_enum_constants_wrap = off 838 | ij_groovy_extends_keyword_wrap = off 839 | ij_groovy_extends_list_wrap = off 840 | ij_groovy_field_annotation_wrap = split_into_lines 841 | ij_groovy_finally_on_new_line = false 842 | ij_groovy_for_brace_force = never 843 | ij_groovy_for_statement_new_line_after_left_paren = false 844 | ij_groovy_for_statement_right_paren_on_new_line = false 845 | ij_groovy_for_statement_wrap = off 846 | ij_groovy_if_brace_force = never 847 | ij_groovy_import_annotation_wrap = 2 848 | ij_groovy_imports_layout = *, |, javax.**, java.**, |, $* 849 | ij_groovy_indent_case_from_switch = true 850 | ij_groovy_indent_label_blocks = true 851 | ij_groovy_insert_inner_class_imports = false 852 | ij_groovy_keep_blank_lines_before_right_brace = 2 853 | ij_groovy_keep_blank_lines_in_code = 2 854 | ij_groovy_keep_blank_lines_in_declarations = 2 855 | ij_groovy_keep_control_statement_in_one_line = true 856 | ij_groovy_keep_first_column_comment = true 857 | ij_groovy_keep_indents_on_empty_lines = false 858 | ij_groovy_keep_line_breaks = true 859 | ij_groovy_keep_multiple_expressions_in_one_line = false 860 | ij_groovy_keep_simple_blocks_in_one_line = false 861 | ij_groovy_keep_simple_classes_in_one_line = true 862 | ij_groovy_keep_simple_lambdas_in_one_line = true 863 | ij_groovy_keep_simple_methods_in_one_line = true 864 | ij_groovy_label_indent_absolute = false 865 | ij_groovy_label_indent_size = 0 866 | ij_groovy_lambda_brace_style = end_of_line 867 | ij_groovy_layout_static_imports_separately = true 868 | ij_groovy_line_comment_add_space = false 869 | ij_groovy_line_comment_add_space_on_reformat = false 870 | ij_groovy_line_comment_at_first_column = true 871 | ij_groovy_method_annotation_wrap = split_into_lines 872 | ij_groovy_method_brace_style = end_of_line 873 | ij_groovy_method_call_chain_wrap = off 874 | ij_groovy_method_parameters_new_line_after_left_paren = false 875 | ij_groovy_method_parameters_right_paren_on_new_line = false 876 | ij_groovy_method_parameters_wrap = off 877 | ij_groovy_modifier_list_wrap = false 878 | ij_groovy_names_count_to_use_import_on_demand = 3 879 | ij_groovy_packages_to_use_import_on_demand = java.awt.*, javax.swing.* 880 | ij_groovy_parameter_annotation_wrap = off 881 | ij_groovy_parentheses_expression_new_line_after_left_paren = false 882 | ij_groovy_parentheses_expression_right_paren_on_new_line = false 883 | ij_groovy_prefer_parameters_wrap = false 884 | ij_groovy_resource_list_new_line_after_left_paren = false 885 | ij_groovy_resource_list_right_paren_on_new_line = false 886 | ij_groovy_resource_list_wrap = off 887 | ij_groovy_space_after_assert_separator = true 888 | ij_groovy_space_after_colon = true 889 | ij_groovy_space_after_comma = true 890 | ij_groovy_space_after_comma_in_type_arguments = true 891 | ij_groovy_space_after_for_semicolon = true 892 | ij_groovy_space_after_quest = true 893 | ij_groovy_space_after_type_cast = true 894 | ij_groovy_space_before_annotation_parameter_list = false 895 | ij_groovy_space_before_array_initializer_left_brace = false 896 | ij_groovy_space_before_assert_separator = false 897 | ij_groovy_space_before_catch_keyword = true 898 | ij_groovy_space_before_catch_left_brace = true 899 | ij_groovy_space_before_catch_parentheses = true 900 | ij_groovy_space_before_class_left_brace = true 901 | ij_groovy_space_before_closure_left_brace = true 902 | ij_groovy_space_before_colon = true 903 | ij_groovy_space_before_comma = false 904 | ij_groovy_space_before_do_left_brace = true 905 | ij_groovy_space_before_else_keyword = true 906 | ij_groovy_space_before_else_left_brace = true 907 | ij_groovy_space_before_finally_keyword = true 908 | ij_groovy_space_before_finally_left_brace = true 909 | ij_groovy_space_before_for_left_brace = true 910 | ij_groovy_space_before_for_parentheses = true 911 | ij_groovy_space_before_for_semicolon = false 912 | ij_groovy_space_before_if_left_brace = true 913 | ij_groovy_space_before_if_parentheses = true 914 | ij_groovy_space_before_method_call_parentheses = false 915 | ij_groovy_space_before_method_left_brace = true 916 | ij_groovy_space_before_method_parentheses = false 917 | ij_groovy_space_before_quest = true 918 | ij_groovy_space_before_record_parentheses = false 919 | ij_groovy_space_before_switch_left_brace = true 920 | ij_groovy_space_before_switch_parentheses = true 921 | ij_groovy_space_before_synchronized_left_brace = true 922 | ij_groovy_space_before_synchronized_parentheses = true 923 | ij_groovy_space_before_try_left_brace = true 924 | ij_groovy_space_before_try_parentheses = true 925 | ij_groovy_space_before_while_keyword = true 926 | ij_groovy_space_before_while_left_brace = true 927 | ij_groovy_space_before_while_parentheses = true 928 | ij_groovy_space_in_named_argument = true 929 | ij_groovy_space_in_named_argument_before_colon = false 930 | ij_groovy_space_within_empty_array_initializer_braces = false 931 | ij_groovy_space_within_empty_method_call_parentheses = false 932 | ij_groovy_spaces_around_additive_operators = true 933 | ij_groovy_spaces_around_assignment_operators = true 934 | ij_groovy_spaces_around_bitwise_operators = true 935 | ij_groovy_spaces_around_equality_operators = true 936 | ij_groovy_spaces_around_lambda_arrow = true 937 | ij_groovy_spaces_around_logical_operators = true 938 | ij_groovy_spaces_around_multiplicative_operators = true 939 | ij_groovy_spaces_around_regex_operators = true 940 | ij_groovy_spaces_around_relational_operators = true 941 | ij_groovy_spaces_around_shift_operators = true 942 | ij_groovy_spaces_within_annotation_parentheses = false 943 | ij_groovy_spaces_within_array_initializer_braces = false 944 | ij_groovy_spaces_within_braces = true 945 | ij_groovy_spaces_within_brackets = false 946 | ij_groovy_spaces_within_cast_parentheses = false 947 | ij_groovy_spaces_within_catch_parentheses = false 948 | ij_groovy_spaces_within_for_parentheses = false 949 | ij_groovy_spaces_within_gstring_injection_braces = false 950 | ij_groovy_spaces_within_if_parentheses = false 951 | ij_groovy_spaces_within_list_or_map = false 952 | ij_groovy_spaces_within_method_call_parentheses = false 953 | ij_groovy_spaces_within_method_parentheses = false 954 | ij_groovy_spaces_within_parentheses = false 955 | ij_groovy_spaces_within_switch_parentheses = false 956 | ij_groovy_spaces_within_synchronized_parentheses = false 957 | ij_groovy_spaces_within_try_parentheses = false 958 | ij_groovy_spaces_within_tuple_expression = false 959 | ij_groovy_spaces_within_while_parentheses = false 960 | ij_groovy_special_else_if_treatment = true 961 | ij_groovy_ternary_operation_wrap = off 962 | ij_groovy_throws_keyword_wrap = off 963 | ij_groovy_throws_list_wrap = off 964 | ij_groovy_use_flying_geese_braces = false 965 | ij_groovy_use_fq_class_names = false 966 | ij_groovy_use_fq_class_names_in_javadoc = true 967 | ij_groovy_use_relative_indents = false 968 | ij_groovy_use_single_class_imports = true 969 | ij_groovy_variable_annotation_wrap = off 970 | ij_groovy_while_brace_force = never 971 | ij_groovy_while_on_new_line = false 972 | ij_groovy_wrap_chain_calls_after_dot = false 973 | ij_groovy_wrap_long_lines = false 974 | 975 | [{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.stylelintrc,bowerrc,jest.config}] 976 | indent_size = 2 977 | ij_json_keep_blank_lines_in_code = 0 978 | ij_json_keep_indents_on_empty_lines = false 979 | ij_json_keep_line_breaks = true 980 | ij_json_space_after_colon = true 981 | ij_json_space_after_comma = true 982 | ij_json_space_before_colon = true 983 | ij_json_space_before_comma = false 984 | ij_json_spaces_within_braces = false 985 | ij_json_spaces_within_brackets = false 986 | ij_json_wrap_long_lines = false 987 | 988 | [{*.htm,*.html,*.ng,*.sht,*.shtm,*.shtml}] 989 | ij_html_add_new_line_before_tags = body, div, p, form, h1, h2, h3 990 | ij_html_align_attributes = true 991 | ij_html_align_text = false 992 | ij_html_attribute_wrap = normal 993 | ij_html_block_comment_add_space = false 994 | ij_html_block_comment_at_first_column = true 995 | ij_html_do_not_align_children_of_min_lines = 0 996 | ij_html_do_not_break_if_inline_tags = title, h1, h2, h3, h4, h5, h6, p 997 | ij_html_do_not_indent_children_of_tags = html, body, thead, tbody, tfoot 998 | ij_html_enforce_quotes = false 999 | 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 1000 | ij_html_keep_blank_lines = 2 1001 | ij_html_keep_indents_on_empty_lines = false 1002 | ij_html_keep_line_breaks = true 1003 | ij_html_keep_line_breaks_in_text = true 1004 | ij_html_keep_whitespaces = false 1005 | ij_html_keep_whitespaces_inside = span, pre, textarea 1006 | ij_html_line_comment_at_first_column = true 1007 | ij_html_new_line_after_last_attribute = never 1008 | ij_html_new_line_before_first_attribute = never 1009 | ij_html_quote_style = double 1010 | ij_html_remove_new_line_before_tags = br 1011 | ij_html_space_after_tag_name = false 1012 | ij_html_space_around_equality_in_attribute = false 1013 | ij_html_space_inside_empty_tag = false 1014 | ij_html_text_wrap = normal 1015 | 1016 | [{*.jsf,*.jsp,*.jspf,*.tag,*.tagf,*.xjsp}] 1017 | ij_jsp_jsp_prefer_comma_separated_import_list = false 1018 | ij_jsp_keep_indents_on_empty_lines = false 1019 | 1020 | [{*.jspx,*.tagx}] 1021 | ij_jspx_keep_indents_on_empty_lines = false 1022 | 1023 | [{*.kt,*.kts}] 1024 | ij_kotlin_align_in_columns_case_branch = false 1025 | ij_kotlin_align_multiline_binary_operation = false 1026 | ij_kotlin_align_multiline_extends_list = false 1027 | ij_kotlin_align_multiline_method_parentheses = false 1028 | ij_kotlin_align_multiline_parameters = true 1029 | ij_kotlin_align_multiline_parameters_in_calls = false 1030 | ij_kotlin_allow_trailing_comma = false 1031 | ij_kotlin_allow_trailing_comma_on_call_site = false 1032 | ij_kotlin_assignment_wrap = normal 1033 | ij_kotlin_blank_lines_after_class_header = 0 1034 | ij_kotlin_blank_lines_around_block_when_branches = 0 1035 | ij_kotlin_blank_lines_before_declaration_with_comment_or_annotation_on_separate_line = 1 1036 | ij_kotlin_block_comment_add_space = false 1037 | ij_kotlin_block_comment_at_first_column = true 1038 | ij_kotlin_call_parameters_new_line_after_left_paren = true 1039 | ij_kotlin_call_parameters_right_paren_on_new_line = true 1040 | ij_kotlin_call_parameters_wrap = on_every_item 1041 | ij_kotlin_catch_on_new_line = false 1042 | ij_kotlin_class_annotation_wrap = split_into_lines 1043 | ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL 1044 | ij_kotlin_continuation_indent_for_chained_calls = false 1045 | ij_kotlin_continuation_indent_for_expression_bodies = false 1046 | ij_kotlin_continuation_indent_in_argument_lists = false 1047 | ij_kotlin_continuation_indent_in_elvis = false 1048 | ij_kotlin_continuation_indent_in_if_conditions = false 1049 | ij_kotlin_continuation_indent_in_parameter_lists = false 1050 | ij_kotlin_continuation_indent_in_supertype_lists = false 1051 | ij_kotlin_else_on_new_line = false 1052 | ij_kotlin_enum_constants_wrap = off 1053 | ij_kotlin_extends_list_wrap = normal 1054 | ij_kotlin_field_annotation_wrap = split_into_lines 1055 | ij_kotlin_finally_on_new_line = false 1056 | ij_kotlin_if_rparen_on_new_line = true 1057 | ij_kotlin_import_nested_classes = false 1058 | ij_kotlin_imports_layout = *, java.**, javax.**, kotlin.**, ^ 1059 | ij_kotlin_insert_whitespaces_in_simple_one_line_method = true 1060 | ij_kotlin_keep_blank_lines_before_right_brace = 2 1061 | ij_kotlin_keep_blank_lines_in_code = 2 1062 | ij_kotlin_keep_blank_lines_in_declarations = 2 1063 | ij_kotlin_keep_first_column_comment = true 1064 | ij_kotlin_keep_indents_on_empty_lines = false 1065 | ij_kotlin_keep_line_breaks = true 1066 | ij_kotlin_lbrace_on_next_line = false 1067 | ij_kotlin_line_comment_add_space = false 1068 | ij_kotlin_line_comment_add_space_on_reformat = false 1069 | ij_kotlin_line_comment_at_first_column = true 1070 | ij_kotlin_method_annotation_wrap = split_into_lines 1071 | ij_kotlin_method_call_chain_wrap = normal 1072 | ij_kotlin_method_parameters_new_line_after_left_paren = true 1073 | ij_kotlin_method_parameters_right_paren_on_new_line = true 1074 | ij_kotlin_method_parameters_wrap = on_every_item 1075 | ij_kotlin_name_count_to_use_star_import = 2147483647 1076 | ij_kotlin_name_count_to_use_star_import_for_members = 2147483647 1077 | ij_kotlin_packages_to_use_import_on_demand = 1078 | ij_kotlin_parameter_annotation_wrap = off 1079 | ij_kotlin_space_after_comma = true 1080 | ij_kotlin_space_after_extend_colon = true 1081 | ij_kotlin_space_after_type_colon = true 1082 | ij_kotlin_space_before_catch_parentheses = true 1083 | ij_kotlin_space_before_comma = false 1084 | ij_kotlin_space_before_extend_colon = true 1085 | ij_kotlin_space_before_for_parentheses = true 1086 | ij_kotlin_space_before_if_parentheses = true 1087 | ij_kotlin_space_before_lambda_arrow = true 1088 | ij_kotlin_space_before_type_colon = false 1089 | ij_kotlin_space_before_when_parentheses = true 1090 | ij_kotlin_space_before_while_parentheses = true 1091 | ij_kotlin_spaces_around_additive_operators = true 1092 | ij_kotlin_spaces_around_assignment_operators = true 1093 | ij_kotlin_spaces_around_equality_operators = true 1094 | ij_kotlin_spaces_around_function_type_arrow = true 1095 | ij_kotlin_spaces_around_logical_operators = true 1096 | ij_kotlin_spaces_around_multiplicative_operators = true 1097 | ij_kotlin_spaces_around_range = false 1098 | ij_kotlin_spaces_around_relational_operators = true 1099 | ij_kotlin_spaces_around_unary_operator = false 1100 | ij_kotlin_spaces_around_when_arrow = true 1101 | ij_kotlin_variable_annotation_wrap = off 1102 | ij_kotlin_while_on_new_line = false 1103 | ij_kotlin_wrap_elvis_expressions = 1 1104 | ij_kotlin_wrap_expression_body_functions = 1 1105 | ij_kotlin_wrap_first_method_in_call_chain = false 1106 | 1107 | [{*.markdown,*.md}] 1108 | ij_markdown_force_one_space_after_blockquote_symbol = true 1109 | ij_markdown_force_one_space_after_header_symbol = true 1110 | ij_markdown_force_one_space_after_list_bullet = true 1111 | ij_markdown_force_one_space_between_words = true 1112 | ij_markdown_insert_quote_arrows_on_wrap = true 1113 | ij_markdown_keep_indents_on_empty_lines = false 1114 | ij_markdown_keep_line_breaks_inside_text_blocks = true 1115 | ij_markdown_max_lines_around_block_elements = 1 1116 | ij_markdown_max_lines_around_header = 1 1117 | ij_markdown_max_lines_between_paragraphs = 1 1118 | ij_markdown_min_lines_around_block_elements = 1 1119 | ij_markdown_min_lines_around_header = 1 1120 | ij_markdown_min_lines_between_paragraphs = 1 1121 | ij_markdown_wrap_text_if_long = true 1122 | ij_markdown_wrap_text_inside_blockquotes = true 1123 | 1124 | [{*.pb,*.textproto}] 1125 | indent_size = 2 1126 | tab_width = 2 1127 | ij_continuation_indent_size = 4 1128 | ij_prototext_keep_blank_lines_in_code = 2 1129 | ij_prototext_keep_indents_on_empty_lines = false 1130 | ij_prototext_keep_line_breaks = true 1131 | ij_prototext_space_after_colon = true 1132 | ij_prototext_space_after_comma = true 1133 | ij_prototext_space_before_colon = false 1134 | ij_prototext_space_before_comma = false 1135 | ij_prototext_spaces_within_braces = true 1136 | ij_prototext_spaces_within_brackets = false 1137 | 1138 | [{*.properties,spring.handlers,spring.schemas}] 1139 | ij_properties_align_group_field_declarations = false 1140 | ij_properties_keep_blank_lines = false 1141 | ij_properties_key_value_delimiter = equals 1142 | ij_properties_spaces_around_key_value_delimiter = false 1143 | 1144 | [{*.qute.html,*.qute.json,*.qute.txt,*.qute.yaml,*.qute.yml}] 1145 | ij_qute_keep_indents_on_empty_lines = false 1146 | 1147 | [{*.toml,Cargo.lock,Cargo.toml.orig,Gopkg.lock,Pipfile,poetry.lock}] 1148 | ij_toml_keep_indents_on_empty_lines = false 1149 | 1150 | [{*.yaml,*.yml}] 1151 | indent_size = 2 1152 | ij_yaml_align_values_properties = do_not_align 1153 | ij_yaml_autoinsert_sequence_marker = true 1154 | ij_yaml_block_mapping_on_new_line = false 1155 | ij_yaml_indent_sequence_value = true 1156 | ij_yaml_keep_indents_on_empty_lines = false 1157 | ij_yaml_keep_line_breaks = true 1158 | ij_yaml_sequence_on_new_line = false 1159 | ij_yaml_space_before_colon = false 1160 | ij_yaml_spaces_within_braces = true 1161 | ij_yaml_spaces_within_brackets = true 1162 | -------------------------------------------------------------------------------- /.github/workflows/check.yml: -------------------------------------------------------------------------------- 1 | name: CI Check 2 | 3 | on: 4 | push: 5 | branches: [ "**" ] 6 | 7 | jobs: 8 | check: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 13 | - name: Setup Java 14 | uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4 15 | with: 16 | distribution: temurin 17 | java-version: 11 18 | - name: Setup Gradle 19 | uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4 20 | - name: Check 21 | run: ./gradlew check 22 | env: 23 | ORG_GRADLE_PROJECT_dockerHubUsername: ${{ secrets.DOCKER_USERNAME }} 24 | ORG_GRADLE_PROJECT_dockerHubPassword: ${{ secrets.DOCKER_TOKEN }} 25 | -------------------------------------------------------------------------------- /.github/workflows/releaseExtension.yml: -------------------------------------------------------------------------------- 1 | name: Release Extension 2 | 3 | on: 4 | release: 5 | types: [ published ] 6 | 7 | jobs: 8 | release: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 13 | - name: Setup Java 14 | uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4 15 | with: 16 | distribution: temurin 17 | java-version: 11 18 | - name: Setup Gradle 19 | uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4 20 | - name: Build Zip 21 | run: ./gradlew hivemqExtensionZip 22 | - name: Upload GitHub Release Asset 23 | run: gh release upload ${{ github.event.release.tag_name }} ./build/hivemq-extension/hivemq-influxdb-extension-${{ github.event.release.name }}.zip 24 | env: 25 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Gradle 2 | .gradle 3 | build/ 4 | 5 | # IntelliJ 6 | out/ 7 | *.iml 8 | .idea/* 9 | !.idea/codeStyles 10 | !.idea/inspectionProfiles 11 | !.idea/runConfigurations 12 | 13 | .java-version 14 | .DS_Store 15 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 27 | 28 | 324 | 325 | 336 | 337 | 338 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # HiveMQ Code of Conduct 2 | 3 | Please refer to our [HiveMQ Code of Conduct](https://github.com/hivemq/hivemq-community/blob/master/code-of-conduct.md). 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Welcome to the HiveMQ Community! 4 | Glad to see your interest in contributing to HiveMQ InfluxDB Extension. 5 | Please checkout our [Contribution Guide](https://github.com/hivemq/hivemq-community/blob/master/CONTRIBUTING.adoc) to make sure your contribution will be accepted by the HiveMQ team. 6 | 7 | For information on how the HiveMQ Community is organized and how contributions will be accepted please have a look at our [HiveMQ Community Repo](https://github.com/hivemq/hivemq-community). 8 | -------------------------------------------------------------------------------- /HEADER: -------------------------------------------------------------------------------- 1 | Copyright 2018-present HiveMQ GmbH 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2018-present HiveMQ GmbH 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use the contents of this repository except in 5 | compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | :hivemq-link: https://www.hivemq.com 2 | :influxdb-link: https://www.influxdata.com/time-series-platform/influxdb/ 3 | :hivemq-support: {hivemq-link}/support/ 4 | :docker: https://www.docker.com/ 5 | :influxdb-docker: https://hub.docker.com/_/influxdb/ 6 | :download-influxdb-extension: https://www.hivemq.com/products/extensions/influxdb-extension/ 7 | 8 | = HiveMQ InfluxDB Monitoring Extension 9 | 10 | image:https://img.shields.io/badge/Extension_Type-Monitoring-orange?style=for-the-badge[Extension Type] 11 | image:https://img.shields.io/github/v/release/hivemq/hivemq-influxdb-extension?style=for-the-badge[GitHub release (latest by date),link=https://github.com/hivemq/hivemq-influxdb-extension/releases/latest] 12 | image:https://img.shields.io/github/license/hivemq/hivemq-influxdb-extension?style=for-the-badge&color=brightgreen[GitHub,link=LICENSE] 13 | image:https://img.shields.io/github/actions/workflow/status/hivemq/hivemq-influxdb-extension/check.yml?branch=master&style=for-the-badge[GitHub Workflow Status,link=https://github.com/hivemq/hivemq-influxdb-extension/actions/workflows/check.yml?query=branch%3Amaster] 14 | 15 | == Purpose 16 | 17 | The HiveMQ {influxdb-link}[InfluxDB^] Extension can be leveraged to gather metrics from {hivemq-link}[HiveMQ^] and persist them into a time series database. 18 | This database can be used as the data source for a monitoring dashboard (like Grafana) that drills down into the inner workings of HiveMQ and provides valuable insights to your operations team. 19 | 20 | == Installation 21 | 22 | Installing the extension for HiveMQ is very easy: 23 | 24 | . Download the extension from the {download-influxdb-extension}[HiveMQ website] and unzip the downloaded zip file. 25 | . In the folder `hivemq-influxdb-extension`, modify the `influxdb.properties` file to fit your needs. 26 | Check that the mandatory properties (host, port) are set 27 | . Copy the folder `hivemq-influxdb-extension` to your `/extensions` folder 28 | . Done 29 | 30 | == Configuration 31 | 32 | The InfluxDB Monitoring extension uses its own configuration file `influxdb.properties`. 33 | The extension won't start if this file is missing or the required properties are not set. 34 | 35 | === General Configuration 36 | 37 | |=== 38 | | Config name | Required | Description | Default 39 | 40 | | mode | no | The mode configured for the InfluxDB sender. 41 | Possibilities are: http, tcp, udp, cloud | http 42 | | host | yes | The host name of the InfluxDB instance. | - 43 | | port | yes | The port number the InfluxDB instance is listening. | 8086 44 | | protocol | no | The protocol the InfluxDB sender uses in http mode. | http (or https for cloud mode) 45 | | auth | no | The authorization string to be used to connect to InfluxDB, of format username:password. 46 | If mode "cloud" is used, the token must be passed here| - 47 | | prefix | no | The measurement prefix. | - 48 | | database | no | The database name. | hivemq 49 | | reportingInterval | no | The reporting interval in seconds. | 1 50 | | connectTimeout | no | The connect and read timeout in seconds. | 5000 51 | | tags | no | The tags for each metric. 52 | Listed as a semicolon ( `;` ) separated list. | - 53 | | organization | only for mode: "cloud" | The organization to push data to | - 54 | | bucket | only for mode: "cloud" | The bucket to push data to | - 55 | |=== 56 | 57 | NOTE: When using InfluxDB 2 the *_Cloud_* mode should be configured. 58 | 59 | .Example Configuration 60 | [source] 61 | ---- 62 | mode:http 63 | host:localhost 64 | port:8086 65 | protocol:http 66 | auth: 67 | 68 | prefix: 69 | database:hivemq 70 | 71 | reportingInterval:1 72 | connectTimeout:5000 73 | 74 | tags:host=hivemq1 75 | ---- 76 | 77 | == First Steps 78 | 79 | === Quick Start InfluxDB 80 | 81 | If you don't already have an InfluxDB instance set up, here is an instruction how to start a not configured InfluxDB instance with Docker. 82 | 83 | . Download and install {docker}[Docker^] for your platform 84 | . Start an InfluxDB docker container with the command `docker run -p 8086:8086 -v $PWD:/var/lib/influxdb influxdb`. 85 | For more information about using InfluxDB with Docker visit the {influxdb-docker}[official Docker repository^] for InfluxDB 86 | . A local instance of InfluxDB should be running with the port for the database set to 8086 87 | . Create a database that matches the name set in the property `database` in `influxdb.properties`. 88 | For the default `database` value use the command `curl -G http://localhost:8086/query --data-urlencode "q=CREATE DATABASE hivemq"` 89 | . Done 90 | 91 | === Usage 92 | 93 | After the extension is installed and an InfluxDB instance exists. 94 | 95 | . Start HiveMQ 96 | . Extension successfully started if configuration file exists and contains required properties 97 | 98 | == Need Help? 99 | 100 | If you encounter any problems, we are happy to help. 101 | The best place to get in contact is our {hivemq-support}[support^]. 102 | 103 | == Contributing 104 | 105 | If you want to contribute to HiveMQ InfluxDB Extension, see the link:CONTRIBUTING.md[contribution guidelines]. 106 | 107 | == License 108 | 109 | HiveMQ InfluxDB Extension is licensed under the `APACHE LICENSE, VERSION 2.0`. 110 | A copy of the license can be found link:LICENSE[here]. 111 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.hivemq.extension) 3 | alias(libs.plugins.defaults) 4 | alias(libs.plugins.oci) 5 | alias(libs.plugins.license) 6 | } 7 | 8 | group = "com.hivemq.extensions" 9 | description = "HiveMQ extension for transferring monitoring data to the time series database InfluxDB" 10 | 11 | hivemqExtension { 12 | name = "InfluxDB Monitoring Extension" 13 | author = "HiveMQ" 14 | priority = 1000 15 | startPriority = 1000 16 | sdkVersion = libs.versions.hivemq.extensionSdk 17 | 18 | resources { 19 | from("LICENSE") 20 | } 21 | } 22 | 23 | java { 24 | toolchain { 25 | languageVersion = JavaLanguageVersion.of(11) 26 | } 27 | } 28 | 29 | dependencies { 30 | compileOnly(libs.jetbrains.annotations) 31 | implementation(libs.metrics.influxdb) 32 | implementation(libs.commonsLang) 33 | } 34 | 35 | oci { 36 | registries { 37 | dockerHub { 38 | optionalCredentials() 39 | } 40 | } 41 | imageMapping { 42 | mapModule("com.hivemq", "hivemq-community-edition") { 43 | toImage("hivemq/hivemq-ce") 44 | } 45 | } 46 | imageDefinitions.register("main") { 47 | allPlatforms { 48 | dependencies { 49 | runtime("com.hivemq:hivemq-community-edition:latest") { isChanging = true } 50 | } 51 | layer("main") { 52 | contents { 53 | permissions("opt/hivemq/", 0b111_111_101) 54 | permissions("opt/hivemq/extensions/", 0b111_111_101) 55 | into("opt/hivemq/extensions") { 56 | from(zipTree(tasks.hivemqExtensionZip.flatMap { it.archiveFile })) 57 | } 58 | } 59 | } 60 | } 61 | } 62 | } 63 | 64 | @Suppress("UnstableApiUsage") 65 | testing { 66 | suites { 67 | withType { 68 | useJUnitJupiter(libs.versions.junit.jupiter) 69 | } 70 | "test"(JvmTestSuite::class) { 71 | dependencies { 72 | compileOnly(libs.jetbrains.annotations) 73 | implementation(libs.mockito) 74 | implementation(libs.wiremock) 75 | runtimeOnly(libs.logback.classic) 76 | } 77 | } 78 | "integrationTest"(JvmTestSuite::class) { 79 | dependencies { 80 | compileOnly(libs.jetbrains.annotations) 81 | implementation(libs.assertj) 82 | implementation(libs.awaitility) 83 | implementation(libs.hivemq.mqttClient) 84 | implementation(libs.testcontainers.junitJupiter) 85 | implementation(libs.testcontainers.hivemq) 86 | implementation(libs.testcontainers.influxdb) 87 | implementation(libs.gradleOci.junitJupiter) 88 | implementation(libs.influxdb) 89 | implementation(libs.okhttp) 90 | runtimeOnly(libs.logback.classic) 91 | } 92 | oci.of(this) { 93 | imageDependencies { 94 | runtime(project).tag("latest") 95 | runtime("library:influxdb:1.4.3").name("influxdb").tag("latest") 96 | } 97 | } 98 | } 99 | } 100 | } 101 | 102 | license { 103 | header = rootDir.resolve("HEADER") 104 | mapping("java", "SLASHSTAR_STYLE") 105 | exclude("**/logback-test.xml") 106 | } 107 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | version=4.1.4 2 | -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | assertj = "3.27.3" 3 | awaitility = "4.3.0" 4 | commonsLang = "3.17.0" 5 | gradleOci-junitJupiter = "0.7.0" 6 | hivemq-extensionSdk = "4.1.0" 7 | hivemq-mqttClient = "1.3.6" 8 | influxdb = "2.25" 9 | jetbrains-annotations = "26.0.2" 10 | junit-jupiter = "5.10.0" 11 | logback = "1.5.18" 12 | metrics-influxdb = "1.3.4" 13 | mockito = "5.18.0" 14 | okhttp = "4.12.0" 15 | testcontainers = "1.21.1" 16 | wiremock = "3.13.0" 17 | 18 | [libraries] 19 | assertj = { module = "org.assertj:assertj-core", version.ref = "assertj" } 20 | awaitility = { module = "org.awaitility:awaitility", version.ref = "awaitility" } 21 | commonsLang = { module = "org.apache.commons:commons-lang3", version.ref = "commonsLang" } 22 | gradleOci-junitJupiter = { module = "io.github.sgtsilvio:gradle-oci-junit-jupiter", version.ref = "gradleOci-junitJupiter" } 23 | hivemq-mqttClient = { module = "com.hivemq:hivemq-mqtt-client", version.ref = "hivemq-mqttClient" } 24 | influxdb = { module = "org.influxdb:influxdb-java", version.ref = "influxdb" } 25 | jetbrains-annotations = { module = "org.jetbrains:annotations", version.ref = "jetbrains-annotations" } 26 | logback-classic = { module = "ch.qos.logback:logback-classic", version.ref = "logback" } 27 | metrics-influxdb = { module = "com.izettle:metrics-influxdb", version.ref = "metrics-influxdb" } 28 | mockito = { module = "org.mockito:mockito-core", version.ref = "mockito" } 29 | okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" } 30 | testcontainers-hivemq = { module = "org.testcontainers:hivemq", version.ref = "testcontainers" } 31 | testcontainers-influxdb = { module = "org.testcontainers:influxdb", version.ref = "testcontainers" } 32 | testcontainers-junitJupiter = { module = "org.testcontainers:junit-jupiter", version.ref = "testcontainers" } 33 | wiremock = { module = "org.wiremock:wiremock", version.ref = "wiremock" } 34 | 35 | [plugins] 36 | defaults = { id = "io.github.sgtsilvio.gradle.defaults", version = "0.2.0" } 37 | hivemq-extension = { id = "com.hivemq.extension", version = "4.0.0" } 38 | license = { id = "com.github.hierynomus.license", version = "0.16.1" } 39 | oci = { id = "io.github.sgtsilvio.gradle.oci", version = "0.23.0" } 40 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hivemq/hivemq-influxdb-extension/0794df3bf3fc39dd7d964f30f14464d7acd33d73/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s 90 | ' "$PWD" ) || exit 91 | 92 | # Use the maximum available, or set MAX_FD != -1 to use that value. 93 | MAX_FD=maximum 94 | 95 | warn () { 96 | echo "$*" 97 | } >&2 98 | 99 | die () { 100 | echo 101 | echo "$*" 102 | echo 103 | exit 1 104 | } >&2 105 | 106 | # OS specific support (must be 'true' or 'false'). 107 | cygwin=false 108 | msys=false 109 | darwin=false 110 | nonstop=false 111 | case "$( uname )" in #( 112 | CYGWIN* ) cygwin=true ;; #( 113 | Darwin* ) darwin=true ;; #( 114 | MSYS* | MINGW* ) msys=true ;; #( 115 | NONSTOP* ) nonstop=true ;; 116 | esac 117 | 118 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 119 | 120 | 121 | # Determine the Java command to use to start the JVM. 122 | if [ -n "$JAVA_HOME" ] ; then 123 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 124 | # IBM's JDK on AIX uses strange locations for the executables 125 | JAVACMD=$JAVA_HOME/jre/sh/java 126 | else 127 | JAVACMD=$JAVA_HOME/bin/java 128 | fi 129 | if [ ! -x "$JAVACMD" ] ; then 130 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 131 | 132 | Please set the JAVA_HOME variable in your environment to match the 133 | location of your Java installation." 134 | fi 135 | else 136 | JAVACMD=java 137 | if ! command -v java >/dev/null 2>&1 138 | then 139 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 140 | 141 | Please set the JAVA_HOME variable in your environment to match the 142 | location of your Java installation." 143 | fi 144 | fi 145 | 146 | # Increase the maximum file descriptors if we can. 147 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 148 | case $MAX_FD in #( 149 | max*) 150 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 151 | # shellcheck disable=SC2039,SC3045 152 | MAX_FD=$( ulimit -H -n ) || 153 | warn "Could not query maximum file descriptor limit" 154 | esac 155 | case $MAX_FD in #( 156 | '' | soft) :;; #( 157 | *) 158 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 159 | # shellcheck disable=SC2039,SC3045 160 | ulimit -n "$MAX_FD" || 161 | warn "Could not set maximum file descriptor limit to $MAX_FD" 162 | esac 163 | fi 164 | 165 | # Collect all arguments for the java command, stacking in reverse order: 166 | # * args from the command line 167 | # * the main class name 168 | # * -classpath 169 | # * -D...appname settings 170 | # * --module-path (only if needed) 171 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 172 | 173 | # For Cygwin or MSYS, switch paths to Windows format before running java 174 | if "$cygwin" || "$msys" ; then 175 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 176 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 177 | 178 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 179 | 180 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 181 | for arg do 182 | if 183 | case $arg in #( 184 | -*) false ;; # don't mess with options #( 185 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 186 | [ -e "$t" ] ;; #( 187 | *) false ;; 188 | esac 189 | then 190 | arg=$( cygpath --path --ignore --mixed "$arg" ) 191 | fi 192 | # Roll the args list around exactly as many times as the number of 193 | # args, so each arg winds up back in the position where it started, but 194 | # possibly modified. 195 | # 196 | # NB: a `for` loop captures its iteration list before it begins, so 197 | # changing the positional parameters here affects neither the number of 198 | # iterations, nor the values presented in `arg`. 199 | shift # remove old arg 200 | set -- "$@" "$arg" # push replacement arg 201 | done 202 | fi 203 | 204 | 205 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 206 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 207 | 208 | # Collect all arguments for the java command: 209 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 210 | # and any embedded shellness will be escaped. 211 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 212 | # treated as '${Hostname}' itself on the command line. 213 | 214 | set -- \ 215 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 216 | -classpath "$CLASSPATH" \ 217 | org.gradle.wrapper.GradleWrapperMain \ 218 | "$@" 219 | 220 | # Stop when "xargs" is not available. 221 | if ! command -v xargs >/dev/null 2>&1 222 | then 223 | die "xargs is not available" 224 | fi 225 | 226 | # Use "xargs" to parse quoted args. 227 | # 228 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 229 | # 230 | # In Bash we could simply go: 231 | # 232 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 233 | # set -- "${ARGS[@]}" "$@" 234 | # 235 | # but POSIX shell has neither arrays nor command substitution, so instead we 236 | # post-process each arg (as a line of input to sed) to backslash-escape any 237 | # character that might be a shell metacharacter, then use eval to reverse 238 | # that process (while maintaining the separation between arguments), and wrap 239 | # the whole thing up as a single "set" statement. 240 | # 241 | # This will of course break if any of these variables contains a newline or 242 | # an unmatched quote. 243 | # 244 | 245 | eval "set -- $( 246 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 247 | xargs -n1 | 248 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 249 | tr '\n' ' ' 250 | )" '"$@"' 251 | 252 | exec "$JAVACMD" "$@" 253 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /renovate.json5: -------------------------------------------------------------------------------- 1 | { 2 | $schema: "https://docs.renovatebot.com/renovate-schema.json", 3 | extends: [ 4 | "local>hivemq/renovate-config:default.json5", 5 | ], 6 | addLabels: [ 7 | "tooling-and-extensions-coordination", 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "hivemq-influxdb-extension" 2 | -------------------------------------------------------------------------------- /src/hivemq-extension/influxdb.properties: -------------------------------------------------------------------------------- 1 | mode:http 2 | host:--INFLUX-DB-IP-- 3 | port:8086 4 | protocol:http 5 | auth: 6 | prefix: 7 | database:hivemq 8 | reportingInterval:1 9 | connectTimeout:5000 10 | tags:host=--NODE-NAME-- 11 | # InfluxDB cloud options 12 | bucket: 13 | organization: -------------------------------------------------------------------------------- /src/integrationTest/java/com/hivemq/extensions/influxdb/InfluxDbExtensionIT.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.influxdb; 17 | 18 | import com.hivemq.client.mqtt.mqtt5.Mqtt5BlockingClient; 19 | import com.hivemq.client.mqtt.mqtt5.Mqtt5Client; 20 | import io.github.sgtsilvio.gradle.oci.junit.jupiter.OciImages; 21 | import org.influxdb.InfluxDB; 22 | import org.influxdb.dto.Query; 23 | import org.influxdb.dto.QueryResult; 24 | import org.jetbrains.annotations.NotNull; 25 | import org.junit.jupiter.api.Test; 26 | import org.slf4j.Logger; 27 | import org.slf4j.LoggerFactory; 28 | import org.testcontainers.containers.InfluxDBContainer; 29 | import org.testcontainers.containers.Network; 30 | import org.testcontainers.hivemq.HiveMQContainer; 31 | import org.testcontainers.junit.jupiter.Container; 32 | import org.testcontainers.junit.jupiter.Testcontainers; 33 | import org.testcontainers.utility.MountableFile; 34 | 35 | import java.util.List; 36 | 37 | import static org.awaitility.Awaitility.await; 38 | import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.select; 39 | 40 | @SuppressWarnings({"resource"}) 41 | @Testcontainers 42 | public class InfluxDbExtensionIT { 43 | 44 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(InfluxDbExtensionIT.class); 45 | 46 | private static final @NotNull String INFLUXDB_NAME = "hivemq"; 47 | 48 | private final @NotNull Network network = Network.newNetwork(); 49 | 50 | @Container 51 | private final @NotNull HiveMQContainer hivemq = 52 | new HiveMQContainer(OciImages.getImageName("hivemq/extensions/hivemq-influxdb-extension") 53 | .asCompatibleSubstituteFor("hivemq/hivemq-ce")) // 54 | .withNetwork(network) 55 | .withCopyToContainer(MountableFile.forClasspathResource("influxdb.properties"), 56 | "/opt/hivemq/extensions/hivemq-influxdb-extension/influxdb.properties") 57 | .withLogConsumer(outputFrame -> System.out.print("HIVEMQ: " + outputFrame.getUtf8String())); 58 | 59 | @Container 60 | private final @NotNull InfluxDBContainer influxDB = 61 | new InfluxDBContainer<>(OciImages.getImageName("influxdb")).withAuthEnabled(false) 62 | .withNetwork(network) 63 | .withNetworkAliases("influxdb"); 64 | 65 | @Test 66 | void testMetricsAreForwardedToInfluxDB() { 67 | final InfluxDB influxDbClient = influxDB.getNewInfluxDB(); 68 | influxDbClient.setDatabase("hivemq"); 69 | 70 | final QueryResult query = influxDbClient.query(new Query("CREATE DATABASE \"" + INFLUXDB_NAME + "\"")); 71 | LOG.info("created database with query result: {}", query); 72 | influxDbClient.setDatabase(INFLUXDB_NAME); 73 | 74 | final Mqtt5BlockingClient mqttClient = 75 | Mqtt5Client.builder().serverHost(hivemq.getHost()).serverPort(hivemq.getMqttPort()).buildBlocking(); 76 | mqttClient.connect(); 77 | mqttClient.publishWith().topic("my/topic1").send(); 78 | mqttClient.publishWith().topic("my/topic2").send(); 79 | mqttClient.publishWith().topic("my/topic3").send(); 80 | mqttClient.disconnect(); 81 | 82 | await().until(() -> getMetricMax(influxDbClient, "com.hivemq.messages.incoming.publish.count") == 3); 83 | await().until(() -> getMetricMax(influxDbClient, "com.hivemq.messages.incoming.connect.count") == 1); 84 | } 85 | 86 | private long getMetricMax(final @NotNull InfluxDB client, final @NotNull String metric) { 87 | long acc = 0; 88 | final QueryResult queryResult = client.query(select("count").from(INFLUXDB_NAME, metric)); 89 | for (final QueryResult.Result result : queryResult.getResults()) { 90 | final List series = result.getSeries(); 91 | if (series == null) { 92 | break; 93 | } 94 | final List> values = series.get(series.size() - 1).getValues(); 95 | if (values == null) { 96 | break; 97 | } 98 | long max = 0; 99 | for (final List value : values) { 100 | if (value == null) { 101 | break; 102 | } 103 | final double val = (double) value.get(1); 104 | if (max < val) { 105 | max = (long) val; 106 | } 107 | } 108 | acc += max; 109 | } 110 | return acc; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/integrationTest/resources/influxdb.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2018-present HiveMQ GmbH 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | mode=http 17 | host=influxdb 18 | port=8086 19 | protocol=http 20 | auth= 21 | prefix= 22 | database=hivemq 23 | reportingInterval=1 24 | connectTimeout=5000 25 | tags=host=hivemq 26 | # InfluxDB cloud options 27 | bucket= 28 | organization= -------------------------------------------------------------------------------- /src/integrationTest/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %-30(%d %level)- %msg%n%ex 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/influxdb/InfluxDbCloudSender.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.influxdb; 17 | 18 | import com.izettle.metrics.influxdb.InfluxDbHttpSender; 19 | import com.izettle.metrics.influxdb.utils.TimeUtils; 20 | import org.jetbrains.annotations.NotNull; 21 | 22 | import java.io.IOException; 23 | import java.io.OutputStream; 24 | import java.net.HttpURLConnection; 25 | import java.net.URL; 26 | import java.net.URLEncoder; 27 | import java.nio.charset.StandardCharsets; 28 | import java.util.concurrent.TimeUnit; 29 | import java.util.zip.GZIPOutputStream; 30 | 31 | /** 32 | * Sender for InfluxDB Cloud. 33 | * 34 | * @author Simon Baier 35 | */ 36 | public class InfluxDbCloudSender extends InfluxDbHttpSender { 37 | 38 | private final @NotNull String authToken; 39 | private final int connectTimeout; 40 | private final int readTimeout; 41 | private final @NotNull URL url; 42 | 43 | public InfluxDbCloudSender( 44 | final @NotNull String protocol, 45 | final @NotNull String host, 46 | final int port, 47 | final @NotNull String authToken, 48 | final @NotNull TimeUnit timePrecision, 49 | final int connectTimeout, 50 | final int readTimeout, 51 | final @NotNull String measurementPrefix, 52 | final @NotNull String organization, 53 | final @NotNull String bucket) throws Exception { 54 | super(protocol, host, port, "", authToken, timePrecision, connectTimeout, readTimeout, measurementPrefix); 55 | this.authToken = authToken; 56 | this.connectTimeout = connectTimeout; 57 | this.readTimeout = readTimeout; 58 | 59 | final String endpoint = new URL(protocol, host, port, "/api/v2/write").toString(); 60 | final String queryPrecision = String.format("precision=%s", TimeUtils.toTimePrecision(timePrecision)); 61 | final String orgParameter = String.format("org=%s", URLEncoder.encode(organization, StandardCharsets.UTF_8)); 62 | final String bucketParameter = String.format("bucket=%s", URLEncoder.encode(bucket, StandardCharsets.UTF_8)); 63 | this.url = new URL(endpoint + "?" + queryPrecision + "&" + orgParameter + "&" + bucketParameter); 64 | } 65 | 66 | @Override 67 | protected int writeData(final byte @NotNull [] line) throws Exception { 68 | final HttpURLConnection con = (HttpURLConnection) url.openConnection(); 69 | con.setRequestMethod("POST"); 70 | con.setRequestProperty("Authorization", "Token " + authToken); 71 | con.setDoOutput(true); 72 | con.setConnectTimeout(connectTimeout); 73 | con.setReadTimeout(readTimeout); 74 | con.setRequestProperty("Content-Encoding", "gzip"); 75 | 76 | try (final OutputStream out = con.getOutputStream(); 77 | final GZIPOutputStream gzipOutputStream = new GZIPOutputStream(out)) { 78 | gzipOutputStream.write(line); 79 | gzipOutputStream.flush(); 80 | out.flush(); 81 | } 82 | 83 | final int responseCode = con.getResponseCode(); 84 | 85 | // Check if non 2XX response code. 86 | if (responseCode / 100 != 2) { 87 | throw new IOException("Server returned HTTP response code: " + 88 | responseCode + 89 | " for URL: " + 90 | url + 91 | " with content :'" + 92 | con.getResponseMessage() + 93 | "'"); 94 | } 95 | return responseCode; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/influxdb/InfluxDbExtensionMain.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.influxdb; 17 | 18 | import com.codahale.metrics.MetricFilter; 19 | import com.codahale.metrics.MetricRegistry; 20 | import com.codahale.metrics.ScheduledReporter; 21 | import com.hivemq.extension.sdk.api.ExtensionMain; 22 | import com.hivemq.extension.sdk.api.parameter.ExtensionStartInput; 23 | import com.hivemq.extension.sdk.api.parameter.ExtensionStartOutput; 24 | import com.hivemq.extension.sdk.api.parameter.ExtensionStopInput; 25 | import com.hivemq.extension.sdk.api.parameter.ExtensionStopOutput; 26 | import com.hivemq.extension.sdk.api.services.Services; 27 | import com.hivemq.extensions.influxdb.configuration.InfluxDbConfiguration; 28 | import com.izettle.metrics.influxdb.InfluxDbHttpSender; 29 | import com.izettle.metrics.influxdb.InfluxDbReporter; 30 | import com.izettle.metrics.influxdb.InfluxDbSender; 31 | import com.izettle.metrics.influxdb.InfluxDbTcpSender; 32 | import com.izettle.metrics.influxdb.InfluxDbUdpSender; 33 | import org.jetbrains.annotations.NotNull; 34 | import org.jetbrains.annotations.Nullable; 35 | import org.slf4j.Logger; 36 | import org.slf4j.LoggerFactory; 37 | 38 | import java.io.File; 39 | import java.util.Collections; 40 | import java.util.HashSet; 41 | import java.util.Map; 42 | import java.util.Objects; 43 | import java.util.concurrent.TimeUnit; 44 | 45 | /** 46 | * @author Michael Walter 47 | */ 48 | public class InfluxDbExtensionMain implements ExtensionMain { 49 | 50 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(InfluxDbExtensionMain.class); 51 | 52 | private static final @NotNull HashSet METER_FIELDS = 53 | newHashSet("count", "m1_rate", "m5_rate", "m15_rate", "mean_rate"); 54 | private static final @NotNull HashSet TIMER_FIELDS = newHashSet("count", 55 | "min", 56 | "max", 57 | "mean", 58 | "stddev", 59 | "p50", 60 | "p75", 61 | "p95", 62 | "p98", 63 | "p99", 64 | "p999", 65 | "m1_rate", 66 | "m5_rate", 67 | "m15_rate", 68 | "mean_rate"); 69 | 70 | private @Nullable ScheduledReporter reporter; 71 | 72 | @Override 73 | public void extensionStart( 74 | final @NotNull ExtensionStartInput extensionStartInput, 75 | final @NotNull ExtensionStartOutput extensionStartOutput) { 76 | try { 77 | final File extensionHomeFolder = extensionStartInput.getExtensionInformation().getExtensionHomeFolder(); 78 | final InfluxDbConfiguration configuration = new InfluxDbConfiguration(extensionHomeFolder); 79 | 80 | if (!configuration.readPropertiesFromFile()) { 81 | extensionStartOutput.preventExtensionStartup("Could not read influxdb properties"); 82 | return; 83 | } 84 | 85 | if (!configuration.validateConfiguration()) { 86 | extensionStartOutput.preventExtensionStartup("At least one mandatory property not set"); 87 | return; 88 | } 89 | 90 | final InfluxDbSender sender = setupSender(configuration); 91 | 92 | if (sender == null) { 93 | extensionStartOutput.preventExtensionStartup( 94 | "Couldn't create an influxdb sender. Please check that the configuration is correct"); 95 | return; 96 | } 97 | 98 | final MetricRegistry metricRegistry = Services.metricRegistry(); 99 | reporter = setupReporter(metricRegistry, sender, configuration); 100 | reporter.start(configuration.getReportingInterval(), TimeUnit.SECONDS); 101 | } catch (final Exception e) { 102 | LOG.warn("Start failed because of", e); 103 | extensionStartOutput.preventExtensionStartup("Start failed because of an exception"); 104 | } 105 | } 106 | 107 | @Override 108 | public void extensionStop( 109 | final @NotNull ExtensionStopInput extensionStopInput, 110 | final @NotNull ExtensionStopOutput extensionStopOutput) { 111 | if (reporter != null) { 112 | reporter.stop(); 113 | } 114 | } 115 | 116 | private @NotNull ScheduledReporter setupReporter( 117 | final @NotNull MetricRegistry metricRegistry, 118 | final @NotNull InfluxDbSender sender, 119 | final @NotNull InfluxDbConfiguration configuration) { 120 | Objects.requireNonNull(metricRegistry, "MetricRegistry for influxdb must not be null"); 121 | Objects.requireNonNull(sender, "InfluxDbSender for influxdb must not be null"); 122 | Objects.requireNonNull(configuration, "Configuration for influxdb must not be null"); 123 | 124 | final Map tags = configuration.getTags(); 125 | 126 | return InfluxDbReporter.forRegistry(metricRegistry) 127 | .withTags(tags) 128 | .convertRatesTo(TimeUnit.SECONDS) 129 | .convertDurationsTo(TimeUnit.MILLISECONDS) 130 | .filter(MetricFilter.ALL) 131 | .groupGauges(false) 132 | .skipIdleMetrics(false) 133 | .includeMeterFields(METER_FIELDS) 134 | .includeTimerFields(TIMER_FIELDS) 135 | .build(sender); 136 | } 137 | 138 | private @Nullable InfluxDbSender setupSender(final @NotNull InfluxDbConfiguration configuration) { 139 | Objects.requireNonNull(configuration, "Configuration for influxdb must not be null"); 140 | 141 | final String host = configuration.getHost(); 142 | final int port = configuration.getPort(); 143 | final String database = configuration.getDatabase(); 144 | final String auth = configuration.getAuth(); 145 | final int connectTimeout = configuration.getConnectTimeout(); 146 | final String prefix = configuration.getPrefix(); 147 | 148 | // cloud 149 | final String bucket = configuration.getBucket(); 150 | final String organization = configuration.getOrganization(); 151 | 152 | InfluxDbSender sender = null; 153 | 154 | try { 155 | switch (configuration.getMode()) { 156 | case "http": 157 | LOG.info("Creating InfluxDB HTTP sender for server {}:{} and database {}", host, port, database); 158 | sender = new InfluxDbHttpSender(configuration.getProtocolOrDefault("http"), 159 | host, 160 | port, 161 | database, 162 | auth, 163 | TimeUnit.SECONDS, 164 | connectTimeout, 165 | connectTimeout, 166 | prefix); 167 | break; 168 | case "tcp": 169 | LOG.info("Creating InfluxDB TCP sender for server {}:{} and database {}", host, port, database); 170 | sender = new InfluxDbTcpSender(host, port, connectTimeout, database, prefix); 171 | break; 172 | case "udp": 173 | LOG.info("Creating InfluxDB UDP sender for server {}:{} and database {}", host, port, database); 174 | sender = new InfluxDbUdpSender(host, port, connectTimeout, database, prefix); 175 | break; 176 | case "cloud": 177 | LOG.info("Creating InfluxDB Cloud sender for endpoint {}, bucket {}, organization {}", 178 | host, 179 | bucket, 180 | organization); 181 | Objects.requireNonNull(bucket, "Bucket name must be defined in cloud mode"); 182 | Objects.requireNonNull(organization, "Organization must be defined in cloud mode"); 183 | sender = new InfluxDbCloudSender(configuration.getProtocolOrDefault("https"), 184 | host, 185 | port, 186 | auth, 187 | TimeUnit.SECONDS, 188 | connectTimeout, 189 | connectTimeout, 190 | prefix, 191 | organization, 192 | bucket); 193 | break; 194 | 195 | } 196 | } catch (final Exception ex) { 197 | LOG.error("Not able to start InfluxDB sender, please check your configuration: {}", ex.getMessage()); 198 | LOG.debug("Original Exception: ", ex); 199 | } 200 | 201 | return sender; 202 | } 203 | 204 | public static HashSet newHashSet(final String @NotNull ... elements) { 205 | final HashSet set = new HashSet<>(); 206 | Collections.addAll(set, elements); 207 | return set; 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/influxdb/configuration/InfluxDbConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.influxdb.configuration; 17 | 18 | import org.apache.commons.lang3.StringUtils; 19 | import org.jetbrains.annotations.NotNull; 20 | import org.jetbrains.annotations.Nullable; 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | import java.io.File; 25 | import java.util.HashMap; 26 | import java.util.Map; 27 | import java.util.Objects; 28 | import java.util.Properties; 29 | 30 | /** 31 | * Reads a property file containing influxdb properties 32 | * and provides some utility methods for working with {@link Properties}. 33 | * 34 | * @author Christoph Schäbel 35 | * @author Michael Walter 36 | */ 37 | public class InfluxDbConfiguration extends PropertiesReader { 38 | 39 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(InfluxDbConfiguration.class); 40 | 41 | private static final @NotNull String HOST = "host"; 42 | private static final @NotNull String PORT = "port"; 43 | private static final @NotNull String MODE = "mode"; 44 | private static final @NotNull String MODE_DEFAULT = "http"; 45 | private static final @NotNull String PROTOCOL = "protocol"; 46 | private static final @NotNull String REPORTING_INTERVAL = "reportingInterval"; 47 | private static final int REPORTING_INTERVAL_DEFAULT = 1; 48 | private static final @NotNull String PREFIX = "prefix"; 49 | private static final @NotNull String PREFIX_DEFAULT = ""; 50 | private static final @NotNull String DATABASE = "database"; 51 | private static final @NotNull String DATABASE_DEFAULT = "hivemq"; 52 | private static final @NotNull String CONNECT_TIMEOUT = "connectTimeout"; 53 | private static final int CONNECT_TIMEOUT_DEFAULT = 5000; 54 | private static final @NotNull String AUTH = "auth"; 55 | private static final @NotNull String TAGS = "tags"; 56 | private static final @NotNull HashMap TAGS_DEFAULT = new HashMap<>(); 57 | 58 | //InfluxDB Cloud 59 | private static final @NotNull String BUCKET = "bucket"; 60 | private static final @NotNull String ORGANIZATION = "organization"; 61 | 62 | 63 | public InfluxDbConfiguration(final @NotNull File configFilePath) { 64 | super(configFilePath); 65 | } 66 | 67 | /** 68 | * Check if mandatory properties exist and are valid. Mandatory properties are port and host. 69 | * 70 | * @return true if all mandatory properties exist, else false. 71 | */ 72 | public boolean validateConfiguration() { 73 | int countError = 0; 74 | 75 | countError += checkMandatoryProperty(HOST); 76 | countError += checkMandatoryProperty(PORT); 77 | 78 | if (countError != 0) { 79 | return false; 80 | } 81 | 82 | // check for valid port value 83 | final String port = getProperty(PORT); 84 | try { 85 | final int intPort = Integer.parseInt(port); 86 | 87 | if (intPort < 0 || intPort > 65535) { 88 | LOG.error("Value for mandatory InfluxDB property {} is not in valid port range.", PORT); 89 | countError++; 90 | } 91 | 92 | } catch (final NumberFormatException e) { 93 | LOG.error("Value for mandatory InfluxDB property {} is not a number.", PORT); 94 | countError++; 95 | } 96 | 97 | // check if host is still --INFLUX-DB-IP-- 98 | final String host = getProperty(HOST); 99 | 100 | if ("--INFLUX-DB-IP--".equals(host)) { 101 | countError++; 102 | } 103 | 104 | return countError == 0; 105 | } 106 | 107 | /** 108 | * Check if mandatory property exists. 109 | * 110 | * @param property Property to check. 111 | * @return 0 if property exists, else 1. 112 | */ 113 | private int checkMandatoryProperty(final @NotNull String property) { 114 | Objects.requireNonNull(property, "Mandatory property must not be null"); 115 | 116 | final String value = getProperty(property); 117 | 118 | if (value == null) { 119 | LOG.error("Mandatory property {} is not set.", property); 120 | return 1; 121 | } 122 | return 0; 123 | } 124 | 125 | 126 | public @NotNull String getMode() { 127 | return validateStringProperty(MODE, MODE_DEFAULT); 128 | } 129 | 130 | public @Nullable String getHost() { 131 | return getProperty(HOST); 132 | } 133 | 134 | public @NotNull String getDatabase() { 135 | return validateStringProperty(DATABASE, DATABASE_DEFAULT); 136 | } 137 | 138 | public @Nullable Integer getPort() { 139 | final int port; 140 | try { 141 | port = Integer.parseInt(getProperty(PORT)); 142 | } catch (final NumberFormatException e) { 143 | LOG.error("Value for {} is not a number", PORT); 144 | return null; 145 | } 146 | return port; 147 | } 148 | 149 | public int getReportingInterval() { 150 | return validateIntProperty(REPORTING_INTERVAL, REPORTING_INTERVAL_DEFAULT); 151 | } 152 | 153 | public int getConnectTimeout() { 154 | return validateIntProperty(CONNECT_TIMEOUT, CONNECT_TIMEOUT_DEFAULT); 155 | } 156 | 157 | public @NotNull String getProtocolOrDefault(final @NotNull String defaultProtocol) { 158 | final String protocol = getProperty(PROTOCOL); 159 | if (protocol == null) { 160 | LOG.warn("No protocol configured for InfluxDb in mode '{}', using default: '{}'", 161 | getMode(), 162 | defaultProtocol); 163 | return defaultProtocol; 164 | } 165 | return protocol; 166 | } 167 | 168 | public @NotNull String getPrefix() { 169 | return validateStringProperty(PREFIX, PREFIX_DEFAULT); 170 | } 171 | 172 | public @Nullable String getAuth() { 173 | return getProperty(AUTH); 174 | } 175 | 176 | public @NotNull Map getTags() { 177 | final String tags = getProperty(TAGS); 178 | if (tags == null) { 179 | return TAGS_DEFAULT; 180 | } 181 | 182 | final String[] split = StringUtils.splitPreserveAllTokens(tags, ";"); 183 | 184 | final HashMap tagMap = new HashMap<>(); 185 | 186 | for (final String tag : split) { 187 | final String[] tagPair = StringUtils.split(tag, "="); 188 | if (tagPair.length != 2 || tagPair[0].isEmpty() || tagPair[1].isEmpty()) { 189 | LOG.warn("Invalid tag format {} for InfluxDB", tag); 190 | continue; 191 | } 192 | 193 | tagMap.put(tagPair[0], tagPair[1]); 194 | } 195 | 196 | return tagMap; 197 | } 198 | 199 | public @Nullable String getBucket() { 200 | return getProperty(BUCKET); 201 | } 202 | 203 | public @Nullable String getOrganization() { 204 | return getProperty(ORGANIZATION); 205 | } 206 | 207 | @Override 208 | public @NotNull String getFilename() { 209 | return "influxdb.properties"; 210 | } 211 | 212 | /** 213 | * Fetch property with given key. If the fetched {@link String} is null the defaultValue will 214 | * be returned. 215 | * 216 | * @param key Key of the property. 217 | * @param defaultValue Default value as fallback, if property has no value. 218 | * @return the actual value of the property if it is set, else the defaultValue. 219 | */ 220 | private String validateStringProperty(final @NotNull String key, final @NotNull String defaultValue) { 221 | Objects.requireNonNull(key, "Key to fetch property must not be null"); 222 | Objects.requireNonNull(defaultValue, "Default value for property must not be null"); 223 | 224 | final String value = getProperty(key); 225 | 226 | if (value == null) { 227 | 228 | if (!defaultValue.isEmpty()) { 229 | LOG.warn("No '{}' configured for InfluxDb, using default: {}", key, defaultValue); 230 | } 231 | return defaultValue; 232 | } 233 | 234 | return value; 235 | } 236 | 237 | /** 238 | * Fetch property with given key. 239 | * If the fetched {@link String} value is not null convert the value to an int and check validation 240 | * constraints if given flags are false before returning the value. 241 | * 242 | * @param key Key of the property 243 | * @param defaultValue Default value as fallback, if property has no value 244 | * @return the actual value of the property if it is set and valid, else the defaultValue 245 | */ 246 | private int validateIntProperty( 247 | final @NotNull String key, final int defaultValue) { 248 | Objects.requireNonNull(key, "Key to fetch property must not be null"); 249 | 250 | final String value = properties.getProperty(key); 251 | 252 | if (value == null) { 253 | LOG.warn("No '{}' configured for InfluxDb, using default: {}", key, defaultValue); 254 | return defaultValue; 255 | } 256 | 257 | final int valueAsInt; 258 | try { 259 | valueAsInt = Integer.parseInt(value); 260 | } catch (final NumberFormatException e) { 261 | LOG.warn("Value for InfluxDB property '{}' is not a number, original value {}. Using default: {}", 262 | key, 263 | value, 264 | defaultValue); 265 | return defaultValue; 266 | } 267 | 268 | if (valueAsInt == 0) { 269 | LOG.warn("Value for InfluxDB property '{}' can't be zero. Using default: {}", key, defaultValue); 270 | return defaultValue; 271 | } 272 | 273 | if (valueAsInt < 0) { 274 | LOG.warn("Value for InfluxDB property '{}' can't be negative. Using default: {}", key, defaultValue); 275 | return defaultValue; 276 | } 277 | 278 | return valueAsInt; 279 | } 280 | } 281 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/influxdb/configuration/PropertiesReader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.influxdb.configuration; 17 | 18 | import org.jetbrains.annotations.NotNull; 19 | import org.jetbrains.annotations.Nullable; 20 | import org.slf4j.Logger; 21 | import org.slf4j.LoggerFactory; 22 | 23 | import java.io.File; 24 | import java.io.FileReader; 25 | import java.io.IOException; 26 | import java.util.Objects; 27 | import java.util.Properties; 28 | 29 | /** 30 | * Load the content of a {@link File} into {@link Properties}. 31 | * 32 | * @author Michael Walter 33 | */ 34 | public abstract class PropertiesReader { 35 | 36 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(PropertiesReader.class); 37 | 38 | private final @NotNull File configFilePath; 39 | protected @Nullable Properties properties; 40 | 41 | PropertiesReader(final @NotNull File configFilePath) { 42 | Objects.requireNonNull(configFilePath, "Path to config file must not be null"); 43 | this.configFilePath = configFilePath; 44 | } 45 | 46 | /** 47 | * Read the {@link Properties} from the properties {@link File}. 48 | * 49 | * @return true if properties are loaded, else false. 50 | */ 51 | public boolean readPropertiesFromFile() { 52 | final File file = new File(configFilePath + File.separator + getFilename()); 53 | 54 | try { 55 | loadProperties(file); 56 | 57 | } catch (IOException e) { 58 | LOG.error("Not able to load configuration file '{}'", file.getAbsolutePath()); 59 | return false; 60 | } 61 | 62 | return true; 63 | } 64 | 65 | /** 66 | * Fetch a property with given key from {@link Properties}. 67 | * 68 | * @param key The name of the property to look for. 69 | * @return The property for the value if it exists, null if key or {@link Properties} doesn't exist or the 70 | * value is an empty string. 71 | */ 72 | @Nullable String getProperty(final @NotNull String key) { 73 | Objects.requireNonNull(key, "Key to fetch property for must not be null."); 74 | 75 | if (properties == null) { 76 | return null; 77 | } 78 | 79 | final String property = properties.getProperty(key); 80 | 81 | if (property == null || property.isEmpty()) { 82 | return null; 83 | } 84 | 85 | return property; 86 | } 87 | 88 | /** 89 | * Loads the properties from the configuration {@link File} into {@link Properties}. 90 | * 91 | * @param file {@link File} where to load the properties from. 92 | * @throws IOException If properties could not be read from file. 93 | */ 94 | private void loadProperties(final @NotNull File file) throws IOException { 95 | Objects.requireNonNull(file, "File that contains properties must not be null"); 96 | 97 | try (final FileReader in = new FileReader(file)) { 98 | properties = new Properties(); 99 | properties.load(in); 100 | } 101 | } 102 | 103 | public abstract @NotNull String getFilename(); 104 | } 105 | -------------------------------------------------------------------------------- /src/test/java/com/hivemq/extensions/influxdb/InfluxDbCloudSenderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.influxdb; 17 | 18 | import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; 19 | import com.github.tomakehurst.wiremock.junit5.WireMockTest; 20 | import org.jetbrains.annotations.NotNull; 21 | import org.junit.jupiter.api.Test; 22 | 23 | import java.util.concurrent.TimeUnit; 24 | 25 | import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; 26 | import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; 27 | import static com.github.tomakehurst.wiremock.client.WireMock.post; 28 | import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; 29 | import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; 30 | import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; 31 | import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; 32 | import static com.github.tomakehurst.wiremock.client.WireMock.verify; 33 | 34 | /** 35 | * @author Christoph Schäbel 36 | */ 37 | @WireMockTest 38 | class InfluxDbCloudSenderTest { 39 | 40 | @Test 41 | void test_write_data(final @NotNull WireMockRuntimeInfo wireMockRuntimeInfo) throws Exception { 42 | final InfluxDbCloudSender sender = new InfluxDbCloudSender("http", 43 | "localhost", 44 | wireMockRuntimeInfo.getHttpPort(), 45 | "token", 46 | TimeUnit.MILLISECONDS, 47 | 3000, 48 | 3000, 49 | "", 50 | "testorg", 51 | "testbucket"); 52 | 53 | stubFor(post(urlPathEqualTo("/api/v2/write")).willReturn(aResponse().withStatus(200).withBody(""))); 54 | 55 | sender.writeData("line=line".getBytes()); 56 | 57 | verify(postRequestedFor(urlEqualTo("/api/v2/write?precision=ms&org=testorg&bucket=testbucket")).withHeader( 58 | "Authorization", 59 | equalTo("Token token")).withRequestBody(equalTo("line=line"))); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/com/hivemq/extensions/influxdb/InfluxDbExtensionMainTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.influxdb; 17 | 18 | import com.hivemq.extension.sdk.api.parameter.ExtensionInformation; 19 | import com.hivemq.extension.sdk.api.parameter.ExtensionStartInput; 20 | import com.hivemq.extension.sdk.api.parameter.ExtensionStartOutput; 21 | import org.jetbrains.annotations.NotNull; 22 | import org.junit.jupiter.api.BeforeEach; 23 | import org.junit.jupiter.api.Test; 24 | import org.junit.jupiter.api.io.TempDir; 25 | 26 | import java.io.IOException; 27 | import java.nio.file.Files; 28 | import java.nio.file.Path; 29 | import java.util.List; 30 | 31 | import static org.mockito.ArgumentMatchers.anyString; 32 | import static org.mockito.Mockito.mock; 33 | import static org.mockito.Mockito.verify; 34 | import static org.mockito.Mockito.when; 35 | 36 | class InfluxDbExtensionMainTest { 37 | 38 | private @NotNull InfluxDbExtensionMain main; 39 | private @NotNull ExtensionStartInput extensionStartInput; 40 | private @NotNull ExtensionStartOutput extensionStartOutput; 41 | private @NotNull Path file; 42 | 43 | @BeforeEach 44 | void setUp(final @TempDir @NotNull Path tempDir) { 45 | main = new InfluxDbExtensionMain(); 46 | 47 | extensionStartInput = mock(ExtensionStartInput.class); 48 | extensionStartOutput = mock(ExtensionStartOutput.class); 49 | final ExtensionInformation extensionInformation = mock(ExtensionInformation.class); 50 | when(extensionStartInput.getExtensionInformation()).thenReturn(extensionInformation); 51 | when(extensionStartInput.getExtensionInformation().getExtensionHomeFolder()).thenReturn(tempDir.toFile()); 52 | 53 | file = tempDir.resolve("influxdb.properties"); 54 | } 55 | 56 | @Test 57 | void extensionStart_whenNoConfigurationFile_thenPreventStartup() { 58 | main.extensionStart(extensionStartInput, extensionStartOutput); 59 | verify(extensionStartOutput).preventExtensionStartup(anyString()); 60 | } 61 | 62 | @Test 63 | void extensionStart_whenConfigurationFileNotValid_thenPreventStartup() throws IOException { 64 | Files.write(file, List.of("host:localhost", "port:-3000")); 65 | 66 | main.extensionStart(extensionStartInput, extensionStartOutput); 67 | verify(extensionStartOutput).preventExtensionStartup(anyString()); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/test/java/com/hivemq/extensions/influxdb/configuration/InfluxDbConfigurationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.influxdb.configuration; 17 | 18 | import org.jetbrains.annotations.NotNull; 19 | import org.junit.jupiter.api.BeforeEach; 20 | import org.junit.jupiter.api.Test; 21 | import org.junit.jupiter.api.io.TempDir; 22 | 23 | import java.io.IOException; 24 | import java.nio.file.Files; 25 | import java.nio.file.Path; 26 | import java.util.List; 27 | import java.util.Map; 28 | 29 | import static org.junit.jupiter.api.Assertions.assertEquals; 30 | import static org.junit.jupiter.api.Assertions.assertFalse; 31 | import static org.junit.jupiter.api.Assertions.assertNull; 32 | import static org.junit.jupiter.api.Assertions.assertTrue; 33 | 34 | class InfluxDbConfigurationTest { 35 | 36 | private @NotNull InfluxDbConfiguration influxDbConfiguration; 37 | private @NotNull Path file; 38 | 39 | @BeforeEach 40 | void setUp(final @TempDir @NotNull Path tempDir) { 41 | influxDbConfiguration = new InfluxDbConfiguration(tempDir.toFile()); 42 | file = tempDir.resolve("influxdb.properties"); 43 | } 44 | 45 | @Test 46 | void validateConfiguration_ok() throws IOException { 47 | Files.write(file, List.of("host:localhost", "port:3000")); 48 | 49 | assertTrue(influxDbConfiguration.readPropertiesFromFile()); 50 | assertTrue(influxDbConfiguration.validateConfiguration()); 51 | } 52 | 53 | @Test 54 | void validateConfiguration_wrong_port() throws IOException { 55 | Files.write(file, List.of("host:localhost", "port:-3000")); 56 | 57 | assertTrue(influxDbConfiguration.readPropertiesFromFile()); 58 | assertFalse(influxDbConfiguration.validateConfiguration()); 59 | } 60 | 61 | @Test 62 | void validateConfiguration_host_missing() throws IOException { 63 | Files.write(file, List.of("port:3000")); 64 | 65 | assertTrue(influxDbConfiguration.readPropertiesFromFile()); 66 | assertFalse(influxDbConfiguration.validateConfiguration()); 67 | } 68 | 69 | @Test 70 | void validateConfiguration_port_missing() throws IOException { 71 | Files.write(file, List.of("host:localhost")); 72 | 73 | assertTrue(influxDbConfiguration.readPropertiesFromFile()); 74 | assertFalse(influxDbConfiguration.validateConfiguration()); 75 | } 76 | 77 | @Test 78 | void validateConfiguration_port_null() throws IOException { 79 | Files.write(file, List.of("host:localhost", "port:")); 80 | 81 | assertTrue(influxDbConfiguration.readPropertiesFromFile()); 82 | assertFalse(influxDbConfiguration.validateConfiguration()); 83 | 84 | assertNull(influxDbConfiguration.getProperty("port")); 85 | } 86 | 87 | @Test 88 | void validateConfiguration_host_null() throws IOException { 89 | Files.write(file, List.of("host:", "port:3000")); 90 | 91 | assertTrue(influxDbConfiguration.readPropertiesFromFile()); 92 | assertFalse(influxDbConfiguration.validateConfiguration()); 93 | 94 | assertNull(influxDbConfiguration.getProperty("host")); 95 | } 96 | 97 | @Test 98 | void all_properties_empty() throws IOException { 99 | Files.write(file, 100 | List.of("mode:", 101 | "host:", 102 | "port:", 103 | "tags:", 104 | "prefix:", 105 | "protocol:", 106 | "database:", 107 | "connectTimeout:", 108 | "reportingInterval:", 109 | "auth:")); 110 | 111 | assertTrue(influxDbConfiguration.readPropertiesFromFile()); 112 | assertFalse(influxDbConfiguration.validateConfiguration()); 113 | 114 | assertEquals("http", influxDbConfiguration.getMode()); 115 | assertTrue(influxDbConfiguration.getTags().isEmpty()); 116 | assertEquals("", influxDbConfiguration.getPrefix()); 117 | assertEquals("http", influxDbConfiguration.getProtocolOrDefault("http")); 118 | assertEquals("hivemq", influxDbConfiguration.getDatabase()); 119 | assertEquals(5000, influxDbConfiguration.getConnectTimeout()); 120 | assertEquals(1, influxDbConfiguration.getReportingInterval()); 121 | assertNull(influxDbConfiguration.getAuth()); 122 | assertNull(influxDbConfiguration.getHost()); 123 | assertNull(influxDbConfiguration.getPort()); 124 | } 125 | 126 | @Test 127 | void all_properties_null() throws IOException { 128 | Files.write(file, List.of()); 129 | 130 | assertTrue(influxDbConfiguration.readPropertiesFromFile()); 131 | assertFalse(influxDbConfiguration.validateConfiguration()); 132 | 133 | assertEquals("http", influxDbConfiguration.getMode()); 134 | assertTrue(influxDbConfiguration.getTags().isEmpty()); 135 | assertEquals("", influxDbConfiguration.getPrefix()); 136 | assertEquals("http", influxDbConfiguration.getProtocolOrDefault("http")); 137 | assertEquals("hivemq", influxDbConfiguration.getDatabase()); 138 | assertEquals(5000, influxDbConfiguration.getConnectTimeout()); 139 | assertEquals(1, influxDbConfiguration.getReportingInterval()); 140 | assertNull(influxDbConfiguration.getAuth()); 141 | assertNull(influxDbConfiguration.getHost()); 142 | assertNull(influxDbConfiguration.getPort()); 143 | } 144 | 145 | @Test 146 | void all_properties_have_correct_values() throws IOException { 147 | Files.write(file, 148 | List.of("mode:tcp", 149 | "host:hivemq.monitoring.com", 150 | "port:3000", 151 | "tags:host=hivemq1;version=3.4.1", 152 | "prefix:node1", 153 | "protocol:tcp", 154 | "database:test-hivemq", 155 | "connectTimeout:10000", 156 | "reportingInterval:5", 157 | "auth:username:password")); 158 | 159 | assertTrue(influxDbConfiguration.readPropertiesFromFile()); 160 | assertTrue(influxDbConfiguration.validateConfiguration()); 161 | 162 | final Map tags = influxDbConfiguration.getTags(); 163 | assertEquals("tcp", influxDbConfiguration.getMode()); 164 | assertEquals(2, tags.size()); 165 | assertEquals("hivemq1", tags.get("host")); 166 | assertEquals("3.4.1", tags.get("version")); 167 | assertEquals("node1", influxDbConfiguration.getPrefix()); 168 | assertEquals("tcp", influxDbConfiguration.getProtocolOrDefault("default")); 169 | assertEquals("test-hivemq", influxDbConfiguration.getDatabase()); 170 | assertEquals(10000, influxDbConfiguration.getConnectTimeout()); 171 | assertEquals(5, influxDbConfiguration.getReportingInterval()); 172 | assertEquals("username:password", influxDbConfiguration.getAuth()); 173 | assertEquals("hivemq.monitoring.com", influxDbConfiguration.getHost()); 174 | assertEquals(3000, influxDbConfiguration.getPort()); 175 | } 176 | 177 | @Test 178 | void tags_invalid_configured() throws IOException { 179 | Files.write(file, List.of("tags:host=hivemq1;version=;use=monitoring")); 180 | 181 | assertTrue(influxDbConfiguration.readPropertiesFromFile()); 182 | assertFalse(influxDbConfiguration.validateConfiguration()); 183 | 184 | final Map tags = influxDbConfiguration.getTags(); 185 | assertEquals(2, tags.size()); 186 | assertEquals("hivemq1", tags.get("host")); 187 | assertEquals("monitoring", tags.get("use")); 188 | assertNull(tags.get("version")); 189 | } 190 | 191 | @Test 192 | void tags_has_only_semicolons() throws IOException { 193 | Files.write(file, List.of("tags:;;;;;;")); 194 | 195 | assertTrue(influxDbConfiguration.readPropertiesFromFile()); 196 | assertFalse(influxDbConfiguration.validateConfiguration()); 197 | 198 | final Map tags = influxDbConfiguration.getTags(); 199 | assertEquals(0, tags.size()); 200 | } 201 | 202 | @Test 203 | void tags_has_only_a_key() throws IOException { 204 | Files.write(file, List.of("tags:okay")); 205 | 206 | assertTrue(influxDbConfiguration.readPropertiesFromFile()); 207 | assertFalse(influxDbConfiguration.validateConfiguration()); 208 | 209 | final Map tags = influxDbConfiguration.getTags(); 210 | assertEquals(0, tags.size()); 211 | } 212 | 213 | @Test 214 | void tags_has_correct_tag_but_missing_semicolon() throws IOException { 215 | Files.write(file, List.of("tags:key=value")); 216 | 217 | assertTrue(influxDbConfiguration.readPropertiesFromFile()); 218 | assertFalse(influxDbConfiguration.validateConfiguration()); 219 | 220 | final Map tags = influxDbConfiguration.getTags(); 221 | assertEquals(1, tags.size()); 222 | } 223 | 224 | @Test 225 | void properties_that_are_numbers_have_invalid_string() throws IOException { 226 | Files.write(file, List.of("host:test", "port:800000", "reportingInterval:0", "connectTimeout:-1")); 227 | 228 | assertTrue(influxDbConfiguration.readPropertiesFromFile()); 229 | //false because port is out of range 230 | assertFalse(influxDbConfiguration.validateConfiguration()); 231 | 232 | //default values because values in file are no valid (zero or negative number) 233 | assertEquals(5000, influxDbConfiguration.getConnectTimeout()); 234 | assertEquals(1, influxDbConfiguration.getReportingInterval()); 235 | } 236 | 237 | @Test 238 | void validateConfiguration_cloud_token_missing() throws IOException { 239 | Files.write(file, List.of("mode:cloud", "host:localhost", "bucket:mybucket")); 240 | 241 | assertTrue(influxDbConfiguration.readPropertiesFromFile()); 242 | assertFalse(influxDbConfiguration.validateConfiguration()); 243 | } 244 | 245 | @Test 246 | void validateConfiguration_cloud_bucket_missing() throws IOException { 247 | Files.write(file, List.of("mode:cloud", "host:localhost", "token:mytoken")); 248 | 249 | assertTrue(influxDbConfiguration.readPropertiesFromFile()); 250 | assertFalse(influxDbConfiguration.validateConfiguration()); 251 | } 252 | 253 | @Test 254 | void validateConfiguration_cloud_ok() throws IOException { 255 | Files.write(file, List.of("mode:cloud", "host:localhost", "token:mytoken", "bucket:mybucket")); 256 | 257 | assertTrue(influxDbConfiguration.readPropertiesFromFile()); 258 | assertFalse(influxDbConfiguration.validateConfiguration()); 259 | } 260 | } -------------------------------------------------------------------------------- /src/test/java/com/hivemq/extensions/influxdb/configuration/PropertiesReaderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.influxdb.configuration; 17 | 18 | import org.jetbrains.annotations.NotNull; 19 | import org.junit.jupiter.api.Test; 20 | import org.junit.jupiter.api.io.TempDir; 21 | 22 | import java.io.IOException; 23 | import java.nio.file.Files; 24 | import java.nio.file.Path; 25 | import java.util.List; 26 | 27 | import static org.junit.jupiter.api.Assertions.assertEquals; 28 | import static org.junit.jupiter.api.Assertions.assertFalse; 29 | import static org.junit.jupiter.api.Assertions.assertNull; 30 | import static org.junit.jupiter.api.Assertions.assertThrows; 31 | import static org.junit.jupiter.api.Assertions.assertTrue; 32 | 33 | class PropertiesReaderTest { 34 | 35 | @Test 36 | void readPropertiesFromFile_file_null() { 37 | //noinspection DataFlowIssue 38 | assertThrows(NullPointerException.class, () -> new PropertiesReader(null) { 39 | @Override 40 | public @NotNull String getFilename() { 41 | return "test"; 42 | } 43 | }); 44 | } 45 | 46 | @Test 47 | void readPropertiesFromFile_file_does_not_exist(final @TempDir @NotNull Path tempDir) { 48 | final PropertiesReader propertiesReader = new PropertiesReader(tempDir.toFile()) { 49 | @Override 50 | public @NotNull String getFilename() { 51 | return "test"; 52 | } 53 | }; 54 | assertFalse(propertiesReader.readPropertiesFromFile()); 55 | } 56 | 57 | @Test 58 | void readPropertiesFromFile_file_does_exist(final @TempDir @NotNull Path tempDir) throws IOException { 59 | assertTrue(tempDir.resolve("test").toFile().createNewFile()); 60 | 61 | final PropertiesReader propertiesReader = new PropertiesReader(tempDir.toFile()) { 62 | @Override 63 | public @NotNull String getFilename() { 64 | return "test"; 65 | } 66 | }; 67 | assertTrue(propertiesReader.readPropertiesFromFile()); 68 | } 69 | 70 | @Test 71 | void getProperty_key_null(final @TempDir @NotNull Path tempDir) throws IOException { 72 | final Path file = tempDir.resolve("test"); 73 | assertTrue(file.toFile().createNewFile()); 74 | Files.write(file, List.of("key:value")); 75 | 76 | final PropertiesReader propertiesReader = new PropertiesReader(tempDir.toFile()) { 77 | @Override 78 | public @NotNull String getFilename() { 79 | return "test"; 80 | } 81 | }; 82 | assertTrue(propertiesReader.readPropertiesFromFile()); 83 | assertEquals("value", propertiesReader.getProperty("key")); 84 | 85 | //noinspection DataFlowIssue 86 | assertThrows(NullPointerException.class, () -> propertiesReader.getProperty(null)); 87 | } 88 | 89 | @Test 90 | void getProperty_key_doesnt_exist(final @TempDir @NotNull Path tempDir) throws IOException { 91 | final Path file = tempDir.resolve("test"); 92 | assertTrue(file.toFile().createNewFile()); 93 | Files.write(file, List.of("key:value")); 94 | 95 | final PropertiesReader propertiesReader = new PropertiesReader(tempDir.toFile()) { 96 | @Override 97 | public @NotNull String getFilename() { 98 | return "test"; 99 | } 100 | }; 101 | assertTrue(propertiesReader.readPropertiesFromFile()); 102 | assertEquals("value", propertiesReader.getProperty("key")); 103 | 104 | assertNull(propertiesReader.getProperty("unknown")); 105 | } 106 | 107 | @Test 108 | void getProperty_key_exists(final @TempDir @NotNull Path tempDir) throws IOException { 109 | final Path file = tempDir.resolve("test"); 110 | assertTrue(file.toFile().createNewFile()); 111 | Files.write(file, List.of("key:value")); 112 | 113 | final PropertiesReader propertiesReader = new PropertiesReader(tempDir.toFile()) { 114 | @Override 115 | public @NotNull String getFilename() { 116 | return "test"; 117 | } 118 | }; 119 | assertTrue(propertiesReader.readPropertiesFromFile()); 120 | assertEquals("value", propertiesReader.getProperty("key")); 121 | } 122 | 123 | @Test 124 | void getProperty_before_loading_properties(final @TempDir @NotNull Path tempDir) throws IOException { 125 | final Path file = tempDir.resolve("test"); 126 | assertTrue(file.toFile().createNewFile()); 127 | Files.write(file, List.of("key:value")); 128 | 129 | final PropertiesReader propertiesReader = new PropertiesReader(tempDir.toFile()) { 130 | @Override 131 | public @NotNull String getFilename() { 132 | return "test"; 133 | } 134 | }; 135 | assertNull(propertiesReader.getProperty("key")); 136 | } 137 | } 138 | --------------------------------------------------------------------------------