diff options
author | Simon Kaegi | 2008-02-18 21:51:26 +0000 |
---|---|---|
committer | Simon Kaegi | 2008-02-18 21:51:26 +0000 |
commit | fc508e5e5bfe9af2d702cbd8dddba0221bfd3cb7 (patch) | |
tree | f6f8b6509994c182728e0067ac6d4dbb81ede08a /bundles/org.eclipse.equinox.cm | |
parent | 47234b69b53dfbae8b8d81463d40d54a200c6405 (diff) | |
download | rt.equinox.bundles-fc508e5e5bfe9af2d702cbd8dddba0221bfd3cb7.tar.gz rt.equinox.bundles-fc508e5e5bfe9af2d702cbd8dddba0221bfd3cb7.tar.xz rt.equinox.bundles-fc508e5e5bfe9af2d702cbd8dddba0221bfd3cb7.zip |
Diffstat (limited to 'bundles/org.eclipse.equinox.cm')
25 files changed, 3518 insertions, 0 deletions
diff --git a/bundles/org.eclipse.equinox.cm/.classpath b/bundles/org.eclipse.equinox.cm/.classpath new file mode 100644 index 000000000..866a165d0 --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/.classpath @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/OSGi%Minimum-1.1"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/bundles/org.eclipse.equinox.cm/.cvsignore b/bundles/org.eclipse.equinox.cm/.cvsignore new file mode 100644 index 000000000..ba077a403 --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/.cvsignore @@ -0,0 +1 @@ +bin diff --git a/bundles/org.eclipse.equinox.cm/.project b/bundles/org.eclipse.equinox.cm/.project new file mode 100644 index 000000000..7dbe22a24 --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/.project @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.equinox.cm</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ManifestBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.SchemaBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.pde.PluginNature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/bundles/org.eclipse.equinox.cm/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.equinox.cm/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..f31f25003 --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,331 @@ +#Tue Aug 21 11:27:47 CDT 2007 +eclipse.preferences.version=1 +org.eclipse.jdt.core.builder.cleanOutputFolder=clean +org.eclipse.jdt.core.builder.duplicateResourceTask=warning +org.eclipse.jdt.core.builder.invalidClasspath=abort +org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch +org.eclipse.jdt.core.circularClasspath=error +org.eclipse.jdt.core.classpath.exclusionPatterns=enabled +org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=disabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.4 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.doc.comment.support=enabled +org.eclipse.jdt.core.compiler.maxProblemPerUnit=1000 +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=error +org.eclipse.jdt.core.compiler.problem.emptyStatement=warning +org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +org.eclipse.jdt.core.compiler.problem.finalParameterBound=ignore +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=error +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.invalidJavadoc=error +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=private +org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=enabled +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public +org.eclipse.jdt.core.compiler.problem.missingJavadocTags=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=enabled +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=public +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unsafeTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled +org.eclipse.jdt.core.compiler.problem.unusedImport=error +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.source=1.3 +org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_assignment=0 +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 +org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_field=0 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.format_block_comments=false +org.eclipse.jdt.core.formatter.comment.format_header=false +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=false +org.eclipse.jdt.core.formatter.comment.format_line_comments=false +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false +org.eclipse.jdt.core.formatter.comment.indent_root_tags=false +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert +org.eclipse.jdt.core.formatter.comment.line_length=80 +org.eclipse.jdt.core.formatter.compact_else_if=true +org.eclipse.jdt.core.formatter.continuation_indentation=2 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 +org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true +org.eclipse.jdt.core.formatter.indentation.size=4 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false +org.eclipse.jdt.core.formatter.lineSplit=800 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=false +org.eclipse.jdt.core.formatter.tabulation.char=tab +org.eclipse.jdt.core.formatter.tabulation.size=4 +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false +org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.incompatibleJDKLevel=ignore +org.eclipse.jdt.core.incompleteClasspath=error diff --git a/bundles/org.eclipse.equinox.cm/.settings/org.eclipse.jdt.ui.prefs b/bundles/org.eclipse.equinox.cm/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 000000000..21bd9f3c7 --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,57 @@ +#Tue Aug 21 11:30:07 CDT 2007 +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +formatter_profile=_core +formatter_settings_version=11 +org.eclipse.jdt.ui.ignorelowercasenames=true +org.eclipse.jdt.ui.importorder=; +org.eclipse.jdt.ui.ondemandthreshold=3 +org.eclipse.jdt.ui.staticondemandthreshold=3 +sp_cleanup.add_default_serial_version_id=true +sp_cleanup.add_generated_serial_version_id=false +sp_cleanup.add_missing_annotations=true +sp_cleanup.add_missing_deprecated_annotations=true +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_serial_version_id=false +sp_cleanup.always_use_blocks=true +sp_cleanup.always_use_parentheses_in_expressions=false +sp_cleanup.always_use_this_for_non_static_field_access=false +sp_cleanup.always_use_this_for_non_static_method_access=false +sp_cleanup.convert_to_enhanced_for_loop=false +sp_cleanup.correct_indentation=false +sp_cleanup.format_source_code=true +sp_cleanup.make_local_variable_final=false +sp_cleanup.make_parameters_final=false +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_variable_declarations_final=true +sp_cleanup.never_use_blocks=false +sp_cleanup.never_use_parentheses_in_expressions=true +sp_cleanup.on_save_use_additional_actions=false +sp_cleanup.organize_imports=true +sp_cleanup.qualify_static_field_accesses_with_declaring_class=false +sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_with_declaring_class=false +sp_cleanup.qualify_static_method_accesses_with_declaring_class=false +sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_trailing_whitespaces=false +sp_cleanup.remove_trailing_whitespaces_all=true +sp_cleanup.remove_trailing_whitespaces_ignore_empty=false +sp_cleanup.remove_unnecessary_casts=true +sp_cleanup.remove_unnecessary_nls_tags=false +sp_cleanup.remove_unused_imports=false +sp_cleanup.remove_unused_local_variables=false +sp_cleanup.remove_unused_private_fields=true +sp_cleanup.remove_unused_private_members=false +sp_cleanup.remove_unused_private_methods=true +sp_cleanup.remove_unused_private_types=true +sp_cleanup.sort_members=false +sp_cleanup.sort_members_all=false +sp_cleanup.use_blocks=false +sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_parentheses_in_expressions=false +sp_cleanup.use_this_for_non_static_field_access=false +sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true +sp_cleanup.use_this_for_non_static_method_access=false +sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true diff --git a/bundles/org.eclipse.equinox.cm/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.cm/META-INF/MANIFEST.MF new file mode 100644 index 000000000..c72acae5a --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/META-INF/MANIFEST.MF @@ -0,0 +1,18 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %bundleName +Bundle-Vendor: %providerName +Bundle-Localization: plugin +Bundle-SymbolicName: org.eclipse.equinox.cm +Bundle-Version: 1.0.0.qualifier +Bundle-Activator: org.eclipse.equinox.internal.cm.Activator +Import-Package: org.osgi.framework;version="1.3.0", + org.osgi.service.cm;version="1.2.0", + org.osgi.service.log;version="1.3.0", + org.osgi.service.event;version="1.0"; resolution:=optional, + org.osgi.util.tracker;version="1.3.1" +Export-Package: org.eclipse.equinox.internal.cm;x-internal:=true, + org.eclipse.equinox.internal.cm.reliablefile;x-internal:=true +Bundle-RequiredExecutionEnvironment: OSGi/Minimum-1.1, + CDC-1.0/Foundation-1.0, + J2SE-1.3 diff --git a/bundles/org.eclipse.equinox.cm/about.html b/bundles/org.eclipse.equinox.cm/about.html new file mode 100644 index 000000000..d7e1cdf1e --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/about.html @@ -0,0 +1,28 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/> +<title>About</title> +</head> +<body lang="EN-US"> +<h2>About This Content</h2> + +<p>January 30, 2007</p> +<h3>License</h3> + +<p>The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available +at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>. +For purposes of the EPL, "Program" will mean the Content.</p> + +<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>.</p> + +</body> +</html>
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.cm/build.properties b/bundles/org.eclipse.equinox.cm/build.properties new file mode 100644 index 000000000..cdd2db7f1 --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/build.properties @@ -0,0 +1,7 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + about.html,\ + plugin.properties +src.includes = about.html diff --git a/bundles/org.eclipse.equinox.cm/plugin.properties b/bundles/org.eclipse.equinox.cm/plugin.properties new file mode 100644 index 000000000..16a1ebcf3 --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/plugin.properties @@ -0,0 +1,12 @@ +############################################################################### +# Copyright (c) 2007, 2008 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### +bundleName = Configuration Admin +providerName = Eclipse.org diff --git a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/Activator.java b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/Activator.java new file mode 100644 index 000000000..d09e892c5 --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/Activator.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright (c) 2006, 2007 Cognos Incorporated, IBM Corporation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cognos Incorporated - initial API and implementation + * Chris Aniszczyk <zx@us.ibm.com> - bug 209294 + *******************************************************************************/ +package org.eclipse.equinox.internal.cm; + +import org.osgi.framework.*; +import org.osgi.service.cm.ConfigurationAdmin; + +/** + * Activator start the ConfigurationAdminFactory but also handles passing in the Service + * Registration needed by Asynch threads. Asynch threads are controlled by ConfigurationAdminFactory + * start and stop. It requires some care to handle pending events as the service is registered before + * activating the threads. (see EventDispatcher) + */ +public class Activator implements BundleActivator { + private static final String EVENT_ADMIN_CLASS = "org.osgi.service.event.EventAdmin"; //$NON-NLS-1$ + private LogTracker logTracker; + private ServiceRegistration registration; + private ConfigurationAdminFactory factory; + private ConfigurationEventAdapter eventAdapter; + private static BundleContext bundleContext; + + private static synchronized void setBundleContext(BundleContext context) { + bundleContext = context; + } + + public static synchronized String getProperty(String key) { + if (bundleContext != null) + return bundleContext.getProperty(key); + + return null; + } + + public void start(BundleContext context) throws Exception { + setBundleContext(context); + logTracker = new LogTracker(context, System.err); + logTracker.open(); + if (checkEventAdmin()) { + eventAdapter = new ConfigurationEventAdapter(context); + eventAdapter.start(); + } + factory = new ConfigurationAdminFactory(context, logTracker); + factory.start(); + context.addBundleListener(factory); + registration = context.registerService(ConfigurationAdmin.class.getName(), factory, null); + } + + public void stop(BundleContext context) throws Exception { + registration.unregister(); + registration = null; + context.removeBundleListener(factory); + factory.stop(); + factory = null; + if (eventAdapter != null) { + eventAdapter.stop(); + eventAdapter = null; + } + logTracker.close(); + logTracker = null; + setBundleContext(null); + } + + private static boolean checkEventAdmin() { + // cannot support scheduling without the event admin package + try { + Class.forName(EVENT_ADMIN_CLASS); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } +} diff --git a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationAdminFactory.java b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationAdminFactory.java new file mode 100644 index 000000000..2bd87c900 --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationAdminFactory.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2006-2007 Cognos Incorporated, IBM Corporation and others + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cognos Incorporated - initial API and implementation + * IBM Corporation - bug fixes and enhancements + *******************************************************************************/ +package org.eclipse.equinox.internal.cm; + +import java.security.Permission; +import java.util.Dictionary; +import org.osgi.framework.*; +import org.osgi.service.cm.ConfigurationPermission; +import org.osgi.service.log.LogService; + +/** + * ConfigurationAdminFactory provides a Configuration Admin ServiceFactory but more significantly + * launches the whole implementation. + */ + +public class ConfigurationAdminFactory implements ServiceFactory, BundleListener { + + private final Permission configurationPermission = new ConfigurationPermission("*", ConfigurationPermission.CONFIGURE); //$NON-NLS-1$ + private final EventDispatcher eventDispatcher; + private final PluginManager pluginManager; + private final LogService log; + private final ManagedServiceTracker managedServiceTracker; + private final ManagedServiceFactoryTracker managedServiceFactoryTracker; + private final ConfigurationStore configurationStore; + + public ConfigurationAdminFactory(BundleContext context, LogService log) { + this.log = log; + configurationStore = new ConfigurationStore(this, context); + eventDispatcher = new EventDispatcher(context, log); + pluginManager = new PluginManager(context); + managedServiceTracker = new ManagedServiceTracker(this, configurationStore, context); + managedServiceFactoryTracker = new ManagedServiceFactoryTracker(this, configurationStore, context); + } + + void start() { + eventDispatcher.start(); + pluginManager.start(); + managedServiceTracker.open(); + managedServiceFactoryTracker.open(); + } + + void stop() { + managedServiceTracker.close(); + managedServiceFactoryTracker.close(); + eventDispatcher.stop(); + pluginManager.stop(); + } + + public Object getService(Bundle bundle, ServiceRegistration registration) { + ServiceReference reference = registration.getReference(); + eventDispatcher.setServiceReference(reference); + return new ConfigurationAdminImpl(this, configurationStore, bundle); + } + + public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) { + // do nothing + } + + public void bundleChanged(BundleEvent event) { + if (event.getType() == BundleEvent.UNINSTALLED) + configurationStore.unbindConfigurations(event.getBundle()); + } + + public void checkConfigurationPermission() throws SecurityException { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(configurationPermission); + } + + void log(int level, String message) { + log.log(level, message); + } + + void log(int level, String message, Throwable exception) { + log.log(level, message, exception); + } + + void dispatchEvent(int type, String factoryPid, String pid) { + eventDispatcher.dispatchEvent(type, factoryPid, pid); + } + + void notifyConfigurationUpdated(ConfigurationImpl config, boolean isFactory) { + if (isFactory) + managedServiceFactoryTracker.notifyUpdated(config); + else + managedServiceTracker.notifyUpdated(config); + } + + void notifyConfigurationDeleted(ConfigurationImpl config, boolean isFactory) { + if (isFactory) + managedServiceFactoryTracker.notifyDeleted(config); + else + managedServiceTracker.notifyDeleted(config); + } + + void modifyConfiguration(ServiceReference reference, Dictionary properties) { + pluginManager.modifyConfiguration(reference, properties); + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationAdminImpl.java b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationAdminImpl.java new file mode 100644 index 000000000..56ffebd70 --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationAdminImpl.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2006-2007 Cognos Incorporated, IBM Corporation and others + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cognos Incorporated - initial API and implementation + * IBM Corporation - bug fixes and enhancements + *******************************************************************************/ +package org.eclipse.equinox.internal.cm; + +import java.io.IOException; +import org.osgi.framework.*; +import org.osgi.service.cm.Configuration; +import org.osgi.service.cm.ConfigurationAdmin; + +/** + * ConfigurationAdminImpl provides the ConfigurationAdmin service implementation + */ +class ConfigurationAdminImpl implements ConfigurationAdmin { + + private final ConfigurationAdminFactory configurationAdminFactory; + private final Bundle bundle; + private final ConfigurationStore configurationStore; + + public ConfigurationAdminImpl(ConfigurationAdminFactory configurationAdminFactory, ConfigurationStore configurationStore, Bundle bundle) { + this.configurationAdminFactory = configurationAdminFactory; + this.configurationStore = configurationStore; + this.bundle = bundle; + } + + public Configuration createFactoryConfiguration(String factoryPid) throws IOException { + checkPID(factoryPid); + return configurationStore.createFactoryConfiguration(factoryPid, bundle.getLocation()); + } + + public Configuration createFactoryConfiguration(String factoryPid, String location) throws IOException { + checkPID(factoryPid); + this.configurationAdminFactory.checkConfigurationPermission(); + return configurationStore.createFactoryConfiguration(factoryPid, location); + } + + public Configuration getConfiguration(String pid) throws IOException { + checkPID(pid); + Configuration config = configurationStore.getConfiguration(pid, bundle.getLocation()); + if (config.getBundleLocation() != null && !config.getBundleLocation().equals(bundle.getLocation())) + this.configurationAdminFactory.checkConfigurationPermission(); + return config; + } + + public Configuration getConfiguration(String pid, String location) throws IOException { + checkPID(pid); + this.configurationAdminFactory.checkConfigurationPermission(); + return configurationStore.getConfiguration(pid, location); + } + + public Configuration[] listConfigurations(String filterString) throws IOException, InvalidSyntaxException { + if (filterString == null) + filterString = "(" + Constants.SERVICE_PID + "=*)"; //$NON-NLS-1$ //$NON-NLS-2$ + + try { + this.configurationAdminFactory.checkConfigurationPermission(); + } catch (SecurityException e) { + filterString = "(&(" + ConfigurationAdmin.SERVICE_BUNDLELOCATION + "=" + bundle.getLocation() + ")" + filterString + ")"; //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$ //$NON-NLS-4$ + } + return configurationStore.listConfigurations(FrameworkUtil.createFilter(filterString)); + } + + private void checkPID(String pid) { + if (pid == null) + throw new IllegalArgumentException("PID cannot be null"); //$NON-NLS-1$ + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationDictionary.java b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationDictionary.java new file mode 100644 index 000000000..51e8c4bdf --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationDictionary.java @@ -0,0 +1,151 @@ +/******************************************************************************* + * Copyright (c) 2006-2007 Cognos Incorporated, IBM Corporation and others + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cognos Incorporated - initial API and implementation + * IBM Corporation - bug fixes and enhancements + *******************************************************************************/ +package org.eclipse.equinox.internal.cm; + +import java.io.Serializable; +import java.lang.reflect.Array; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Dictionary; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Map; +import java.util.TreeMap; +import java.util.Vector; +import java.util.Map.Entry; + +/** + * ConfigurationDictionary holds the actual configuration data and meets the various comparison + * requirements of the Configuration Admin Service specification. + */ + +public class ConfigurationDictionary extends Dictionary implements Serializable { + + private static final long serialVersionUID = -3583299578203095532L; + private static final Collection simples = Arrays.asList(new Class[] {String.class, Integer.class, Long.class, Float.class, Double.class, Byte.class, Short.class, Character.class, Boolean.class}); + private static final Collection simpleArrays = Arrays.asList(new Class[] {String[].class, Integer[].class, Long[].class, Float[].class, Double[].class, Byte[].class, Short[].class, Character[].class, Boolean[].class}); + private static final Collection primitiveArrays = Arrays.asList(new Class[] {long[].class, int[].class, short[].class, char[].class, byte[].class, double[].class, float[].class, boolean[].class}); + + static class CaseInsensitiveStringComparator implements Comparator, Serializable { + private static final long serialVersionUID = 6501536810492374044L; + + public int compare(Object o1, Object o2) { + return ((String) o1).compareToIgnoreCase((String) o2); + } + } + + protected final Map configurationProperties = Collections.synchronizedMap(new TreeMap(new CaseInsensitiveStringComparator())); + + private static void validateValue(Object value) { + Class clazz = value.getClass(); + + // Is it in the set of simple types + if (simples.contains(clazz)) + return; + + // Is it an array of primitives or simples + if (simpleArrays.contains(clazz) || primitiveArrays.contains(clazz)) + return; + + // Is it a vector of simples + if (clazz == Vector.class) { + Vector valueVector = (Vector) value; + for (Iterator it = valueVector.iterator(); it.hasNext();) { + Class containedClazz = it.next().getClass(); + if (!simples.contains(containedClazz)) { + throw new IllegalArgumentException(containedClazz.getName() + " in " + Vector.class.getName()); //$NON-NLS-1$ + } + } + return; + } + throw new IllegalArgumentException(clazz.getName()); + } + + public Enumeration elements() { + return new Enumeration() { + final Iterator valuesIterator = configurationProperties.values().iterator(); + + public boolean hasMoreElements() { + return valuesIterator.hasNext(); + } + + public Object nextElement() { + return valuesIterator.next(); + } + }; + } + + public Object get(Object key) { + if (key == null) + throw new NullPointerException(); + return configurationProperties.get(key); + } + + public boolean isEmpty() { + return configurationProperties.isEmpty(); + } + + public Enumeration keys() { + return new Enumeration() { + Iterator keysIterator = configurationProperties.keySet().iterator(); + + public boolean hasMoreElements() { + return keysIterator.hasNext(); + } + + public Object nextElement() { + return keysIterator.next(); + } + }; + } + + public Object put(Object key, Object value) { + if (key == null || value == null) + throw new NullPointerException(); + + // Will throw an illegal argument exception if not a valid configuration property type + validateValue(value); + + return configurationProperties.put(key, value); + } + + public Object remove(Object key) { + if (key == null) + throw new NullPointerException(); + return configurationProperties.remove(key); + } + + public int size() { + return configurationProperties.size(); + } + + ConfigurationDictionary copy() { + ConfigurationDictionary result = new ConfigurationDictionary(); + for (Iterator it = configurationProperties.entrySet().iterator(); it.hasNext();) { + Entry entry = (Entry) it.next(); + Object key = entry.getKey(); + Object value = entry.getValue(); + if (value.getClass().isArray()) { + int arrayLength = Array.getLength(value); + Object copyOfArray = Array.newInstance(value.getClass().getComponentType(), arrayLength); + System.arraycopy(value, 0, copyOfArray, 0, arrayLength); + result.configurationProperties.put(key, copyOfArray); + } else if (value instanceof Vector) + result.configurationProperties.put(key, ((Vector) value).clone()); + else + result.configurationProperties.put(key, value); + } + return result; + } +} diff --git a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationEventAdapter.java b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationEventAdapter.java new file mode 100644 index 000000000..a4a43804f --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationEventAdapter.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * Copyright (c) 2007 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.cm; + +import java.util.Hashtable; +import org.osgi.framework.*; +import org.osgi.service.cm.ConfigurationEvent; +import org.osgi.service.cm.ConfigurationListener; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventAdmin; +import org.osgi.util.tracker.ServiceTracker; + +public class ConfigurationEventAdapter implements ConfigurationListener { + // constants for Event topic substring + public static final String TOPIC = "org/osgi/service/cm/ConfigurationEvent"; //$NON-NLS-1$ + public static final char TOPIC_SEPARATOR = '/'; + // constants for Event types + public static final String CM_UPDATED = "CM_UPDATED"; //$NON-NLS-1$ + public static final String CM_DELETED = "CM_DELETED"; //$NON-NLS-1$ + // constants for Event properties + public static final String CM_FACTORY_PID = "cm.factoryPid"; //$NON-NLS-1$ + public static final String CM_PID = "cm.pid"; //$NON-NLS-1$ + public static final String SERVICE = "service"; //$NON-NLS-1$ + public static final String SERVICE_ID = "service.id"; //$NON-NLS-1$ + public static final String SERVICE_OBJECTCLASS = "service.objectClass"; //$NON-NLS-1$ + public static final String SERVICE_PID = "service.pid"; //$NON-NLS-1$ + + private final BundleContext context; + private ServiceRegistration configListenerRegistration; + private final ServiceTracker eventAdminTracker; + + public ConfigurationEventAdapter(BundleContext context) { + this.context = context; + eventAdminTracker = new ServiceTracker(context, EventAdmin.class.getName(), null); + } + + public void start() throws Exception { + eventAdminTracker.open(); + configListenerRegistration = context.registerService(ConfigurationListener.class.getName(), this, null); + } + + public void stop() throws Exception { + configListenerRegistration.unregister(); + configListenerRegistration = null; + eventAdminTracker.close(); + } + + public void configurationEvent(ConfigurationEvent event) { + EventAdmin eventAdmin = (EventAdmin) eventAdminTracker.getService(); + if (eventAdmin == null) { + return; + } + String typename = null; + switch (event.getType()) { + case ConfigurationEvent.CM_UPDATED : + typename = CM_UPDATED; + break; + case ConfigurationEvent.CM_DELETED : + typename = CM_DELETED; + break; + default : // do nothing + return; + } + String topic = TOPIC + TOPIC_SEPARATOR + typename; + ServiceReference ref = event.getReference(); + if (ref == null) { + throw new RuntimeException("ServiceEvent.getServiceReference() is null"); //$NON-NLS-1$ + } + Hashtable properties = new Hashtable(); + properties.put(CM_PID, event.getPid()); + if (event.getFactoryPid() != null) { + properties.put(CM_FACTORY_PID, event.getFactoryPid()); + } + putServiceReferenceProperties(properties, ref); + Event convertedEvent = new Event(topic, properties); + eventAdmin.postEvent(convertedEvent); + } + + public void putServiceReferenceProperties(Hashtable properties, ServiceReference ref) { + properties.put(SERVICE, ref); + properties.put(SERVICE_ID, ref.getProperty(org.osgi.framework.Constants.SERVICE_ID)); + Object o = ref.getProperty(org.osgi.framework.Constants.SERVICE_PID); + if ((o != null) && (o instanceof String)) { + properties.put(SERVICE_PID, o); + } + Object o2 = ref.getProperty(org.osgi.framework.Constants.OBJECTCLASS); + if ((o2 != null) && (o2 instanceof String[])) { + properties.put(SERVICE_OBJECTCLASS, o2); + } + } +} diff --git a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationImpl.java b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationImpl.java new file mode 100644 index 000000000..99e68ac64 --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationImpl.java @@ -0,0 +1,286 @@ +/******************************************************************************* + * Copyright (c) 2006-2007 Cognos Incorporated, IBM Corporation and others + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cognos Incorporated - initial API and implementation + * IBM Corporation - bug fixes and enhancements + *******************************************************************************/ +package org.eclipse.equinox.internal.cm; + +import java.io.IOException; +import java.util.Dictionary; +import java.util.Enumeration; +import org.osgi.framework.Bundle; +import org.osgi.framework.Constants; +import org.osgi.service.cm.*; + +/** + * ConfigurationImpl provides the Configuration implementation. + * The lock and unlock methods are used for synchronization. Operations outside of + * ConfigurationImpl that expect to have control of the lock should call checkLocked + */ +class ConfigurationImpl implements Configuration { + + private final ConfigurationAdminFactory configurationAdminFactory; + private final ConfigurationStore configurationStore; + /** @GuardedBy this*/ + private String bundleLocation; + private final String factoryPid; + private final String pid; + private ConfigurationDictionary dictionary; + /** @GuardedBy this*/ + private boolean deleted = false; + /** @GuardedBy this*/ + private Bundle boundBundle; + /** @GuardedBy this*/ + private int lockedCount = 0; + /** @GuardedBy this*/ + private Thread lockHolder = null; + + public ConfigurationImpl(ConfigurationAdminFactory configurationAdminFactory, ConfigurationStore configurationStore, String factoryPid, String pid, String bundleLocation) { + this.configurationAdminFactory = configurationAdminFactory; + this.configurationStore = configurationStore; + this.factoryPid = factoryPid; + this.pid = pid; + this.bundleLocation = bundleLocation; + } + + public ConfigurationImpl(ConfigurationAdminFactory configurationAdminFactory, ConfigurationStore configurationStore, Dictionary dictionary) { + this.configurationAdminFactory = configurationAdminFactory; + this.configurationStore = configurationStore; + pid = (String) dictionary.get(Constants.SERVICE_PID); + factoryPid = (String) dictionary.get(ConfigurationAdmin.SERVICE_FACTORYPID); + bundleLocation = (String) dictionary.get(ConfigurationAdmin.SERVICE_BUNDLELOCATION); + updateDictionary(dictionary); + } + + protected synchronized void lock() { + Thread current = Thread.currentThread(); + if (lockHolder != current) { + boolean interrupted = false; + try { + while (lockedCount != 0) + try { + wait(); + } catch (InterruptedException e) { + // although we don't handle an interrupt we should still + // save and restore the interrupt for others further up the stack + interrupted = true; + } + } finally { + if (interrupted) + current.interrupt(); // restore interrupted status + } + } + lockedCount++; + lockHolder = current; + } + + protected synchronized void unlock() { + Thread current = Thread.currentThread(); + if (lockHolder != current) + throw new IllegalStateException("Thread not lock owner"); //$NON-NLS-1$ + + lockedCount--; + if (lockedCount == 0) { + lockHolder = null; + notify(); + } + } + + protected synchronized void checkLocked() { + Thread current = Thread.currentThread(); + if (lockHolder != current) + throw new IllegalStateException("Thread not lock owner"); //$NON-NLS-1$ + } + + protected boolean bind(Bundle bundle) { + try { + lock(); + if (boundBundle == null && (bundleLocation == null || bundleLocation.equals(bundle.getLocation()))) + boundBundle = bundle; + return (boundBundle == bundle); + } finally { + unlock(); + } + } + + protected void unbind(Bundle bundle) { + try { + lock(); + if (boundBundle == bundle) + boundBundle = null; + } finally { + unlock(); + } + } + + public void delete() throws IOException { + try { + lock(); + checkDeleted(); + deleted = true; + configurationAdminFactory.notifyConfigurationDeleted(this, factoryPid != null); + configurationAdminFactory.dispatchEvent(ConfigurationEvent.CM_DELETED, factoryPid, pid); + } finally { + unlock(); + } + configurationStore.removeConfiguration(pid); + } + + private void checkDeleted() { + if (deleted) + throw new IllegalStateException("deleted"); //$NON-NLS-1$ + } + + public String getBundleLocation() { + try { + lock(); + checkDeleted(); + if (bundleLocation != null) + return bundleLocation; + if (boundBundle != null) + return boundBundle.getLocation(); + return null; + } finally { + unlock(); + } + } + + protected String getFactoryPid(boolean checkDeleted) { + try { + lock(); + if (checkDeleted) + checkDeleted(); + return factoryPid; + } finally { + unlock(); + } + } + + public String getFactoryPid() { + return getFactoryPid(true); + } + + protected String getPid(boolean checkDeleted) { + try { + lock(); + if (checkDeleted) + checkDeleted(); + return pid; + } finally { + unlock(); + } + } + + public String getPid() { + return getPid(true); + } + + public Dictionary getProperties() { + try { + lock(); + checkDeleted(); + if (dictionary == null) + return null; + + Dictionary copy = dictionary.copy(); + copy.put(Constants.SERVICE_PID, pid); + if (factoryPid != null) + copy.put(ConfigurationAdmin.SERVICE_FACTORYPID, factoryPid); + + return copy; + } finally { + unlock(); + } + } + + protected Dictionary getAllProperties() { + try { + lock(); + if (deleted) + return null; + Dictionary copy = getProperties(); + if (copy != null && bundleLocation != null) + copy.put(ConfigurationAdmin.SERVICE_BUNDLELOCATION, getBundleLocation()); + return copy; + } finally { + unlock(); + } + } + + public void setBundleLocation(String bundleLocation) { + try { + lock(); + checkDeleted(); + configurationAdminFactory.checkConfigurationPermission(); + this.bundleLocation = bundleLocation; + } finally { + unlock(); + } + } + + public void update() throws IOException { + try { + lock(); + checkDeleted(); + if (dictionary == null) + dictionary = new ConfigurationDictionary(); + configurationStore.saveConfiguration(pid, this); + configurationAdminFactory.notifyConfigurationUpdated(this, factoryPid != null); + } finally { + unlock(); + } + } + + public void update(Dictionary properties) throws IOException { + try { + lock(); + checkDeleted(); + updateDictionary(properties); + configurationStore.saveConfiguration(pid, this); + configurationAdminFactory.notifyConfigurationUpdated(this, factoryPid != null); + configurationAdminFactory.dispatchEvent(ConfigurationEvent.CM_UPDATED, factoryPid, pid); + } finally { + unlock(); + } + } + + private void updateDictionary(Dictionary properties) { + ConfigurationDictionary newDictionary = new ConfigurationDictionary(); + Enumeration keys = properties.keys(); + while (keys.hasMoreElements()) { + Object key = keys.nextElement(); + if (newDictionary.get(key) == null) + newDictionary.put(key, properties.get(key)); + else + throw new IllegalArgumentException(key + " is already present or is a case variant."); //$NON-NLS-1$ + } + newDictionary.remove(Constants.SERVICE_PID); + newDictionary.remove(ConfigurationAdmin.SERVICE_FACTORYPID); + newDictionary.remove(ConfigurationAdmin.SERVICE_BUNDLELOCATION); + + dictionary = newDictionary; + } + + public boolean equals(Object obj) { + return pid.equals(((Configuration) obj).getPid()); + } + + public int hashCode() { + return pid.hashCode(); + } + + protected boolean isDeleted() { + try { + lock(); + return deleted; + } finally { + unlock(); + } + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationStore.java b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationStore.java new file mode 100644 index 000000000..756dba3a3 --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationStore.java @@ -0,0 +1,202 @@ +/******************************************************************************* + * Copyright (c) 2006-2008 Cognos Incorporated, IBM Corporation and others + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cognos Incorporated - initial API and implementation + * IBM Corporation - bug fixes and enhancements + *******************************************************************************/ +package org.eclipse.equinox.internal.cm; + +import java.io.*; +import java.security.*; +import java.util.*; +import org.eclipse.equinox.internal.cm.reliablefile.*; +import org.osgi.framework.*; +import org.osgi.service.cm.Configuration; +import org.osgi.service.log.LogService; + +/** + * ConfigurationStore manages all active configurations along with persistence. The current + * implementation uses a filestore and serialization of the configuration dictionaries to files + * identified by their pid. Persistence details are in the constructor, saveConfiguration, and + * deleteConfiguration and can be factored out separately if required. + */ +class ConfigurationStore { + + private final ConfigurationAdminFactory configurationAdminFactory; + private static final String STORE_DIR = "store"; //$NON-NLS-1$ + private static final String PID_EXT = ".pid"; //$NON-NLS-1$ + private final Map configurations = new HashMap(); + private int createdPidCount = 0; + private final File store; + + public ConfigurationStore(ConfigurationAdminFactory configurationAdminFactory, BundleContext context) { + this.configurationAdminFactory = configurationAdminFactory; + store = context.getDataFile(STORE_DIR); + if (store == null) + return; // no persistent store + + store.mkdir(); + File[] configurationFiles = store.listFiles(); + for (int i = 0; i < configurationFiles.length; ++i) { + String configurationFileName = configurationFiles[i].getName(); + if (!configurationFileName.endsWith(PID_EXT)) + continue; + + InputStream ris = null; + ObjectInputStream ois = null; + boolean deleteFile = false; + try { + ris = new ReliableFileInputStream(configurationFiles[i]); + ois = new ObjectInputStream(ris); + Dictionary dictionary = (Dictionary) ois.readObject(); + ConfigurationImpl config = new ConfigurationImpl(configurationAdminFactory, this, dictionary); + configurations.put(config.getPid(), config); + } catch (IOException e) { + String message = e.getMessage(); + String pid = configurationFileName.substring(0, configurationFileName.length() - 4); + String errorMessage = "{Configuration Admin - pid = " + pid + "} could not be restored." + ((message == null) ? "" : " " + message); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + configurationAdminFactory.log(LogService.LOG_ERROR, errorMessage); + deleteFile = true; + } catch (ClassNotFoundException e) { + configurationAdminFactory.log(LogService.LOG_ERROR, e.getMessage()); + } finally { + if (ois != null) { + try { + ois.close(); + } catch (IOException e) { + // ignore + } + } + if (ris != null) { + try { + ris.close(); + } catch (IOException e) { + // ignore + } + } + } + if (deleteFile) { + ReliableFile.delete(configurationFiles[i]); + configurationFiles[i].delete(); + } + } + } + + public void saveConfiguration(String pid, ConfigurationImpl config) throws IOException { + if (store == null) + return; // no persistent store + + config.checkLocked(); + final File configFile = new File(store, pid + PID_EXT); + final Dictionary configProperties = config.getAllProperties(); + try { + AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Object run() throws Exception { + writeConfigurationFile(configFile, configProperties); + return null; + } + }); + } catch (PrivilegedActionException e) { + throw (IOException) e.getException(); + } + } + + void writeConfigurationFile(File configFile, Dictionary configProperties) throws IOException { + OutputStream ros = null; + ObjectOutputStream oos = null; + try { + configFile.createNewFile(); + ros = new ReliableFileOutputStream(configFile); + oos = new ObjectOutputStream(ros); + oos.writeObject(configProperties); + } finally { + if (oos != null) { + try { + oos.close(); + } catch (IOException e) { + // ignore + } + } + if (ros != null) { + try { + ros.close(); + } catch (IOException e) { + // ignore + } + } + } + } + + public synchronized void removeConfiguration(String pid) { + configurations.remove(pid); + if (store == null) + return; // no persistent store + final File configFile = new File(store, pid + PID_EXT); + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + deleteConfigurationFile(configFile); + return null; + } + }); + } + + void deleteConfigurationFile(File configFile) { + ReliableFile.delete(configFile); + configFile.delete(); + } + + public synchronized Configuration getConfiguration(String pid, String location) { + Configuration config = (Configuration) configurations.get(pid); + if (config == null) { + config = new ConfigurationImpl(configurationAdminFactory, this, null, pid, location); + configurations.put(pid, config); + } + return config; + } + + public synchronized Configuration createFactoryConfiguration(String factoryPid, String location) { + String pid = factoryPid + "-" + new Date().getTime() + "-" + createdPidCount++; //$NON-NLS-1$ //$NON-NLS-2$ + ConfigurationImpl config = new ConfigurationImpl(configurationAdminFactory, this, factoryPid, pid, location); + configurations.put(pid, config); + return config; + } + + public synchronized ConfigurationImpl findConfiguration(String pid) { + return (ConfigurationImpl) configurations.get(pid); + } + + public synchronized ConfigurationImpl[] getFactoryConfigurations(String factoryPid) { + List resultList = new ArrayList(); + for (Iterator it = configurations.values().iterator(); it.hasNext();) { + ConfigurationImpl config = (ConfigurationImpl) it.next(); + String otherFactoryPid = config.getFactoryPid(); + if (otherFactoryPid != null && otherFactoryPid.equals(factoryPid)) + resultList.add(config); + } + return (ConfigurationImpl[]) resultList.toArray(new ConfigurationImpl[0]); + } + + public synchronized Configuration[] listConfigurations(Filter filter) { + List resultList = new ArrayList(); + for (Iterator it = configurations.values().iterator(); it.hasNext();) { + ConfigurationImpl config = (ConfigurationImpl) it.next(); + Dictionary properties = config.getAllProperties(); + if (properties != null && filter.match(properties)) + resultList.add(config); + } + int size = resultList.size(); + return size == 0 ? null : (Configuration[]) resultList.toArray(new Configuration[size]); + } + + public synchronized void unbindConfigurations(Bundle bundle) { + for (Iterator it = configurations.values().iterator(); it.hasNext();) { + ConfigurationImpl config = (ConfigurationImpl) it.next(); + config.unbind(bundle); + } + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/EventDispatcher.java b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/EventDispatcher.java new file mode 100644 index 000000000..9da1be88f --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/EventDispatcher.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright (c) 2006-2007 Cognos Incorporated, IBM Corporation and others + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cognos Incorporated - initial API and implementation + * IBM Corporation - bug fixes and enhancements + *******************************************************************************/ +package org.eclipse.equinox.internal.cm; + +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.service.cm.ConfigurationEvent; +import org.osgi.service.cm.ConfigurationListener; +import org.osgi.service.log.LogService; +import org.osgi.util.tracker.ServiceTracker; + +/** + * EventDispatcher is responsible for delivering Configuration Events to ConfigurationListeners. + * The originating ConfigAdmin ServiceReference is needed when delivering events. This reference + * is made available by the service factory before returning the service object. + */ + +public class EventDispatcher { + final ServiceTracker tracker; + private final SerializedTaskQueue queue = new SerializedTaskQueue("ConfigurationListener Event Queue"); //$NON-NLS-1$ + /** @GuardedBy this */ + private ServiceReference configAdminReference; + final LogService log; + + public EventDispatcher(BundleContext context, LogService log) { + this.log = log; + tracker = new ServiceTracker(context, ConfigurationListener.class.getName(), null); + } + + public void start() { + tracker.open(); + } + + public void stop() { + tracker.close(); + synchronized (this) { + configAdminReference = null; + } + } + + synchronized void setServiceReference(ServiceReference reference) { + if (configAdminReference == null) + configAdminReference = reference; + } + + public void dispatchEvent(int type, String factoryPid, String pid) { + final ConfigurationEvent event = createConfigurationEvent(type, factoryPid, pid); + if (event == null) + return; + + ServiceReference[] refs = tracker.getServiceReferences(); + if (refs == null) + return; + + for (int i = 0; i < refs.length; ++i) { + final ServiceReference ref = refs[i]; + queue.put(new Runnable() { + public void run() { + ConfigurationListener listener = (ConfigurationListener) tracker.getService(ref); + if (listener == null) { + return; + } + try { + listener.configurationEvent(event); + } catch (Throwable t) { + log.log(LogService.LOG_ERROR, t.getMessage(), t); + } + } + }); + } + } + + private synchronized ConfigurationEvent createConfigurationEvent(int type, String factoryPid, String pid) { + if (configAdminReference == null) + return null; + + return new ConfigurationEvent(configAdminReference, type, factoryPid, pid); + } +} diff --git a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/LogTracker.java b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/LogTracker.java new file mode 100644 index 000000000..d13db9e81 --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/LogTracker.java @@ -0,0 +1,169 @@ +/******************************************************************************* + * Copyright (c) 1998, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.cm; + +import java.io.PrintStream; +import java.util.Calendar; +import java.util.Date; + +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.service.log.LogService; +import org.osgi.util.tracker.ServiceTracker; + +/** + * LogTracker class. This class encapsulates the LogService + * and handles all issues such as the service coming and going. + */ + +public class LogTracker extends ServiceTracker implements LogService { + /** LogService interface class name */ + protected final static String clazz = "org.osgi.service.log.LogService"; //$NON-NLS-1$ + + /** PrintStream to use if LogService is unavailable */ + private final PrintStream out; + + /** + * Create new LogTracker. + * + * @param context BundleContext of parent bundle. + * @param out Default PrintStream to use if LogService is unavailable. + */ + public LogTracker(BundleContext context, PrintStream out) { + super(context, clazz, null); + this.out = out; + } + + /* + * ---------------------------------------------------------------------- + * LogService Interface implementation + * ---------------------------------------------------------------------- + */ + + public void log(int level, String message) { + log(null, level, message, null); + } + + public void log(int level, String message, Throwable exception) { + log(null, level, message, exception); + } + + public void log(ServiceReference reference, int level, String message) { + log(reference, level, message, null); + } + + public synchronized void log(ServiceReference reference, int level, String message, Throwable exception) { + ServiceReference[] references = getServiceReferences(); + + if (references != null) { + int size = references.length; + + for (int i = 0; i < size; i++) { + LogService service = (LogService) getService(references[i]); + if (service != null) { + try { + service.log(reference, level, message, exception); + } catch (Exception e) { + // TODO: consider printing to System Error + } + } + } + + return; + } + + noLogService(level, message, exception, reference); + } + + /** + * The LogService is not available so we write the message to a PrintStream. + * + * @param level Logging level + * @param message Log message. + * @param throwable Log exception or null if none. + * @param reference ServiceReference associated with message or null if none. + */ + protected void noLogService(int level, String message, Throwable throwable, ServiceReference reference) { + if (out != null) { + synchronized (out) { + // Bug #113286. If no log service present and messages are being + // printed to stdout, prepend message with a timestamp. + String timestamp = getDate(new Date()); + out.print(timestamp + " "); //$NON-NLS-1$ + + switch (level) { + case LOG_DEBUG : { + out.print("Debug"); //$NON-NLS-1$ + break; + } + case LOG_INFO : { + out.print("Info"); //$NON-NLS-1$ + break; + } + case LOG_WARNING : { + out.print("Warning"); //$NON-NLS-1$ + break; + } + case LOG_ERROR : { + out.print("Error"); //$NON-NLS-1$ + break; + } + default : { + out.print("["); //$NON-NLS-1$ + out.print("Unknown Log Level"); //$NON-NLS-1$ + out.print("]"); //$NON-NLS-1$ + break; + } + } + out.print(": "); //$NON-NLS-1$ + out.println(message); + + if (reference != null) { + out.println(reference); + } + + if (throwable != null) { + throwable.printStackTrace(out); + } + } + } + } + + // from EclipseLog to avoid using DateFormat -- see bug 149892#c10 + private String getDate(Date date) { + Calendar c = Calendar.getInstance(); + c.setTime(date); + StringBuffer sb = new StringBuffer(); + appendPaddedInt(c.get(Calendar.YEAR), 4, sb).append('-'); + appendPaddedInt(c.get(Calendar.MONTH) + 1, 2, sb).append('-'); + appendPaddedInt(c.get(Calendar.DAY_OF_MONTH), 2, sb).append(' '); + appendPaddedInt(c.get(Calendar.HOUR_OF_DAY), 2, sb).append(':'); + appendPaddedInt(c.get(Calendar.MINUTE), 2, sb).append(':'); + appendPaddedInt(c.get(Calendar.SECOND), 2, sb).append('.'); + appendPaddedInt(c.get(Calendar.MILLISECOND), 3, sb); + return sb.toString(); + } + + private StringBuffer appendPaddedInt(int value, int pad, StringBuffer buffer) { + pad = pad - 1; + if (pad == 0) + return buffer.append(Integer.toString(value)); + int padding = (int) Math.pow(10, pad); + if (value >= padding) + return buffer.append(Integer.toString(value)); + while (padding > value && padding > 1) { + buffer.append('0'); + padding = padding / 10; + } + buffer.append(value); + return buffer; + } +} diff --git a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ManagedServiceFactoryTracker.java b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ManagedServiceFactoryTracker.java new file mode 100644 index 000000000..2d7d89082 --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ManagedServiceFactoryTracker.java @@ -0,0 +1,188 @@ +/******************************************************************************* + * Copyright (c) 2006-2007 Cognos Incorporated, IBM Corporation and others + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cognos Incorporated - initial API and implementation + * IBM Corporation - bug fixes and enhancements + *******************************************************************************/ +package org.eclipse.equinox.internal.cm; + +import java.util.*; +import java.util.Map.Entry; +import org.osgi.framework.*; +import org.osgi.service.cm.ConfigurationException; +import org.osgi.service.cm.ManagedServiceFactory; +import org.osgi.service.log.LogService; +import org.osgi.util.tracker.ServiceTracker; + +/** + * ManagedServiceFactoryTracker tracks... ManagedServiceFactory(s) and notifies them about related configuration changes + */ +class ManagedServiceFactoryTracker extends ServiceTracker { + + final ConfigurationAdminFactory configurationAdminFactory; + private final ConfigurationStore configurationStore; + private final Map managedServiceFactories = new HashMap(); + private final Map managedServiceFactoryReferences = new HashMap(); + private final SerializedTaskQueue queue = new SerializedTaskQueue("ManagedServiceFactory Update Queue"); //$NON-NLS-1$ + + public ManagedServiceFactoryTracker(ConfigurationAdminFactory configurationAdminFactory, ConfigurationStore configurationStore, BundleContext context) { + super(context, ManagedServiceFactory.class.getName(), null); + this.configurationAdminFactory = configurationAdminFactory; + this.configurationStore = configurationStore; + } + + protected void notifyDeleted(ConfigurationImpl config) { + config.checkLocked(); + String factoryPid = config.getFactoryPid(false); + ServiceReference reference = getManagedServiceFactoryReference(factoryPid); + if (reference != null && config.bind(reference.getBundle())) + asynchDeleted(getManagedServiceFactory(factoryPid), config.getPid(false)); + } + + protected void notifyUpdated(ConfigurationImpl config) { + config.checkLocked(); + String factoryPid = config.getFactoryPid(); + ServiceReference reference = getManagedServiceFactoryReference(factoryPid); + if (reference != null && config.bind(reference.getBundle())) { + Dictionary properties = config.getProperties(); + configurationAdminFactory.modifyConfiguration(reference, properties); + asynchUpdated(getManagedServiceFactory(factoryPid), config.getPid(), properties); + } + } + + public Object addingService(ServiceReference reference) { + String factoryPid = (String) reference.getProperty(Constants.SERVICE_PID); + if (factoryPid == null) + return null; + + ManagedServiceFactory service = (ManagedServiceFactory) context.getService(reference); + if (service == null) + return null; + + synchronized (configurationStore) { + add(reference, factoryPid, service); + } + return service; + } + + public void modifiedService(ServiceReference reference, Object service) { + String factoryPid = (String) reference.getProperty(Constants.SERVICE_PID); + synchronized (configurationStore) { + if (getManagedServiceFactory(factoryPid) == service) + return; + String previousPid = getPidForManagedServiceFactory(service); + remove(reference, previousPid); + addingService(reference); + } + } + + public void removedService(ServiceReference reference, Object service) { + String factoryPid = (String) reference.getProperty(Constants.SERVICE_PID); + synchronized (configurationStore) { + remove(reference, factoryPid); + } + context.ungetService(reference); + } + + private void add(ServiceReference reference, String factoryPid, ManagedServiceFactory service) { + ConfigurationImpl[] configs = configurationStore.getFactoryConfigurations(factoryPid); + try { + for (int i = 0; i < configs.length; ++i) + configs[i].lock(); + + if (trackManagedServiceFactory(factoryPid, reference, service)) { + for (int i = 0; i < configs.length; ++i) { + if (configs[i].isDeleted()) { + // ignore this config + } else if (configs[i].bind(reference.getBundle())) { + Dictionary properties = configs[i].getProperties(); + configurationAdminFactory.modifyConfiguration(reference, properties); + asynchUpdated(service, configs[i].getPid(), properties); + } else { + configurationAdminFactory.log(LogService.LOG_WARNING, "Configuration for " + Constants.SERVICE_PID + "=" + configs[i].getPid() + " could not be bound to " + reference.getBundle().getLocation()); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + } + } + } + } finally { + for (int i = 0; i < configs.length; ++i) + configs[i].unlock(); + } + } + + private void remove(ServiceReference reference, String factoryPid) { + ConfigurationImpl[] configs = configurationStore.getFactoryConfigurations(factoryPid); + try { + for (int i = 0; i < configs.length; ++i) + configs[i].lock(); + untrackManagedServiceFactory(factoryPid, reference); + } finally { + for (int i = 0; i < configs.length; ++i) + configs[i].unlock(); + } + } + + private synchronized boolean trackManagedServiceFactory(String factoryPid, ServiceReference reference, ManagedServiceFactory service) { + if (managedServiceFactoryReferences.containsKey(factoryPid)) { + configurationAdminFactory.log(LogService.LOG_WARNING, ManagedServiceFactory.class.getName() + " already registered for " + Constants.SERVICE_PID + "=" + factoryPid); //$NON-NLS-1$ //$NON-NLS-2$ + return false; + } + managedServiceFactoryReferences.put(factoryPid, reference); + managedServiceFactories.put(factoryPid, service); + return true; + } + + private synchronized void untrackManagedServiceFactory(String factoryPid, ServiceReference reference) { + managedServiceFactoryReferences.remove(factoryPid); + managedServiceFactories.remove(factoryPid); + } + + private synchronized ManagedServiceFactory getManagedServiceFactory(String factoryPid) { + return (ManagedServiceFactory) managedServiceFactories.get(factoryPid); + } + + private synchronized ServiceReference getManagedServiceFactoryReference(String factoryPid) { + return (ServiceReference) managedServiceFactoryReferences.get(factoryPid); + } + + private String getPidForManagedServiceFactory(Object service) { + for (Iterator it = managedServiceFactories.entrySet().iterator(); it.hasNext();) { + Entry entry = (Entry) it.next(); + if (entry.getValue() == service) + return (String) entry.getKey(); + } + return null; + } + + private void asynchDeleted(final ManagedServiceFactory service, final String pid) { + queue.put(new Runnable() { + public void run() { + try { + service.deleted(pid); + } catch (Throwable t) { + configurationAdminFactory.log(LogService.LOG_ERROR, t.getMessage(), t); + } + } + }); + } + + private void asynchUpdated(final ManagedServiceFactory service, final String pid, final Dictionary properties) { + queue.put(new Runnable() { + public void run() { + try { + service.updated(pid, properties); + } catch (ConfigurationException e) { + // we might consider doing more for ConfigurationExceptions + Throwable cause = e.getCause(); + configurationAdminFactory.log(LogService.LOG_ERROR, e.getMessage(), cause != null ? cause : e); + } catch (Throwable t) { + configurationAdminFactory.log(LogService.LOG_ERROR, t.getMessage(), t); + } + } + }); + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ManagedServiceTracker.java b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ManagedServiceTracker.java new file mode 100644 index 000000000..4b0cf5b3a --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ManagedServiceTracker.java @@ -0,0 +1,179 @@ +/******************************************************************************* + * Copyright (c) 2006-2007 Cognos Incorporated, IBM Corporation and others + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cognos Incorporated - initial API and implementation + * IBM Corporation - bug fixes and enhancements + *******************************************************************************/ +package org.eclipse.equinox.internal.cm; + +import java.util.*; +import java.util.Map.Entry; +import org.osgi.framework.*; +import org.osgi.service.cm.*; +import org.osgi.service.log.LogService; +import org.osgi.util.tracker.ServiceTracker; + +/** + * ManagedServiceTracker tracks... ManagedServices and notifies them about related configuration changes + */ +class ManagedServiceTracker extends ServiceTracker { + + final ConfigurationAdminFactory configurationAdminFactory; + private final ConfigurationStore configurationStore; + private final Map managedServices = new HashMap(); + private final Map managedServiceReferences = new HashMap(); + private final SerializedTaskQueue queue = new SerializedTaskQueue("ManagedService Update Queue"); //$NON-NLS-1$ + + public ManagedServiceTracker(ConfigurationAdminFactory configurationAdminFactory, ConfigurationStore configurationStore, BundleContext context) { + super(context, ManagedService.class.getName(), null); + this.configurationAdminFactory = configurationAdminFactory; + this.configurationStore = configurationStore; + } + + protected void notifyDeleted(ConfigurationImpl config) { + config.checkLocked(); + String pid = config.getPid(false); + ServiceReference reference = getManagedServiceReference(pid); + if (reference != null && config.bind(reference.getBundle())) + asynchUpdated(getManagedService(pid), null); + } + + protected void notifyUpdated(ConfigurationImpl config) { + config.checkLocked(); + String pid = config.getPid(); + ServiceReference reference = getManagedServiceReference(pid); + if (reference != null && config.bind(reference.getBundle())) { + Dictionary properties = config.getProperties(); + configurationAdminFactory.modifyConfiguration(reference, properties); + asynchUpdated(getManagedService(pid), properties); + } + } + + public Object addingService(ServiceReference reference) { + String pid = (String) reference.getProperty(Constants.SERVICE_PID); + if (pid == null) + return null; + + ManagedService service = (ManagedService) context.getService(reference); + if (service == null) + return null; + + synchronized (configurationStore) { + add(reference, pid, service); + } + return service; + } + + public void modifiedService(ServiceReference reference, Object service) { + String pid = (String) reference.getProperty(Constants.SERVICE_PID); + synchronized (configurationStore) { + if (getManagedService(pid) == service) + return; + String previousPid = getPidForManagedService(service); + remove(reference, previousPid); + addingService(reference); + } + } + + public void removedService(ServiceReference reference, Object service) { + String pid = (String) reference.getProperty(Constants.SERVICE_PID); + synchronized (configurationStore) { + remove(reference, pid); + } + context.ungetService(reference); + } + + private void add(ServiceReference reference, String pid, ManagedService service) { + ConfigurationImpl config = configurationStore.findConfiguration(pid); + if (config == null && trackManagedService(pid, reference, service)) { + asynchUpdated(service, null); + } else { + try { + config.lock(); + if (trackManagedService(pid, reference, service)) { + if (config.getFactoryPid() != null) { + configurationAdminFactory.log(LogService.LOG_WARNING, "Configuration for " + Constants.SERVICE_PID + "=" + pid + " should only be used by a " + ManagedServiceFactory.class.getName()); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + } else if (config.isDeleted()) { + asynchUpdated(service, null); + } else if (config.bind(reference.getBundle())) { + Dictionary properties = config.getProperties(); + configurationAdminFactory.modifyConfiguration(reference, properties); + asynchUpdated(service, properties); + } else { + configurationAdminFactory.log(LogService.LOG_WARNING, "Configuration for " + Constants.SERVICE_PID + "=" + pid + " could not be bound to " + reference.getBundle().getLocation()); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + } + } + } finally { + config.unlock(); + } + } + } + + private void remove(ServiceReference reference, String pid) { + ConfigurationImpl config = configurationStore.findConfiguration(pid); + if (config == null) { + untrackManagedService(pid, reference); + } else { + try { + config.lock(); + untrackManagedService(pid, reference); + } finally { + config.unlock(); + } + } + } + + private synchronized boolean trackManagedService(String pid, ServiceReference reference, ManagedService service) { + if (managedServiceReferences.containsKey(pid)) { + String message = ManagedService.class.getName() + " already registered for " + Constants.SERVICE_PID + "=" + pid; //$NON-NLS-1$ //$NON-NLS-2$ + configurationAdminFactory.log(LogService.LOG_WARNING, message); + return false; + } + managedServiceReferences.put(pid, reference); + managedServices.put(pid, service); + return true; + } + + private synchronized void untrackManagedService(String pid, ServiceReference reference) { + managedServiceReferences.remove(pid); + managedServices.remove(pid); + } + + private synchronized ManagedService getManagedService(String pid) { + return (ManagedService) managedServices.get(pid); + } + + private synchronized ServiceReference getManagedServiceReference(String pid) { + return (ServiceReference) managedServiceReferences.get(pid); + } + + private synchronized String getPidForManagedService(Object service) { + for (Iterator it = managedServices.entrySet().iterator(); it.hasNext();) { + Entry entry = (Entry) it.next(); + if (entry.getValue() == service) + return (String) entry.getKey(); + } + return null; + } + + private void asynchUpdated(final ManagedService service, final Dictionary properties) { + queue.put(new Runnable() { + public void run() { + try { + service.updated(properties); + } catch (ConfigurationException e) { + // we might consider doing more for ConfigurationExceptions + Throwable cause = e.getCause(); + configurationAdminFactory.log(LogService.LOG_ERROR, e.getMessage(), cause != null ? cause : e); + } catch (Throwable t) { + configurationAdminFactory.log(LogService.LOG_ERROR, t.getMessage(), t); + } + } + }); + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/PluginManager.java b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/PluginManager.java new file mode 100644 index 000000000..0d11b136c --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/PluginManager.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2006-2007 Cognos Incorporated, IBM Corporation and others + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cognos Incorporated - initial API and implementation + * IBM Corporation - bug fixes and enhancements + *******************************************************************************/ +package org.eclipse.equinox.internal.cm; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.Dictionary; +import java.util.TreeSet; + +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceReference; +import org.osgi.service.cm.ConfigurationPlugin; +import org.osgi.util.tracker.ServiceTracker; + +/** + * PluginManager tracks and allows customization via ConfigurationPlugin + */ +public class PluginManager { + private final PluginTracker pluginTracker; + + public PluginManager(BundleContext context) { + pluginTracker = new PluginTracker(context); + } + + public void start() { + pluginTracker.open(); + } + + public void stop() { + pluginTracker.close(); + } + + public void modifyConfiguration(ServiceReference managedReference, Dictionary properties) { + if (properties == null) + return; + + ServiceReference[] references = pluginTracker.getServiceReferences(); + for (int i = 0; i < references.length; ++i) { + String[] pids = (String[]) references[i].getProperty(ConfigurationPlugin.CM_TARGET); + if (pids != null) { + String pid = (String) properties.get(Constants.SERVICE_PID); + if (!Arrays.asList(pids).contains(pid)) + continue; + } + ConfigurationPlugin plugin = (ConfigurationPlugin) pluginTracker.getService(references[i]); + if (plugin != null) + plugin.modifyConfiguration(managedReference, properties); + } + } + + private static class PluginTracker extends ServiceTracker { + final Integer ZERO = new Integer(0); + private TreeSet serviceReferences = new TreeSet(new Comparator() { + public int compare(Object o1, Object o2) { + return getRank((ServiceReference) o1).compareTo(getRank((ServiceReference) o2)); + } + + private Integer getRank(ServiceReference ref) { + Object ranking = ref.getProperty(ConfigurationPlugin.CM_RANKING); + if (ranking == null || !(ranking instanceof Integer)) + return ZERO; + return ((Integer) ranking); + } + }); + + public PluginTracker(BundleContext context) { + super(context, ConfigurationPlugin.class.getName(), null); + } + + /* NOTE: this method alters the contract of the overriden method. + * Rather than returning null if no references are present, it + * returns an empty array. + */ + public ServiceReference[] getServiceReferences() { + synchronized (serviceReferences) { + return (ServiceReference[]) serviceReferences.toArray(new ServiceReference[0]); + } + } + + public Object addingService(ServiceReference reference) { + synchronized (serviceReferences) { + serviceReferences.add(reference); + } + return context.getService(reference); + } + + public void modifiedService(ServiceReference reference, Object service) { + // nothing to do + } + + public void removedService(ServiceReference reference, Object service) { + synchronized (serviceReferences) { + serviceReferences.remove(reference); + } + context.ungetService(reference); + } + } +} diff --git a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/SerializedTaskQueue.java b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/SerializedTaskQueue.java new file mode 100644 index 000000000..89a5760b1 --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/SerializedTaskQueue.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2006 Cognos Incorporated + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cognos Incorporated - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.cm; + +import java.util.LinkedList; + +/** + * SerializedTaskQueue is a utility class that will allow asynchronous but serialized execution of tasks + */ +public class SerializedTaskQueue { + + private static final int MAX_WAIT = 5000; + private final LinkedList tasks = new LinkedList(); + private Thread thread; + private final String queueName; + + public SerializedTaskQueue(String queueName) { + this.queueName = queueName; + } + + public synchronized void put(Runnable newTask) { + tasks.add(newTask); + if (thread == null) { + thread = new Thread(queueName) { + public void run() { + Runnable task = nextTask(MAX_WAIT); + while (task != null) { + task.run(); + task = nextTask(MAX_WAIT); + } + } + }; + thread.start(); + } else + notify(); + } + + synchronized Runnable nextTask(int maxWait) { + if (tasks.isEmpty()) { + try { + wait(maxWait); + } catch (InterruptedException e) { + // ignore -- we control the stack here and do not need to propagate it. + } + + if (tasks.isEmpty()) { + thread = null; + return null; + } + } + return (Runnable) tasks.removeFirst(); + } +} diff --git a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/reliablefile/ReliableFile.java b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/reliablefile/ReliableFile.java new file mode 100644 index 000000000..3d141a6e0 --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/reliablefile/ReliableFile.java @@ -0,0 +1,840 @@ +/******************************************************************************* + * Copyright (c) 2003, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.equinox.internal.cm.reliablefile; + +import java.io.*; +import java.util.*; +import java.util.zip.CRC32; +import java.util.zip.Checksum; +import org.eclipse.equinox.internal.cm.Activator; + +//This is a copy of org.eclipse.osgi.framework.internal.reliablefile.ReliableFile + +/** + * ReliableFile class used by ReliableFileInputStream and ReliableOutputStream. + * This class encapsulates all the logic for reliable file support. + * + */ +public class ReliableFile { + /** + * Open mask. Obtain the best data stream available. If the primary data + * contents are invalid (corrupt, missing, etc.), the data for a prior + * version may be used. + * An IOException will be thrown if a valid data content can not be + * determined. + * This is mutually exclusive with <code>OPEN_FAIL_ON_PRIMARY</code>. + */ + public static final int OPEN_BEST_AVAILABLE = 0; + /** + * Open mask. Obtain only the data stream for the primary file where any other + * version will not be valid. This should be used for data streams that are + * managed as a group as a prior contents may not match the other group data. + * If the primary data is not invalid, a IOException will be thrown. + * This is mutually exclusive with <code>OPEN_BEST_AVAILABLE</code>. + */ + public static final int OPEN_FAIL_ON_PRIMARY = 1; + + /** + * Use the last generation of the file + */ + public static final int GENERATION_LATEST = 0; + /** + * Keep infinite backup files + */ + public static final int GENERATIONS_INFINITE = 0; + + /** + * Extension of tmp file used during writing. + * A reliable file with this extension should + * never be directly used. + */ + public static final String tmpExt = ".tmp"; //$NON-NLS-1$ + + /** + * Property to set the maximum size of a file that will be buffered. When calculating a ReliableFile + * checksum, if the file is this size or small, ReliableFile will read the file contents into a + * <code>BufferedInputStream</code> and reset the buffer to avoid having to read the data from the + * media twice. Since this method require memory for storage, it is limited to this size. The default + * maximum is 128-KBytes. + */ + public static final String PROP_MAX_BUFFER = "osgi.reliableFile.maxInputStreamBuffer"; //$NON-NLS-1$ + /** + * The maximum number of generations to keep as backup files in case last generation + * file is determined to be invalid. + */ + public static final String PROP_MAX_GENERATIONS = "osgi.ReliableFile.maxGenerations"; //$NON-NLS-1$ + /** + *see org.eclipse.core.runtime.internal.adaptor.BasicLocation#PROP_OSGI_LOCKING + */ + public static final String PROP_OSGI_LOCKING = "osgi.locking"; //$NON-NLS-1$ + + private static final int FILETYPE_VALID = 0; + private static final int FILETYPE_CORRUPT = 1; + private static final int FILETYPE_NOSIGNATURE = 2; + + private static final byte identifier1[] = {'.', 'c', 'r', 'c'}; + private static final byte identifier2[] = {'.', 'v', '1', '\n'}; + + private static final int BUF_SIZE = 4096; + private static final int maxInputStreamBuffer; + private static final int defaultMaxGenerations; + private static final boolean fileSharing; + //our cache of the last looked up generations for a file + private static File lastGenerationFile = null; + private static int[] lastGenerations = null; + private static final Object lastGenerationLock = new Object(); + + static { + String prop = Activator.getProperty(PROP_MAX_BUFFER); + int tmpMaxInput = 128 * 1024; //128k + if (prop != null) { + try { + tmpMaxInput = Integer.parseInt(prop); + } catch (NumberFormatException e) {/*ignore*/ + } + } + maxInputStreamBuffer = tmpMaxInput; + + int tmpDefaultMax = 2; + prop = Activator.getProperty(PROP_MAX_GENERATIONS); + if (prop != null) { + try { + tmpDefaultMax = Integer.parseInt(prop); + } catch (NumberFormatException e) {/*ignore*/ + } + } + defaultMaxGenerations = tmpDefaultMax; + + prop = Activator.getProperty(PROP_OSGI_LOCKING); + boolean tmpFileSharing = true; + if (prop != null) { + if (prop.equals("none")) { //$NON-NLS-1$ + tmpFileSharing = false; + } + } + fileSharing = tmpFileSharing; + } + + /** File object for original reference file */ + private File referenceFile; + + /** List of checksum file objects: File => specific ReliableFile generation */ + private static Hashtable cacheFiles = new Hashtable(20); + + private File inputFile = null; + private File outputFile = null; + private Checksum appendChecksum = null; + + /** + * ReliableFile object factory. This method is called by ReliableFileInputStream + * and ReliableFileOutputStream to get a ReliableFile object for a target file. + * If the object is in the cache, the cached copy is returned. + * Otherwise a new ReliableFile object is created and returned. + * The use count of the returned ReliableFile object is incremented. + * + * @param name Name of the target file. + * @return A ReliableFile object for the target file. + * @throws IOException If the target file is a directory. + */ + static ReliableFile getReliableFile(String name) throws IOException { + return getReliableFile(new File(name)); + } + + /** + * ReliableFile object factory. This method is called by ReliableFileInputStream + * and ReliableFileOutputStream to get a ReliableFile object for a target file. + * If the object is in the cache, the cached copy is returned. + * Otherwise a new ReliableFile object is created and returned. + * The use count of the returned ReliableFile object is incremented. + * + * @param file File object for the target file. + * @return A ReliableFile object for the target file. + * @throws IOException If the target file is a directory. + */ + static ReliableFile getReliableFile(File file) throws IOException { + if (file.isDirectory()) { + throw new FileNotFoundException("file is a directory"); //$NON-NLS-1$ + } + return new ReliableFile(file); + } + + /** + * Private constructor used by the static getReliableFile factory methods. + * + * @param file File object for the target file. + */ + private ReliableFile(File file) { + referenceFile = file; + } + + private static int[] getFileGenerations(File file) { + if (!fileSharing) { + synchronized (lastGenerationLock) { + if (lastGenerationFile != null) { + //shortcut maybe, only if filesharing is not supported + if (file.equals(lastGenerationFile)) + return lastGenerations; + } + } + } + int[] generations = null; + try { + String name = file.getName(); + String prefix = name + '.'; + int prefixLen = prefix.length(); + File parent = new File(file.getParent()); + String[] files = parent.list(); + if (files == null) + return null; + ArrayList list = new ArrayList(defaultMaxGenerations); + if (file.exists()) + list.add(new Integer(0)); //base file exists + for (int i = 0; i < files.length; i++) { + if (files[i].startsWith(prefix)) { + try { + int id = Integer.parseInt(files[i].substring(prefixLen)); + list.add(new Integer(id)); + } catch (NumberFormatException e) {/*ignore*/ + } + } + } + if (list.size() == 0) + return null; + Object[] array = list.toArray(); + Arrays.sort(array); + generations = new int[array.length]; + for (int i = 0, j = array.length - 1; i < array.length; i++, j--) { + generations[i] = ((Integer) array[j]).intValue(); + } + return generations; + } finally { + if (!fileSharing) { + synchronized (lastGenerationLock) { + lastGenerationFile = file; + lastGenerations = generations; + } + } + } + } + + /** + * Returns an InputStream object for reading the target file. + * + * @param generation the maximum generation to evaluate + * @param openMask mask used to open data. + * are invalid (corrupt, missing, etc). + * @return An InputStream object which can be used to read the target file. + * @throws IOException If an error occurs preparing the file. + */ + InputStream getInputStream(int generation, int openMask) throws IOException { + if (inputFile != null) { + throw new IOException("Input stream already open"); //$NON-NLS-1$ + } + int[] generations = getFileGenerations(referenceFile); + if (generations == null) { + throw new FileNotFoundException("File not found"); //$NON-NLS-1$ + } + String name = referenceFile.getName(); + File parent = new File(referenceFile.getParent()); + + boolean failOnPrimary = (openMask & OPEN_FAIL_ON_PRIMARY) != 0; + if (failOnPrimary && generation == GENERATIONS_INFINITE) + generation = generations[0]; + + File textFile = null; + InputStream textIS = null; + for (int idx = 0; idx < generations.length; idx++) { + if (generation != 0) { + if (generations[idx] > generation || (failOnPrimary && generations[idx] != generation)) + continue; + } + File file; + if (generations[idx] != 0) + file = new File(parent, name + '.' + generations[idx]); + else + file = referenceFile; + InputStream is = null; + CacheInfo info; + synchronized (cacheFiles) { + info = (CacheInfo) cacheFiles.get(file); + long timeStamp = file.lastModified(); + if (info == null || timeStamp != info.timeStamp) { + try { + is = new FileInputStream(file); + if (is.available() < maxInputStreamBuffer) + is = new BufferedInputStream(is); + Checksum cksum = getChecksumCalculator(); + int filetype = getStreamType(is, cksum); + info = new CacheInfo(filetype, cksum, timeStamp); + cacheFiles.put(file, info); + } catch (IOException e) {/*ignore*/ + } + } + } + + // if looking for a specific generation only, only look at one + // and return the result. + if (failOnPrimary) { + if (info != null && info.filetype == FILETYPE_VALID) { + inputFile = file; + if (is != null) + return is; + return new FileInputStream(file); + } + throw new IOException("ReliableFile is corrupt"); //$NON-NLS-1$ + } + + // if error, ignore this file & try next + if (info == null) + continue; + + // we're not looking for a specific version, so let's pick the best case + switch (info.filetype) { + case FILETYPE_VALID : + inputFile = file; + if (is != null) + return is; + return new FileInputStream(file); + + case FILETYPE_NOSIGNATURE : + if (textFile == null) { + textFile = file; + textIS = is; + } + break; + } + } + + // didn't find any valid files, if there are any plain text files + // use it instead + if (textFile != null) { + inputFile = textFile; + if (textIS != null) + return textIS; + return new FileInputStream(textFile); + } + throw new IOException("ReliableFile is corrupt"); //$NON-NLS-1$ + } + + /** + * Returns an OutputStream object for writing the target file. + * + * @param append append new data to an existing file. + * @param appendGeneration specific generation of file to append from. + * @return An OutputStream object which can be used to write the target file. + * @throws IOException IOException If an error occurs preparing the file. + */ + OutputStream getOutputStream(boolean append, int appendGeneration) throws IOException { + if (outputFile != null) + throw new IOException("Output stream is already open"); //$NON_NLS-1$ //$NON-NLS-1$ + String name = referenceFile.getName(); + File parent = new File(referenceFile.getParent()); + File tmpFile = File.createTempFile(name, tmpExt, parent); + + if (!append) { + OutputStream os = new FileOutputStream(tmpFile); + outputFile = tmpFile; + return os; + } + + InputStream is; + try { + is = getInputStream(appendGeneration, OPEN_BEST_AVAILABLE); + } catch (FileNotFoundException e) { + OutputStream os = new FileOutputStream(tmpFile); + outputFile = tmpFile; + return os; + } + + try { + CacheInfo info = (CacheInfo) cacheFiles.get(inputFile); + appendChecksum = info.checksum; + OutputStream os = new FileOutputStream(tmpFile); + if (info.filetype == FILETYPE_NOSIGNATURE) { + cp(is, os, 0); + } else { + cp(is, os, 16); // don't copy checksum signature + } + outputFile = tmpFile; + return os; + } finally { + closeInputFile(); + } + } + + /** + * Close the target file for reading. + * + * @param checksum Checksum of the file contents + * @throws IOException If an error occurs closing the file. + */ + void closeOutputFile(Checksum checksum) throws IOException { + if (outputFile == null) + throw new IOException("Output stream is not open"); //$NON-NLS-1$ + int[] generations = getFileGenerations(referenceFile); + String name = referenceFile.getName(); + File parent = new File(referenceFile.getParent()); + File newFile; + if (generations == null) + newFile = new File(parent, name + ".1"); //$NON-NLS-1$ + else + newFile = new File(parent, name + '.' + (generations[0] + 1)); + + mv(outputFile, newFile); // throws IOException if problem + outputFile = null; + appendChecksum = null; + CacheInfo info = new CacheInfo(FILETYPE_VALID, checksum, newFile.lastModified()); + cacheFiles.put(newFile, info); + cleanup(generations, true); + lastGenerationFile = null; + lastGenerations = null; + } + + /** + * Abort the current output stream and do not update the reliable file table. + * + */ + void abortOutputFile() { + if (outputFile == null) + return; + outputFile.delete(); + outputFile = null; + appendChecksum = null; + } + + File getOutputFile() { + return outputFile; + } + + /** + * Close the target file for reading. + */ + void closeInputFile() { + inputFile = null; + } + + private void cleanup(int[] generations, boolean generationAdded) { + if (generations == null) + return; + String name = referenceFile.getName(); + File parent = new File(referenceFile.getParent()); + int generationCount = generations.length; + // if a base file is in the list (0 in generations[]), we will + // never delete these files, so don't count them in the old + // generation count. + if (generations[generationCount - 1] == 0) + generationCount--; + // assume here that the int[] does not include a file just created + int rmCount = generationCount - defaultMaxGenerations; + if (generationAdded) + rmCount++; + if (rmCount < 1) + return; + synchronized (cacheFiles) { + // first, see if any of the files not deleted are known to + // be corrupt. If so, be sure to keep not to delete good + // backup files. + for (int idx = 0, count = generationCount - rmCount; idx < count; idx++) { + File file = new File(parent, name + '.' + generations[idx]); + CacheInfo info = (CacheInfo) cacheFiles.get(file); + if (info != null) { + if (info.filetype == FILETYPE_CORRUPT) + rmCount--; + } + } + for (int idx = generationCount - 1; rmCount > 0; idx--, rmCount--) { + File rmFile = new File(parent, name + '.' + generations[idx]); + rmFile.delete(); + cacheFiles.remove(rmFile); + } + } + } + + /** + * Rename a file. + * + * @param from The original file. + * @param to The new file name. + * @throws IOException If the rename failed. + */ + private static void mv(File from, File to) throws IOException { + if (!from.renameTo(to)) { + throw new IOException("rename failed"); //$NON-NLS-1$ + } + } + + /** + * Copy a file. + * + * @throws IOException If the copy failed. + */ + private static void cp(InputStream in, OutputStream out, int truncateSize) throws IOException { + try { + int length = in.available(); + if (truncateSize > length) + length = 0; + else + length -= truncateSize; + if (length > 0) { + int bufferSize; + if (length > BUF_SIZE) { + bufferSize = BUF_SIZE; + } else { + bufferSize = length; + } + + byte buffer[] = new byte[bufferSize]; + int size = 0; + int count; + while ((count = in.read(buffer, 0, length)) > 0) { + if ((size + count) >= length) + count = length - size; + out.write(buffer, 0, count); + size += count; + } + } + } finally { + try { + in.close(); + } catch (IOException e) {/*ignore*/ + } + out.close(); + } + } + + /** + * Answers a boolean indicating whether or not the specified reliable file + * exists on the underlying file system. This call only returns if a file + * exists and not if the file contents are valid. + * @param file returns true if the specified reliable file exists; otherwise false is returned + * + * @return <code>true</code> if the specified reliable file exists, + * <code>false</code> otherwise. + */ + public static boolean exists(File file) { + String prefix = file.getName() + '.'; + File parent = new File(file.getParent()); + int prefixLen = prefix.length(); + String[] files = parent.list(); + if (files == null) + return false; + for (int i = 0; i < files.length; i++) { + if (files[i].startsWith(prefix)) { + try { + Integer.parseInt(files[i].substring(prefixLen)); + return true; + } catch (NumberFormatException e) {/*ignore*/ + } + } + } + return file.exists(); + } + + /** + * Returns the time that the reliable file was last modified. Only the time + * of the last file generation is returned. + * @param file the file to determine the time of. + * @return time the file was last modified (see java.io.File.lastModified()). + */ + public static long lastModified(File file) { + int[] generations = getFileGenerations(file); + if (generations == null) + return 0L; + if (generations[0] == 0) + return file.lastModified(); + String name = file.getName(); + File parent = new File(file.getParent()); + File newFile = new File(parent, name + '.' + generations[0]); + return newFile.lastModified(); + } + + /** + * Returns the time that this ReliableFile was last modified. This method is only valid + * after requesting an input stream and the time of the actual input file is returned. + * + * @return time the file was last modified (see java.io.File.lastModified()) or + * 0L if an input stream is not open. + */ + public long lastModified() { + if (inputFile != null) { + return inputFile.lastModified(); + } + return 0L; + } + + /** + * Returns the a version number of a reliable managed file. The version can be expected + * to be unique for each successful file update. + * + * @param file the file to determine the version of. + * @return a unique version of this current file. A value of -1 indicates the file does + * not exist or an error occurred. + */ + public static int lastModifiedVersion(File file) { + int[] generations = getFileGenerations(file); + if (generations == null) + return -1; + return generations[0]; + } + + /** + * Delete the specified reliable file on the underlying file system. + * @param deleteFile the reliable file to delete + * + * @return <code>true</code> if the specified reliable file was deleted, + * <code>false</code> otherwise. + */ + public static boolean delete(File deleteFile) { + int[] generations = getFileGenerations(deleteFile); + if (generations == null) + return false; + String name = deleteFile.getName(); + File parent = new File(deleteFile.getParent()); + synchronized (cacheFiles) { + for (int idx = 0; idx < generations.length; idx++) { + // base files (.0 in generations[]) will never be deleted + if (generations[idx] == 0) + continue; + File file = new File(parent, name + '.' + generations[idx]); + if (file.exists()) { + file.delete(); + } + cacheFiles.remove(file); + } + } + return true; + } + + /** + * Get a list of ReliableFile base names in a given directory. Only files with a valid + * ReliableFile generation are included. + * @param directory the directory to inquire. + * @return an array of ReliableFile names in the directory. + * @throws IOException if an error occurs. + */ + public static String[] getBaseFiles(File directory) throws IOException { + if (!directory.isDirectory()) + throw new IOException("Not a valid directory"); //$NON-NLS-1$ + String files[] = directory.list(); + HashSet list = new HashSet(files.length / 2); + for (int idx = 0; idx < files.length; idx++) { + String file = files[idx]; + int pos = file.lastIndexOf('.'); + if (pos == -1) + continue; + String ext = file.substring(pos + 1); + int generation = 0; + try { + generation = Integer.parseInt(ext); + } catch (NumberFormatException e) {/*skip*/ + } + if (generation == 0) + continue; + String base = file.substring(0, pos); + list.add(base); + } + files = new String[list.size()]; + int idx = 0; + for (Iterator iter = list.iterator(); iter.hasNext();) { + files[idx++] = (String) iter.next(); + } + return files; + } + + /** + * Delete any old excess generations of a given reliable file. + * @param base realible file. + */ + public static void cleanupGenerations(File base) { + ReliableFile rf = new ReliableFile(base); + int[] generations = getFileGenerations(base); + rf.cleanup(generations, false); + lastGenerationFile = null; + lastGenerations = null; + } + + /** + * Inform ReliableFile that a file has been updated outside of + * ReliableFile. + * @param file + */ + public static void fileUpdated(File file) { + lastGenerationFile = null; + lastGenerations = null; + } + + /** + * Append a checksum value to the end of an output stream. + * @param out the output stream. + * @param checksum the checksum value to append to the file. + * @throws IOException if a write error occurs. + */ + void writeChecksumSignature(OutputStream out, Checksum checksum) throws IOException { + // tag on our signature and checksum + out.write(ReliableFile.identifier1); + out.write(intToHex((int) checksum.getValue())); + out.write(ReliableFile.identifier2); + } + + /** + * Returns the size of the ReliableFile signature + CRC at the end of the file. + * This method should be called only after calling getInputStream() or + * getOutputStream() methods. + * + * @return <code>int</code> size of the ReliableFIle signature + CRC appended + * to the end of the file. + * @throws IOException if getInputStream() or getOutputStream has not been + * called. + */ + int getSignatureSize() throws IOException { + if (inputFile != null) { + CacheInfo info = (CacheInfo) cacheFiles.get(inputFile); + if (info != null) { + switch (info.filetype) { + case FILETYPE_VALID : + case FILETYPE_CORRUPT : + return 16; + case FILETYPE_NOSIGNATURE : + return 0; + } + } + } + throw new IOException("ReliableFile signature size is unknown"); //$NON-NLS-1$ + } + + /** + * Returns a Checksum object for the current file contents. This method + * should be called only after calling getInputStream() or + * getOutputStream() methods. + * + * @return Object implementing Checksum interface initialized to the + * current file contents. + * @throws IOException if getOutputStream for append has not been called. + */ + Checksum getFileChecksum() throws IOException { + if (appendChecksum == null) + throw new IOException("Checksum is invalid!"); //$NON-NLS-1$ + return appendChecksum; + } + + /** + * Create a checksum implementation used by ReliableFile. + * + * @return Object implementing Checksum interface used to calculate + * a reliable file checksum + */ + Checksum getChecksumCalculator() { + // Using CRC32 because Adler32 isn't in the eeMinimum library. + return new CRC32(); + } + + /** + * Determine if a File is a valid ReliableFile + * + * @return <code>true</code> if the file is a valid ReliableFile + * @throws IOException If an error occurs verifying the file. + */ + private int getStreamType(InputStream is, Checksum crc) throws IOException { + boolean markSupported = is.markSupported(); + if (markSupported) + is.mark(is.available()); + try { + int len = is.available(); + if (len < 16) { + if (crc != null) { + byte data[] = new byte[16]; + int num = is.read(data); + if (num > 0) + crc.update(data, 0, num); + } + return FILETYPE_NOSIGNATURE; + } + len -= 16; + + int pos = 0; + byte data[] = new byte[BUF_SIZE]; + + while (pos < len) { + int read = data.length; + if (pos + read > len) + read = len - pos; + + int num = is.read(data, 0, read); + if (num == -1) { + throw new IOException("Unable to read entire file."); //$NON-NLS-1$ + } + + crc.update(data, 0, num); + pos += num; + } + + int num = is.read(data); // read last 16-byte signature + if (num != 16) { + throw new IOException("Unable to read entire file."); //$NON-NLS-1$ + } + + int i, j; + for (i = 0; i < 4; i++) + if (identifier1[i] != data[i]) { + crc.update(data, 0, 16); // update crc w/ sig bytes + return FILETYPE_NOSIGNATURE; + } + for (i = 0, j = 12; i < 4; i++, j++) + if (identifier2[i] != data[j]) { + crc.update(data, 0, 16); // update crc w/ sig bytes + return FILETYPE_NOSIGNATURE; + } + long crccmp; + try { + crccmp = Long.valueOf(new String(data, 4, 8, "UTF-8"), 16).longValue(); //$NON-NLS-1$ + } catch (UnsupportedEncodingException e) { + crccmp = Long.valueOf(new String(data, 4, 8), 16).longValue(); + } + if (crccmp == crc.getValue()) { + return FILETYPE_VALID; + } + // do not update CRC + return FILETYPE_CORRUPT; + } finally { + if (markSupported) + is.reset(); + } + } + + private static byte[] intToHex(int l) { + byte[] buffer = new byte[8]; + int count = 8; + + do { + int ch = (l & 0xf); + if (ch > 9) + ch = ch - 10 + 'a'; + else + ch += '0'; + buffer[--count] = (byte) ch; + l >>= 4; + } while (count > 0); + return buffer; + } + + private class CacheInfo { + int filetype; + Checksum checksum; + long timeStamp; + + CacheInfo(int filetype, Checksum checksum, long timeStamp) { + this.filetype = filetype; + this.checksum = checksum; + this.timeStamp = timeStamp; + } + } +} diff --git a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/reliablefile/ReliableFileInputStream.java b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/reliablefile/ReliableFileInputStream.java new file mode 100644 index 000000000..5b61c8a55 --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/reliablefile/ReliableFileInputStream.java @@ -0,0 +1,211 @@ +/******************************************************************************* + * Copyright (c) 2003, 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.equinox.internal.cm.reliablefile; + +import java.io.*; + +//This is a copy of org.eclipse.osgi.framework.internal.reliablefile.ReliableFileInputStream + +/** + * A ReliableFile FileInputStream replacement class. + * This class can be used just like FileInputStream. The class + * is in partnership with ReliableFileOutputStream to avoid losing + * file data by using multiple files. + * + * @see ReliableFileOutputStream + */ +public class ReliableFileInputStream extends FilterInputStream { + /** + * ReliableFile object for this file. + */ + private ReliableFile reliable; + + /** + * size of crc and signature + */ + private int sigSize; + + /** + * current position reading from file + */ + private int readPos; + + /** + * total file length available for reading + */ + private int length; + + /** + * Constructs a new ReliableFileInputStream on the file named <code>name</code>. If the + * file does not exist, the <code>FileNotFoundException</code> is thrown. + * The <code>name</code> may be absolute or relative + * to the System property <code>"user.dir"</code>. + * + * @param name the file on which to stream reads. + * @exception java.io.IOException If an error occurs opening the file. + */ + public ReliableFileInputStream(String name) throws IOException { + this(ReliableFile.getReliableFile(name), ReliableFile.GENERATION_LATEST, ReliableFile.OPEN_BEST_AVAILABLE); + } + + /** + * Constructs a new ReliableFileInputStream on the File <code>file</code>. If the + * file does not exist, the <code>FileNotFoundException</code> is thrown. + * + * @param file the File on which to stream reads. + * @exception java.io.IOException If an error occurs opening the file. + */ + public ReliableFileInputStream(File file) throws IOException { + this(ReliableFile.getReliableFile(file), ReliableFile.GENERATION_LATEST, ReliableFile.OPEN_BEST_AVAILABLE); + } + + /** + * Constructs a new ReliableFileInputStream on the File <code>file</code>. If the + * file does not exist, the <code>FileNotFoundException</code> is thrown. + * + * @param file the File on which to stream reads. + * @param generation a specific generation requested. + * @param openMask mask used to open data. + * are invalid (corrupt, missing, etc). + * @exception java.io.IOException If an error occurs opening the file. + */ + public ReliableFileInputStream(File file, int generation, int openMask) throws IOException { + this(ReliableFile.getReliableFile(file), generation, openMask); + } + + /** + * + * @param reliable The ReliableFile on which to read. + * @param generation a specific generation requested. + * @param openMask mask used to open data. + * are invalid (corrupt, missing, etc). + * @throws IOException If an error occurs opening the file. + */ + private ReliableFileInputStream(ReliableFile reliable, int generation, int openMask) throws IOException { + super(reliable.getInputStream(generation, openMask)); + + this.reliable = reliable; + sigSize = reliable.getSignatureSize(); + readPos = 0; + length = super.available(); + if (sigSize > length) + length = 0; // shouldn't ever happen + else + length -= sigSize; + } + + /** + * Closes this input stream and releases any system resources associated + * with the stream. + * + * @exception java.io.IOException If an error occurs closing the file. + */ + public synchronized void close() throws IOException { + if (reliable != null) { + try { + super.close(); + } finally { + reliable.closeInputFile(); + reliable = null; + } + } + } + + /** + * Override default FilterInputStream method. + * @see FilterInputStream#read(byte[], int, int) + */ + public synchronized int read(byte b[], int off, int len) throws IOException { + if (readPos >= length) { + return -1; + } + int num = super.read(b, off, len); + + if (num != -1) { + if (num + readPos > length) { + num = length - readPos; + } + readPos += num; + } + return num; + } + + /** + * Override default FilterInputStream method. + * @see FilterInputStream#read(byte[]) + */ + public synchronized int read(byte b[]) throws IOException { + return read(b, 0, b.length); + } + + /** + * Override default FilterInputStream method. + * @see FilterInputStream#read() + */ + public synchronized int read() throws IOException { + if (readPos >= length) { + return -1; + } + int num = super.read(); + + if (num != -1) { + readPos++; + } + return num; + } + + /** + * Override default available method. + * @see FilterInputStream#available() + */ + public synchronized int available() throws IOException { + if (readPos < length) // just in case + return (length - readPos); + return 0; + } + + /** + * Override default skip method. + * @see FilterInputStream#skip(long) + */ + public synchronized long skip(long n) throws IOException { + long len = super.skip(n); + if (readPos + len > length) + len = length - readPos; + readPos += len; + return len; + } + + /** + * Override default markSupported method. + * @see FilterInputStream#markSupported() + */ + public boolean markSupported() { + return false; + } + + /** + * Override default mark method. + * @see FilterInputStream#mark(int) + */ + public void mark(int readlimit) { + //ignore + } + + /** + * Override default reset method. + * @see FilterInputStream#reset() + */ + public void reset() throws IOException { + throw new IOException("reset not supported."); //$NON-NLS-1$ + } +} diff --git a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/reliablefile/ReliableFileOutputStream.java b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/reliablefile/ReliableFileOutputStream.java new file mode 100644 index 000000000..9a39a1a05 --- /dev/null +++ b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/reliablefile/ReliableFileOutputStream.java @@ -0,0 +1,184 @@ +/******************************************************************************* + * Copyright (c) 2003, 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.equinox.internal.cm.reliablefile; + +import java.io.*; +import java.util.zip.Checksum; + +//This is a copy of org.eclipse.osgi.framework.internal.reliablefile.ReliableFileOutputStream + +/** + * A ReliableFile FileOutputStream replacement class. + * This class can be used just like FileOutputStream. The class + * is in partnership with ReliableFileInputStream to avoid losing + * file data by using multiple files. + * + * @see ReliableFileInputStream + */ +public class ReliableFileOutputStream extends FilterOutputStream { + /** + * ReliableFile object for the file. + */ + private ReliableFile reliable; + + /** + * Checksum calculator + */ + private Checksum crc; + + private boolean outputOpen = false; + + /** + * Constructs a new ReliableFileOutputStream on the File <code>file</code>. If the + * file exists, it is written over. See the constructor which can append to + * the file if so desired. + * + * @param file the File on which to stream reads. + * @exception java.io.IOException If an error occurs opening the file. + */ + public ReliableFileOutputStream(File file) throws IOException { + this(ReliableFile.getReliableFile(file), false); + } + + /** + * Constructs a new ReliableFileOutputStream on the File <code>file</code>. + * + * @param file the File on which to stream reads. + * @param append a boolean indicating whether or not to append to an existing file. + * @exception java.io.IOException If an error occurs opening the file. + */ + public ReliableFileOutputStream(File file, boolean append) throws IOException { + this(ReliableFile.getReliableFile(file), append); + } + + /** + * Constructs a new ReliableFileOutputStream on the file named <code>name</code>. If + * the file exists, it is written over. See the constructor which can append to + * the file if so desired. + * The <code>name</code> may be absolute or relative + * to the System property <code>"user.dir"</code>. + * + * @param name the file on which to stream writes. + * @exception java.io.IOException If an error occurs opening the file. + */ + public ReliableFileOutputStream(String name) throws IOException { + this(ReliableFile.getReliableFile(name), false); + } + + /** + * Constructs a new ReliableFileOutputStream on the file named <code>name</code>. + * The <code>name</code> may be absolute or relative + * to the System property <code>"user.dir"</code>. + * + * @param name the file on which to stream writes. + * @param append a boolean indicating whether or not to append to an existing file. + * @exception java.io.IOException If an error occurs opening the file. + */ + public ReliableFileOutputStream(String name, boolean append) throws IOException { + this(ReliableFile.getReliableFile(name), append); + } + + /** + * Private constructor used by other constructors. + * + * @param reliable the ReliableFile on which to read. + * @param append a boolean indicating whether or not to append to an existing file. + * @exception java.io.IOException If an error occurs opening the file. + */ + private ReliableFileOutputStream(ReliableFile reliable, boolean append) throws IOException { + super(reliable.getOutputStream(append, ReliableFile.GENERATION_LATEST)); + + this.reliable = reliable; + outputOpen = true; + if (append) + crc = reliable.getFileChecksum(); + else + crc = reliable.getChecksumCalculator(); + } + + /** + * Closes this output stream and releases any system resources + * associated with this stream. The general contract of <code>close</code> + * is that it closes the output stream. A closed stream cannot perform + * output operations and cannot be reopened. + * + * @exception java.io.IOException If an error occurs closing the file. + */ + public synchronized void close() throws IOException { + closeIntermediateFile(); + reliable.closeOutputFile(crc); + // if the previouse closeOutpuFile() throws exception, + // we don't null out reliable to give another opportunity + // to rename the file. + reliable = null; + } + + public File closeIntermediateFile() throws IOException { + if (reliable == null) + throw new IOException("ReliableFile stream not open"); //$NON-NLS-1$ + if (outputOpen) { + // tag on our signature and checksum + reliable.writeChecksumSignature(out, crc); + out.flush(); + try { + ((FileOutputStream) out).getFD().sync(); + } catch (IOException e) { + // just ignore this Exception + //Debug + e.printStackTrace(); + } + out.close(); + outputOpen = false; + } + return reliable.getOutputFile(); + } + + /** + * Override default FilterOutputStream method. + * @see FilterOutputStream#write(byte[]) + */ + public void write(byte[] b) throws IOException { + this.write(b, 0, b.length); + } + + /** + * Override default FilterOutputStream method. + * @see FilterOutputStream#write(byte[], int, int) + */ + public void write(byte[] b, int off, int len) throws IOException { + out.write(b, off, len); + crc.update(b, off, len); + } + + /** + * Override default FilterOutputStream method. + * @see FilterOutputStream#write(int) + */ + public void write(int b) throws IOException { + out.write(b); + crc.update((byte) b); + } + + public void abort() { + if (reliable == null) + return; + if (outputOpen) { + try { + out.close(); + } catch (IOException e) {/*ignore*/ + } + outputOpen = false; + } + reliable.abortOutputFile(); + reliable = null; + } +} |