Formatted code

Added Eclipse formatter and cleanup configuration
This commit is contained in:
Patrick Gotthard 2013-10-12 15:05:21 +02:00
parent a482dcb959
commit 12fa5bbab6
26 changed files with 1913 additions and 1491 deletions

56
cleanup.xml Normal file
View file

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="2">
<profile kind="CleanUpProfile" name="ROME" version="2">
<setting id="cleanup.remove_unused_private_fields" value="true"/>
<setting id="cleanup.always_use_parentheses_in_expressions" value="false"/>
<setting id="cleanup.never_use_blocks" value="false"/>
<setting id="cleanup.remove_unused_private_methods" value="true"/>
<setting id="cleanup.add_missing_deprecated_annotations" value="true"/>
<setting id="cleanup.convert_to_enhanced_for_loop" value="true"/>
<setting id="cleanup.remove_unnecessary_nls_tags" value="true"/>
<setting id="cleanup.sort_members" value="false"/>
<setting id="cleanup.remove_unused_local_variables" value="false"/>
<setting id="cleanup.never_use_parentheses_in_expressions" value="true"/>
<setting id="cleanup.remove_unused_private_members" value="false"/>
<setting id="cleanup.remove_unnecessary_casts" value="true"/>
<setting id="cleanup.make_parameters_final" value="true"/>
<setting id="cleanup.use_this_for_non_static_field_access" value="true"/>
<setting id="cleanup.remove_private_constructors" value="true"/>
<setting id="cleanup.use_blocks" value="true"/>
<setting id="cleanup.always_use_this_for_non_static_method_access" value="false"/>
<setting id="cleanup.remove_trailing_whitespaces_all" value="true"/>
<setting id="cleanup.always_use_this_for_non_static_field_access" value="false"/>
<setting id="cleanup.use_this_for_non_static_field_access_only_if_necessary" value="true"/>
<setting id="cleanup.add_default_serial_version_id" value="true"/>
<setting id="cleanup.make_type_abstract_if_missing_method" value="false"/>
<setting id="cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class" value="true"/>
<setting id="cleanup.make_variable_declarations_final" value="true"/>
<setting id="cleanup.add_missing_nls_tags" value="false"/>
<setting id="cleanup.format_source_code" value="true"/>
<setting id="cleanup.qualify_static_method_accesses_with_declaring_class" value="false"/>
<setting id="cleanup.add_missing_override_annotations" value="true"/>
<setting id="cleanup.remove_unused_private_types" value="true"/>
<setting id="cleanup.add_missing_methods" value="false"/>
<setting id="cleanup.make_local_variable_final" value="true"/>
<setting id="cleanup.correct_indentation" value="true"/>
<setting id="cleanup.add_missing_override_annotations_interface_methods" value="true"/>
<setting id="cleanup.remove_unused_imports" value="true"/>
<setting id="cleanup.remove_trailing_whitespaces_ignore_empty" value="false"/>
<setting id="cleanup.make_private_fields_final" value="true"/>
<setting id="cleanup.add_generated_serial_version_id" value="false"/>
<setting id="cleanup.organize_imports" value="true"/>
<setting id="cleanup.remove_trailing_whitespaces" value="true"/>
<setting id="cleanup.sort_members_all" value="false"/>
<setting id="cleanup.use_blocks_only_for_return_and_throw" value="false"/>
<setting id="cleanup.add_missing_annotations" value="true"/>
<setting id="cleanup.use_parentheses_in_expressions" value="true"/>
<setting id="cleanup.qualify_static_field_accesses_with_declaring_class" value="false"/>
<setting id="cleanup.use_this_for_non_static_method_access_only_if_necessary" value="true"/>
<setting id="cleanup.use_this_for_non_static_method_access" value="true"/>
<setting id="cleanup.qualify_static_member_accesses_through_instances_with_declaring_class" value="true"/>
<setting id="cleanup.add_serial_version_id" value="false"/>
<setting id="cleanup.format_source_code_changes_only" value="false"/>
<setting id="cleanup.qualify_static_member_accesses_with_declaring_class" value="true"/>
<setting id="cleanup.always_use_blocks" value="true"/>
</profile>
</profiles>

291
formatter.xml Normal file
View file

@ -0,0 +1,291 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="12">
<profile kind="CodeFormatterProfile" name="ROME" version="12">
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
<setting id="org.eclipse.jdt.core.compiler.source" value="1.7"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="160"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.7"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode" value="enabled"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.7"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
</profile>
</profiles>

View file

