diff --git a/.classpath b/.classpath
index 7d2ffae..2c86875 100644
--- a/.classpath
+++ b/.classpath
@@ -8,9 +8,9 @@
+
-
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
index 04cfa2c..8bc0e1c 100644
--- a/.settings/org.eclipse.core.resources.prefs
+++ b/.settings/org.eclipse.core.resources.prefs
@@ -1,6 +1,5 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
-encoding//src/main/resources=UTF-8
encoding//src/test/java=UTF-8
encoding//src/test/resources=UTF-8
encoding/=UTF-8
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
index 6fe4a00..3ef0bd1 100644
--- a/.settings/org.eclipse.jdt.core.prefs
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -109,3 +109,364 @@ org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
org.eclipse.jdt.core.compiler.release=disabled
org.eclipse.jdt.core.compiler.source=11
+org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=true
+org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=1
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=true
+org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=true
+org.eclipse.jdt.core.formatter.align_with_spaces=false
+org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=84
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=80
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=20
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_module_statements=16
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_relational_operator=0
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=84
+org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0
+org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
+org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=1
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch=0
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=true
+org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=true
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=true
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=false
+org.eclipse.jdt.core.formatter.comment.indent_tag_description=false
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags=do not insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=true
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_not_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case=insert
+org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=false
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_if_single_item
+org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_if_empty
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=true
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_if_single_item
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_always
+org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_if_empty
+org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_if_single_item
+org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=true
+org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=true
+org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.lineSplit=150
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block=0
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block=0
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block=0
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=separate_lines_if_wrapped
+org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.text_block_indentation=0
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/.settings/org.eclipse.jdt.ui.prefs b/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..035cdab
--- /dev/null
+++ b/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,5 @@
+eclipse.preferences.version=1
+formatter_profile=_KSKE
+formatter_settings_version=18
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.text.custom_code_templates=/**\r\n * @return the ${bare_field_name}\r\n * @since Envoy Common v0.1-beta\r\n *//**\r\n * @param ${param} the ${bare_field_name} to set\r\n * @since Envoy Common v0.1-beta\r\n *//**\r\n * ${tags}\r\n * @since Envoy Common v0.1-beta\r\n *//**\r\n * Project\: <strong>${project_name}</strong><br>\r\n * File\: <strong>${file_name}</strong><br>\r\n * Created\: <strong>${date}</strong><br>\r\n * \r\n * @author ${user}\r\n * @since Envoy Common v0.1-beta\r\n *//**\r\n * ${tags}\r\n * @since Envoy Common v0.1-beta\r\n *//**\r\n * @author ${user}\r\n *\r\n * ${tags}\r\n * @since Envoy Common v0.1-beta\r\n *//**\r\n * {@inheritDoc}\r\n *//**\r\n * ${tags}\r\n * ${see_to_target}\r\n * @since Envoy Common v0.1-beta\r\n */${filecomment}\r\n${package_declaration}\r\n\r\n${typecomment}\r\n${type_declaration}\r\n\r\n\r\n\r\n${exception_var}.printStackTrace();${body_statement}${body_statement}return ${field};${field} \= ${param};
diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component
index 08f7658..44aa2b3 100644
--- a/.settings/org.eclipse.wst.common.component
+++ b/.settings/org.eclipse.wst.common.component
@@ -1,21 +1,32 @@
-
+
+
+
+
-
+
+
+
+
-
-
+
+
+
+
-
+
+
+
+
diff --git a/pom.xml b/pom.xml
index 0add6eb..0060e9a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -16,13 +16,19 @@
11
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ 5.5.2
+
+
envoy-common
-
-
- src/main/resources
-
-
+
+
+
+
diff --git a/src/main/java/envoy/data/Config.java b/src/main/java/envoy/data/Config.java
index c281d0e..bcff68c 100644
--- a/src/main/java/envoy/data/Config.java
+++ b/src/main/java/envoy/data/Config.java
@@ -61,6 +61,14 @@ public class Config {
} else throw new EnvoyException("Malformed command line argument at position " + i);
}
+ /**
+ * Initializes config items from a map.
+ *
+ * @param items the items to include in this config
+ * @since Envoy Common v0.1-beta
+ */
+ public void load(Map> items) { this.items.putAll(items); }
+
/**
* @return {@code true} if all mandatory config items are initialized
* @since Envoy Common v0.1-beta
diff --git a/src/main/java/envoy/data/Contact.java b/src/main/java/envoy/data/Contact.java
new file mode 100644
index 0000000..9a5fd0a
--- /dev/null
+++ b/src/main/java/envoy/data/Contact.java
@@ -0,0 +1,91 @@
+package envoy.data;
+
+import java.io.Serializable;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * This class is the superclass for both {@link User} and {@link Group}.
+ * It provides an id and a name for each user and group.
+ *
+ * Project: envoy-common
+ * File: Contact.java
+ * Created: 24 Mar 2020
+ *
+ * @author Leon Hofmeister
+ * @since Envoy v0.1-beta
+ */
+public abstract class Contact implements Serializable {
+
+ private final long id;
+ private final transient Set extends Contact> contacts;
+ private String name;
+
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Creates a new instance of a {@link Contact}.
+ *
+ * @param id the ID of this contact
+ * @param name the name of this contact
+ * @param contacts the contacts of this {@link Contact}
+ * @since Envoy Common v0.1-beta
+ */
+ public Contact(long id, String name, Set extends Contact> contacts) {
+ this.id = id;
+ this.name = name;
+ this.contacts = contacts;
+ }
+
+ /**
+ * @return the ID of this {@link Contact}
+ * @since Envoy Common v0.2-alpha
+ */
+ public long getID() { return id; }
+
+ /**
+ * @return the name of this {@link Contact}
+ * @since Envoy Common v0.2-alpha
+ */
+ public String getName() { return name; }
+
+ /**
+ * @param name the new name of this {@link Contact}
+ * @since Envoy Common v0.1-beta
+ */
+ public void setName(String name) { this.name = name; }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() { return String.format("Contact[id=%d,name=%s, contacts=%s]", id, name, contacts); }
+
+ /**
+ * Provides a hash code based on the ID of this contact.
+ *
+ * @since Envoy Common v0.1-beta
+ */
+ @Override
+ public int hashCode() { return Objects.hash(id); }
+
+ /**
+ * Tests equality to another object. If that object is a contact as well,
+ * equality is determined by the ID.
+ *
+ * @param obj the object to test for equality to this contact
+ * @return {code true} if both objects are contacts and have identical IDs
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (!(obj instanceof Contact)) return false;
+ return id == ((Contact) obj).id;
+ }
+
+ /**
+ * @return the contacts of this {@link Contact}
+ * @since Envoy Common v0.1-beta
+ */
+ public Set extends Contact> getContacts() { return contacts; }
+}
diff --git a/src/main/java/envoy/data/Contacts.java b/src/main/java/envoy/data/Contacts.java
deleted file mode 100644
index c86c1fc..0000000
--- a/src/main/java/envoy/data/Contacts.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package envoy.data;
-
-import java.io.Serializable;
-import java.util.List;
-
-/**
- * Project: envoy-common
- * File: Contacts.java
- * Created: 02.01.2020
- *
- * @author Kai S. K. Engelbart
- * @since Envoy Common v0.2-alpha
- */
-public class Contacts implements Serializable {
-
- private final List contacts;
-
- private static final long serialVersionUID = 136970804968152871L;
-
- /**
- * Creates an instance of {@link Contacts}.
- *
- * @param contacts the contact list
- * @since Envoy Common v0.2-alpha
- */
- public Contacts(List contacts) { this.contacts = contacts; }
-
- @Override
- public String toString() { return String.format("Contacts[%s]", contacts); }
-
- /**
- * @return a list of users messages can be sent to
- * @since Envoy Common v0.2-alpha
- */
- public List getContacts() { return contacts; }
-}
diff --git a/src/main/java/envoy/data/Group.java b/src/main/java/envoy/data/Group.java
new file mode 100644
index 0000000..4eb6b02
--- /dev/null
+++ b/src/main/java/envoy/data/Group.java
@@ -0,0 +1,55 @@
+package envoy.data;
+
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Project: envoy-common
+ * File: Group.java
+ * Created: 24 Mar 2020
+ *
+ * @author Leon Hofmeister
+ * @since Envoy Common v0.1-beta
+ */
+public final class Group extends Contact {
+
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Creates a new instance of a {@link Group} without any members.
+ *
+ * @param id the ID of this group
+ * @param name the name of this group
+ * @since Envoy Common v0.1-beta
+ */
+ public Group(long id, String name) { this(id, name, new HashSet()); }
+
+ /**
+ * Creates an instance of a {@link Group}.
+ *
+ * @param id the ID of this group
+ * @param name the name of this group
+ * @param members all members that should be preinitialized
+ * @since Envoy Common v0.1-beta
+ */
+ public Group(long id, String name, Set members) { super(id, name, members); }
+
+ private void readObject(ObjectInputStream inputStream) throws Exception {
+ inputStream.defaultReadObject();
+ var contacts = Contact.class.getDeclaredField("contacts");
+ contacts.setAccessible(true);
+ contacts.set(this, inputStream.readObject());
+ }
+
+ private void writeObject(ObjectOutputStream outputStream) throws Exception {
+ outputStream.defaultWriteObject();
+ getContacts().forEach(user -> user.serializeContacts(false));
+ outputStream.writeObject(getContacts());
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Set getContacts() { return (Set) super.getContacts(); }
+}
diff --git a/src/main/java/envoy/data/GroupMessage.java b/src/main/java/envoy/data/GroupMessage.java
new file mode 100644
index 0000000..a2f8488
--- /dev/null
+++ b/src/main/java/envoy/data/GroupMessage.java
@@ -0,0 +1,69 @@
+package envoy.data;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * Project: envoy-common
+ * File: GroupMessage.java
+ * Created: 26.03.2020
+ *
+ * @author Maximilian Käfer
+ * @since Envoy Common v0.1-beta
+ */
+public final class GroupMessage extends Message {
+
+ private final Map memberStatuses;
+
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Initializes a {@link GroupMessage} with values for all of its properties. The
+ * use
+ * of this constructor is only intended for the {@link MessageBuilder} class, as
+ * this class provides {@code null} checks and default values for all
+ * properties.
+ *
+ * @param id unique ID
+ * @param senderID the ID of the user who sends the message
+ * @param groupID the ID of the group which receives the message
+ * @param creationDate the creation date of the message
+ * @param text the text content of the message
+ * @param attachment the attachment of the message, if present
+ * @param status the current {@link Message.MessageStatus} of the
+ * message
+ * @param forwarded whether this message was forwarded
+ * @param memberStatuses a map of all members and their status according to this
+ * {@link GroupMessage}
+ * @since Envoy Common v0.1-beta
+ */
+ GroupMessage(long id, long senderID, long groupID, Date creationDate, String text, MessageAttachment> attachment, MessageStatus status,
+ boolean forwarded, Map memberStatuses) {
+ super(id, senderID, groupID, creationDate, text, attachment, status, forwarded);
+ this.memberStatuses = memberStatuses;
+ }
+
+ /**
+ * Sets the status to be the minimum of all members.
+ *
+ * @since Envoy Common v0.1-beta
+ */
+ public void updateStatus() {
+ setStatus(Collections.min(memberStatuses.values()));
+ switch (getStatus()) {
+ case RECEIVED:
+ setReceivedDate(new Date());
+ break;
+ case READ:
+ setReadDate(new Date());
+ break;
+ }
+ }
+
+ /**
+ * @return the map of all statuses in this {@link GroupMessage}
+ * @since Envoy Common v0.1-beta
+ */
+ public Map getMemberStatuses() { return memberStatuses; }
+}
diff --git a/src/main/java/envoy/data/IdGenerator.java b/src/main/java/envoy/data/IDGenerator.java
similarity index 73%
rename from src/main/java/envoy/data/IdGenerator.java
rename to src/main/java/envoy/data/IDGenerator.java
index 26b7131..91681e0 100644
--- a/src/main/java/envoy/data/IdGenerator.java
+++ b/src/main/java/envoy/data/IDGenerator.java
@@ -6,33 +6,33 @@ import java.io.Serializable;
* Generates increasing IDs between two numbers.
*
* Project: envoy-common
- * File: IdGenerator.java
+ * File: IDGenerator.java
* Created: 31.12.2019
*
* @author Kai S. K. Engelbart
* @since Envoy Common v0.2-alpha
*/
-public class IdGenerator implements Serializable {
+public class IDGenerator implements Serializable {
private final long end;
private long current;
- private static final long serialVersionUID = -1517378307055845147L;
+ private static final long serialVersionUID = 0L;
/**
- * Creates an instance of {@link IdGenerator}.
+ * Creates an instance of {@link IDGenerator}.
*
* @param begin the first ID
* @param size the amount of IDs to provide
* @since Envoy Common v0.2-alpha
*/
- public IdGenerator(long begin, long size) {
+ public IDGenerator(long begin, long size) {
current = begin;
end = begin + size;
}
@Override
- public String toString() { return String.format("IdGenerator[current=%d,end=%d]", current, end); }
+ public String toString() { return String.format("IDGenerator[current=%d,end=%d]", current, end); }
/**
* @return {@code true} if there are unused IDs remaining
diff --git a/src/main/java/envoy/data/LoginCredentials.java b/src/main/java/envoy/data/LoginCredentials.java
index 8007796..e097047 100644
--- a/src/main/java/envoy/data/LoginCredentials.java
+++ b/src/main/java/envoy/data/LoginCredentials.java
@@ -30,16 +30,22 @@ public class LoginCredentials implements Serializable {
* @param password the password of the user (will be converted to a hash)
* @param registration signifies that these credentials are used for user
* registration instead of user login
- * @throws NoSuchAlgorithmException if the algorithm used is unknown
* @since Envoy Common v0.2-alpha
*/
- public LoginCredentials(String identifier, char[] password, boolean registration) throws NoSuchAlgorithmException {
+ public LoginCredentials(String identifier, char[] password, boolean registration) {
this.identifier = identifier;
passwordHash = getSha256(toByteArray(password));
this.registration = registration;
}
- private byte[] getSha256(byte[] input) throws NoSuchAlgorithmException { return MessageDigest.getInstance("SHA-256").digest(input); }
+ private byte[] getSha256(byte[] input) {
+ try {
+ return MessageDigest.getInstance("SHA-256").digest(input);
+ } catch (NoSuchAlgorithmException e) {
+ // This will never happen
+ throw new RuntimeException(e);
+ }
+ }
private byte[] toByteArray(char[] chars) {
byte[] bytes = new byte[chars.length * 2];
@@ -54,8 +60,8 @@ public class LoginCredentials implements Serializable {
public String toString() {
try (Formatter form = new Formatter()) {
form.format("LoginCredentials[identifier=%s,passwordHash=", identifier);
- for (byte element : passwordHash)
- form.format("%02x", element);
+ for (int i = 0; i < 3; i++)
+ form.format("%02x", passwordHash[i]);
return form.format(",registration=%b]", registration).toString();
}
}
diff --git a/src/main/java/envoy/data/Message.java b/src/main/java/envoy/data/Message.java
index 7a8adc4..ec7faf4 100644
--- a/src/main/java/envoy/data/Message.java
+++ b/src/main/java/envoy/data/Message.java
@@ -48,7 +48,7 @@ public class Message implements Serializable {
READ
}
- private final long id, senderId, recipientId;
+ private final long id, senderID, recipientID;
private final boolean forwarded;
private final Date creationDate;
private final String text;
@@ -57,7 +57,7 @@ public class Message implements Serializable {
private Date receivedDate, readDate;
private MessageStatus status;
- private static final long serialVersionUID = -4393477412979594435L;
+ private static final long serialVersionUID = 0L;
/**
* Initializes a {@link Message} with values for all of its properties. The use
@@ -66,8 +66,8 @@ public class Message implements Serializable {
* properties.
*
* @param id unique ID
- * @param senderId the ID of the user who sends the message
- * @param recipientId the ID of the user who receives the message
+ * @param senderID the ID of the user who sends the message
+ * @param recipientID the ID of the user who receives the message
* @param creationDate the creation date of the message
* @param text the text content of the message
* @param attachment the attachment of the message, if present
@@ -75,11 +75,11 @@ public class Message implements Serializable {
* @param forwarded whether this message was forwarded
* @since Envoy Common v0.2-alpha
*/
- Message(long id, long senderId, long recipientId, Date creationDate, String text, MessageAttachment> attachment, MessageStatus status,
+ Message(long id, long senderID, long recipientID, Date creationDate, String text, MessageAttachment> attachment, MessageStatus status,
boolean forwarded) {
this.id = id;
- this.senderId = senderId;
- this.recipientId = recipientId;
+ this.senderID = senderID;
+ this.recipientID = recipientID;
this.creationDate = creationDate;
this.text = text;
this.attachment = attachment;
@@ -107,13 +107,14 @@ public class Message implements Serializable {
@Override
public String toString() {
- return String.format("TextMessage[id=%d,sender=%s,recipient=%s,date=%s,status=%s,text=%s,hasAttachment=%b]",
+ return String.format("Message[id=%d,sender=%s,recipient=%s,date=%s,status=%s,text=%s,forwarded=%b,hasAttachment=%b]",
id,
- senderId,
- recipientId,
+ senderID,
+ recipientID,
new SimpleDateFormat("dd.MM.yyyy HH:mm:ss").format(creationDate),
status,
text,
+ forwarded,
attachment != null);
}
@@ -121,19 +122,19 @@ public class Message implements Serializable {
* @return the ID of this message
* @since Envoy Common v0.2-alpha
*/
- public long getId() { return id; }
+ public long getID() { return id; }
/**
* @return the sender ID of this message
* @since Envoy Common v0.2-alpha
*/
- public long getSenderId() { return senderId; }
+ public long getSenderID() { return senderID; }
/**
* @return the recipient ID of this message
* @since Envoy Common v0.2-alpha
*/
- public long getRecipientId() { return recipientId; }
+ public long getRecipientID() { return recipientID; }
/**
* @return the date at which this message was created
diff --git a/src/main/java/envoy/data/MessageAttachment.java b/src/main/java/envoy/data/MessageAttachment.java
index 23a2c2e..3d04eab 100644
--- a/src/main/java/envoy/data/MessageAttachment.java
+++ b/src/main/java/envoy/data/MessageAttachment.java
@@ -19,7 +19,7 @@ import envoy.util.SerializationUtils;
*/
public class MessageAttachment implements Serializable {
- private static final long serialVersionUID = 262683855157198013L;
+ private static final long serialVersionUID = 0L;
private T value;
/**
diff --git a/src/main/java/envoy/data/MessageBuilder.java b/src/main/java/envoy/data/MessageBuilder.java
index 9129357..87c6bf9 100644
--- a/src/main/java/envoy/data/MessageBuilder.java
+++ b/src/main/java/envoy/data/MessageBuilder.java
@@ -1,6 +1,8 @@
package envoy.data;
import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
import envoy.data.Message.MessageStatus;
@@ -17,7 +19,7 @@ import envoy.data.Message.MessageStatus;
public class MessageBuilder {
// Mandatory properties without default values
- private final long senderId, recipientId;
+ private final long senderID, recipientID;
// Properties with default values
private long id;
@@ -31,26 +33,26 @@ public class MessageBuilder {
* Creates an instance of {@link MessageBuilder} with all mandatory values
* without defaults for the {@link Message} class.
*
- * @param senderId the ID of the user who sends the {@link Message}
- * @param recipientId the ID of the user who receives the {@link Message}
+ * @param senderID the ID of the user who sends the {@link Message}
+ * @param recipientID the ID of the user who receives the {@link Message}
* @param idGenerator the ID generator used to generate a unique {@link Message}
* id
* @since Envoy Common v0.2-alpha
*/
- public MessageBuilder(long senderId, long recipientId, IdGenerator idGenerator) { this(senderId, recipientId, idGenerator.next()); }
+ public MessageBuilder(long senderID, long recipientID, IDGenerator idGenerator) { this(senderID, recipientID, idGenerator.next()); }
/**
* Creates an instance of {@link MessageBuilder} with all mandatory values
* without defaults for the {@link Message} class.
*
- * @param senderId the ID of the user who sends the {@link Message}
- * @param recipientId the ID of the user who receives the {@link Message}
+ * @param senderID the ID of the user who sends the {@link Message}
+ * @param recipientID the ID of the user who receives the {@link Message}
* @param messageId the ID of the {@link Message}
* @since Envoy Common v0.2-alpha
*/
- public MessageBuilder(long senderId, long recipientId, long messageId) {
- this.senderId = senderId;
- this.recipientId = recipientId;
+ public MessageBuilder(long senderID, long recipientID, long messageId) {
+ this.senderID = senderID;
+ this.recipientID = recipientID;
id = messageId;
}
@@ -60,13 +62,13 @@ public class MessageBuilder {
* This makes it especially useful in the case of forwarding messages.
*
* @param msg the message to copy
- * @param recipientId the ID of the user who receives the {@link Message}
- * @param idGenerator the ID generator used to generate a unique {@link Message}
+ * @param recipientID the ID of the user who receives the {@link Message}
+ * @param iDGenerator the ID generator used to generate a unique {@link Message}
* id
* @since Envoy v0.1-beta
*/
- public MessageBuilder(Message msg, long recipientId, IdGenerator idGenerator) {
- this(msg.getRecipientId(), recipientId, idGenerator.next());
+ public MessageBuilder(Message msg, long recipientID, IDGenerator iDGenerator) {
+ this(msg.getRecipientID(), recipientID, iDGenerator.next());
this.attachment = msg.getAttachment();
this.creationDate = new Date();
this.forwarded = true;
@@ -97,12 +99,71 @@ public class MessageBuilder {
* @since Envoy Common v0.2-alpha
*/
public Message build() {
- // Supplement default values
+ supplyDefaults();
+ return new Message(id, senderID, recipientID, creationDate, text, attachment, status, forwarded);
+ }
+
+ /**
+ * Creates an instance of {@link GroupMessage} with the previously supplied
+ * values.
+ * Sets all member statuses to {@link MessageStatus#WAITING}.
+ * If a mandatory value is not set, a default value will be used
+ * instead:
+ *
+ *
+ *
+ * {@code date} |
+ * {@code new Date()} |
+ *
+ *
+ * {@code text} |
+ * {@code ""} |
+ *
+ *
+ *
+ * @param group the {@link Group} that is used to fill the map of member
+ * statuses
+ * @return a new instance of {@link GroupMessage}
+ * @since Envoy Common v0.2-alpha
+ */
+ public GroupMessage buildGroupMessage(Group group) {
+ var memberStatuses = new HashMap();
+ group.getContacts().forEach(user -> memberStatuses.put(user.getID(), MessageStatus.WAITING));
+ return buildGroupMessage(group, memberStatuses);
+ }
+
+ /**
+ * Creates an instance of {@link GroupMessage} with the previously supplied
+ * values. If a mandatory value is not set, a default value will be used
+ * instead:
+ *
+ *
+ *
+ * {@code date} |
+ * {@code new Date()} |
+ *
+ *
+ * {@code text} |
+ * {@code ""} |
+ *
+ *
+ *
+ * @param group the {@link Group} that is used to fill the map of
+ * member statuses
+ * @param memberStatuses the map of all current statuses
+ * @return a new instance of {@link GroupMessage}
+ * @since Envoy Common v0.1-beta
+ */
+ public GroupMessage buildGroupMessage(Group group, Map memberStatuses) {
+ if (group == null || memberStatuses == null) throw new NullPointerException();
+ supplyDefaults();
+ return new GroupMessage(id, senderID, recipientID, creationDate, text, attachment, status, forwarded, memberStatuses);
+ }
+
+ private void supplyDefaults() {
if (creationDate == null) creationDate = new Date();
if (text == null) text = "";
if (status == null) status = MessageStatus.WAITING;
-
- return new Message(id, senderId, recipientId, creationDate, text, attachment, status, forwarded);
}
/**
diff --git a/src/main/java/envoy/data/User.java b/src/main/java/envoy/data/User.java
index 25be9e8..7751ce3 100644
--- a/src/main/java/envoy/data/User.java
+++ b/src/main/java/envoy/data/User.java
@@ -1,6 +1,9 @@
package envoy.data;
-import java.io.Serializable;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.HashSet;
+import java.util.Set;
/**
* Represents a unique user with a unique, numeric ID, a name and a current
@@ -13,7 +16,16 @@ import java.io.Serializable;
* @author Kai S. K. Engelbart
* @since Envoy Common v0.2-alpha
*/
-public class User implements Serializable {
+public final class User extends Contact {
+
+ private UserStatus status;
+
+ /**
+ * Used to serialize contact list to a maximum depth of one.
+ */
+ private transient boolean serializeContacts = true;
+
+ private static final long serialVersionUID = 1L;
/**
* This enumeration defines all possible statuses a user can have.
@@ -44,54 +56,50 @@ public class User implements Serializable {
OFFLINE;
}
- private final long id;
- private final String name;
-
- private UserStatus status;
-
- private static final long serialVersionUID = 3530947374856708236L;
-
/**
- * Initializes a {@link User}. The {@link UserStatus} is set to
- * {@link UserStatus#ONLINE}.
+ * Initializes a {@link User}.
+ * The {@link UserStatus} is set to {@link UserStatus#ONLINE}.
+ * No contacts are initialized.
*
* @param id unique ID
* @param name user name
* @since Envoy Common v0.2-alpha
*/
public User(long id, String name) {
- this.id = id;
- this.name = name;
- status = UserStatus.ONLINE;
+ super(id, name, new HashSet<>());
+ status = UserStatus.ONLINE;
+ }
+
+ /**
+ * Initializes a {@link User}.
+ * The {@link UserStatus} is set to {@link UserStatus#ONLINE}.
+ *
+ * @param id unique ID
+ * @param name user name
+ * @param contacts the contacts of this user
+ * @since Envoy Common v0.2-alpha
+ */
+ public User(long id, String name, Set contacts) {
+ super(id, name, contacts);
+ status = UserStatus.ONLINE;
}
/**
* Initializes a {@link User}.
*
- * @param id unique ID
- * @param name user name
- * @param status the status of the user
+ * @param id unique ID
+ * @param name user name
+ * @param status the status of this user
+ * @param contacts the contacts of this user
* @since Envoy Common v0.2-alpha
*/
- public User(long id, String name, UserStatus status) {
- this(id, name);
+ public User(long id, String name, UserStatus status, Set contacts) {
+ super(id, name, contacts);
this.status = status;
}
@Override
- public String toString() { return String.format("User[id=%d,name=%s,status=%s]", id, name, status); }
-
- /**
- * @return the ID of this {@link User}
- * @since Envoy Common v0.2-alpha
- */
- public long getId() { return id; }
-
- /**
- * @return the name of this {@link User}
- * @since Envoy Common v0.2-alpha
- */
- public String getName() { return name; }
+ public String toString() { return String.format("User[id=%d,name=%s,status=%s,contacts=%s]", getID(), getName(), status, getContacts()); }
/**
* @return the current status of this user
@@ -104,4 +112,26 @@ public class User implements Serializable {
* @since Envoy Common v0.2-alpha
*/
public void setStatus(UserStatus status) { this.status = status; }
+
+ private void readObject(ObjectInputStream inputStream) throws Exception {
+ inputStream.defaultReadObject();
+ var contacts = Contact.class.getDeclaredField("contacts");
+ contacts.setAccessible(true);
+ contacts.set(this, inputStream.readObject());
+ }
+
+ private void writeObject(ObjectOutputStream outputStream) throws Exception {
+ outputStream.defaultWriteObject();
+ if (serializeContacts) {
+ getContacts().stream().filter(User.class::isInstance).map(User.class::cast).forEach(user -> user.serializeContacts = false);
+ outputStream.writeObject(getContacts());
+ } else outputStream.writeObject(new HashSet<>());
+ }
+
+ /**
+ * @param serializeContacts whether the contacts of this {@link User} should be
+ * serialized
+ * @since Envoy Common v0.1-beta
+ */
+ public void serializeContacts(boolean serializeContacts) { this.serializeContacts = serializeContacts; }
}
diff --git a/src/main/java/envoy/event/ContactOperationEvent.java b/src/main/java/envoy/event/ContactOperationEvent.java
deleted file mode 100644
index 7410e65..0000000
--- a/src/main/java/envoy/event/ContactOperationEvent.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package envoy.event;
-
-import envoy.data.User;
-
-/**
- * Signifies the modification of a contact list.
- *
- * Project: envoy-common
- * File: ContactOperationEvent.java
- * Created: 05.02.2020
- *
- * @author Maximilian Käfer
- * @since Envoy Common v0.2-alpha
- */
-public class ContactOperationEvent extends Event {
-
- /**
- * Specifies the operation performed on a contact list.
- *
- * Project: envoy-common
- * File: ContactOperationEvent.java
- * Created: 05.02.2020
- *
- * @author Maximilian Käfer
- * @since Envoy Common v0.2-alpha
- */
- public enum Operation {
-
- /**
- * Adds a user to the contact list.
- */
- ADD,
-
- /**
- * Removes a user from the contact list.
- */
- REMOVE;
- }
-
- private final Operation operationType;
-
- private static final long serialVersionUID = -1166652868189511553L;
-
- /**
- * Initializes a {@link ContactOperationEvent}.
- *
- * @param contact the user on which the operation is performed
- * @param operationType the type of operation to perform
- * @since Envoy Common v0.2-alpha
- */
- public ContactOperationEvent(User contact, Operation operationType) {
- super(contact);
- this.operationType = operationType;
- }
-
- /**
- * @return the type of operation to perform
- * @since Envoy Common v0.2-alpha
- */
- public Operation getOperationType() { return operationType; }
-}
diff --git a/src/main/java/envoy/event/ElementOperation.java b/src/main/java/envoy/event/ElementOperation.java
new file mode 100644
index 0000000..b7d4c10
--- /dev/null
+++ b/src/main/java/envoy/event/ElementOperation.java
@@ -0,0 +1,28 @@
+package envoy.event;
+
+/**
+ * This enum declares all modification possibilities for a given container.
+ * These can be: {@link ElementOperation#ADD} or
+ * {@link ElementOperation#REMOVE}.
+ *
+ * Project: envoy-common
+ * File: ElementOperation.java
+ * Created: 25 Mar 2020
+ *
+ * @author Leon Hofmeister
+ * @since Envoy Common v0.1-beta
+ */
+public enum ElementOperation {
+
+ /**
+ * Select this element, if the given element should be added to the given
+ * container.
+ */
+ ADD,
+
+ /**
+ * Select this element, if the given element should be removed from the given
+ * container.
+ */
+ REMOVE
+}
diff --git a/src/main/java/envoy/event/Event.java b/src/main/java/envoy/event/Event.java
index 5b13306..809c5ec 100644
--- a/src/main/java/envoy/event/Event.java
+++ b/src/main/java/envoy/event/Event.java
@@ -15,7 +15,7 @@ public abstract class Event implements Serializable {
protected final T value;
- private static final long serialVersionUID = 4673659457380399167L;
+ private static final long serialVersionUID = 0L;
protected Event(T value) { this.value = value; }
@@ -39,7 +39,7 @@ public abstract class Event implements Serializable {
*/
public static abstract class Valueless extends Event {
- private static final long serialVersionUID = -9019362144094097997L;
+ private static final long serialVersionUID = 0L;
protected Valueless() { super(null); }
diff --git a/src/main/java/envoy/event/GroupCreationEvent.java b/src/main/java/envoy/event/GroupCreationEvent.java
new file mode 100644
index 0000000..88c405d
--- /dev/null
+++ b/src/main/java/envoy/event/GroupCreationEvent.java
@@ -0,0 +1,42 @@
+package envoy.event;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import envoy.data.User;
+
+/**
+ * This event creates a group with the given name.
+ *
+ * Project: envoy-common
+ * File: GroupCreationEvent.java
+ * Created: 25 Mar 2020
+ *
+ * @author Leon Hofmeister
+ * @since Envoy Common v0.1-beta
+ */
+public class GroupCreationEvent extends Event {
+
+ private final Set initialMemberIDs;
+
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * @param value the name of this group at creation time
+ * @param initialMemberIDs the IDs of all {@link User}s that should be group
+ * members from the beginning on (excluding the creator
+ * of this group)
+ * @since Envoy Common v0.1-beta
+ */
+ public GroupCreationEvent(String value, Set initialMemberIDs) {
+ super(value);
+ this.initialMemberIDs = (initialMemberIDs != null) ? initialMemberIDs : new HashSet<>();
+ }
+
+ /**
+ * @return the IDs of all {@link User}s that are members from the beginning
+ * (excluding the creator of this group)
+ * @since Envoy Common v0.1-beta
+ */
+ public Set getInitialMemberIDs() { return initialMemberIDs; }
+}
diff --git a/src/main/java/envoy/event/GroupMessageStatusChangeEvent.java b/src/main/java/envoy/event/GroupMessageStatusChangeEvent.java
new file mode 100644
index 0000000..b02f980
--- /dev/null
+++ b/src/main/java/envoy/event/GroupMessageStatusChangeEvent.java
@@ -0,0 +1,46 @@
+package envoy.event;
+
+import java.util.Date;
+
+import envoy.data.GroupMessage;
+import envoy.data.Message.MessageStatus;
+
+/**
+ * Project: envoy-common
+ * File: GroupMessageStatusChangeEvent.java
+ * Created: 18.04.2020
+ *
+ * @author Maximilian Käfer
+ * @since Envoy Common v0.1-beta
+ */
+public class GroupMessageStatusChangeEvent extends MessageStatusChangeEvent {
+
+ private final long memberID;
+
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Initializes a {@link GroupMessageStatusChangeEvent}.
+ *
+ * @param id the ID of the {@link GroupMessage} this event is related to
+ * @param status the status of this specific members {@link GroupMessage}
+ * @param date the date at which the MessageStatus change occurred for
+ * this specific member
+ * @param memberID the ID of the group member that caused the status change
+ * @since Envoy Common v0.1-beta
+ */
+ public GroupMessageStatusChangeEvent(long id, MessageStatus status, Date date, long memberID) {
+ super(id, status, date);
+ this.memberID = memberID;
+ }
+
+ /**
+ * @return the memberID which the user who sends this event has
+ * @since Envoy Common v0.1-beta
+ */
+ public long getMemberID() { return memberID; }
+
+ @Override
+ public String toString() { return String.format("GroupMessageStatusChangeEvent[meta=%s,memberID=%d]", super.toString(), memberID); }
+
+}
diff --git a/src/main/java/envoy/event/GroupResizeEvent.java b/src/main/java/envoy/event/GroupResizeEvent.java
new file mode 100644
index 0000000..46952d5
--- /dev/null
+++ b/src/main/java/envoy/event/GroupResizeEvent.java
@@ -0,0 +1,65 @@
+package envoy.event;
+
+import envoy.data.Contact;
+import envoy.data.Group;
+import envoy.data.User;
+
+/**
+ * This event is used to communicate changes in the group size between client
+ * and server.
+ * Possible actions are adding or removing certain {@link User}s to or from a
+ * certain {@link Group}.
+ *
+ * Project: envoy-common
+ * File: GroupResizeEvent.java
+ * Created: 25 Mar 2020
+ *
+ * @author Leon Hofmeister
+ * @since Envoy Common v0.1-beta
+ */
+public class GroupResizeEvent extends Event {
+
+ private final long groupID;
+ private final ElementOperation operation;
+
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Initializes a {@link GroupResizeEvent} through a Contact where the name has
+ * already been set.
+ *
+ * @param user the {@link User} who wants to join or leave a group
+ * @param group the {@link Group} he wants to join or leave
+ * @param operation describes what to do with the given user:
+ * add him to this group or remove him from it
+ * @since Envoy Common v0.2-alpha
+ */
+ public GroupResizeEvent(User user, Group group, ElementOperation operation) {
+ super(user);
+ if (group.getContacts().contains(user)) {
+ if (operation.equals(ElementOperation.ADD)) throw new IllegalArgumentException(
+ "Cannot add " + user + " to group " + group.getID() + " because he is already a member of this group");
+ } else if (operation.equals(ElementOperation.REMOVE))
+ throw new IllegalArgumentException("Cannot remove " + user + " from group " + group.getID() + " because he is no part of this group");
+ groupID = group.getID();
+ this.operation = operation;
+ }
+
+ /**
+ * @return the ID of the {@link Contact} this event is related to
+ * @since Envoy Common v0.2-alpha
+ */
+ public long getGroupID() { return groupID; }
+
+ /**
+ * @return the operationType
+ * @since Envoy Common v0.1-beta
+ */
+ public ElementOperation getOperation() { return operation; }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() { return String.format("GroupResizeEvent[userid=%d,groupid=%d,operation=%s]", get(), groupID, operation); }
+}
diff --git a/src/main/java/envoy/event/HandshakeRejectionEvent.java b/src/main/java/envoy/event/HandshakeRejectionEvent.java
index c89405d..fea1058 100644
--- a/src/main/java/envoy/event/HandshakeRejectionEvent.java
+++ b/src/main/java/envoy/event/HandshakeRejectionEvent.java
@@ -1,7 +1,5 @@
package envoy.event;
-import envoy.data.LoginCredentials;
-
/**
* Signifies to the client that the handshake failed for the attached
* reason.
@@ -16,35 +14,16 @@ import envoy.data.LoginCredentials;
public class HandshakeRejectionEvent extends Event {
/**
- * Select this value if a given password hash was incorrect
+ * Select this value if a given password hash or user was incorrect.
*/
- public static final String WRONG_PASSWORD = "an incorrect password was entered";
+ public static final String WRONG_PASSWORD_OR_USER = "Incorrect user name or password.";
/**
- * Select this value if a given {@link LoginCredentials} pointed at a client who
- * is already online
+ * Select this value if the handshake could not be completed for some reason.
*/
- public static final String ALREADY_ONLINE = "user is already online";
+ public static final String INTERNAL_ERROR = "An internal error occured.";
- /**
- * Select this value if a given {@link LoginCredentials} pointed at a client who
- * does not exist
- */
- public static final String USER_DOES_NOT_EXIST = "user does not exist";
-
- /**
- * Select this value if a given {@link LoginCredentials} with
- * {@link LoginCredentials#isRegistration()}==true points at an already existing
- * user
- */
- public static final String USER_EXISTS_ALREADY = "user can not be created as he already exists";
-
- /**
- * Select this value if an unknown error occurred
- */
- public static final String UNKNOWN_REASON = "cause of failure is unknown";
-
- private static final long serialVersionUID = -8723270093452609197L;
+ private static final long serialVersionUID = 0L;
/**
* Creates an instance of {@link HandshakeRejectionEvent} with an empty reason.
diff --git a/src/main/java/envoy/event/IdGeneratorRequest.java b/src/main/java/envoy/event/IDGeneratorRequest.java
similarity index 66%
rename from src/main/java/envoy/event/IdGeneratorRequest.java
rename to src/main/java/envoy/event/IDGeneratorRequest.java
index fe7871d..2994c75 100644
--- a/src/main/java/envoy/event/IdGeneratorRequest.java
+++ b/src/main/java/envoy/event/IDGeneratorRequest.java
@@ -2,16 +2,16 @@ package envoy.event;
/**
* Signifies to the server that the client needs a new
- * {@link envoy.data.IdGenerator} instance.
+ * {@link envoy.data.IDGenerator} instance.
*
* Project: envoy-common
- * File: IdGeneratorRequest.java
+ * File: IDGeneratorRequest.java
* Created: 28 Jan 2020
*
* @author Kai S. K. Engelbart
* @since Envoy Common v0.3-alpha
*/
-public class IdGeneratorRequest extends Event.Valueless {
+public class IDGeneratorRequest extends Event.Valueless {
private static final long serialVersionUID = 1431107413883364583L;
}
diff --git a/src/main/java/envoy/event/MessageStatusChangeEvent.java b/src/main/java/envoy/event/MessageStatusChangeEvent.java
index d7e7e4a..2068c7f 100644
--- a/src/main/java/envoy/event/MessageStatusChangeEvent.java
+++ b/src/main/java/envoy/event/MessageStatusChangeEvent.java
@@ -14,10 +14,10 @@ import envoy.data.Message;
*/
public class MessageStatusChangeEvent extends Event {
- private final long id;
- private final Date date;
+ private final long id;
+ private final Date date;
- private static final long serialVersionUID = 4566145392192761313L;
+ private static final long serialVersionUID = 0L;
/**
* Initializes a {@link MessageStatusChangeEvent}.
@@ -40,13 +40,13 @@ public class MessageStatusChangeEvent extends Event {
* @param message the message from which to build the event
* @since Envoy Common v0.2-alpha
*/
- public MessageStatusChangeEvent(Message message) { this(message.getId(), message.getStatus(), new Date()); }
+ public MessageStatusChangeEvent(Message message) { this(message.getID(), message.getStatus(), new Date()); }
/**
* @return the ID of the {@link Message} this event is related to
* @since Envoy Common v0.2-alpha
*/
- public long getId() { return id; }
+ public long getID() { return id; }
/**
* @return the date at which the status change occurred
diff --git a/src/main/java/envoy/event/NameChangeEvent.java b/src/main/java/envoy/event/NameChangeEvent.java
new file mode 100644
index 0000000..bced039
--- /dev/null
+++ b/src/main/java/envoy/event/NameChangeEvent.java
@@ -0,0 +1,52 @@
+package envoy.event;
+
+import envoy.data.Contact;
+
+/**
+ * This event informs
+ * a) the server of the name change of a user or a group.
+ * b) another user of this users name change.
+ *
+ * Project: envoy-common
+ * File: NameChangeEvent.java
+ * Created: 25 Mar 2020
+ *
+ * @author Leon Hofmeister
+ * @since Envoy Common v0.1-beta
+ */
+public class NameChangeEvent extends Event {
+
+ private final long id;
+
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Creates a new {@link NameChangeEvent} for a user or a group.
+ *
+ * @param contactID the id of the {@link Contact} who wishes to change his name
+ * @param newName the new name of this contact
+ * @since Envoy Common v0.1-beta
+ */
+ public NameChangeEvent(long contactID, String newName) {
+ super(newName);
+ id = contactID;
+ }
+
+ /**
+ * Initializes a {@link NameChangeEvent} through a Contact where the name has
+ * already been set.
+ *
+ * @param contact the contact whose name was updated
+ * @since Envoy Common v0.2-alpha
+ */
+ public NameChangeEvent(Contact contact) { this(contact.getID(), contact.getName()); }
+
+ /**
+ * @return the ID of the {@link Contact} this event is related to
+ * @since Envoy Common v0.2-alpha
+ */
+ public long getID() { return id; }
+
+ @Override
+ public String toString() { return String.format("NameChangeEvent[id=%d,name=%s]", id, value); }
+}
diff --git a/src/main/java/envoy/event/UserStatusChangeEvent.java b/src/main/java/envoy/event/UserStatusChangeEvent.java
index ed6e79f..2a85676 100644
--- a/src/main/java/envoy/event/UserStatusChangeEvent.java
+++ b/src/main/java/envoy/event/UserStatusChangeEvent.java
@@ -15,7 +15,7 @@ public class UserStatusChangeEvent extends Event {
private final long id;
- private static final long serialVersionUID = 4566145392192761313L;
+ private static final long serialVersionUID = 0L;
/**
* Initializes a {@link UserStatusChangeEvent}.
@@ -36,13 +36,13 @@ public class UserStatusChangeEvent extends Event {
* @param user the User from which to build the event
* @since Envoy Common v0.2-alpha
*/
- public UserStatusChangeEvent(User user) { this(user.getId(), user.getStatus()); }
+ public UserStatusChangeEvent(User user) { this(user.getID(), user.getStatus()); }
/**
* @return the ID of the {@link User} this event is related to
* @since Envoy Common v0.2-alpha
*/
- public long getId() { return id; }
+ public long getID() { return id; }
@Override
public String toString() { return String.format("UserStatusChangeEvent[id=%d,status=%s]", id, value); }
diff --git a/src/main/java/envoy/event/contact/ContactOperationEvent.java b/src/main/java/envoy/event/contact/ContactOperationEvent.java
new file mode 100644
index 0000000..6758858
--- /dev/null
+++ b/src/main/java/envoy/event/contact/ContactOperationEvent.java
@@ -0,0 +1,40 @@
+package envoy.event.contact;
+
+import envoy.data.Contact;
+import envoy.event.ElementOperation;
+import envoy.event.Event;
+
+/**
+ * Signifies the modification of a contact list.
+ *
+ * Project: envoy-common
+ * File: ContactOperationEvent.java
+ * Created: 05.02.2020
+ *
+ * @author Maximilian Käfer
+ * @since Envoy Common v0.2-alpha
+ */
+public class ContactOperationEvent extends Event {
+
+ private final ElementOperation operationType;
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Initializes a {@link ContactOperationEvent}.
+ *
+ * @param contact the user on which the operation is performed
+ * @param operationType the type of operation to perform
+ * @since Envoy Common v0.2-alpha
+ */
+ public ContactOperationEvent(Contact contact, ElementOperation operationType) {
+ super(contact);
+ this.operationType = operationType;
+ }
+
+ /**
+ * @return the type of operation to perform
+ * @since Envoy Common v0.2-alpha
+ */
+ public ElementOperation getOperationType() { return operationType; }
+}
diff --git a/src/main/java/envoy/event/ContactSearchRequest.java b/src/main/java/envoy/event/contact/ContactSearchRequest.java
similarity index 83%
rename from src/main/java/envoy/event/ContactSearchRequest.java
rename to src/main/java/envoy/event/contact/ContactSearchRequest.java
index 4076265..e7c4f22 100644
--- a/src/main/java/envoy/event/ContactSearchRequest.java
+++ b/src/main/java/envoy/event/contact/ContactSearchRequest.java
@@ -1,24 +1,26 @@
-package envoy.event;
-
-/**
- * Requests a contact search from the server.
- *
- * Project: envoy-common
- * File: ContactSearchRequest.java
- * Created: 05.02.2020
- *
- * @author Maximilian Käfer
- * @since Envoy Common v0.2-alpha
- */
-public class ContactSearchRequest extends Event {
-
- private static final long serialVersionUID = -7969312055630533627L;
-
- /**
- * Initializes a {@link ContactSearchRequest}.
- *
- * @param searchPhrase the search phrase to use in the contact search
- * @since Envoy Common v0.2-alpha
- */
- public ContactSearchRequest(String searchPhrase) { super(searchPhrase); }
-}
+package envoy.event.contact;
+
+import envoy.event.Event;
+
+/**
+ * Requests a contact search from the server.
+ *
+ * Project: envoy-common
+ * File: ContactSearchRequest.java
+ * Created: 05.02.2020
+ *
+ * @author Maximilian Käfer
+ * @since Envoy Common v0.2-alpha
+ */
+public class ContactSearchRequest extends Event {
+
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Initializes a {@link ContactSearchRequest}.
+ *
+ * @param searchPhrase the search phrase to use in the contact search
+ * @since Envoy Common v0.2-alpha
+ */
+ public ContactSearchRequest(String searchPhrase) { super(searchPhrase); }
+}
diff --git a/src/main/java/envoy/event/ContactSearchResult.java b/src/main/java/envoy/event/contact/ContactSearchResult.java
similarity index 55%
rename from src/main/java/envoy/event/ContactSearchResult.java
rename to src/main/java/envoy/event/contact/ContactSearchResult.java
index 929ee30..aed8b12 100644
--- a/src/main/java/envoy/event/ContactSearchResult.java
+++ b/src/main/java/envoy/event/contact/ContactSearchResult.java
@@ -1,11 +1,12 @@
-package envoy.event;
+package envoy.event.contact;
import java.util.List;
-import envoy.data.User;
+import envoy.data.Contact;
+import envoy.event.Event;
/**
- * Contains a list of {@link User}s for which a search was performed.
+ * Contains a list of {@link Contact}s for which a search was performed.
*
* Project: envoy-common
* File: ContactSearchResult.java
@@ -14,9 +15,9 @@ import envoy.data.User;
* @author Kai S. K. Engelbart
* @since Envoy Common v0.2-alpha
*/
-public class ContactSearchResult extends Event> {
+public class ContactSearchResult extends Event> {
- private static final long serialVersionUID = -8934154116102031561L;
+ private static final long serialVersionUID = 0L;
/**
* Creates an instance of {@link ContactSearchResult}.
@@ -24,5 +25,5 @@ public class ContactSearchResult extends Event> {
* @param users the users found during the search
* @since Envoy Common v0.2-alpha
*/
- public ContactSearchResult(List users) { super(users); }
+ public ContactSearchResult(List users) { super(users); }
}
diff --git a/src/main/java/envoy/event/contact/package-info.java b/src/main/java/envoy/event/contact/package-info.java
new file mode 100644
index 0000000..375ea89
--- /dev/null
+++ b/src/main/java/envoy/event/contact/package-info.java
@@ -0,0 +1,13 @@
+/**
+ * This package contains all contact-related events.
+ *
+ * Project: envoy-common
+ * File: package-info.java
+ * Created: 28 Mar 2020
+ *
+ * @author Leon Hofmeister
+ * @author Maximilian Käfer
+ * @author Kai S.K. Engelbart
+ * @since Envoy Common v0.1-beta
+ */
+package envoy.event.contact;
diff --git a/src/main/java/envoy/util/EnvoyLog.java b/src/main/java/envoy/util/EnvoyLog.java
index deba66d..f3bc919 100644
--- a/src/main/java/envoy/util/EnvoyLog.java
+++ b/src/main/java/envoy/util/EnvoyLog.java
@@ -60,7 +60,14 @@ public class EnvoyLog {
} catch (SecurityException | IOException e) {
e.printStackTrace();
}
- consoleHandler = new StreamHandler(System.out, formatter);
+ consoleHandler = new StreamHandler(System.out, formatter) {
+
+ @Override
+ public synchronized void publish(LogRecord record) {
+ super.publish(record);
+ flush();
+ }
+ };
consoleHandler.setLevel((Level) config.get("consoleLevelBarrier").get());
consoleHandler.setFormatter(formatter);
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index 5cfe504..e4aa197 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -5,7 +5,7 @@
* @author Leon Hofmeister
* @author Maximilian Käfer
* @author Kai S.K. Engelbart
- * @since Envoy common v0.1-beta
+ * @since Envoy Common v0.1-beta
*/
module envoy.common {
@@ -13,6 +13,7 @@ module envoy.common {
exports envoy.util;
exports envoy.exception;
exports envoy.event;
+ exports envoy.event.contact;
requires transitive java.logging;
-}
\ No newline at end of file
+}
diff --git a/src/test/java/envoy/data/UserTest.java b/src/test/java/envoy/data/UserTest.java
new file mode 100644
index 0000000..4a1688b
--- /dev/null
+++ b/src/test/java/envoy/data/UserTest.java
@@ -0,0 +1,34 @@
+package envoy.data;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.io.IOException;
+import java.util.Set;
+
+import org.junit.jupiter.api.Test;
+
+import envoy.data.User.UserStatus;
+import envoy.util.SerializationUtils;
+
+/**
+ * Project: envoy-common
+ * File: UserTest.java
+ * Created: 31 Mar 2020
+ *
+ * @author Leon Hofmeister
+ * @since Envoy Common v0.1-beta
+ */
+class UserTest {
+
+ @Test
+ void test() throws IOException, ClassNotFoundException {
+ User user2 = new User(2, "kai");
+ User user3 = new User(3, "ai");
+ User user4 = new User(4, "ki", Set.of(user2, user3));
+ User user5 = new User(5, "ka", Set.of(user2, user3, user4));
+ User user = new User(1, "maxi", UserStatus.AWAY, Set.of(user2, user3, user4, user5));
+ var serializedUser = SerializationUtils.writeToByteArray(user);
+ var deserializedUser = SerializationUtils.read(serializedUser, User.class);
+ assertEquals(user.getContacts(), deserializedUser.getContacts());
+ }
+}