@ -16,23 +16,22 @@
*/ */
package org.rometools.fetcher; package org.rometools.fetcher;
import java.io.IOException;
import java.net.URL;
import com.sun.syndication.feed.synd.SyndFeed; import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.FeedException; import com.sun.syndication.io.FeedException;
import java.io.IOException;
import java.net.URL;
public interface FeedFetcher { public interface FeedFetcher {
/** /**
* <p>The default user agent. It is not marked final so * <p>
* buggy java compiler will not write this string * The default user agent. It is not marked final so buggy java compiler will not write this string into all classes that reference it.
* into all classes that reference it.</p> * </p>
* *
* <p>http://tinyurl.com/64t5n points to https://rome.dev.java.net * <p>
* Some servers ban user agents with "Java" in the name.</p> * http://tinyurl.com/64t5n points to https://rome.dev.java.net Some servers ban user agents with "Java" in the name.
* * </p>
*
*/ */
public static String DEFAULT_USER_AGENT = "Rome Client (http://tinyurl.com/64t5n)"; public static String DEFAULT_USER_AGENT = "Rome Client (http://tinyurl.com/64t5n)";
@ -47,43 +46,56 @@ public interface FeedFetcher {
public abstract String getUserAgent(); public abstract String getUserAgent();
/** /**
* <p>Turn on or off rfc3229 delta encoding</p> * <p>
* * Turn on or off rfc3229 delta encoding
* <p>See http://www.ietf.org/rfc/rfc3229.txt and http://bobwyman.pubsub.com/main/2004/09/using_rfc3229_w.html</p> * </p>
* *
* <p>NOTE: This is experimental and feedback is welcome!</p> * <p>
* * See http://www.ietf.org/rfc/rfc3229.txt and http://bobwyman.pubsub.com/main/2004/09/using_rfc3229_w.html
* </p>
*
* <p>
* NOTE: This is experimental and feedback is welcome!
* </p>
*
* @param useDeltaEncoding * @param useDeltaEncoding
*/ */
public abstract void setUsingDeltaEncoding(boolean useDeltaEncoding); public abstract void setUsingDeltaEncoding(boolean useDeltaEncoding);
/** /**
* <p>Is this fetcher using rfc3229 delta encoding?</p> * <p>
* * Is this fetcher using rfc3229 delta encoding?
* </p>
*
* @return * @return
*/ */
public abstract boolean isUsingDeltaEncoding(); public abstract boolean isUsingDeltaEncoding();
/** /**
* <p>Add a FetcherListener.</p> * <p>
* * Add a FetcherListener.
* <p>The FetcherListener will receive an FetcherEvent when * </p>
* a Fetcher event (feed polled, retrieved, etc) occurs</p> *
* * <p>
* The FetcherListener will receive an FetcherEvent when a Fetcher event (feed polled, retrieved, etc) occurs
* </p>
*
* @param listener The FetcherListener to recieve the event * @param listener The FetcherListener to recieve the event
*/ */
public abstract void addFetcherEventListener(FetcherListener listener); public abstract void addFetcherEventListener(FetcherListener listener);
/** /**
* <p>Remove a FetcherListener</p> * <p>
* * Remove a FetcherListener
* </p>
*
* @param listener The FetcherListener to remove * @param listener The FetcherListener to remove
*/ */
public abstract void removeFetcherEventListener(FetcherListener listener); public abstract void removeFetcherEventListener(FetcherListener listener);
/** /**
* Retrieve a feed over HTTP * Retrieve a feed over HTTP
* *
* @param feedUrl A non-null URL of a RSS/Atom feed to retrieve * @param feedUrl A non-null URL of a RSS/Atom feed to retrieve
* @return A {@link com.sun.syndication.feed.synd.SyndFeed} object * @return A {@link com.sun.syndication.feed.synd.SyndFeed} object
* @throws IllegalArgumentException if the URL is null; * @throws IllegalArgumentException if the URL is null;
@ -91,15 +103,13 @@ public interface FeedFetcher {
* @throws FeedException if the feed is not valid * @throws FeedException if the feed is not valid
* @throws FetcherException if a HTTP error occurred * @throws FetcherException if a HTTP error occurred
*/ */
public abstract SyndFeed retrieveFeed(URL feedUrl) public abstract SyndFeed retrieveFeed(URL feedUrl) throws IllegalArgumentException, IOException, FeedException, FetcherException;
throws IllegalArgumentException, IOException, FeedException, FetcherException;
public SyndFeed retrieveFeed(String userAgent, URL url) public SyndFeed retrieveFeed(String userAgent, URL url) throws IllegalArgumentException, IOException, FeedException, FetcherException;
throws IllegalArgumentException, IOException, FeedException, FetcherException;
/** /**
* If set to true, the WireFeed will be made accessible from the SyndFeed object returned from the Fetcher * If set to true, the WireFeed will be made accessible from the SyndFeed object returned from the Fetcher via the originalWireFeed() method. Each Entry in
* via the originalWireFeed() method. Each Entry in the feed will have the corresponding wireEntry property set. * the feed will have the corresponding wireEntry property set.
*/ */
void setPreserveWireFeed(boolean preserveWireFeed); void setPreserveWireFeed(boolean preserveWireFeed);
} }

View file

@ -5,81 +5,85 @@ import java.util.EventObject;
import com.sun.syndication.feed.synd.SyndFeed; import com.sun.syndication.feed.synd.SyndFeed;
/** /**
* Implementation note: FetcherEvent is not thread safe. Make sure that * Implementation note: FetcherEvent is not thread safe. Make sure that they are only ever accessed by one thread. If necessary, make all getters and setters
* they are only ever accessed by one thread. If necessary, make all getters * synchronized, or alternatively make all fields final.
* and setters synchronized, or alternatively make all fields final.
* *
* @author nl * @author nl
*/ */
public class FetcherEvent extends EventObject { public class FetcherEvent extends EventObject {
private static final long serialVersionUID = 3985600601904140103L; private static final long serialVersionUID = 3985600601904140103L;
public static final String EVENT_TYPE_FEED_POLLED = "FEED_POLLED"; public static final String EVENT_TYPE_FEED_POLLED = "FEED_POLLED";
public static final String EVENT_TYPE_FEED_RETRIEVED = "FEED_RETRIEVED"; public static final String EVENT_TYPE_FEED_RETRIEVED = "FEED_RETRIEVED";
public static final String EVENT_TYPE_FEED_UNCHANGED = "FEED_UNCHANGED"; public static final String EVENT_TYPE_FEED_UNCHANGED = "FEED_UNCHANGED";
private String eventType;
private String urlString;
private SyndFeed feed;
public FetcherEvent(Object source) {
super(source);
}
private String eventType;
private String urlString;
private SyndFeed feed;
public FetcherEvent(Object source, String urlStr, String eventType) { public FetcherEvent(final Object source) {
this(source); super(source);
setUrlString(urlStr); }
setEventType(eventType);
} public FetcherEvent(final Object source, final String urlStr, final String eventType) {
this(source);
setUrlString(urlStr);
setEventType(eventType);
}
public FetcherEvent(final Object source, final String urlStr, final String eventType, final SyndFeed feed) {
this(source, urlStr, eventType);
setFeed(feed);
}
public FetcherEvent(Object source, String urlStr, String eventType, SyndFeed feed) {
this(source, urlStr, eventType);
setFeed(feed);
}
/** /**
* @return Returns the feed. * @return Returns the feed.
* *
* <p>The feed will only be set if the eventType is EVENT_TYPE_FEED_RETRIEVED</p> * <p>
* The feed will only be set if the eventType is EVENT_TYPE_FEED_RETRIEVED
* </p>
*/ */
public SyndFeed getFeed() { public SyndFeed getFeed() {
return feed; return feed;
} }
/** /**
* @param feed The feed to set. * @param feed The feed to set.
* *
* <p>The feed will only be set if the eventType is EVENT_TYPE_FEED_RETRIEVED</p> * <p>
* The feed will only be set if the eventType is EVENT_TYPE_FEED_RETRIEVED
* </p>
*/ */
public void setFeed(SyndFeed feed) { public void setFeed(final SyndFeed feed) {
this.feed = feed; this.feed = feed;
} }
/** /**
* @return Returns the eventType. * @return Returns the eventType.
*/ */
public String getEventType() { public String getEventType() {
return eventType; return eventType;
} }
/**
* @param eventType The eventType to set. /**
*/ * @param eventType The eventType to set.
public void setEventType(String eventType) { */
this.eventType = eventType; public void setEventType(final String eventType) {
} this.eventType = eventType;
/** }
* @return Returns the urlString.
*/ /**
public String getUrlString() { * @return Returns the urlString.
return urlString; */
} public String getUrlString() {
/** return urlString;
* @param urlString The urlString to set. }
*/
public void setUrlString(String urlString) { /**
this.urlString = urlString; * @param urlString The urlString to set.
} */
public void setUrlString(final String urlString) {
this.urlString = urlString;
}
} }

View file

@ -18,34 +18,34 @@ package org.rometools.fetcher;
/** /**
* @author Nick Lothian * @author Nick Lothian
* *
*/ */
public class FetcherException extends Exception { public class FetcherException extends Exception {
private static final long serialVersionUID = -7479645796948092380L; private static final long serialVersionUID = -7479645796948092380L;
int responseCode; int responseCode;
public FetcherException(Throwable cause) {
super();
initCause(cause);
}
public FetcherException(String message, Throwable cause) {
super(message);
initCause(cause);
}
public FetcherException(String message) {
super(message);
}
public FetcherException(int responseCode, String message) {
this(message);
this.responseCode = responseCode;
}
public int getResponseCode() { public FetcherException(final Throwable cause) {
return responseCode; super();
} initCause(cause);
}
public FetcherException(final String message, final Throwable cause) {
super(message);
initCause(cause);
}
public FetcherException(final String message) {
super(message);
}
public FetcherException(final int responseCode, final String message) {
this(message);
this.responseCode = responseCode;
}
public int getResponseCode() {
return responseCode;
}
} }

View file

@ -2,14 +2,15 @@ package org.rometools.fetcher;
import java.util.EventListener; import java.util.EventListener;
public interface FetcherListener extends EventListener { public interface FetcherListener extends EventListener {
/** /**
* <p>Called when a fetcher event occurs</p> * <p>
* * Called when a fetcher event occurs
* @param event the event that fired * </p>
*/ *
public void fetcherEvent(FetcherEvent event); * @param event the event that fired
*/
public void fetcherEvent(FetcherEvent event);
} }

View file

@ -26,194 +26,203 @@ import java.util.Iterator;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import com.sun.syndication.feed.synd.SyndFeed;
import org.rometools.fetcher.FeedFetcher; import org.rometools.fetcher.FeedFetcher;
import org.rometools.fetcher.FetcherEvent; import org.rometools.fetcher.FetcherEvent;
import org.rometools.fetcher.FetcherException; import org.rometools.fetcher.FetcherException;
import org.rometools.fetcher.FetcherListener; import org.rometools.fetcher.FetcherListener;
import com.sun.syndication.feed.synd.SyndFeed;
public abstract class AbstractFeedFetcher implements FeedFetcher { public abstract class AbstractFeedFetcher implements FeedFetcher {
private final Set fetcherEventListeners; private final Set fetcherEventListeners;
private String userAgent; private String userAgent;
private boolean usingDeltaEncoding; private boolean usingDeltaEncoding;
private boolean preserveWireFeed; private boolean preserveWireFeed;
public AbstractFeedFetcher() {
fetcherEventListeners = Collections.synchronizedSet(new HashSet());
Properties props = new Properties(System.getProperties());
String resourceName = "fetcher.properties";
try {
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(resourceName);
if (inputStream == null) {
inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(resourceName);
}
if (inputStream != null) {
props.load(inputStream);
System.getProperties().putAll(props);
inputStream.close();
} else {
System.err.println("Could not find " + resourceName + " on classpath");
}
} catch (IOException e) {
// do nothing - we don't want to fail just because we could not find the version
System.err.println("Error reading " + resourceName + " from classpath: " + e.getMessage());
}
setUserAgent(DEFAULT_USER_AGENT + " Ver: " + System.getProperty("rome.fetcher.version", "UNKNOWN"));
}
/** public AbstractFeedFetcher() {
* @return the User-Agent currently being sent to servers fetcherEventListeners = Collections.synchronizedSet(new HashSet());
*/
public synchronized String getUserAgent() {
return userAgent;
}
/** final Properties props = new Properties(System.getProperties());
* @param string The User-Agent to sent to servers final String resourceName = "fetcher.properties";
*/
public synchronized void setUserAgent(String string) {
userAgent = string;
}
/** try {
* @param eventType The event type to fire InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(resourceName);
* @param connection the current connection if (inputStream == null) {
*/ inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(resourceName);
protected void fireEvent(String eventType, URLConnection connection) { }
fireEvent(eventType, connection.getURL().toExternalForm(), null); if (inputStream != null) {
} props.load(inputStream);
System.getProperties().putAll(props);
inputStream.close();
/** } else {
* @param eventType The event type to fire System.err.println("Could not find " + resourceName + " on classpath");
* @param connection the current connection }
* @param feed The feed to pass to the event } catch (final IOException e) {
*/ // do nothing - we don't want to fail just because we could not find the version
protected void fireEvent(String eventType, URLConnection connection, SyndFeed feed) { System.err.println("Error reading " + resourceName + " from classpath: " + e.getMessage());
fireEvent(eventType, connection.getURL().toExternalForm(), feed); }
}
/** setUserAgent(DEFAULT_USER_AGENT + " Ver: " + System.getProperty("rome.fetcher.version", "UNKNOWN"));
* @param eventType The event type to fire }
* @param urlStr the current url as a string
*/
protected void fireEvent(String eventType, String urlStr) {
fireEvent(eventType, urlStr, null);
}
/**
* @param eventType The event type to fire
* @param urlStr the current url as a string
* @param feed The feed to pass to the event
*/
protected void fireEvent(String eventType, String urlStr, SyndFeed feed) {
FetcherEvent fetcherEvent = new FetcherEvent(this, urlStr, eventType, feed);
synchronized(fetcherEventListeners) {
Iterator iter = fetcherEventListeners.iterator();
while ( iter.hasNext()) {
FetcherListener fetcherEventListener = (FetcherListener) iter.next();
fetcherEventListener.fetcherEvent(fetcherEvent);
}
}
}
/**
* @see com.sun.syndication.fetcher.FeedFetcher#addFetcherEventListener(com.sun.syndication.fetcher.FetcherListener)
*/
public void addFetcherEventListener(FetcherListener listener) {
if (listener != null) {
fetcherEventListeners.add(listener);
}
}
/** /**
* @see com.sun.syndication.fetcher.FeedFetcher#removeFetcherEventListener(com.sun.syndication.fetcher.FetcherListener) * @return the User-Agent currently being sent to servers
*/ */
public void removeFetcherEventListener(FetcherListener listener) { @Override
if (listener != null) { public synchronized String getUserAgent() {
fetcherEventListeners.remove(listener); return userAgent;
} }
}
/**
* @param string The User-Agent to sent to servers
*/
@Override
public synchronized void setUserAgent(final String string) {
userAgent = string;
}
/**
* @param eventType The event type to fire
* @param connection the current connection
*/
protected void fireEvent(final String eventType, final URLConnection connection) {
fireEvent(eventType, connection.getURL().toExternalForm(), null);
}
/**
* @param eventType The event type to fire
* @param connection the current connection
* @param feed The feed to pass to the event
*/
protected void fireEvent(final String eventType, final URLConnection connection, final SyndFeed feed) {
fireEvent(eventType, connection.getURL().toExternalForm(), feed);
}
/**
* @param eventType The event type to fire
* @param urlStr the current url as a string
*/
protected void fireEvent(final String eventType, final String urlStr) {
fireEvent(eventType, urlStr, null);
}
/**
* @param eventType The event type to fire
* @param urlStr the current url as a string
* @param feed The feed to pass to the event
*/
protected void fireEvent(final String eventType, final String urlStr, final SyndFeed feed) {
final FetcherEvent fetcherEvent = new FetcherEvent(this, urlStr, eventType, feed);
synchronized (fetcherEventListeners) {
final Iterator iter = fetcherEventListeners.iterator();
while (iter.hasNext()) {
final FetcherListener fetcherEventListener = (FetcherListener) iter.next();
fetcherEventListener.fetcherEvent(fetcherEvent);
}
}
}
/**
* @see com.sun.syndication.fetcher.FeedFetcher#addFetcherEventListener(com.sun.syndication.fetcher.FetcherListener)
*/
@Override
public void addFetcherEventListener(final FetcherListener listener) {
if (listener != null) {
fetcherEventListeners.add(listener);
}
}
/**
* @see com.sun.syndication.fetcher.FeedFetcher#removeFetcherEventListener(com.sun.syndication.fetcher.FetcherListener)
*/
@Override
public void removeFetcherEventListener(final FetcherListener listener) {
if (listener != null) {
fetcherEventListeners.remove(listener);
}
}
/** /**
* @return Returns the useDeltaEncoding. * @return Returns the useDeltaEncoding.
*/ */
@Override
public synchronized boolean isUsingDeltaEncoding() { public synchronized boolean isUsingDeltaEncoding() {
return usingDeltaEncoding; return usingDeltaEncoding;
} }
/** /**
* @param useDeltaEncoding The useDeltaEncoding to set. * @param useDeltaEncoding The useDeltaEncoding to set.
*/ */
public synchronized void setUsingDeltaEncoding(boolean useDeltaEncoding) { @Override
this.usingDeltaEncoding = useDeltaEncoding; public synchronized void setUsingDeltaEncoding(final boolean useDeltaEncoding) {
} usingDeltaEncoding = useDeltaEncoding;
}
/**
* <p>Handles HTTP error codes.</p>
*
* @param responseCode the HTTP response code
* @throws FetcherException if response code is in the range 400 to 599 inclusive
*/
protected void handleErrorCodes(int responseCode) throws FetcherException {
// Handle 2xx codes as OK, so ignore them here
// 3xx codes are handled by the HttpURLConnection class
if (responseCode == 403) {
// Authentication is required
throwAuthenticationError(responseCode);
} else if (responseCode >= 400 && responseCode < 500) {
throw4XXError(responseCode);
} else if (responseCode >= 500 && responseCode < 600) {
throw new FetcherException(responseCode, "The server encounted an error. HTTP Response code was:" + responseCode);
}
}
protected void throw4XXError(int responseCode) throws FetcherException {
throw new FetcherException(responseCode, "The requested resource could not be found. HTTP Response code was:" + responseCode);
}
protected void throwAuthenticationError(int responseCode) throws FetcherException { /**
throw new FetcherException(responseCode, "Authentication required for that resource. HTTP Response code was:" + responseCode); * <p>
} * Handles HTTP error codes.
* </p>
/** *
* <p>Combine the entries in two feeds into a single feed.</p> * @param responseCode the HTTP response code
* * @throws FetcherException if response code is in the range 400 to 599 inclusive
* <p>The returned feed will have the same data as the newFeed parameter, with */
* the entries from originalFeed appended to the end of its entries.</p> protected void handleErrorCodes(final int responseCode) throws FetcherException {
* // Handle 2xx codes as OK, so ignore them here
* @param originalFeed // 3xx codes are handled by the HttpURLConnection class
* @param newFeed if (responseCode == 403) {
* @return // Authentication is required
*/ throwAuthenticationError(responseCode);
public static SyndFeed combineFeeds(SyndFeed originalFeed, SyndFeed newFeed) { } else if (responseCode >= 400 && responseCode < 500) {
SyndFeed result; throw4XXError(responseCode);
} else if (responseCode >= 500 && responseCode < 600) {
throw new FetcherException(responseCode, "The server encounted an error. HTTP Response code was:" + responseCode);
}
}
protected void throw4XXError(final int responseCode) throws FetcherException {
throw new FetcherException(responseCode, "The requested resource could not be found. HTTP Response code was:" + responseCode);
}
protected void throwAuthenticationError(final int responseCode) throws FetcherException {
throw new FetcherException(responseCode, "Authentication required for that resource. HTTP Response code was:" + responseCode);
}
/**
* <p>
* Combine the entries in two feeds into a single feed.
* </p>
*
* <p>
* The returned feed will have the same data as the newFeed parameter, with the entries from originalFeed appended to the end of its entries.
* </p>
*
* @param originalFeed
* @param newFeed
* @return
*/
public static SyndFeed combineFeeds(final SyndFeed originalFeed, final SyndFeed newFeed) {
SyndFeed result;
try { try {
result = (SyndFeed) newFeed.clone(); result = (SyndFeed) newFeed.clone();
result.getEntries().addAll(result.getEntries().size(), originalFeed.getEntries()); result.getEntries().addAll(result.getEntries().size(), originalFeed.getEntries());
return result; return result;
} catch (CloneNotSupportedException e) { } catch (final CloneNotSupportedException e) {
IllegalArgumentException iae = new IllegalArgumentException("Cannot clone feed"); final IllegalArgumentException iae = new IllegalArgumentException("Cannot clone feed");
iae.initCause(e); iae.initCause(e);
throw iae; throw iae;
} }
} }
public boolean isPreserveWireFeed() { public boolean isPreserveWireFeed() {
return preserveWireFeed; return preserveWireFeed;
} }
@Override
public void setPreserveWireFeed(final boolean preserveWireFeed) {
this.preserveWireFeed = preserveWireFeed;
}
public void setPreserveWireFeed(boolean preserveWireFeed) {
this.preserveWireFeed = preserveWireFeed;
}
} }

View file

@ -9,21 +9,22 @@ import org.rometools.fetcher.FetcherListener;
public class AbstractFeedFetcherBeanInfo extends SimpleBeanInfo { public class AbstractFeedFetcherBeanInfo extends SimpleBeanInfo {
public EventSetDescriptor[] getEventSetDescriptors() { @Override
try { public EventSetDescriptor[] getEventSetDescriptors() {
Class clz = AbstractFeedFetcher.class; // get the class object which we'll describe try {
Method addMethod = clz.getMethod("addFetcherEventListener", new Class[] { FetcherListener.class }); final Class clz = AbstractFeedFetcher.class; // get the class object which we'll describe
Method removeMethod = clz.getMethod("removeFetcherEventListener", new Class[] { FetcherListener.class }); final Method addMethod = clz.getMethod("addFetcherEventListener", new Class[] { FetcherListener.class });
Method listenerMethod = FetcherListener.class.getMethod("fetcherEvent", new Class[] { FetcherEvent.class }); final Method removeMethod = clz.getMethod("removeFetcherEventListener", new Class[] { FetcherListener.class });
final Method listenerMethod = FetcherListener.class.getMethod("fetcherEvent", new Class[] { FetcherEvent.class });
EventSetDescriptor est = new EventSetDescriptor("fetcherEvent", clz, new Method[] { listenerMethod }, addMethod, removeMethod); final EventSetDescriptor est = new EventSetDescriptor("fetcherEvent", clz, new Method[] { listenerMethod }, addMethod, removeMethod);
EventSetDescriptor[] results = new EventSetDescriptor[] { est }; final EventSetDescriptor[] results = new EventSetDescriptor[] { est };
return results; return results;
} catch (Exception e) { } catch (final Exception e) {
// IntrospectionException, SecurityException and/or NoSuchMethodException can be thrown here // IntrospectionException, SecurityException and/or NoSuchMethodException can be thrown here
// the best we can do is to convert them to runtime exceptions // the best we can do is to convert them to runtime exceptions
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
} }

View file

@ -23,112 +23,113 @@ import java.io.IOException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.net.URL; import java.net.URL;
import javax.swing.text.Utilities;
/** /**
* Disk based cache. * Disk based cache.
*/ */
public class DiskFeedInfoCache implements FeedFetcherCache { public class DiskFeedInfoCache implements FeedFetcherCache {
protected String cachePath = null; protected String cachePath = null;
public DiskFeedInfoCache(String cachePath) {
public DiskFeedInfoCache(final String cachePath) {
this.cachePath = cachePath; this.cachePath = cachePath;
} }
public SyndFeedInfo getFeedInfo(URL url) {
@Override
public SyndFeedInfo getFeedInfo(final URL url) {
SyndFeedInfo info = null; SyndFeedInfo info = null;
String fileName = cachePath + File.separator + "feed_" final String fileName = cachePath + File.separator + "feed_" + replaceNonAlphanumeric(url.toString(), '_').trim();
+ replaceNonAlphanumeric(url.toString(),'_').trim();
FileInputStream fis; FileInputStream fis;
try { try {
fis = new FileInputStream(fileName); fis = new FileInputStream(fileName);
ObjectInputStream ois = new ObjectInputStream(fis); final ObjectInputStream ois = new ObjectInputStream(fis);
info = (SyndFeedInfo)ois.readObject(); info = (SyndFeedInfo) ois.readObject();
fis.close(); fis.close();
} catch (FileNotFoundException fnfe) { } catch (final FileNotFoundException fnfe) {
// That's OK, we'l return null // That's OK, we'l return null
} catch (ClassNotFoundException cnfe) { } catch (final ClassNotFoundException cnfe) {
// Error writing to cache is fatal // Error writing to cache is fatal
throw new RuntimeException("Attempting to read from cache", cnfe); throw new RuntimeException("Attempting to read from cache", cnfe);
} catch (IOException fnfe) { } catch (final IOException fnfe) {
// Error writing to cache is fatal // Error writing to cache is fatal
throw new RuntimeException("Attempting to read from cache", fnfe); throw new RuntimeException("Attempting to read from cache", fnfe);
} }
return info; return info;
} }
public void setFeedInfo(URL url, SyndFeedInfo feedInfo) { @Override
String fileName = cachePath + File.separator + "feed_" public void setFeedInfo(final URL url, final SyndFeedInfo feedInfo) {
+ replaceNonAlphanumeric(url.toString(),'_').trim(); final String fileName = cachePath + File.separator + "feed_" + replaceNonAlphanumeric(url.toString(), '_').trim();
FileOutputStream fos; FileOutputStream fos;
try { try {
fos = new FileOutputStream(fileName); fos = new FileOutputStream(fileName);
ObjectOutputStream oos = new ObjectOutputStream(fos); final ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(feedInfo); oos.writeObject(feedInfo);
fos.flush(); fos.flush();
fos.close(); fos.close();
} catch (Exception e) { } catch (final Exception e) {
// Error writing to cache is fatal // Error writing to cache is fatal
throw new RuntimeException("Attempting to write to cache", e); throw new RuntimeException("Attempting to write to cache", e);
} }
} }
public static String replaceNonAlphanumeric(String str, char subst) { public static String replaceNonAlphanumeric(final String str, final char subst) {
StringBuffer ret = new StringBuffer(str.length()); final StringBuffer ret = new StringBuffer(str.length());
char[] testChars = str.toCharArray(); final char[] testChars = str.toCharArray();
for (int i = 0; i < testChars.length; i++) { for (final char testChar : testChars) {
if (Character.isLetterOrDigit(testChars[i])) { if (Character.isLetterOrDigit(testChar)) {
ret.append(testChars[i]); ret.append(testChar);
} else { } else {
ret.append( subst ); ret.append(subst);
} }
} }
return ret.toString(); return ret.toString();
} }
/** /**
* Clear the cache. * Clear the cache.
*/ */
@Override
public synchronized void clear() { public synchronized void clear() {
final File file = new File(this.cachePath); final File file = new File(cachePath);
//only do the delete if the directory exists // only do the delete if the directory exists
if( file.exists() && file.canWrite() ) { if (file.exists() && file.canWrite()) {
//make the directory empty // make the directory empty
final String[] files = file.list(); final String[] files = file.list();
final int len = files.length; final int len = files.length;
for( int i=0; i<len; i++ ) { for (int i = 0; i < len; i++) {
File deleteMe = new File(this.cachePath + File.separator + files[i]); final File deleteMe = new File(cachePath + File.separator + files[i]);
deleteMe.delete(); deleteMe.delete();
} }
//don't delete the cache directory // don't delete the cache directory
} }
} }
public SyndFeedInfo remove( URL url ) { @Override
public SyndFeedInfo remove(final URL url) {
SyndFeedInfo info = null; SyndFeedInfo info = null;
String fileName = cachePath + File.separator + "feed_" final String fileName = cachePath + File.separator + "feed_" + replaceNonAlphanumeric(url.toString(), '_').trim();
+ replaceNonAlphanumeric(url.toString(),'_').trim();
FileInputStream fis; FileInputStream fis;
try { try {
fis = new FileInputStream(fileName); fis = new FileInputStream(fileName);
ObjectInputStream ois = new ObjectInputStream(fis); final ObjectInputStream ois = new ObjectInputStream(fis);
info = (SyndFeedInfo)ois.readObject(); info = (SyndFeedInfo) ois.readObject();
fis.close(); fis.close();
File file = new File( fileName ); final File file = new File(fileName);
if( file.exists() ) { if (file.exists()) {
file.delete(); file.delete();
} }
} catch (FileNotFoundException fnfe) { } catch (final FileNotFoundException fnfe) {
// That's OK, we'l return null // That's OK, we'l return null
} catch (ClassNotFoundException cnfe) { } catch (final ClassNotFoundException cnfe) {
// Error writing to cahce is fatal // Error writing to cahce is fatal
throw new RuntimeException("Attempting to read from cache", cnfe); throw new RuntimeException("Attempting to read from cache", cnfe);
} catch (IOException fnfe) { } catch (final IOException fnfe) {
// Error writing to cahce is fatal // Error writing to cahce is fatal
throw new RuntimeException("Attempting to read from cache", fnfe); throw new RuntimeException("Attempting to read from cache", fnfe);
} }
return info; return info;
} }
} }

View file

@ -19,38 +19,40 @@ package org.rometools.fetcher.impl;
import java.net.URL; import java.net.URL;
/** /**
* <p>An interface to allow caching of feed details. Implementing this allows the * <p>
* {@link org.rometools.fetcher.io.HttpURLFeedFetcher} class to * An interface to allow caching of feed details. Implementing this allows the {@link org.rometools.fetcher.io.HttpURLFeedFetcher} class to enable conditional
* enable conditional gets</p> * gets
* </p>
* *
* @author Nick Lothian * @author Nick Lothian
* *
*/ */
public interface FeedFetcherCache { public interface FeedFetcherCache {
/** /**
* Get a SyndFeedInfo object from the cache. * Get a SyndFeedInfo object from the cache.
* *
* @param feedUrl The url of the feed * @param feedUrl The url of the feed
* @return A SyndFeedInfo or null if it is not in the cache * @return A SyndFeedInfo or null if it is not in the cache
*/ */
public SyndFeedInfo getFeedInfo(URL feedUrl); public SyndFeedInfo getFeedInfo(URL feedUrl);
/** /**
* Add a SyndFeedInfo object to the cache * Add a SyndFeedInfo object to the cache
* *
* @param feedUrl The url of the feed * @param feedUrl The url of the feed
* @param syndFeedInfo A SyndFeedInfo for the feed * @param syndFeedInfo A SyndFeedInfo for the feed
*/ */
public void setFeedInfo(URL feedUrl, SyndFeedInfo syndFeedInfo); public void setFeedInfo(URL feedUrl, SyndFeedInfo syndFeedInfo);
/** /**
* Removes all items from the cache. * Removes all items from the cache.
*/ */
public void clear(); public void clear();
/** /**
* Removes the SyndFeedInfo identified by the url from the cache. * Removes the SyndFeedInfo identified by the url from the cache.
* @return The removed SyndFeedInfo *
*/ * @return The removed SyndFeedInfo
public SyndFeedInfo remove( URL feedUrl ); */
public SyndFeedInfo remove(URL feedUrl);
} }

View file

@ -22,104 +22,113 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* <p>A very simple implementation of the {@link org.rometools.fetcher.impl.FeedFetcherCache} interface.</p> * <p>
* A very simple implementation of the {@link org.rometools.fetcher.impl.FeedFetcherCache} interface.
* </p>
* *
* <p>This implementation uses a HashMap to cache retrieved feeds. This implementation is * <p>
* most suitible for sort term (client aggregator?) use, as the memory usage will increase * This implementation uses a HashMap to cache retrieved feeds. This implementation is most suitible for sort term (client aggregator?) use, as the memory usage
* over time as the number of feeds in the cache increases.</p> * will increase over time as the number of feeds in the cache increases.
* </p>
* *
* @author Nick Lothian * @author Nick Lothian
* *
*/ */
public class HashMapFeedInfoCache implements FeedFetcherCache, Serializable { public class HashMapFeedInfoCache implements FeedFetcherCache, Serializable {
private static final long serialVersionUID = -1594665619950916222L; private static final long serialVersionUID = -1594665619950916222L;
static HashMapFeedInfoCache _instance; static HashMapFeedInfoCache _instance;
private Map infoCache;
/**
* <p>Constructor for HashMapFeedInfoCache</p>
*
* <p>Only use this if you want multiple instances of the cache.
* Usually getInstance() is more appropriate.</p>
*
*/
public HashMapFeedInfoCache() {
setInfoCache(createInfoCache());
}
/** private Map infoCache;
* Get the global instance of the cache
* @return an implementation of FeedFetcherCache
*/
public static synchronized FeedFetcherCache getInstance() {
if (_instance == null) {
_instance = new HashMapFeedInfoCache();
}
return _instance;
}
protected Map createInfoCache() { /**
return (Collections.synchronizedMap(new HashMap())); * <p>
} * Constructor for HashMapFeedInfoCache
* </p>
*
* <p>
* Only use this if you want multiple instances of the cache. Usually getInstance() is more appropriate.
* </p>
*
*/
public HashMapFeedInfoCache() {
setInfoCache(createInfoCache());
}
/**
protected Object get(Object key) { * Get the global instance of the cache
return getInfoCache().get(key); *
} * @return an implementation of FeedFetcherCache
*/
public static synchronized FeedFetcherCache getInstance() {
if (_instance == null) {
_instance = new HashMapFeedInfoCache();
}
return _instance;
}
/** protected Map createInfoCache() {
* @see extensions.io.FeedFetcherCache#getFeedInfo(java.net.URL) return Collections.synchronizedMap(new HashMap());
*/ }
public SyndFeedInfo getFeedInfo(URL feedUrl) {
return (SyndFeedInfo) get(feedUrl.toString());
}
protected void put(Object key, Object value) { protected Object get(final Object key) {
getInfoCache().put(key, value); return getInfoCache().get(key);
} }
/** /**
* @see extensions.io.FeedFetcherCache#setFeedInfo(java.net.URL, extensions.io.SyndFeedInfo) * @see extensions.io.FeedFetcherCache#getFeedInfo(java.net.URL)
*/ */
public void setFeedInfo(URL feedUrl, SyndFeedInfo syndFeedInfo) { @Override
put(feedUrl.toString(), syndFeedInfo); public SyndFeedInfo getFeedInfo(final URL feedUrl) {
} return (SyndFeedInfo) get(feedUrl.toString());
}
protected synchronized final Map getInfoCache() { protected void put(final Object key, final Object value) {
return infoCache; getInfoCache().put(key, value);
} }
/** /**
* The API of this class indicates that map must thread safe. In other * @see extensions.io.FeedFetcherCache#setFeedInfo(java.net.URL, extensions.io.SyndFeedInfo)
* words, be sure to wrap it in a synchronized map unless you know */
* what you are doing. @Override
* public void setFeedInfo(final URL feedUrl, final SyndFeedInfo syndFeedInfo) {
* @param map the map to use as the info cache. put(feedUrl.toString(), syndFeedInfo);
*/ }
protected synchronized final void setInfoCache(Map map) {
infoCache = map; protected synchronized final Map getInfoCache() {
} return infoCache;
}
/**
* @see com.sun.syndication.fetcher.impl.FeedFetcherCache#clear() /**
*/ * The API of this class indicates that map must thread safe. In other words, be sure to wrap it in a synchronized map unless you know what you are doing.
public void clear() { *
synchronized( infoCache ) { * @param map the map to use as the info cache.
infoCache.clear(); */
} protected synchronized final void setInfoCache(final Map map) {
} infoCache = map;
}
/**
* @see com.sun.syndication.fetcher.impl.FeedFetcherCache#remove(java.net.URL) /**
*/ * @see com.sun.syndication.fetcher.impl.FeedFetcherCache#clear()
public SyndFeedInfo remove( final URL url ) { */
if( url == null ) return null; @Override
public void clear() {
return (SyndFeedInfo) infoCache.remove( url.toString() ); synchronized (infoCache) {
} infoCache.clear();
}
}
/**
* @see com.sun.syndication.fetcher.impl.FeedFetcherCache#remove(java.net.URL)
*/
@Override
public SyndFeedInfo remove(final URL url) {
if (url == null) {
return null;
}
return (SyndFeedInfo) infoCache.remove(url.toString());
}
} }

View file

@ -16,10 +16,12 @@
*/ */
package org.rometools.fetcher.impl; package org.rometools.fetcher.impl;
import com.sun.syndication.feed.synd.SyndFeed; import java.io.IOException;
import com.sun.syndication.io.FeedException; import java.io.InputStream;
import com.sun.syndication.io.SyndFeedInput; import java.net.HttpURLConnection;
import com.sun.syndication.io.XmlReader; import java.net.MalformedURLException;
import java.net.URL;
import java.util.zip.GZIPInputStream;
import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.Header;
@ -28,19 +30,13 @@ import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpClientParams; import org.apache.commons.httpclient.params.HttpClientParams;
import org.rometools.fetcher.FetcherEvent; import org.rometools.fetcher.FetcherEvent;
import org.rometools.fetcher.FetcherException; import org.rometools.fetcher.FetcherException;
import java.io.IOException; import com.sun.syndication.feed.synd.SyndFeed;
import java.io.InputStream; import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.SyndFeedInput;
import java.net.HttpURLConnection; import com.sun.syndication.io.XmlReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.zip.GZIPInputStream;
/** /**
* @author Nick Lothian * @author Nick Lothian
@ -59,53 +55,52 @@ public class HttpClientFeedFetcher extends AbstractFeedFetcher {
/** /**
* @param cache * @param cache
*/ */
public HttpClientFeedFetcher(FeedFetcherCache cache) { public HttpClientFeedFetcher(final FeedFetcherCache cache) {
this(); this();
setFeedInfoCache(cache); setFeedInfoCache(cache);
} }
public HttpClientFeedFetcher(FeedFetcherCache cache, CredentialSupplier credentialSupplier) { public HttpClientFeedFetcher(final FeedFetcherCache cache, final CredentialSupplier credentialSupplier) {
this(cache); this(cache);
setCredentialSupplier(credentialSupplier); setCredentialSupplier(credentialSupplier);
} }
/** /**
* @param timeout Sets the connect timeout for the HttpClient but using the URLConnection method name. * @param timeout Sets the connect timeout for the HttpClient but using the URLConnection method name. Uses the HttpClientParams method
* Uses the HttpClientParams method setConnectionManagerTimeout instead of setConnectTimeout * setConnectionManagerTimeout instead of setConnectTimeout
* *
*/ */
public synchronized void setConnectTimeout(int timeout) { public synchronized void setConnectTimeout(final int timeout) {
httpClientParams.setConnectionManagerTimeout(timeout); httpClientParams.setConnectionManagerTimeout(timeout);
} }
/** /**
* @return The currently used connect timeout for the HttpClient but using the URLConnection method name. * @return The currently used connect timeout for the HttpClient but using the URLConnection method name. Uses the HttpClientParams method
* Uses the HttpClientParams method getConnectionManagerTimeout instead of getConnectTimeout * getConnectionManagerTimeout instead of getConnectTimeout
* *
*/ */
public int getConnectTimeout() { public int getConnectTimeout() {
return (int) this.getHttpClientParams() return (int) getHttpClientParams().getConnectionManagerTimeout();
.getConnectionManagerTimeout();
} }
/** /**
* @param credentialSupplier The credentialSupplier to set. * @param credentialSupplier The credentialSupplier to set.
*/ */
public synchronized void setCredentialSupplier(CredentialSupplier credentialSupplier) { public synchronized void setCredentialSupplier(final CredentialSupplier credentialSupplier) {
this.credentialSupplier = credentialSupplier; this.credentialSupplier = credentialSupplier;
} }
/** /**
* @return Returns the credentialSupplier. * @return Returns the credentialSupplier.
*/ */
public synchronized CredentialSupplier getCredentialSupplier() { public synchronized CredentialSupplier getCredentialSupplier() {
return credentialSupplier; return credentialSupplier;
} }
/** /**
* @param feedInfoCache the feedInfoCache to set * @param feedInfoCache the feedInfoCache to set
*/ */
public synchronized void setFeedInfoCache(FeedFetcherCache feedInfoCache) { public synchronized void setFeedInfoCache(final FeedFetcherCache feedInfoCache) {
this.feedInfoCache = feedInfoCache; this.feedInfoCache = feedInfoCache;
} }
@ -116,7 +111,7 @@ public class HttpClientFeedFetcher extends AbstractFeedFetcher {
return feedInfoCache; return feedInfoCache;
} }
public synchronized void setHttpClientMethodCallback(HttpClientMethodCallbackIntf httpClientMethodCallback) { public synchronized void setHttpClientMethodCallback(final HttpClientMethodCallbackIntf httpClientMethodCallback) {
this.httpClientMethodCallback = httpClientMethodCallback; this.httpClientMethodCallback = httpClientMethodCallback;
} }
@ -127,21 +122,21 @@ public class HttpClientFeedFetcher extends AbstractFeedFetcher {
/** /**
* @param httpClientParams The httpClientParams to set. * @param httpClientParams The httpClientParams to set.
*/ */
public synchronized void setHttpClientParams(HttpClientParams httpClientParams) { public synchronized void setHttpClientParams(final HttpClientParams httpClientParams) {
this.httpClientParams = httpClientParams; this.httpClientParams = httpClientParams;
} }
/** /**
* @return Returns the httpClientParams. * @return Returns the httpClientParams.
*/ */
public synchronized HttpClientParams getHttpClientParams() { public synchronized HttpClientParams getHttpClientParams() {
return this.httpClientParams; return httpClientParams;
} }
/** /**
* @return The currently used read timeout for the URLConnection, 0 is unlimited, i.e. no timeout * @return The currently used read timeout for the URLConnection, 0 is unlimited, i.e. no timeout
*/ */
public synchronized void setReadTimeout(int timeout) { public synchronized void setReadTimeout(final int timeout) {
httpClientParams.setSoTimeout(timeout); httpClientParams.setSoTimeout(timeout);
} }
@ -149,46 +144,43 @@ public class HttpClientFeedFetcher extends AbstractFeedFetcher {
* @return timeout the read timeout for the URLConnection to a specified timeout, in milliseconds. * @return timeout the read timeout for the URLConnection to a specified timeout, in milliseconds.
*/ */
public int getReadTimeout() { public int getReadTimeout() {
return (int) this.getHttpClientParams() return getHttpClientParams().getSoTimeout();
.getSoTimeout();
} }
public SyndFeed retrieveFeed(URL url) throws IllegalArgumentException, IOException, FeedException, FetcherException { @Override
return this.retrieveFeed(this.getUserAgent(), url); public SyndFeed retrieveFeed(final URL url) throws IllegalArgumentException, IOException, FeedException, FetcherException {
return this.retrieveFeed(getUserAgent(), url);
} }
/** /**
* @see org.rometools.fetcher.FeedFetcher#retrieveFeed(java.net.URL) * @see org.rometools.fetcher.FeedFetcher#retrieveFeed(java.net.URL)
*/ */
public SyndFeed retrieveFeed(String userAgent, URL feedUrl) @Override
throws IllegalArgumentException, IOException, FeedException, FetcherException { public SyndFeed retrieveFeed(final String userAgent, final URL feedUrl) throws IllegalArgumentException, IOException, FeedException, FetcherException {
if (feedUrl == null) { if (feedUrl == null) {
throw new IllegalArgumentException("null is not a valid URL"); throw new IllegalArgumentException("null is not a valid URL");
} }
// TODO Fix this // TODO Fix this
//System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog"); // System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog");
HttpClient client = new HttpClient(httpClientParams); final HttpClient client = new HttpClient(httpClientParams);
if (getCredentialSupplier() != null) { if (getCredentialSupplier() != null) {
client.getState() client.getState().setAuthenticationPreemptive(true);
.setAuthenticationPreemptive(true);
// TODO what should realm be here? // TODO what should realm be here?
Credentials credentials = getCredentialSupplier() final Credentials credentials = getCredentialSupplier().getCredentials(null, feedUrl.getHost());
.getCredentials(null, feedUrl.getHost());
if (credentials != null) { if (credentials != null) {
client.getState() client.getState().setCredentials(null, feedUrl.getHost(), credentials);
.setCredentials(null, feedUrl.getHost(), credentials);
} }
} }
System.setProperty("httpclient.useragent", userAgent); System.setProperty("httpclient.useragent", userAgent);
String urlStr = feedUrl.toString(); final String urlStr = feedUrl.toString();
HttpMethod method = new GetMethod(urlStr); final HttpMethod method = new GetMethod(urlStr);
method.addRequestHeader("Accept-Encoding", "gzip"); method.addRequestHeader("Accept-Encoding", "gzip");
method.addRequestHeader("User-Agent", userAgent); method.addRequestHeader("User-Agent", userAgent);
method.setFollowRedirects(true); method.setFollowRedirects(true);
@ -199,7 +191,7 @@ public class HttpClientFeedFetcher extends AbstractFeedFetcher {
} }
} }
FeedFetcherCache cache = getFeedInfoCache(); final FeedFetcherCache cache = getFeedInfoCache();
if (cache != null) { if (cache != null) {
// retrieve feed // retrieve feed
@ -220,7 +212,7 @@ public class HttpClientFeedFetcher extends AbstractFeedFetcher {
} }
} }
int statusCode = client.executeMethod(method); final int statusCode = client.executeMethod(method);
fireEvent(FetcherEvent.EVENT_TYPE_FEED_POLLED, urlStr); fireEvent(FetcherEvent.EVENT_TYPE_FEED_POLLED, urlStr);
handleErrorCodes(statusCode); handleErrorCodes(statusCode);
@ -240,9 +232,9 @@ public class HttpClientFeedFetcher extends AbstractFeedFetcher {
method.recycle(); method.recycle();
} }
} else { } else {
// cache is not in use // cache is not in use
try { try {
int statusCode = client.executeMethod(method); final int statusCode = client.executeMethod(method);
fireEvent(FetcherEvent.EVENT_TYPE_FEED_POLLED, urlStr); fireEvent(FetcherEvent.EVENT_TYPE_FEED_POLLED, urlStr);
handleErrorCodes(statusCode); handleErrorCodes(statusCode);
@ -254,30 +246,30 @@ public class HttpClientFeedFetcher extends AbstractFeedFetcher {
} }
} }
private SyndFeed getFeed(SyndFeedInfo syndFeedInfo, String urlStr, HttpMethod method, int statusCode) private SyndFeed getFeed(final SyndFeedInfo syndFeedInfo, final String urlStr, final HttpMethod method, final int statusCode) throws IOException,
throws IOException, HttpException, FetcherException, FeedException { HttpException, FetcherException, FeedException {
if ((statusCode == HttpURLConnection.HTTP_NOT_MODIFIED) && (syndFeedInfo != null)) { if (statusCode == HttpURLConnection.HTTP_NOT_MODIFIED && syndFeedInfo != null) {
fireEvent(FetcherEvent.EVENT_TYPE_FEED_UNCHANGED, urlStr); fireEvent(FetcherEvent.EVENT_TYPE_FEED_UNCHANGED, urlStr);
return syndFeedInfo.getSyndFeed(); return syndFeedInfo.getSyndFeed();
} }
SyndFeed feed = retrieveFeed(urlStr, method); final SyndFeed feed = retrieveFeed(urlStr, method);
fireEvent(FetcherEvent.EVENT_TYPE_FEED_RETRIEVED, urlStr, feed); fireEvent(FetcherEvent.EVENT_TYPE_FEED_RETRIEVED, urlStr, feed);
return feed; return feed;
} }
/** /**
* @param feedUrl * @param feedUrl
* @param urlStr * @param urlStr
* @param method * @param method
* @param feed * @param feed
* @return * @return
* @throws MalformedURLException * @throws MalformedURLException
*/ */
private SyndFeedInfo buildSyndFeedInfo(URL feedUrl, String urlStr, HttpMethod method, SyndFeed feed, int statusCode) private SyndFeedInfo buildSyndFeedInfo(final URL feedUrl, final String urlStr, final HttpMethod method, SyndFeed feed, final int statusCode)
throws MalformedURLException { throws MalformedURLException {
SyndFeedInfo syndFeedInfo; SyndFeedInfo syndFeedInfo;
syndFeedInfo = new SyndFeedInfo(); syndFeedInfo = new SyndFeedInfo();
@ -285,19 +277,18 @@ public class HttpClientFeedFetcher extends AbstractFeedFetcher {
syndFeedInfo.setUrl(new URL(urlStr)); syndFeedInfo.setUrl(new URL(urlStr));
syndFeedInfo.setId(feedUrl.toString()); syndFeedInfo.setId(feedUrl.toString());
Header imHeader = method.getResponseHeader("IM"); final Header imHeader = method.getResponseHeader("IM");
if ((imHeader != null) && (imHeader.getValue() if (imHeader != null && imHeader.getValue().indexOf("feed") >= 0 && isUsingDeltaEncoding()) {
.indexOf("feed") >= 0) && isUsingDeltaEncoding()) { final FeedFetcherCache cache = getFeedInfoCache();
FeedFetcherCache cache = getFeedInfoCache();
if ((cache != null) && (statusCode == 226)) { if (cache != null && statusCode == 226) {
// client is setup to use http delta encoding and the server supports it and has returned a delta encoded response // client is setup to use http delta encoding and the server supports it and has returned a delta encoded response
// This response only includes new items // This response only includes new items
SyndFeedInfo cachedInfo = cache.getFeedInfo(feedUrl); final SyndFeedInfo cachedInfo = cache.getFeedInfo(feedUrl);
if (cachedInfo != null) { if (cachedInfo != null) {
SyndFeed cachedFeed = cachedInfo.getSyndFeed(); final SyndFeed cachedFeed = cachedInfo.getSyndFeed();
// set the new feed to be the orginal feed plus the new items // set the new feed to be the orginal feed plus the new items
feed = combineFeeds(cachedFeed, feed); feed = combineFeeds(cachedFeed, feed);
@ -305,13 +296,13 @@ public class HttpClientFeedFetcher extends AbstractFeedFetcher {
} }
} }
Header lastModifiedHeader = method.getResponseHeader("Last-Modified"); final Header lastModifiedHeader = method.getResponseHeader("Last-Modified");
if (lastModifiedHeader != null) { if (lastModifiedHeader != null) {
syndFeedInfo.setLastModified(lastModifiedHeader.getValue()); syndFeedInfo.setLastModified(lastModifiedHeader.getValue());
} }
Header eTagHeader = method.getResponseHeader("ETag"); final Header eTagHeader = method.getResponseHeader("ETag");
if (eTagHeader != null) { if (eTagHeader != null) {
syndFeedInfo.setETag(eTagHeader.getValue()); syndFeedInfo.setETag(eTagHeader.getValue());
@ -323,21 +314,19 @@ public class HttpClientFeedFetcher extends AbstractFeedFetcher {
} }
/** /**
* @param client * @param client
* @param urlStr * @param urlStr
* @param method * @param method
* @return * @return
* @throws IOException * @throws IOException
* @throws HttpException * @throws HttpException
* @throws FetcherException * @throws FetcherException
* @throws FeedException * @throws FeedException
*/ */
private SyndFeed retrieveFeed(String urlStr, HttpMethod method) private SyndFeed retrieveFeed(final String urlStr, final HttpMethod method) throws IOException, HttpException, FetcherException, FeedException {
throws IOException, HttpException, FetcherException, FeedException {
InputStream stream = null; InputStream stream = null;
if ((method.getResponseHeader("Content-Encoding") != null) && if (method.getResponseHeader("Content-Encoding") != null && "gzip".equalsIgnoreCase(method.getResponseHeader("Content-Encoding").getValue())) {
("gzip".equalsIgnoreCase(method.getResponseHeader("Content-Encoding").getValue()))) {
stream = new GZIPInputStream(method.getResponseBodyAsStream()); stream = new GZIPInputStream(method.getResponseBodyAsStream());
} else { } else {
stream = method.getResponseBodyAsStream(); stream = method.getResponseBodyAsStream();
@ -352,7 +341,7 @@ public class HttpClientFeedFetcher extends AbstractFeedFetcher {
reader = new XmlReader(stream, true); reader = new XmlReader(stream, true);
} }
SyndFeedInput syndFeedInput = new SyndFeedInput(); final SyndFeedInput syndFeedInput = new SyndFeedInput();
syndFeedInput.setPreserveWireFeed(isPreserveWireFeed()); syndFeedInput.setPreserveWireFeed(isPreserveWireFeed());
return syndFeedInput.build(reader); return syndFeedInput.build(reader);
@ -369,12 +358,11 @@ public class HttpClientFeedFetcher extends AbstractFeedFetcher {
public interface HttpClientMethodCallbackIntf { public interface HttpClientMethodCallbackIntf {
/** /**
* Allows access to the underlying HttpClient HttpMethod object. * Allows access to the underlying HttpClient HttpMethod object. Note that in most cases, method.setRequestHeader(String, String) is what you want to do
* Note that in most cases, method.setRequestHeader(String, String) * (rather than method.addRequestHeader(String, String))
* is what you want to do (rather than method.addRequestHeader(String, String)) *
* * @param method
* @param method */
*/
public void afterHttpClientMethodCreate(HttpMethod method); public void afterHttpClientMethodCreate(HttpMethod method);
} }
} }

View file

@ -24,276 +24,292 @@ import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import com.sun.syndication.feed.synd.SyndFeed;
import org.rometools.fetcher.FetcherEvent; import org.rometools.fetcher.FetcherEvent;
import org.rometools.fetcher.FetcherException; import org.rometools.fetcher.FetcherException;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.FeedException; import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.SyndFeedInput; import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.XmlReader; import com.sun.syndication.io.XmlReader;
/** /**
* <p>Class to retrieve syndication files via HTTP.</p> * <p>
* * Class to retrieve syndication files via HTTP.
* <p>If passed a {@link org.rometools.fetcher.impl.FeedFetcherCache} in the
* constructor it will use conditional gets to only retrieve modified content.</p>
*
* <p>The class uses the Accept-Encoding: gzip header to retrieve gzipped feeds where
* supported by the server.</p>
*
* <p>Simple usage:
* <pre>
* // create the cache
* FeedFetcherCache feedInfoCache = HashMapFeedInfoCache.getFeedInfoCache();
* // retrieve the feed the first time
* // any subsequent request will use conditional gets and only
* // retrieve the resource if it has changed
* SyndFeed feed = new HttpURLFeedFetcher(feedInfoCache).retrieveFeed(feedUrl);
*</pre>
*
* </p> * </p>
* *
* @see <a href="http://fishbowl.pastiche.org/2002/10/21/http_conditional_get_for_rss_hackers">http://fishbowl.pastiche.org/2002/10/21/http_conditional_get_for_rss_hackers</a> * <p>
* @see <a href="http://diveintomark.org/archives/2003/07/21/atom_aggregator_behavior_http_level">http://diveintomark.org/archives/2003/07/21/atom_aggregator_behavior_http_level</a> * If passed a {@link org.rometools.fetcher.impl.FeedFetcherCache} in the constructor it will use conditional gets to only retrieve modified content.
* </p>
*
* <p>
* The class uses the Accept-Encoding: gzip header to retrieve gzipped feeds where supported by the server.
* </p>
*
* <p>
* Simple usage:
*
* <pre>
* // create the cache
* FeedFetcherCache feedInfoCache = HashMapFeedInfoCache.getFeedInfoCache();
* // retrieve the feed the first time
* // any subsequent request will use conditional gets and only
* // retrieve the resource if it has changed
* SyndFeed feed = new HttpURLFeedFetcher(feedInfoCache).retrieveFeed(feedUrl);
* </pre>
*
* </p>
*
* @see <a
* href="http://fishbowl.pastiche.org/2002/10/21/http_conditional_get_for_rss_hackers">http://fishbowl.pastiche.org/2002/10/21/http_conditional_get_for_rss_hackers</a>
* @see <a
* href="http://diveintomark.org/archives/2003/07/21/atom_aggregator_behavior_http_level">http://diveintomark.org/archives/2003/07/21/atom_aggregator_behavior_http_level</a>
* @see <a href="http://bobwyman.pubsub.com/main/2004/09/using_rfc3229_w.html">http://bobwyman.pubsub.com/main/2004/09/using_rfc3229_w.html</a> * @see <a href="http://bobwyman.pubsub.com/main/2004/09/using_rfc3229_w.html">http://bobwyman.pubsub.com/main/2004/09/using_rfc3229_w.html</a>
* @author Nick Lothian * @author Nick Lothian
*/ */
public class HttpURLFeedFetcher extends AbstractFeedFetcher { public class HttpURLFeedFetcher extends AbstractFeedFetcher {
static final int POLL_EVENT = 1; static final int POLL_EVENT = 1;
static final int RETRIEVE_EVENT = 2; static final int RETRIEVE_EVENT = 2;
static final int UNCHANGED_EVENT = 3; static final int UNCHANGED_EVENT = 3;
private FeedFetcherCache feedInfoCache; private FeedFetcherCache feedInfoCache;
/**
* Constructor to use HttpURLFeedFetcher without caching of feeds
*
*/
public HttpURLFeedFetcher() {
super();
}
/** /**
* Constructor to use HttpURLFeedFetcher without caching of feeds * Constructor to enable HttpURLFeedFetcher to cache feeds
* *
*/ * @param feedCache - an instance of the FeedFetcherCache interface
public HttpURLFeedFetcher() { */
super(); public HttpURLFeedFetcher(final FeedFetcherCache feedInfoCache) {
} this();
setFeedInfoCache(feedInfoCache);
}
/** @Override
* Constructor to enable HttpURLFeedFetcher to cache feeds public SyndFeed retrieveFeed(final URL feedUrl) throws IllegalArgumentException, IOException, FeedException, FetcherException {
* return this.retrieveFeed(getUserAgent(), feedUrl);
* @param feedCache - an instance of the FeedFetcherCache interface }
*/
public HttpURLFeedFetcher(FeedFetcherCache feedInfoCache) {
this();
setFeedInfoCache(feedInfoCache);
}
public SyndFeed retrieveFeed(URL feedUrl) throws IllegalArgumentException, IOException, FeedException, FetcherException { /**
return this.retrieveFeed(this.getUserAgent(), feedUrl); * Retrieve a feed over HTTP
*
* @param feedUrl A non-null URL of a RSS/Atom feed to retrieve
* @return A {@link com.sun.syndication.feed.synd.SyndFeed} object
* @throws IllegalArgumentException if the URL is null;
* @throws IOException if a TCP error occurs
* @throws FeedException if the feed is not valid
* @throws FetcherException if a HTTP error occurred
*/
@Override
public SyndFeed retrieveFeed(final String userAgent, final URL feedUrl) throws IllegalArgumentException, IOException, FeedException, FetcherException {
if (feedUrl == null) {
throw new IllegalArgumentException("null is not a valid URL");
} }
/** final URLConnection connection = feedUrl.openConnection();
* Retrieve a feed over HTTP if (!(connection instanceof HttpURLConnection)) {
* throw new IllegalArgumentException(feedUrl.toExternalForm() + " is not a valid HTTP Url");
* @param feedUrl A non-null URL of a RSS/Atom feed to retrieve }
* @return A {@link com.sun.syndication.feed.synd.SyndFeed} object final HttpURLConnection httpConnection = (HttpURLConnection) connection;
* @throws IllegalArgumentException if the URL is null; // httpConnection.setInstanceFollowRedirects(true); // this is true by default, but can be changed on a claswide basis
* @throws IOException if a TCP error occurs
* @throws FeedException if the feed is not valid
* @throws FetcherException if a HTTP error occurred
*/
public SyndFeed retrieveFeed(String userAgent, URL feedUrl) throws IllegalArgumentException, IOException, FeedException, FetcherException {
if (feedUrl == null) {
throw new IllegalArgumentException("null is not a valid URL");
}
URLConnection connection = feedUrl.openConnection();
if (!(connection instanceof HttpURLConnection)) {
throw new IllegalArgumentException(feedUrl.toExternalForm() + " is not a valid HTTP Url");
}
HttpURLConnection httpConnection = (HttpURLConnection)connection;
// httpConnection.setInstanceFollowRedirects(true); // this is true by default, but can be changed on a claswide basis
FeedFetcherCache cache = getFeedInfoCache();
if (cache != null) {
SyndFeedInfo syndFeedInfo = cache.getFeedInfo(feedUrl);
setRequestHeaders(connection, syndFeedInfo);
httpConnection.connect();
try {
fireEvent(FetcherEvent.EVENT_TYPE_FEED_POLLED, connection);
if (syndFeedInfo == null) {
// this is a feed that hasn't been retrieved
syndFeedInfo = new SyndFeedInfo();
retrieveAndCacheFeed(feedUrl, syndFeedInfo, httpConnection);
} else {
// check the response code
int responseCode = httpConnection.getResponseCode();
if (responseCode != HttpURLConnection.HTTP_NOT_MODIFIED) {
// the response code is not 304 NOT MODIFIED
// This is either because the feed server
// does not support condition gets
// or because the feed hasn't changed
retrieveAndCacheFeed(feedUrl, syndFeedInfo, httpConnection);
} else {
// the feed does not need retrieving
fireEvent(FetcherEvent.EVENT_TYPE_FEED_UNCHANGED, connection);
}
}
return syndFeedInfo.getSyndFeed();
} finally {
httpConnection.disconnect();
}
} else {
fireEvent(FetcherEvent.EVENT_TYPE_FEED_POLLED, connection);
InputStream inputStream = null;
setRequestHeaders(connection, null);
connection.addRequestProperty("User-Agent", userAgent); final FeedFetcherCache cache = getFeedInfoCache();
if (cache != null) {
SyndFeedInfo syndFeedInfo = cache.getFeedInfo(feedUrl);
setRequestHeaders(connection, syndFeedInfo);
httpConnection.connect();
try {
fireEvent(FetcherEvent.EVENT_TYPE_FEED_POLLED, connection);
httpConnection.connect(); if (syndFeedInfo == null) {
try { // this is a feed that hasn't been retrieved
inputStream = httpConnection.getInputStream(); syndFeedInfo = new SyndFeedInfo();
return getSyndFeedFromStream(inputStream, connection); retrieveAndCacheFeed(feedUrl, syndFeedInfo, httpConnection);
} catch (java.io.IOException e) { } else {
handleErrorCodes(((HttpURLConnection)connection).getResponseCode()); // check the response code
} finally { final int responseCode = httpConnection.getResponseCode();
if (inputStream != null) { if (responseCode != HttpURLConnection.HTTP_NOT_MODIFIED) {
inputStream.close(); // the response code is not 304 NOT MODIFIED
} // This is either because the feed server
httpConnection.disconnect(); // does not support condition gets
} // or because the feed hasn't changed
// we will never actually get to this line retrieveAndCacheFeed(feedUrl, syndFeedInfo, httpConnection);
return null; } else {
} // the feed does not need retrieving
} fireEvent(FetcherEvent.EVENT_TYPE_FEED_UNCHANGED, connection);
}
}
protected void retrieveAndCacheFeed(URL feedUrl, SyndFeedInfo syndFeedInfo, HttpURLConnection connection) throws IllegalArgumentException, FeedException, FetcherException, IOException { return syndFeedInfo.getSyndFeed();
handleErrorCodes(connection.getResponseCode()); } finally {
httpConnection.disconnect();
}
} else {
fireEvent(FetcherEvent.EVENT_TYPE_FEED_POLLED, connection);
InputStream inputStream = null;
setRequestHeaders(connection, null);
resetFeedInfo(feedUrl, syndFeedInfo, connection); connection.addRequestProperty("User-Agent", userAgent);
FeedFetcherCache cache = getFeedInfoCache();
// resetting feed info in the cache
// could be needed for some implementations
// of FeedFetcherCache (eg, distributed HashTables)
if (cache != null) {
cache.setFeedInfo(feedUrl, syndFeedInfo);
}
}
protected void resetFeedInfo(URL orignalUrl, SyndFeedInfo syndFeedInfo, HttpURLConnection connection) throws IllegalArgumentException, IOException, FeedException { httpConnection.connect();
// need to always set the URL because this may have changed due to 3xx redirects try {
syndFeedInfo.setUrl(connection.getURL()); inputStream = httpConnection.getInputStream();
return getSyndFeedFromStream(inputStream, connection);
} catch (final java.io.IOException e) {
handleErrorCodes(((HttpURLConnection) connection).getResponseCode());
} finally {
if (inputStream != null) {
inputStream.close();
}
httpConnection.disconnect();
}
// we will never actually get to this line
return null;
}
}
// the ID is a persistant value that should stay the same even if the URL for the protected void retrieveAndCacheFeed(final URL feedUrl, final SyndFeedInfo syndFeedInfo, final HttpURLConnection connection)
// feed changes (eg, by 3xx redirects) throws IllegalArgumentException, FeedException, FetcherException, IOException {
syndFeedInfo.setId(orignalUrl.toString()); handleErrorCodes(connection.getResponseCode());
// This will be 0 if the server doesn't support or isn't setting the last modified header resetFeedInfo(feedUrl, syndFeedInfo, connection);
syndFeedInfo.setLastModified(new Long(connection.getLastModified())); final FeedFetcherCache cache = getFeedInfoCache();
// resetting feed info in the cache
// could be needed for some implementations
// of FeedFetcherCache (eg, distributed HashTables)
if (cache != null) {
cache.setFeedInfo(feedUrl, syndFeedInfo);
}
}
// This will be null if the server doesn't support or isn't setting the ETag header protected void resetFeedInfo(final URL orignalUrl, final SyndFeedInfo syndFeedInfo, final HttpURLConnection connection) throws IllegalArgumentException,
syndFeedInfo.setETag(connection.getHeaderField("ETag")); IOException, FeedException {
// need to always set the URL because this may have changed due to 3xx redirects
syndFeedInfo.setUrl(connection.getURL());
// get the contents // the ID is a persistant value that should stay the same even if the URL for the
InputStream inputStream = null; // feed changes (eg, by 3xx redirects)
try { syndFeedInfo.setId(orignalUrl.toString());
inputStream = connection.getInputStream();
SyndFeed syndFeed = getSyndFeedFromStream(inputStream, connection);
String imHeader = connection.getHeaderField("IM");
if (isUsingDeltaEncoding() && (imHeader!= null && imHeader.indexOf("feed") >= 0)) {
FeedFetcherCache cache = getFeedInfoCache();
if (cache != null && connection.getResponseCode() == 226) {
// client is setup to use http delta encoding and the server supports it and has returned a delta encoded response
// This response only includes new items
SyndFeedInfo cachedInfo = cache.getFeedInfo(orignalUrl);
if (cachedInfo != null) {
SyndFeed cachedFeed = cachedInfo.getSyndFeed();
// set the new feed to be the orginal feed plus the new items
syndFeed = combineFeeds(cachedFeed, syndFeed);
}
}
}
syndFeedInfo.setSyndFeed(syndFeed);
} finally {
if (inputStream != null) {
inputStream.close();
}
}
}
/** // This will be 0 if the server doesn't support or isn't setting the last modified header
* <p>Set appropriate HTTP headers, including conditional get and gzip encoding headers</p> syndFeedInfo.setLastModified(new Long(connection.getLastModified()));
*
* @param connection A URLConnection
* @param syndFeedInfo The SyndFeedInfo for the feed to be retrieved. May be null
*/
protected void setRequestHeaders(URLConnection connection, SyndFeedInfo syndFeedInfo) {
if (syndFeedInfo != null) {
// set the headers to get feed only if modified
// we support the use of both last modified and eTag headers
if (syndFeedInfo.getLastModified() != null) {
Object lastModified = syndFeedInfo.getLastModified();
if (lastModified instanceof Long) {
connection.setIfModifiedSince(((Long)syndFeedInfo.getLastModified()).longValue());
}
}
if (syndFeedInfo.getETag() != null) {
connection.setRequestProperty("If-None-Match", syndFeedInfo.getETag());
}
} // This will be null if the server doesn't support or isn't setting the ETag header
// header to retrieve feed gzipped syndFeedInfo.setETag(connection.getHeaderField("ETag"));
connection.setRequestProperty("Accept-Encoding", "gzip");
if (isUsingDeltaEncoding()) { // get the contents
connection.addRequestProperty("A-IM", "feed"); InputStream inputStream = null;
} try {
} inputStream = connection.getInputStream();
SyndFeed syndFeed = getSyndFeedFromStream(inputStream, connection);
private SyndFeed readSyndFeedFromStream(InputStream inputStream, URLConnection connection) throws IOException, IllegalArgumentException, FeedException { final String imHeader = connection.getHeaderField("IM");
BufferedInputStream is; if (isUsingDeltaEncoding() && imHeader != null && imHeader.indexOf("feed") >= 0) {
if ("gzip".equalsIgnoreCase(connection.getContentEncoding())) { final FeedFetcherCache cache = getFeedInfoCache();
// handle gzip encoded content if (cache != null && connection.getResponseCode() == 226) {
is = new BufferedInputStream(new GZIPInputStream(inputStream)); // client is setup to use http delta encoding and the server supports it and has returned a delta encoded response
} else { // This response only includes new items
is = new BufferedInputStream(inputStream); final SyndFeedInfo cachedInfo = cache.getFeedInfo(orignalUrl);
} if (cachedInfo != null) {
final SyndFeed cachedFeed = cachedInfo.getSyndFeed();
//InputStreamReader reader = new InputStreamReader(is, ResponseHandler.getCharacterEncoding(connection)); // set the new feed to be the orginal feed plus the new items
syndFeed = combineFeeds(cachedFeed, syndFeed);
}
}
}
//SyndFeedInput input = new SyndFeedInput(); syndFeedInfo.setSyndFeed(syndFeed);
} finally {
if (inputStream != null) {
inputStream.close();
}
}
}
XmlReader reader = null; /**
if (connection.getHeaderField("Content-Type") != null) { * <p>
reader = new XmlReader(is, connection.getHeaderField("Content-Type"), true); * Set appropriate HTTP headers, including conditional get and gzip encoding headers
} else { * </p>
reader = new XmlReader(is, true); *
} * @param connection A URLConnection
* @param syndFeedInfo The SyndFeedInfo for the feed to be retrieved. May be null
SyndFeedInput syndFeedInput = new SyndFeedInput(); */
syndFeedInput.setPreserveWireFeed(isPreserveWireFeed()); protected void setRequestHeaders(final URLConnection connection, final SyndFeedInfo syndFeedInfo) {
if (syndFeedInfo != null) {
return syndFeedInput.build(reader); // set the headers to get feed only if modified
// we support the use of both last modified and eTag headers
} if (syndFeedInfo.getLastModified() != null) {
final Object lastModified = syndFeedInfo.getLastModified();
if (lastModified instanceof Long) {
connection.setIfModifiedSince(((Long) syndFeedInfo.getLastModified()).longValue());
}
}
if (syndFeedInfo.getETag() != null) {
connection.setRequestProperty("If-None-Match", syndFeedInfo.getETag());
}
private SyndFeed getSyndFeedFromStream(InputStream inputStream, URLConnection connection) throws IOException, IllegalArgumentException, FeedException { }
SyndFeed feed = readSyndFeedFromStream(inputStream, connection); // header to retrieve feed gzipped
fireEvent(FetcherEvent.EVENT_TYPE_FEED_RETRIEVED, connection, feed); connection.setRequestProperty("Accept-Encoding", "gzip");
return feed;
}
/** if (isUsingDeltaEncoding()) {
* @return The FeedFetcherCache used by this fetcher (Could be null) connection.addRequestProperty("A-IM", "feed");
*/ }
public synchronized FeedFetcherCache getFeedInfoCache() { }
return feedInfoCache;
}
/** private SyndFeed readSyndFeedFromStream(final InputStream inputStream, final URLConnection connection) throws IOException, IllegalArgumentException,
* @param cache The cache to be used by this fetcher (pass null to stop using a cache) FeedException {
*/ BufferedInputStream is;
public synchronized void setFeedInfoCache(FeedFetcherCache cache) { if ("gzip".equalsIgnoreCase(connection.getContentEncoding())) {
feedInfoCache = cache; // handle gzip encoded content
} is = new BufferedInputStream(new GZIPInputStream(inputStream));
} else {
is = new BufferedInputStream(inputStream);
}
// InputStreamReader reader = new InputStreamReader(is, ResponseHandler.getCharacterEncoding(connection));
// SyndFeedInput input = new SyndFeedInput();
XmlReader reader = null;
if (connection.getHeaderField("Content-Type") != null) {
reader = new XmlReader(is, connection.getHeaderField("Content-Type"), true);
} else {
reader = new XmlReader(is, true);
}
final SyndFeedInput syndFeedInput = new SyndFeedInput();
syndFeedInput.setPreserveWireFeed(isPreserveWireFeed());
return syndFeedInput.build(reader);
}
private SyndFeed getSyndFeedFromStream(final InputStream inputStream, final URLConnection connection) throws IOException, IllegalArgumentException,
FeedException {
final SyndFeed feed = readSyndFeedFromStream(inputStream, connection);
fireEvent(FetcherEvent.EVENT_TYPE_FEED_RETRIEVED, connection, feed);
return feed;
}
/**
* @return The FeedFetcherCache used by this fetcher (Could be null)
*/
public synchronized FeedFetcherCache getFeedInfoCache() {
return feedInfoCache;
}
/**
* @param cache The cache to be used by this fetcher (pass null to stop using a cache)
*/
public synchronized void setFeedInfoCache(final FeedFetcherCache cache) {
feedInfoCache = cache;
}
} }

View file

@ -5,66 +5,75 @@ import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
/** /**
* <p>An implementation of the {@link org.rometools.fetcher.impl.FeedFetcherCache} interface.</p> * <p>
* An implementation of the {@link org.rometools.fetcher.impl.FeedFetcherCache} interface.
* </p>
* *
* <p>Unlike the HashMapFeedInfoCache this implementation will not grow unbound</p> * <p>
* Unlike the HashMapFeedInfoCache this implementation will not grow unbound
* </p>
* *
* @author Javier Kohen * @author Javier Kohen
* @author Nick Lothian * @author Nick Lothian
* *
*/ */
public class LinkedHashMapFeedInfoCache extends HashMapFeedInfoCache { public class LinkedHashMapFeedInfoCache extends HashMapFeedInfoCache {
private final class CacheImpl extends LinkedHashMap { private final class CacheImpl extends LinkedHashMap {
private static final long serialVersionUID = -6977191330127794920L; private static final long serialVersionUID = -6977191330127794920L;
public CacheImpl() { public CacheImpl() {
super(16, 0.75F, true); super(16, 0.75F, true);
} }
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > getMaxEntries();
}
}
private static final int DEFAULT_MAX_ENTRIES = 20;
private static final long serialVersionUID = 1694228973357997417L; @Override
protected boolean removeEldestEntry(final Map.Entry eldest) {
return size() > getMaxEntries();
}
}
private int maxEntries = DEFAULT_MAX_ENTRIES; private static final int DEFAULT_MAX_ENTRIES = 20;
private final static LinkedHashMapFeedInfoCache _instance = new LinkedHashMapFeedInfoCache(); private static final long serialVersionUID = 1694228973357997417L;
/**
* Get the global instance of the cache
* @return an implementation of FeedFetcherCache
*/
public static final FeedFetcherCache getInstance() {
return _instance;
}
/** private int maxEntries = DEFAULT_MAX_ENTRIES;
* <p>Constructor for HashMapFeedInfoCache</p>
*
* <p>Only use this if you want multiple instances of the cache.
* Usually {@link #getInstance()} is more appropriate.</p>
*
* @see #getInstance()
*/
public LinkedHashMapFeedInfoCache() {
super();
}
protected Map createInfoCache() { private final static LinkedHashMapFeedInfoCache _instance = new LinkedHashMapFeedInfoCache();
return Collections.synchronizedMap(new CacheImpl());
}
public synchronized final int getMaxEntries() { /**
return maxEntries; * Get the global instance of the cache
} *
* @return an implementation of FeedFetcherCache
*/
public static final FeedFetcherCache getInstance() {
return _instance;
}
/**
* <p>
* Constructor for HashMapFeedInfoCache
* </p>
*
* <p>
* Only use this if you want multiple instances of the cache. Usually {@link #getInstance()} is more appropriate.
* </p>
*
* @see #getInstance()
*/
public LinkedHashMapFeedInfoCache() {
super();
}
@Override
protected Map createInfoCache() {
return Collections.synchronizedMap(new CacheImpl());
}
public synchronized final int getMaxEntries() {
return maxEntries;
}
public synchronized final void setMaxEntries(final int maxEntries) {
this.maxEntries = maxEntries;
}
public synchronized final void setMaxEntries(int maxEntries) {
this.maxEntries = maxEntries;
}
} }

View file

@ -22,36 +22,37 @@ import java.util.regex.Pattern;
/** /**
* Utility class to help deal with HTTP responses * Utility class to help deal with HTTP responses
* *
*/ */
public class ResponseHandler { public class ResponseHandler {
public static final String defaultCharacterEncoding = "ISO-8859-1"; public static final String defaultCharacterEncoding = "ISO-8859-1";
private final static Pattern characterEncodingPattern = Pattern.compile("charset=([.[^; ]]*)"); private final static Pattern characterEncodingPattern = Pattern.compile("charset=([.[^; ]]*)");
public static String getCharacterEncoding(URLConnection connection) { public static String getCharacterEncoding(final URLConnection connection) {
return getCharacterEncoding(connection.getContentType()); return getCharacterEncoding(connection.getContentType());
} }
/** /**
* *
* <p>Gets the character encoding of a response. (Note that this is different to * <p>
* the content-encoding)</p> * Gets the character encoding of a response. (Note that this is different to the content-encoding)
* * </p>
* @param contentTypeHeader the value of the content-type HTTP header eg: text/html; charset=ISO-8859-4 *
* @return the character encoding, eg: ISO-8859-4 * @param contentTypeHeader the value of the content-type HTTP header eg: text/html; charset=ISO-8859-4
*/ * @return the character encoding, eg: ISO-8859-4
public static String getCharacterEncoding(String contentTypeHeader) { */
if (contentTypeHeader == null) { public static String getCharacterEncoding(final String contentTypeHeader) {
return defaultCharacterEncoding; if (contentTypeHeader == null) {
} return defaultCharacterEncoding;
}
Matcher m = characterEncodingPattern.matcher(contentTypeHeader);
//if (!m.matches()) { final Matcher m = characterEncodingPattern.matcher(contentTypeHeader);
if (!m.find()) { // if (!m.matches()) {
return defaultCharacterEncoding; if (!m.find()) {
} else { return defaultCharacterEncoding;
return m.group(1); } else {
} return m.group(1);
} }
}
} }

View file

@ -23,35 +23,39 @@ import com.sun.syndication.feed.impl.ObjectBean;
import com.sun.syndication.feed.synd.SyndFeed; import com.sun.syndication.feed.synd.SyndFeed;
/** /**
* <p>A class to represent a {@link com.sun.syndication.feed.synd.SyndFeed} * <p>
* and some useful information about it.</p> * A class to represent a {@link com.sun.syndication.feed.synd.SyndFeed} and some useful information about it.
* </p>
*
* <p>
* This class is thread safe, as expected by the different feed fetcher implementations.
* </p>
* *
* <p>This class is thread safe, as expected by the different feed fetcher
* implementations.</p>
*
* @author Nick Lothian * @author Nick Lothian
*/ */
public class SyndFeedInfo implements Cloneable, Serializable { public class SyndFeedInfo implements Cloneable, Serializable {
private static final long serialVersionUID = -1874786860901426015L; private static final long serialVersionUID = -1874786860901426015L;
private final ObjectBean _objBean; private final ObjectBean _objBean;
private String id; private String id;
private URL url; private URL url;
private Object lastModified; private Object lastModified;
private String eTag; private String eTag;
private SyndFeed syndFeed; private SyndFeed syndFeed;
public SyndFeedInfo() { public SyndFeedInfo() {
_objBean = new ObjectBean(this.getClass(),this); _objBean = new ObjectBean(this.getClass(), this);
} }
/** /**
* Creates a deep 'bean' clone of the object. * Creates a deep 'bean' clone of the object.
* <p> * <p>
*
* @return a clone of the object. * @return a clone of the object.
* @throws CloneNotSupportedException thrown if an element of the object cannot be cloned. * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned.
* *
*/ */
@Override
public Object clone() throws CloneNotSupportedException { public Object clone() throws CloneNotSupportedException {
return _objBean.clone(); return _objBean.clone();
} }
@ -59,11 +63,13 @@ public class SyndFeedInfo implements Cloneable, Serializable {
/** /**
* Indicates whether some other object is "equal to" this one as defined by the Object equals() method. * Indicates whether some other object is "equal to" this one as defined by the Object equals() method.
* <p> * <p>
*
* @param other he reference object with which to compare. * @param other he reference object with which to compare.
* @return <b>true</b> if 'this' object is equal to the 'other' object. * @return <b>true</b> if 'this' object is equal to the 'other' object.
* *
*/ */
public boolean equals(Object other) { @Override
public boolean equals(final Object other) {
return _objBean.equals(other); return _objBean.equals(other);
} }
@ -72,9 +78,11 @@ public class SyndFeedInfo implements Cloneable, Serializable {
* <p> * <p>
* It follows the contract defined by the Object hashCode() method. * It follows the contract defined by the Object hashCode() method.
* <p> * <p>
*
* @return the hashcode of the bean object. * @return the hashcode of the bean object.
* *
*/ */
@Override
public int hashCode() { public int hashCode() {
return _objBean.hashCode(); return _objBean.hashCode();
} }
@ -82,68 +90,68 @@ public class SyndFeedInfo implements Cloneable, Serializable {
/** /**
* Returns the String representation for the object. * Returns the String representation for the object.
* <p> * <p>
*
* @return String representation for the object. * @return String representation for the object.
* *
*/ */
@Override
public String toString() { public String toString() {
return _objBean.toString(); return _objBean.toString();
} }
/**
* @return the ETag the feed was last retrieved with
*/
public synchronized String getETag() {
return eTag;
}
/** /**
* @return the ETag the feed was last retrieved with * @return the last modified date for the feed
*/ */
public synchronized String getETag() { public synchronized Object getLastModified() {
return eTag; return lastModified;
} }
/** /**
* @return the last modified date for the feed * @return the URL the feed was served from
*/ */
public synchronized Object getLastModified() { public synchronized URL getUrl() {
return lastModified; return url;
} }
/** public synchronized void setETag(final String string) {
* @return the URL the feed was served from eTag = string;
*/ }
public synchronized URL getUrl() {
return url;
}
public synchronized void setETag(String string) { public synchronized void setLastModified(final Object o) {
eTag = string; lastModified = o;
} }
public synchronized void setLastModified(Object o) { public synchronized void setUrl(final URL url) {
lastModified = o; this.url = url;
} }
public synchronized void setUrl(URL url) { public synchronized SyndFeed getSyndFeed() {
this.url = url; return syndFeed;
} }
public synchronized SyndFeed getSyndFeed() { public synchronized void setSyndFeed(final SyndFeed feed) {
return syndFeed; syndFeed = feed;
} }
public synchronized void setSyndFeed(SyndFeed feed) { /**
syndFeed = feed; * @return A unique ID to identify the feed
} */
public synchronized String getId() {
return id;
}
/** /**
* @return A unique ID to identify the feed * @param string A unique ID to identify the feed. Note that if the URL of the feed changes this will remain the same
*/ */
public synchronized String getId() { public synchronized void setId(final String string) {
return id; id = string;
} }
/**
* @param string A unique ID to identify the feed. Note that if the URL of the feed
* changes this will remain the same
*/
public synchronized void setId(String string) {
id = string;
}
} }

View file

@ -21,33 +21,37 @@ import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.sun.syndication.feed.synd.SyndFeedImpl;
import com.sun.syndication.feed.synd.SyndFeed;
import org.rometools.fetcher.FeedFetcher; import org.rometools.fetcher.FeedFetcher;
import org.rometools.fetcher.impl.FeedFetcherCache; import org.rometools.fetcher.impl.FeedFetcherCache;
import org.rometools.fetcher.impl.HashMapFeedInfoCache; import org.rometools.fetcher.impl.HashMapFeedInfoCache;
import org.rometools.fetcher.impl.HttpURLFeedFetcher; import org.rometools.fetcher.impl.HttpURLFeedFetcher;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.feed.synd.SyndFeedImpl;
import com.sun.syndication.io.SyndFeedOutput; import com.sun.syndication.io.SyndFeedOutput;
/** /**
* <p>It aggregates a list of RSS/Atom feeds (they can be of different types) * <p>
* into a single feed of the specified type.</p> * It aggregates a list of RSS/Atom feeds (they can be of different types) into a single feed of the specified type.
* * </p>
* <p>Converted from the original FeedAggregator sample</p> *
* * <p>
* Converted from the original FeedAggregator sample
* </p>
*
* @author Alejandro Abdelnur * @author Alejandro Abdelnur
* @author Nick Lothian * @author Nick Lothian
* *
*/ */
public class FeedAggregator { public class FeedAggregator {
public static void main(String[] args) { public static void main(final String[] args) {
boolean ok = false; boolean ok = false;
if (args.length>=2) { if (args.length >= 2) {
try { try {
String outputType = args[0]; final String outputType = args[0];
SyndFeed feed = new SyndFeedImpl(); final SyndFeed feed = new SyndFeedImpl();
feed.setFeedType(outputType); feed.setFeedType(outputType);
feed.setTitle("Aggregated Feed"); feed.setTitle("Aggregated Feed");
@ -55,25 +59,24 @@ public class FeedAggregator {
feed.setAuthor("anonymous"); feed.setAuthor("anonymous");
feed.setLink("http://www.anonymous.com"); feed.setLink("http://www.anonymous.com");
List entries = new ArrayList(); final List entries = new ArrayList();
feed.setEntries(entries); feed.setEntries(entries);
FeedFetcherCache feedInfoCache = HashMapFeedInfoCache.getInstance(); final FeedFetcherCache feedInfoCache = HashMapFeedInfoCache.getInstance();
FeedFetcher feedFetcher = new HttpURLFeedFetcher(feedInfoCache); final FeedFetcher feedFetcher = new HttpURLFeedFetcher(feedInfoCache);
for (int i=1;i<args.length;i++) { for (int i = 1; i < args.length; i++) {
URL inputUrl = new URL(args[i]); final URL inputUrl = new URL(args[i]);
SyndFeed inFeed = feedFetcher.retrieveFeed(inputUrl); final SyndFeed inFeed = feedFetcher.retrieveFeed(inputUrl);
entries.addAll(inFeed.getEntries()); entries.addAll(inFeed.getEntries());
} }
SyndFeedOutput output = new SyndFeedOutput(); final SyndFeedOutput output = new SyndFeedOutput();
output.output(feed, new PrintWriter(System.out)); output.output(feed, new PrintWriter(System.out));
ok = true; ok = true;
} } catch (final Exception ex) {
catch (Exception ex) { System.out.println("ERROR: " + ex.getMessage());
System.out.println("ERROR: "+ex.getMessage());
ex.printStackTrace(); ex.printStackTrace();
} }
} }

View file

@ -16,81 +16,84 @@
*/ */
package org.rometools.fetcher.samples; package org.rometools.fetcher.samples;
import java.net.URL; import java.net.URL;
import com.sun.syndication.feed.synd.SyndFeed;
import org.rometools.fetcher.FeedFetcher; import org.rometools.fetcher.FeedFetcher;
import org.rometools.fetcher.FetcherEvent; import org.rometools.fetcher.FetcherEvent;
import org.rometools.fetcher.FetcherListener; import org.rometools.fetcher.FetcherListener;
import org.rometools.fetcher.impl.FeedFetcherCache; import org.rometools.fetcher.impl.FeedFetcherCache;
import org.rometools.fetcher.impl.HashMapFeedInfoCache; import org.rometools.fetcher.impl.HashMapFeedInfoCache;
import org.rometools.fetcher.impl.HttpURLFeedFetcher; import org.rometools.fetcher.impl.HttpURLFeedFetcher;
import com.sun.syndication.feed.synd.SyndFeed;
/** /**
* Reads and prints any RSS/Atom feed type. Converted from the * Reads and prints any RSS/Atom feed type. Converted from the original Rome sample FeedReader
* original Rome sample FeedReader
* <p> * <p>
*
* @author Alejandro Abdelnur * @author Alejandro Abdelnur
* @author Nick Lothian * @author Nick Lothian
* *
*/ */
public class FeedReader { public class FeedReader {
public static void main(String[] args) { public static void main(final String[] args) {
boolean ok = false; boolean ok = false;
if (args.length==1) { if (args.length == 1) {
try { try {
URL feedUrl = new URL(args[0]); final URL feedUrl = new URL(args[0]);
FeedFetcherCache feedInfoCache = HashMapFeedInfoCache.getInstance(); final FeedFetcherCache feedInfoCache = HashMapFeedInfoCache.getInstance();
FeedFetcher fetcher = new HttpURLFeedFetcher(feedInfoCache); final FeedFetcher fetcher = new HttpURLFeedFetcher(feedInfoCache);
FetcherEventListenerImpl listener = new FetcherEventListenerImpl(); final FetcherEventListenerImpl listener = new FetcherEventListenerImpl();
fetcher.addFetcherEventListener(listener); fetcher.addFetcherEventListener(listener);
System.err.println("Retrieving feed " + feedUrl); System.err.println("Retrieving feed " + feedUrl);
// Retrieve the feed. // Retrieve the feed.
// We will get a Feed Polled Event and then a // We will get a Feed Polled Event and then a
// Feed Retrieved event (assuming the feed is valid) // Feed Retrieved event (assuming the feed is valid)
SyndFeed feed = fetcher.retrieveFeed(feedUrl); final SyndFeed feed = fetcher.retrieveFeed(feedUrl);
System.err.println(feedUrl + " retrieved"); System.err.println(feedUrl + " retrieved");
System.err.println(feedUrl + " has a title: " + feed.getTitle() + " and contains " + feed.getEntries().size() + " entries."); System.err.println(feedUrl + " has a title: " + feed.getTitle() + " and contains " + feed.getEntries().size() + " entries.");
// We will now retrieve the feed again. If the feed is unmodified // We will now retrieve the feed again. If the feed is unmodified
// and the server supports conditional gets, we will get a "Feed // and the server supports conditional gets, we will get a "Feed
// Unchanged" event after the Feed Polled event // Unchanged" event after the Feed Polled event
System.err.println("Polling " + feedUrl + " again to test conditional get support."); System.err.println("Polling " + feedUrl + " again to test conditional get support.");
SyndFeed feed2 = fetcher.retrieveFeed(feedUrl); final SyndFeed feed2 = fetcher.retrieveFeed(feedUrl);
System.err.println("If a \"Feed Unchanged\" event fired then the server supports conditional gets."); System.err.println("If a \"Feed Unchanged\" event fired then the server supports conditional gets.");
ok = true; ok = true;
} } catch (final Exception ex) {
catch (Exception ex) { System.out.println("ERROR: " + ex.getMessage());
System.out.println("ERROR: "+ex.getMessage()); ex.printStackTrace();
ex.printStackTrace(); }
} }
}
if (!ok) { if (!ok) {
System.out.println(); System.out.println();
System.out.println("FeedReader reads and prints any RSS/Atom feed type."); System.out.println("FeedReader reads and prints any RSS/Atom feed type.");
System.out.println("The first parameter must be the URL of the feed to read."); System.out.println("The first parameter must be the URL of the feed to read.");
System.out.println(); System.out.println();
} }
} }
static class FetcherEventListenerImpl implements FetcherListener { static class FetcherEventListenerImpl implements FetcherListener {
/** /**
* @see com.sun.syndication.fetcher.FetcherListener#fetcherEvent(com.sun.syndication.fetcher.FetcherEvent) * @see com.sun.syndication.fetcher.FetcherListener#fetcherEvent(com.sun.syndication.fetcher.FetcherEvent)
*/ */
public void fetcherEvent(FetcherEvent event) { @Override
String eventType = event.getEventType(); public void fetcherEvent(final FetcherEvent event) {
if (FetcherEvent.EVENT_TYPE_FEED_POLLED.equals(eventType)) { final String eventType = event.getEventType();
System.err.println("\tEVENT: Feed Polled. URL = " + event.getUrlString()); if (FetcherEvent.EVENT_TYPE_FEED_POLLED.equals(eventType)) {
} else if (FetcherEvent.EVENT_TYPE_FEED_RETRIEVED.equals(eventType)) { System.err.println("\tEVENT: Feed Polled. URL = " + event.getUrlString());
System.err.println("\tEVENT: Feed Retrieved. URL = " + event.getUrlString()); } else if (FetcherEvent.EVENT_TYPE_FEED_RETRIEVED.equals(eventType)) {
} else if (FetcherEvent.EVENT_TYPE_FEED_UNCHANGED.equals(eventType)) { System.err.println("\tEVENT: Feed Retrieved. URL = " + event.getUrlString());
System.err.println("\tEVENT: Feed Unchanged. URL = " + event.getUrlString()); } else if (FetcherEvent.EVENT_TYPE_FEED_UNCHANGED.equals(eventType)) {
} System.err.println("\tEVENT: Feed Unchanged. URL = " + event.getUrlString());
} }
} }
}
} }

1
src/main/resources/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
# needed to commit empty folder

View file

@ -16,8 +16,6 @@
*/ */
package org.rometools.test; package org.rometools.test;
import org.rometools.fetcher.impl.HashMapFeedInfoCache;
import org.rometools.fetcher.impl.FeedFetcherCache;
import java.net.URL; import java.net.URL;
import junit.framework.TestCase; import junit.framework.TestCase;
@ -31,78 +29,81 @@ import org.mortbay.http.SocketListener;
import org.mortbay.http.UserRealm; import org.mortbay.http.UserRealm;
import org.mortbay.http.handler.SecurityHandler; import org.mortbay.http.handler.SecurityHandler;
import org.mortbay.jetty.servlet.ServletHandler; import org.mortbay.jetty.servlet.ServletHandler;
import com.sun.syndication.feed.atom.Entry;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
import org.rometools.fetcher.FeedFetcher; import org.rometools.fetcher.FeedFetcher;
import org.rometools.fetcher.FetcherEvent; import org.rometools.fetcher.FetcherEvent;
import org.rometools.fetcher.FetcherException; import org.rometools.fetcher.FetcherException;
import org.rometools.fetcher.FetcherListener; import org.rometools.fetcher.FetcherListener;
import org.rometools.fetcher.impl.FeedFetcherCache;
import org.rometools.fetcher.impl.HashMapFeedInfoCache;
import com.sun.syndication.feed.atom.Entry;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
/** /**
* @author nl * @author nl
*/ */
public abstract class AbstractJettyTest extends TestCase { public abstract class AbstractJettyTest extends TestCase {
private HttpServer server; private HttpServer server;
private int testPort = 8283; private final int testPort = 8283;
/**
* @param s
*/
public AbstractJettyTest(String s) {
super(s);
}
protected HttpServer getServer() { /**
return server; * @param s
} */
public AbstractJettyTest(final String s) {
super(s);
}
protected abstract FeedFetcher getFeedFetcher(); protected HttpServer getServer() {
return server;
protected abstract FeedFetcher getFeedFetcher(FeedFetcherCache cache); }
/**
* @see junit.framework.TestCase#setUp()
*/
protected void setUp() throws Exception {
setupServer();
HttpContext context = createContext();
ServletHandler servlets = createServletHandler();
context.addHandler(servlets);
server.addContext(context);
server.start();
}
/** protected abstract FeedFetcher getFeedFetcher();
protected abstract FeedFetcher getFeedFetcher(FeedFetcherCache cache);
/**
* @see junit.framework.TestCase#setUp()
*/
@Override
protected void setUp() throws Exception {
setupServer();
final HttpContext context = createContext();
final ServletHandler servlets = createServletHandler();
context.addHandler(servlets);
server.addContext(context);
server.start();
}
/**
* @throws InterruptedException * @throws InterruptedException
*/ */
private void setupServer() throws InterruptedException { private void setupServer() throws InterruptedException {
// Create the server // Create the server
if (server != null) { if (server != null) {
server.stop(); server.stop();
server = null; server = null;
} }
server = new HttpServer(); server = new HttpServer();
// Create a port listener // Create a port listener
SocketListener listener=new SocketListener(); final SocketListener listener = new SocketListener();
listener.setPort(testPort); listener.setPort(testPort);
server.addListener(listener); server.addListener(listener);
} }
/** /**
* @return * @return
*/ */
private ServletHandler createServletHandler() { private ServletHandler createServletHandler() {
ServletHandler servlets = new ServletHandler(); final ServletHandler servlets = new ServletHandler();
servlets.addServlet("FetcherTestServlet",FetcherTestServlet.SERVLET_MAPPING,"org.rometools.test.FetcherTestServlet"); servlets.addServlet("FetcherTestServlet", FetcherTestServlet.SERVLET_MAPPING, "org.rometools.test.FetcherTestServlet");
servlets.addServlet("FetcherTestServlet",FetcherTestServlet.SERVLET_MAPPING2,"org.rometools.test.FetcherTestServlet"); servlets.addServlet("FetcherTestServlet", FetcherTestServlet.SERVLET_MAPPING2, "org.rometools.test.FetcherTestServlet");
return servlets; return servlets;
} }
@ -110,312 +111,313 @@ public abstract class AbstractJettyTest extends TestCase {
* @return * @return
*/ */
private HttpContext createContext() { private HttpContext createContext() {
HttpContext context = new HttpContext(); final HttpContext context = new HttpContext();
context.setContextPath("/rome/*"); context.setContextPath("/rome/*");
return context; return context;
} }
/** /**
* @see junit.framework.TestCase#tearDown() * @see junit.framework.TestCase#tearDown()
*/ */
protected void tearDown() throws Exception { @Override
if (server != null) { protected void tearDown() throws Exception {
server.stop(); if (server != null) {
server.destroy(); server.stop();
server = null; server.destroy();
} server = null;
} }
}
class FetcherEventListenerImpl implements FetcherListener { class FetcherEventListenerImpl implements FetcherListener {
boolean polled = false; boolean polled = false;
boolean retrieved = false; boolean retrieved = false;
boolean unchanged = false; boolean unchanged = false;
public void reset() { public void reset() {
polled = false; polled = false;
retrieved = false; retrieved = false;
unchanged = false; unchanged = false;
} }
/** /**
* @see com.sun.syndication.fetcher.FetcherListener#fetcherEvent(com.sun.syndication.fetcher.FetcherEvent) * @see com.sun.syndication.fetcher.FetcherListener#fetcherEvent(com.sun.syndication.fetcher.FetcherEvent)
*/ */
public void fetcherEvent(FetcherEvent event) { @Override
String eventType = event.getEventType(); public void fetcherEvent(final FetcherEvent event) {
if (FetcherEvent.EVENT_TYPE_FEED_POLLED.equals(eventType)) { final String eventType = event.getEventType();
System.err.println("\tEVENT: Feed Polled. URL = " + event.getUrlString()); if (FetcherEvent.EVENT_TYPE_FEED_POLLED.equals(eventType)) {
polled = true; System.err.println("\tEVENT: Feed Polled. URL = " + event.getUrlString());
} else if (FetcherEvent.EVENT_TYPE_FEED_RETRIEVED.equals(eventType)) { polled = true;
System.err.println("\tEVENT: Feed Retrieved. URL = " + event.getUrlString()); } else if (FetcherEvent.EVENT_TYPE_FEED_RETRIEVED.equals(eventType)) {
retrieved = true; System.err.println("\tEVENT: Feed Retrieved. URL = " + event.getUrlString());
} else if (FetcherEvent.EVENT_TYPE_FEED_UNCHANGED.equals(eventType)) { retrieved = true;
System.err.println("\tEVENT: Feed Unchanged. URL = " + event.getUrlString()); } else if (FetcherEvent.EVENT_TYPE_FEED_UNCHANGED.equals(eventType)) {
unchanged = true; System.err.println("\tEVENT: Feed Unchanged. URL = " + event.getUrlString());
} unchanged = true;
} }
} }
}
public void testRetrieveFeed() { public void testRetrieveFeed() {
FeedFetcher feedFetcher = getFeedFetcher(); final FeedFetcher feedFetcher = getFeedFetcher();
try { try {
SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:"+testPort+"/rome/FetcherTestServlet/")); final SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet/"));
assertNotNull(feed); assertNotNull(feed);
assertEquals("atom_1.0.feed.title", feed.getTitle()); assertEquals("atom_1.0.feed.title", feed.getTitle());
} catch (Exception e) { } catch (final Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
public void testBasicAuthentication() {
try {
setupServer();
HttpContext context = createContext();
URL url = this.getClass().getResource("/testuser.properties");
UserRealm ur = new HashUserRealm("test", url.getFile());
context.setRealm(ur);
BasicAuthenticator ba = new BasicAuthenticator();
context.setAuthenticator(ba);
SecurityHandler sh = new SecurityHandler();
context.addHandler(sh);
SecurityConstraint sc = new SecurityConstraint();
sc.setName("test");
sc.addRole("*");
sc.setAuthenticate(true);
context.addSecurityConstraint("/", sc);
ServletHandler servlets = createServletHandler();
context.addHandler(servlets);
server.addContext(context);
server.start();
FeedFetcher feedFetcher = getAuthenticatedFeedFetcher();
SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:"+testPort+"/rome/FetcherTestServlet/"));
assertNotNull(feed);
assertEquals("atom_1.0.feed.title", feed.getTitle());
} catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
fail(e.getMessage()); fail(e.getMessage());
} }
}
}
public abstract FeedFetcher getAuthenticatedFeedFetcher();
/**
* Test getting a feed via a http 301 redirect
*
*/
public void testRetrieveRedirectedFeed() {
FeedFetcher feedFetcher = getFeedFetcher();
try {
SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:"+testPort+"/rome/FetcherTestServlet?redirect=TRUE"));
assertNotNull(feed);
assertEquals("atom_1.0.feed.title", feed.getTitle());
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
/** public void testBasicAuthentication() {
* Test error handling try {
* setupServer();
*/
public void testErrorHandling() {
FeedFetcher feedFetcher = getFeedFetcher();
try {
SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:"+testPort+"/rome/FetcherTestServlet?error=404"));
fail("4xx error handling did not work correctly");
} catch (FetcherException e) {
// expect this exception
assertEquals(404, e.getResponseCode());
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
try {
SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:"+testPort+"/rome/FetcherTestServlet?error=500"));
fail("5xx error handling did not work correctly");
} catch (FetcherException e) {
// expect this exception
assertEquals(500, e.getResponseCode());
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
public void testUserAgent() { final HttpContext context = createContext();
FeedFetcher feedFetcher = getFeedFetcher();
//System.out.println(feedFetcher.getUserAgent());
//System.out.println(System.getProperty("rome.fetcher.version", "UNKNOWN"));
assertEquals("Rome Client (http://tinyurl.com/64t5n) Ver: " + System.getProperty("rome.fetcher.version", "UNKNOWN"), feedFetcher.getUserAgent());
}
/** final URL url = this.getClass().getResource("/testuser.properties");
* Test events fired when there is no cache in use final UserRealm ur = new HashUserRealm("test", url.getFile());
* context.setRealm(ur);
*/
public void testFetchEvents() {
FeedFetcher feedFetcher = getFeedFetcher();
FetcherEventListenerImpl listener = new FetcherEventListenerImpl();
feedFetcher.addFetcherEventListener(listener);
try {
SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:"+testPort+"/rome/FetcherTestServlet/"));
assertNotNull(feed);
assertTrue(listener.polled);
assertTrue(listener.retrieved);
assertFalse(listener.unchanged);
listener.reset();
// since there is no cache, the events fired should be exactly the same if
// we re-retrieve the feed
feed = feedFetcher.retrieveFeed(new URL("http://localhost:"+testPort+"/rome/FetcherTestServlet/"));
assertNotNull(feed);
assertTrue(listener.polled);
assertTrue(listener.retrieved);
assertFalse(listener.unchanged);
listener.reset();
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
/** final BasicAuthenticator ba = new BasicAuthenticator();
* Test events fired when there is a cache in use context.setAuthenticator(ba);
*
*/
public void testFetchEventsWithCache() {
FeedFetcherCache feedInfoCache = new HashMapFeedInfoCache();
FeedFetcher feedFetcher = getFeedFetcher(feedInfoCache);
FetcherEventListenerImpl listener = new FetcherEventListenerImpl();
feedFetcher.addFetcherEventListener(listener);
try {
SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:"+testPort+"/rome/FetcherTestServlet/"));
assertNotNull(feed);
assertTrue(listener.polled);
assertTrue(listener.retrieved);
assertFalse(listener.unchanged);
listener.reset();
// Since the feed is cached, the second request should not
// actually retrieve the feed
feed = feedFetcher.retrieveFeed(new URL("http://localhost:"+testPort+"/rome/FetcherTestServlet/"));
assertNotNull(feed);
assertTrue(listener.polled);
assertFalse(listener.retrieved);
assertTrue(listener.unchanged);
listener.reset();
// now simulate getting the feed after it has changed
feed = feedFetcher.retrieveFeed(new URL("http://localhost:"+testPort+"/rome/FetcherTestServlet?refreshfeed=TRUE"));
assertNotNull(feed);
assertTrue(listener.polled);
assertTrue(listener.retrieved);
assertFalse(listener.unchanged);
listener.reset();
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
/**
* Test handling of GZipped feed
*
*/
public void testGZippedFeed() {
FeedFetcher feedFetcher = getFeedFetcher();
try {
SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:"+testPort+"/rome/FetcherTestServlet?gzipfeed=TRUE"));
assertNotNull(feed);
assertEquals("atom_1.0.feed.title", feed.getTitle());
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
public void testPreserveWireFeed() throws Exception {
FeedFetcher feedFetcher = getFeedFetcher();
// first check we the WireFeed is not preserved by default final SecurityHandler sh = new SecurityHandler();
SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:"+testPort+"/rome/FetcherTestServlet/")); context.addHandler(sh);
assertNotNull(feed);
assertEquals("atom_1.0.feed.title", feed.getTitle()); final SecurityConstraint sc = new SecurityConstraint();
assertNull(feed.originalWireFeed()); sc.setName("test");
sc.addRole("*");
SyndEntry syndEntry = (SyndEntry)feed.getEntries().get(0); sc.setAuthenticate(true);
assertNotNull(syndEntry); context.addSecurityConstraint("/", sc);
assertNull(syndEntry.getWireEntry());
final ServletHandler servlets = createServletHandler();
// now turn on WireFeed preservation context.addHandler(servlets);
feedFetcher.setPreserveWireFeed(true);
try { server.addContext(context);
feed = feedFetcher.retrieveFeed(new URL("http://localhost:"+testPort+"/rome/FetcherTestServlet/"));
assertNotNull(feed); server.start();
assertEquals("atom_1.0.feed.title", feed.getTitle());
assertNotNull(feed.originalWireFeed()); final FeedFetcher feedFetcher = getAuthenticatedFeedFetcher();
final SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet/"));
assertNotNull(feed);
assertEquals("atom_1.0.feed.title", feed.getTitle());
} catch (final Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
public abstract FeedFetcher getAuthenticatedFeedFetcher();
/**
* Test getting a feed via a http 301 redirect
*
*/
public void testRetrieveRedirectedFeed() {
final FeedFetcher feedFetcher = getFeedFetcher();
try {
final SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet?redirect=TRUE"));
assertNotNull(feed);
assertEquals("atom_1.0.feed.title", feed.getTitle());
} catch (final Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
/**
* Test error handling
*
*/
public void testErrorHandling() {
final FeedFetcher feedFetcher = getFeedFetcher();
try {
final SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet?error=404"));
fail("4xx error handling did not work correctly");
} catch (final FetcherException e) {
// expect this exception
assertEquals(404, e.getResponseCode());
} catch (final Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
try {
final SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet?error=500"));
fail("5xx error handling did not work correctly");
} catch (final FetcherException e) {
// expect this exception
assertEquals(500, e.getResponseCode());
} catch (final Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
public void testUserAgent() {
final FeedFetcher feedFetcher = getFeedFetcher();
// System.out.println(feedFetcher.getUserAgent());
// System.out.println(System.getProperty("rome.fetcher.version", "UNKNOWN"));
assertEquals("Rome Client (http://tinyurl.com/64t5n) Ver: " + System.getProperty("rome.fetcher.version", "UNKNOWN"), feedFetcher.getUserAgent());
}
/**
* Test events fired when there is no cache in use
*
*/
public void testFetchEvents() {
final FeedFetcher feedFetcher = getFeedFetcher();
final FetcherEventListenerImpl listener = new FetcherEventListenerImpl();
feedFetcher.addFetcherEventListener(listener);
try {
SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet/"));
assertNotNull(feed);
assertTrue(listener.polled);
assertTrue(listener.retrieved);
assertFalse(listener.unchanged);
listener.reset();
// since there is no cache, the events fired should be exactly the same if
// we re-retrieve the feed
feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet/"));
assertNotNull(feed);
assertTrue(listener.polled);
assertTrue(listener.retrieved);
assertFalse(listener.unchanged);
listener.reset();
} catch (final Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
/**
* Test events fired when there is a cache in use
*
*/
public void testFetchEventsWithCache() {
final FeedFetcherCache feedInfoCache = new HashMapFeedInfoCache();
final FeedFetcher feedFetcher = getFeedFetcher(feedInfoCache);
final FetcherEventListenerImpl listener = new FetcherEventListenerImpl();
feedFetcher.addFetcherEventListener(listener);
try {
SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet/"));
assertNotNull(feed);
assertTrue(listener.polled);
assertTrue(listener.retrieved);
assertFalse(listener.unchanged);
listener.reset();
// Since the feed is cached, the second request should not
// actually retrieve the feed
feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet/"));
assertNotNull(feed);
assertTrue(listener.polled);
assertFalse(listener.retrieved);
assertTrue(listener.unchanged);
listener.reset();
// now simulate getting the feed after it has changed
feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet?refreshfeed=TRUE"));
assertNotNull(feed);
assertTrue(listener.polled);
assertTrue(listener.retrieved);
assertFalse(listener.unchanged);
listener.reset();
} catch (final Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
/**
* Test handling of GZipped feed
*
*/
public void testGZippedFeed() {
final FeedFetcher feedFetcher = getFeedFetcher();
try {
final SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet?gzipfeed=TRUE"));
assertNotNull(feed);
assertEquals("atom_1.0.feed.title", feed.getTitle());
} catch (final Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
public void testPreserveWireFeed() throws Exception {
final FeedFetcher feedFetcher = getFeedFetcher();
// first check we the WireFeed is not preserved by default
SyndFeed feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet/"));
assertNotNull(feed);
assertEquals("atom_1.0.feed.title", feed.getTitle());
assertNull(feed.originalWireFeed());
SyndEntry syndEntry = feed.getEntries().get(0);
assertNotNull(syndEntry);
assertNull(syndEntry.getWireEntry());
// now turn on WireFeed preservation
feedFetcher.setPreserveWireFeed(true);
try {
feed = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort + "/rome/FetcherTestServlet/"));
assertNotNull(feed);
assertEquals("atom_1.0.feed.title", feed.getTitle());
assertNotNull(feed.originalWireFeed());
syndEntry = feed.getEntries().get(0);
assertNotNull(syndEntry);
assertNotNull(syndEntry.getWireEntry());
final Entry entry = (Entry) syndEntry.getWireEntry();
assertEquals("atom_1.0.feed.entry[0].rights", entry.getRights());
} finally {
feedFetcher.setPreserveWireFeed(false); // reset
}
}
public void testDeltaEncoding() {
final FeedFetcherCache feedInfoCache = new HashMapFeedInfoCache();
final FeedFetcher feedFetcher = getFeedFetcher(feedInfoCache);
try {
feedFetcher.setUsingDeltaEncoding(true);
// first retrieval should just grab the default feed
final SyndFeed feed1 = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort
+ "/rome/FetcherTestServlet?deltaencode=TRUE&refreshfeed=TRUE"));
assertNotNull(feed1);
assertEquals("atom_1.0.feed.title", feed1.getTitle());
assertEquals(2, feed1.getEntries().size());
SyndEntry entry1 = feed1.getEntries().get(0);
assertEquals("atom_1.0.feed.entry[0].title", entry1.getTitle());
// second retrieval should get only the new item
/*
* This is breaking with Rome 0.5 ??
*/
final SyndFeed feed2 = feedFetcher.retrieveFeed(new URL("http://localhost:" + testPort
+ "/rome/FetcherTestServlet?deltaencode=TRUE&refreshfeed=TRUE"));
assertNotNull(feed2);
assertEquals(FetcherTestServlet.DELTA_FEED_TITLE, feed2.getTitle());
assertEquals(3, feed2.getEntries().size());
entry1 = feed2.getEntries().get(0);
assertEquals(FetcherTestServlet.DELTA_FEED_ENTRY_TITLE, entry1.getTitle());
final SyndEntry entry2 = feed2.getEntries().get(1);
assertEquals("atom_1.0.feed.entry[0].title", entry2.getTitle());
} catch (final Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
syndEntry = (SyndEntry)feed.getEntries().get(0);
assertNotNull(syndEntry);
assertNotNull(syndEntry.getWireEntry());
Entry entry = (Entry) syndEntry.getWireEntry();
assertEquals("atom_1.0.feed.entry[0].rights", entry.getRights());
} finally {
feedFetcher.setPreserveWireFeed(false); //reset
}
}
public void testDeltaEncoding() {
FeedFetcherCache feedInfoCache = new HashMapFeedInfoCache();
FeedFetcher feedFetcher = getFeedFetcher(feedInfoCache);
try {
feedFetcher.setUsingDeltaEncoding(true);
// first retrieval should just grab the default feed
SyndFeed feed1 = feedFetcher.retrieveFeed(new URL("http://localhost:"+testPort+"/rome/FetcherTestServlet?deltaencode=TRUE&refreshfeed=TRUE"));
assertNotNull(feed1);
assertEquals("atom_1.0.feed.title", feed1.getTitle());
assertEquals(2, feed1.getEntries().size());
SyndEntry entry1 = (SyndEntry) feed1.getEntries().get(0);
assertEquals("atom_1.0.feed.entry[0].title", entry1.getTitle());
// second retrieval should get only the new item
/*
* This is breaking with Rome 0.5 ??
*/
SyndFeed feed2 = feedFetcher.retrieveFeed(new URL("http://localhost:"+testPort+"/rome/FetcherTestServlet?deltaencode=TRUE&refreshfeed=TRUE"));
assertNotNull(feed2);
assertEquals(FetcherTestServlet.DELTA_FEED_TITLE, feed2.getTitle());
assertEquals(3, feed2.getEntries().size());
entry1 = (SyndEntry) feed2.getEntries().get(0);
assertEquals(FetcherTestServlet.DELTA_FEED_ENTRY_TITLE, entry1.getTitle());
SyndEntry entry2 = (SyndEntry) feed2.getEntries().get(1);
assertEquals("atom_1.0.feed.entry[0].title", entry2.getTitle());
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
} }

View file

@ -1,42 +1,44 @@
package org.rometools.test; package org.rometools.test;
import java.io.File;
import java.net.URL;
import junit.framework.TestCase;
import org.rometools.fetcher.impl.DiskFeedInfoCache; import org.rometools.fetcher.impl.DiskFeedInfoCache;
import org.rometools.fetcher.impl.SyndFeedInfo; import org.rometools.fetcher.impl.SyndFeedInfo;
import java.net.*;
import java.io.File;
import junit.framework.TestCase;
public class DiskFeedInfoCacheTest extends TestCase { public class DiskFeedInfoCacheTest extends TestCase {
public void testClear() throws Exception { public void testClear() throws Exception {
File cacheDir = new File("test-cache"); final File cacheDir = new File("test-cache");
cacheDir.mkdir(); cacheDir.mkdir();
cacheDir.deleteOnExit(); cacheDir.deleteOnExit();
final DiskFeedInfoCache cache = new DiskFeedInfoCache(cacheDir.getCanonicalPath()); final DiskFeedInfoCache cache = new DiskFeedInfoCache(cacheDir.getCanonicalPath());
SyndFeedInfo info = new SyndFeedInfo(); final SyndFeedInfo info = new SyndFeedInfo();
URL url = new URL("http://nowhere.com"); final URL url = new URL("http://nowhere.com");
cache.setFeedInfo(url, info); cache.setFeedInfo(url, info);
cache.clear(); cache.clear();
final Object returned = cache.getFeedInfo(url); final Object returned = cache.getFeedInfo(url);
assertTrue( returned == null ); assertTrue(returned == null);
} }
public void testRemove() throws Exception { public void testRemove() throws Exception {
File cacheDir = new File("test-cache"); final File cacheDir = new File("test-cache");
cacheDir.mkdir(); cacheDir.mkdir();
cacheDir.deleteOnExit(); cacheDir.deleteOnExit();
final DiskFeedInfoCache cache = new DiskFeedInfoCache( cacheDir.getCanonicalPath() ); final DiskFeedInfoCache cache = new DiskFeedInfoCache(cacheDir.getCanonicalPath());
SyndFeedInfo info = new SyndFeedInfo(); final SyndFeedInfo info = new SyndFeedInfo();
URL url = new URL("http://nowhere.com"); final URL url = new URL("http://nowhere.com");
cache.setFeedInfo( url, info ); cache.setFeedInfo(url, info);
SyndFeedInfo removedInfo = cache.remove( url ); final SyndFeedInfo removedInfo = cache.remove(url);
assertTrue( removedInfo.equals(info) ); assertTrue(removedInfo.equals(info));
SyndFeedInfo shouldBeNull = cache.remove( url ); final SyndFeedInfo shouldBeNull = cache.remove(url);
assertTrue( null == shouldBeNull ); assertTrue(null == shouldBeNull);
} }
} }

View file

@ -1,41 +1,42 @@
package org.rometools.test; package org.rometools.test;
import org.rometools.fetcher.impl.HashMapFeedInfoCache;
import org.rometools.fetcher.impl.SyndFeedInfo;
import java.net.URL; import java.net.URL;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.rometools.fetcher.impl.HashMapFeedInfoCache;
import org.rometools.fetcher.impl.SyndFeedInfo;
public class HashMapFeedInfoCacheTest extends TestCase { public class HashMapFeedInfoCacheTest extends TestCase {
public void testRemove() throws Exception { public void testRemove() throws Exception {
final HashMapFeedInfoCache cache = new HashMapFeedInfoCache(); final HashMapFeedInfoCache cache = new HashMapFeedInfoCache();
assertNotNull( cache ); assertNotNull(cache);
final URL url = new URL("http://foo.com"); final URL url = new URL("http://foo.com");
final SyndFeedInfo syndFeedInfo = new SyndFeedInfo(); final SyndFeedInfo syndFeedInfo = new SyndFeedInfo();
syndFeedInfo.setUrl(url); syndFeedInfo.setUrl(url);
cache.setFeedInfo(url, syndFeedInfo); cache.setFeedInfo(url, syndFeedInfo);
final SyndFeedInfo returned = cache.remove(url); final SyndFeedInfo returned = cache.remove(url);
assertTrue( returned.equals(syndFeedInfo) ); assertTrue(returned.equals(syndFeedInfo));
assertTrue( url.equals( returned.getUrl() )); assertTrue(url.equals(returned.getUrl()));
} }
public void testClear() throws Exception { public void testClear() throws Exception {
final HashMapFeedInfoCache cache = new HashMapFeedInfoCache(); final HashMapFeedInfoCache cache = new HashMapFeedInfoCache();
assertNotNull( cache ); assertNotNull(cache);
final URL url = new URL("http://foo.com"); final URL url = new URL("http://foo.com");
final SyndFeedInfo syndFeedInfo = new SyndFeedInfo(); final SyndFeedInfo syndFeedInfo = new SyndFeedInfo();
syndFeedInfo.setUrl(url); syndFeedInfo.setUrl(url);
cache.setFeedInfo(url, syndFeedInfo); cache.setFeedInfo(url, syndFeedInfo);
//clear it // clear it
cache.clear(); cache.clear();
//we should not get a result back // we should not get a result back
final Object returned = cache.getFeedInfo(url); final Object returned = cache.getFeedInfo(url);
assertTrue( returned == null ); assertTrue(returned == null);
} }
} }

View file

@ -16,45 +16,48 @@
*/ */
package org.rometools.test; package org.rometools.test;
import org.rometools.fetcher.impl.HttpClientFeedFetcher;
import org.rometools.fetcher.impl.FeedFetcherCache;
import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.rometools.fetcher.FeedFetcher; import org.rometools.fetcher.FeedFetcher;
import org.rometools.fetcher.impl.FeedFetcherCache;
import org.rometools.fetcher.impl.HttpClientFeedFetcher;
/** /**
* @author Nick Lothian * @author Nick Lothian
*/ */
public class HttpClientFeedFetcherTest extends AbstractJettyTest { public class HttpClientFeedFetcherTest extends AbstractJettyTest {
public HttpClientFeedFetcherTest(String s) { public HttpClientFeedFetcherTest(final String s) {
super(s); super(s);
} }
/** /**
* @see com.sun.syndication.fetcher.impl.AbstractJettyTest#getFeedFetcher() * @see com.sun.syndication.fetcher.impl.AbstractJettyTest#getFeedFetcher()
*/ */
protected FeedFetcher getFeedFetcher() { @Override
return new HttpClientFeedFetcher(); protected FeedFetcher getFeedFetcher() {
} return new HttpClientFeedFetcher();
}
protected FeedFetcher getFeedFetcher(FeedFetcherCache cache) {
return new HttpClientFeedFetcher(cache); @Override
} protected FeedFetcher getFeedFetcher(final FeedFetcherCache cache) {
return new HttpClientFeedFetcher(cache);
}
/** /**
* @see com.sun.syndication.fetcher.impl.AbstractJettyTest#getAuthenticatedFeedFetcher() * @see com.sun.syndication.fetcher.impl.AbstractJettyTest#getAuthenticatedFeedFetcher()
*/ */
@Override
public FeedFetcher getAuthenticatedFeedFetcher() { public FeedFetcher getAuthenticatedFeedFetcher() {
return new HttpClientFeedFetcher(null, new HttpClientFeedFetcher.CredentialSupplier() { return new HttpClientFeedFetcher(null, new HttpClientFeedFetcher.CredentialSupplier() {
public Credentials getCredentials(String realm, String host) { @Override
public Credentials getCredentials(final String realm, final String host) {
if ("localhost".equals(host)) { if ("localhost".equals(host)) {
return new UsernamePasswordCredentials("username", "password"); return new UsernamePasswordCredentials("username", "password");
} else { } else {
return null; return null;
} }
} }
}); });
} }
} }

View file

@ -16,40 +16,40 @@
*/ */
package org.rometools.test; package org.rometools.test;
import org.rometools.fetcher.impl.HttpURLFeedFetcher;
import org.rometools.fetcher.impl.FeedFetcherCache;
import org.rometools.fetcher.FeedFetcher; import org.rometools.fetcher.FeedFetcher;
import org.rometools.fetcher.impl.FeedFetcherCache;
import org.rometools.fetcher.impl.HttpURLFeedFetcher;
public class HttpURLFeedFetcherTest extends AbstractJettyTest { public class HttpURLFeedFetcherTest extends AbstractJettyTest {
public HttpURLFeedFetcherTest(String s) {
super(s);
}
/** public HttpURLFeedFetcherTest(final String s) {
* @see com.sun.syndication.fetcher.impl.AbstractJettyTest#getFeedFetcher() super(s);
*/ }
protected FeedFetcher getFeedFetcher() {
return new HttpURLFeedFetcher(); /**
} * @see com.sun.syndication.fetcher.impl.AbstractJettyTest#getFeedFetcher()
*/
protected FeedFetcher getFeedFetcher(FeedFetcherCache cache) { @Override
return new HttpURLFeedFetcher(cache); protected FeedFetcher getFeedFetcher() {
} return new HttpURLFeedFetcher();
}
@Override
protected FeedFetcher getFeedFetcher(final FeedFetcherCache cache) {
return new HttpURLFeedFetcher(cache);
}
/** /**
* @see com.sun.syndication.fetcher.impl.AbstractJettyTest#getAuthenticatedFeedFetcher() * @see com.sun.syndication.fetcher.impl.AbstractJettyTest#getAuthenticatedFeedFetcher()
*/ */
@Override
public FeedFetcher getAuthenticatedFeedFetcher() { public FeedFetcher getAuthenticatedFeedFetcher() {
// setup the authenticator // setup the authenticator
java.net.Authenticator.setDefault(new TestBasicAuthenticator()); java.net.Authenticator.setDefault(new TestBasicAuthenticator());
FeedFetcher feedFetcher = getFeedFetcher(); final FeedFetcher feedFetcher = getFeedFetcher();
return feedFetcher; return feedFetcher;
} }
} }

View file

@ -16,27 +16,27 @@
*/ */
package org.rometools.test; package org.rometools.test;
import org.rometools.fetcher.impl.ResponseHandler;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.rometools.fetcher.impl.ResponseHandler;
public class ResponseHandlerTest extends TestCase { public class ResponseHandlerTest extends TestCase {
/** /**
* Constructor for ResponseHandlerTest. * Constructor for ResponseHandlerTest.
*/ */
public ResponseHandlerTest(String arg0) { public ResponseHandlerTest(final String arg0) {
super(arg0); super(arg0);
} }
public void testGetCharacterEncodingString() { public void testGetCharacterEncodingString() {
assertEquals(ResponseHandler.defaultCharacterEncoding, ResponseHandler.getCharacterEncoding((String)null)); assertEquals(ResponseHandler.defaultCharacterEncoding, ResponseHandler.getCharacterEncoding((String) null));
assertEquals(ResponseHandler.defaultCharacterEncoding, ResponseHandler.getCharacterEncoding("text/xml")); assertEquals(ResponseHandler.defaultCharacterEncoding, ResponseHandler.getCharacterEncoding("text/xml"));
assertEquals(ResponseHandler.defaultCharacterEncoding, ResponseHandler.getCharacterEncoding("text/xml;")); assertEquals(ResponseHandler.defaultCharacterEncoding, ResponseHandler.getCharacterEncoding("text/xml;"));
assertEquals("ISO-8859-4", ResponseHandler.getCharacterEncoding("text/xml; charset=ISO-8859-4")); assertEquals("ISO-8859-4", ResponseHandler.getCharacterEncoding("text/xml; charset=ISO-8859-4"));
assertEquals("ISO-8859-4", ResponseHandler.getCharacterEncoding("text/xml;charset=ISO-8859-4")); assertEquals("ISO-8859-4", ResponseHandler.getCharacterEncoding("text/xml;charset=ISO-8859-4"));
assertEquals("ISO-8859-4", ResponseHandler.getCharacterEncoding("text/xml;charset=ISO-8859-4;something")); assertEquals("ISO-8859-4", ResponseHandler.getCharacterEncoding("text/xml;charset=ISO-8859-4;something"));
assertEquals(ResponseHandler.defaultCharacterEncoding, ResponseHandler.getCharacterEncoding("text/xml;something")); assertEquals(ResponseHandler.defaultCharacterEncoding, ResponseHandler.getCharacterEncoding("text/xml;something"));
} }
} }

View file

@ -27,6 +27,7 @@ public class TestBasicAuthenticator extends Authenticator {
/** /**
* @see java.net.Authenticator#getPasswordAuthentication() * @see java.net.Authenticator#getPasswordAuthentication()
*/ */
@Override
protected PasswordAuthentication getPasswordAuthentication() { protected PasswordAuthentication getPasswordAuthentication() {
if ("localhost".equals(getRequestingHost())) { if ("localhost".equals(getRequestingHost())) {
return new PasswordAuthentication("username", "password".toCharArray()); return new PasswordAuthentication("username", "password".toCharArray());