diff options
author | Thomas Watson | 2011-04-13 15:48:34 +0000 |
---|---|---|
committer | Thomas Watson | 2011-04-13 15:48:34 +0000 |
commit | d86e4f0fff4e8209754c4ac651ce3ac1880bd679 (patch) | |
tree | 3c12c6071785d68bd9c86cf840dd03fabc960691 | |
parent | 9f5fad996ed2f5d3fb2e0ef84bcd25c7ebed750e (diff) | |
download | rt.equinox.bundles-d86e4f0fff4e8209754c4ac651ce3ac1880bd679.tar.gz rt.equinox.bundles-d86e4f0fff4e8209754c4ac651ce3ac1880bd679.tar.xz rt.equinox.bundles-d86e4f0fff4e8209754c4ac651ce3ac1880bd679.zip |
Initial check in of region digraph to equinox.
81 files changed, 7480 insertions, 0 deletions
diff --git a/bundles/org.eclipse.equinox.region.tests/.classpath b/bundles/org.eclipse.equinox.region.tests/.classpath new file mode 100644 index 000000000..39d7d6e5f --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/.classpath @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry exported="true" kind="lib" path="stubs/org.eclipse.virgo.teststubs.osgi.jar" sourcepath="stubs/org.eclipse.virgo.teststubs.osgi-sources.jar"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="src" path="src"/> + <classpathentry kind="src" output="bundle_tests/PackageProvider1" path="bundles_src/PackageProvider1"/> + <classpathentry kind="src" output="bundle_tests/ServiceProvider1" path="bundles_src/ServiceProvider1"/> + <classpathentry kind="src" output="bundle_tests/CapabilityProvider1" path="bundles_src/CapabilityProvider1"/> + <classpathentry kind="src" output="bundle_tests/PackageProvider2" path="bundles_src/PackageProvider2"/> + <classpathentry kind="src" output="bundle_tests/ServiceProvider2" path="bundles_src/ServiceProvider2"/> + <classpathentry kind="src" output="bundle_tests/CapabilityProvider2" path="bundles_src/CapabilityProvider2"/> + <classpathentry kind="src" output="bundle_tests/PackageClient1" path="bundles_src/PackageClient1"/> + <classpathentry kind="src" output="bundle_tests/BundleClient1" path="bundles_src/BundleClient1"/> + <classpathentry kind="src" output="bundle_tests/ServiceClient1" path="bundles_src/ServiceClient1"/> + <classpathentry kind="src" output="bundle_tests/CapabilityClient1" path="bundles_src/CapabilityClient1"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/bundles/org.eclipse.equinox.region.tests/.project b/bundles/org.eclipse.equinox.region.tests/.project new file mode 100644 index 000000000..18b47aaa6 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/.project @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.equinox.region.tests</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.region.tests/.settings/org.eclipse.core.resources.prefs b/bundles/org.eclipse.equinox.region.tests/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 000000000..16532b29e --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,3 @@ +#Tue May 25 15:00:03 EDT 2004 +encoding/<project>=ISO-8859-1 +eclipse.preferences.version=1 diff --git a/bundles/org.eclipse.equinox.region.tests/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.equinox.region.tests/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..67e8279ce --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,353 @@ +#Thu Apr 07 11:36:51 CDT 2011 +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=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +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=error +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +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=error +org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled +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.includeNullInfoFromAsserts=disabled +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.missingHashCodeMethod=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.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +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.unavoidableGenericTypeProblems=enabled +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.unusedDeclaredThrownException=warning +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled +org.eclipse.jdt.core.compiler.problem.unusedImport=error +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +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.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.source=1.6 +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_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.region.tests/.settings/org.eclipse.jdt.ui.prefs b/bundles/org.eclipse.equinox.region.tests/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 000000000..614ff2ccd --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,61 @@ +#Thu Mar 31 16:02:27 CDT 2011 +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=false +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=99 +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_methods=false +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_missing_override_annotations_interface_methods=false +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.format_source_code_changes_only=false +sp_cleanup.make_local_variable_final=false +sp_cleanup.make_parameters_final=false +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_type_abstract_if_missing_method=false +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.region.tests/.settings/org.eclipse.pde.core.prefs b/bundles/org.eclipse.equinox.region.tests/.settings/org.eclipse.pde.core.prefs new file mode 100644 index 000000000..cd216df0d --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/.settings/org.eclipse.pde.core.prefs @@ -0,0 +1,4 @@ +#Wed Mar 23 12:53:23 CDT 2011 +eclipse.preferences.version=1 +pluginProject.extensions=false +resolve.requirebundle=false diff --git a/bundles/org.eclipse.equinox.region.tests/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.region.tests/META-INF/MANIFEST.MF new file mode 100644 index 000000000..c7ad9eddd --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/META-INF/MANIFEST.MF @@ -0,0 +1,20 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Equinox Region Tests +Bundle-SymbolicName: org.eclipse.equinox.region.tests +Bundle-Version: 1.0.0.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Fragment-Host: org.eclipse.equinox.region +Import-Package: junit.framework;version="4.8.1", + org.easymock;version="2.4.0", + org.eclipse.osgi.service.urlconversion;version="1.0.0", + org.junit;version="4.8.1", + org.osgi.util.tracker;version="1.5.0", + org.aspectj.internal.lang.annotation;version="[1.6.3, 2.0.0)", + org.aspectj.lang;version="[1.6.3, 2.0.0)", + org.aspectj.lang.annotation;version="[1.6.3, 2.0.0)", + org.aspectj.lang.reflect;version="[1.6.3, 2.0.0)", + org.aspectj.runtime.internal;version="[1.6.3, 2.0.0)", + org.aspectj.runtime.reflect;version="[1.6.3, 2.0.0)" +Bundle-ClassPath: stubs/org.eclipse.virgo.teststubs.osgi.jar, + . diff --git a/bundles/org.eclipse.equinox.region.tests/about.html b/bundles/org.eclipse.equinox.region.tests/about.html new file mode 100644 index 000000000..460233046 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/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>June 2, 2006</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.region.tests/build.properties b/bundles/org.eclipse.equinox.region.tests/build.properties new file mode 100644 index 000000000..3a916e482 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/build.properties @@ -0,0 +1,42 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + bundle_tests/*.jar,\ + stubs/org.eclipse.virgo.teststubs.osgi.jar,\ + about.html,\ + test.xml + +source.bundle_tests/PackageProvider1.jar = bundles_src/PackageProvider1/ +manifest.bundle_tests/PackageProvider1.jar = META-INF/MANIFEST.MF +source.bundle_tests/ServiceProvider1.jar = bundles_src/ServiceProvider1/ +manifest.bundle_tests/ServiceProvider1.jar = META-INF/MANIFEST.MF +source.bundle_tests/CapabilityProvider1.jar = bundles_src/CapabilityProvider1/ +manifest.bundle_tests/CapabilityProvider1.jar = META-INF/MANIFEST.MF +source.bundle_tests/PackageProvider2.jar = bundles_src/PackageProvider2/ +manifest.bundle_tests/PackageProvider2.jar = META-INF/MANIFEST.MF +source.bundle_tests/ServiceProvider2.jar = bundles_src/ServiceProvider2/ +manifest.bundle_tests/ServiceProvider2.jar = META-INF/MANIFEST.MF +source.bundle_tests/CapabilityProvider2.jar = bundles_src/CapabilityProvider2/ +manifest.bundle_tests/CapabilityProvider2.jar = META-INF/MANIFEST.MF +source.bundle_tests/PackageClient1.jar = bundles_src/PackageClient1/ +manifest.bundle_tests/PackageClient1.jar = META-INF/MANIFEST.MF +source.bundle_tests/BundleClient1.jar = bundles_src/BundleClient1/ +manifest.bundle_tests/BundleClient1.jar = META-INF/MANIFEST.MF +source.bundle_tests/ServiceClient1.jar = bundles_src/ServiceClient1/ +manifest.bundle_tests/ServiceClient1.jar = META-INF/MANIFEST.MF +source.bundle_tests/CapabilityClient1.jar = bundles_src/CapabilityClient1/ +manifest.bundle_tests/CapabilityClient1.jar = META-INF/MANIFEST.MF + +jars.compile.order = bundle_tests/PackageProvider1.jar,\ + bundles_tests/ServiceProvider1.jar,\ + bundles_tests/CapabilityProvider1.jar,\ + bundles_tests/PackageProvider2.jar,\ + bundles_tests/ServiceProvider2.jar,\ + bundles_tests/CapabilityProvider2.jar,\ + bundles_tests/PackageClient1.jar,\ + bundles_tests/BundleClient1.jar,\ + bundles_tests/ServiceClient1.jar,\ + bundles_tests/CapabilityClient1.jar +src.includes = about.html + diff --git a/bundles/org.eclipse.equinox.region.tests/bundles_src/BundleClient1/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.region.tests/bundles_src/BundleClient1/META-INF/MANIFEST.MF new file mode 100644 index 000000000..ccb19f072 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/bundles_src/BundleClient1/META-INF/MANIFEST.MF @@ -0,0 +1,6 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: BundleClient1 +Bundle-SymbolicName: BundleClient1 +Bundle-Version: 1.0.0 +Require-Bundle: PackageProvider2 diff --git a/bundles/org.eclipse.equinox.region.tests/bundles_src/CapabilityClient1/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.region.tests/bundles_src/CapabilityClient1/META-INF/MANIFEST.MF new file mode 100644 index 000000000..8011a8713 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/bundles_src/CapabilityClient1/META-INF/MANIFEST.MF @@ -0,0 +1,8 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: CapabilityClient1 +Bundle-SymbolicName: CapabilityClient1 +Bundle-Version: 1.0.0 +Export-Package: pkg2.a;version="1.0.0", + pkg2.b;version="1.0.0" +Require-Capability: CapabilityProvider2; filtler:=(name=CapabilityProvider2) diff --git a/bundles/org.eclipse.equinox.region.tests/bundles_src/CapabilityProvider1/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.region.tests/bundles_src/CapabilityProvider1/META-INF/MANIFEST.MF new file mode 100644 index 000000000..244cc9011 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/bundles_src/CapabilityProvider1/META-INF/MANIFEST.MF @@ -0,0 +1,6 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: CapabilityProvider1 +Bundle-SymbolicName: CapabilityProvider1 +Bundle-Version: 1.0.0 +Provide-Capability: CapabilityProvider1; name=CapabilityProvider1 diff --git a/bundles/org.eclipse.equinox.region.tests/bundles_src/CapabilityProvider2/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.region.tests/bundles_src/CapabilityProvider2/META-INF/MANIFEST.MF new file mode 100644 index 000000000..7ac293c18 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/bundles_src/CapabilityProvider2/META-INF/MANIFEST.MF @@ -0,0 +1,11 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: CapabilityProvider2 +Bundle-SymbolicName: CapabilityProvider2 +Bundle-Version: 1.0.0 +Bundle-Activator: capabilityprovider2.Activator +Provide-Capability: CapabilityProvider2; name=CapabilityProvider2 +Import-Package: org.osgi.framework, + org.osgi.util.tracker, + pkg1.a, + pkg1.b diff --git a/bundles/org.eclipse.equinox.region.tests/bundles_src/CapabilityProvider2/capabilityprovider2/Activator.java b/bundles/org.eclipse.equinox.region.tests/bundles_src/CapabilityProvider2/capabilityprovider2/Activator.java new file mode 100644 index 000000000..b02ecf142 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/bundles_src/CapabilityProvider2/capabilityprovider2/Activator.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2011 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 capabilityprovider2; + +import java.util.Hashtable; + +import java.util.Dictionary; + +import org.osgi.framework.*; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; + +public class Activator implements BundleActivator { + + @Override + public void start(final BundleContext context) throws Exception { + new ServiceTracker<pkg1.a.A, pkg1.a.A>(context, pkg1.a.A.class, new ServiceTrackerCustomizer<pkg1.a.A, pkg1.a.A>() { + + @Override + public pkg1.a.A addingService(ServiceReference<pkg1.a.A> reference) { + Dictionary<String, Object> props = new Hashtable<String, Object>(); + props.put("bundle.id", context.getBundle().getBundleId()); + context.registerService(Boolean.class, Boolean.TRUE, props); + return null; + } + + @Override + public void modifiedService(ServiceReference<pkg1.a.A> reference, pkg1.a.A service) { + // TODO Auto-generated method stub + + } + + @Override + public void removedService(ServiceReference<pkg1.a.A> reference, pkg1.a.A service) { + // TODO Auto-generated method stub + + }}).open(); + } + + @Override + public void stop(BundleContext context) throws Exception { + + } + +} diff --git a/bundles/org.eclipse.equinox.region.tests/bundles_src/PackageClient1/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.region.tests/bundles_src/PackageClient1/META-INF/MANIFEST.MF new file mode 100644 index 000000000..c9349bcf3 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/bundles_src/PackageClient1/META-INF/MANIFEST.MF @@ -0,0 +1,7 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: PackageClient1 +Bundle-SymbolicName: PackageClient1 +Bundle-Version: 1.0.0 +Import-Package: pkg2.a, + pkg2.b diff --git a/bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider1/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider1/META-INF/MANIFEST.MF new file mode 100644 index 000000000..f687db403 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider1/META-INF/MANIFEST.MF @@ -0,0 +1,7 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: PackageProvider1 +Bundle-SymbolicName: PackageProvider1 +Bundle-Version: 1.0.0 +Export-Package: pkg1.a;version="1.0.0", + pkg1.b;version="1.0.0" diff --git a/bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider1/pkg1/a/A.java b/bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider1/pkg1/a/A.java new file mode 100644 index 000000000..5b608fd47 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider1/pkg1/a/A.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2011 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 pkg1.a; + +public class A { + +} diff --git a/bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider1/pkg1/b/B.java b/bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider1/pkg1/b/B.java new file mode 100644 index 000000000..0f7beed53 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider1/pkg1/b/B.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2011 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 pkg1.b; + +public class B { + +} diff --git a/bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider2/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider2/META-INF/MANIFEST.MF new file mode 100644 index 000000000..2edfac3c3 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider2/META-INF/MANIFEST.MF @@ -0,0 +1,8 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: PackageProvider2 +Bundle-SymbolicName: PackageProvider2 +Bundle-Version: 1.0.0 +Export-Package: pkg2.a;version="1.0.0", + pkg2.b;version="1.0.0" +Require-Capability: CapabilityProvider1; filtler:=(name=CapabilityProvider1) diff --git a/bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider2/pkg2/a/A.java b/bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider2/pkg2/a/A.java new file mode 100644 index 000000000..32bca2b88 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider2/pkg2/a/A.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2011 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 pkg2.a; + +public class A { + +} diff --git a/bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider2/pkg2/b/B.java b/bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider2/pkg2/b/B.java new file mode 100644 index 000000000..5ef8aee06 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider2/pkg2/b/B.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2011 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 pkg2.b; + +public class B { + +} diff --git a/bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceClient1/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceClient1/META-INF/MANIFEST.MF new file mode 100644 index 000000000..de53d07b3 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceClient1/META-INF/MANIFEST.MF @@ -0,0 +1,10 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: ServiceClient1 +Bundle-SymbolicName: ServiceClient1 +Bundle-Version: 1.0.0 +Bundle-Activator: serviceclient1.Activator +Import-Package: org.osgi.framework, + org.osgi.util.tracker, + pkg2.a, + pkg2.b diff --git a/bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceClient1/serviceclient1/Activator.java b/bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceClient1/serviceclient1/Activator.java new file mode 100644 index 000000000..eba816588 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceClient1/serviceclient1/Activator.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2011 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 serviceclient1; + +import java.util.Dictionary; +import java.util.Hashtable; + +import org.osgi.framework.*; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; + +public class Activator implements BundleActivator { + + @Override + public void start(final BundleContext context) throws Exception { + new ServiceTracker<pkg2.a.A, pkg2.a.A>(context, pkg2.a.A.class, new ServiceTrackerCustomizer<pkg2.a.A, pkg2.a.A>() { + + @Override + public pkg2.a.A addingService(ServiceReference<pkg2.a.A> reference) { + Dictionary<String, Object> props = new Hashtable<String, Object>(); + props.put("bundle.id", context.getBundle().getBundleId()); + context.registerService(Boolean.class, Boolean.TRUE, props); + return null; + } + + @Override + public void modifiedService(ServiceReference<pkg2.a.A> reference, pkg2.a.A service) { + // TODO Auto-generated method stub + + } + + @Override + public void removedService(ServiceReference<pkg2.a.A> reference, pkg2.a.A service) { + // TODO Auto-generated method stub + + }}).open(); + } + + @Override + public void stop(BundleContext context) throws Exception { + + } + +} diff --git a/bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceProvider1/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceProvider1/META-INF/MANIFEST.MF new file mode 100644 index 000000000..925e5f2a2 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceProvider1/META-INF/MANIFEST.MF @@ -0,0 +1,7 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: ServiceProvider1 +Bundle-SymbolicName: ServiceProvider1 +Bundle-Version: 1.0.0 +Bundle-Activator: serviceprovider1.Activator +Import-Package: pkg1.a, pkg1.b, org.osgi.framework diff --git a/bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceProvider1/serviceprovider1/Activator.java b/bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceProvider1/serviceprovider1/Activator.java new file mode 100644 index 000000000..ad31b2024 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceProvider1/serviceprovider1/Activator.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2011 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 serviceprovider1; + +import org.osgi.framework.BundleContext; + +import org.osgi.framework.BundleActivator; + +public class Activator implements BundleActivator { + + @Override + public void start(BundleContext context) throws Exception { + context.registerService(pkg1.a.A.class, new pkg1.a.A(), null); + context.registerService(pkg1.b.B.class, new pkg1.b.B(), null); + } + + @Override + public void stop(BundleContext context) throws Exception { + // TODO Auto-generated method stub + + } + +} diff --git a/bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceProvider2/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceProvider2/META-INF/MANIFEST.MF new file mode 100644 index 000000000..9ffa4ba6b --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceProvider2/META-INF/MANIFEST.MF @@ -0,0 +1,7 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: ServiceProvider2 +Bundle-SymbolicName: ServiceProvider2 +Bundle-Version: 1.0.0 +Bundle-Activator: serviceprovider2.Activator +Import-Package: pkg2.a, pkg2.b, org.osgi.framework diff --git a/bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceProvider2/serviceprovider2/Activator.java b/bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceProvider2/serviceprovider2/Activator.java new file mode 100644 index 000000000..9175e930b --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceProvider2/serviceprovider2/Activator.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2011 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 serviceprovider2; + +import org.osgi.framework.BundleContext; + +import org.osgi.framework.BundleActivator; + +public class Activator implements BundleActivator { + + @Override + public void start(BundleContext context) throws Exception { + context.registerService(pkg2.a.A.class, new pkg2.a.A(), null); + context.registerService(pkg2.b.B.class, new pkg2.b.B(), null); + } + + @Override + public void stop(BundleContext context) throws Exception { + // TODO Auto-generated method stub + + } + +} diff --git a/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/tests/AllTests.java b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/tests/AllTests.java new file mode 100644 index 000000000..8a533e164 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/tests/AllTests.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2011 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.region.tests; + +import junit.framework.TestSuite; + +import org.eclipse.equinox.region.tests.system.RegionSystemTests; + +import junit.framework.*; +import org.eclipse.virgo.kernel.osgi.region.hook.*; +import org.eclipse.virgo.kernel.osgi.region.internal.*; + +public class AllTests { + public static Test suite() { + TestSuite suite = new TestSuite("Equinox Region Tests"); + suite.addTest(new JUnit4TestAdapter(RegionBundleEventHookTests.class)); + suite.addTest(new JUnit4TestAdapter(RegionBundleFindHookTests.class)); + suite.addTest(new JUnit4TestAdapter(RegionResolverHookTests.class)); + suite.addTest(new JUnit4TestAdapter(RegionServiceEventHookTests.class)); + suite.addTest(new JUnit4TestAdapter(RegionServiceFindHookTests.class)); + suite.addTest(new JUnit4TestAdapter(BundleIdBasedRegionTests.class)); + suite.addTest(new JUnit4TestAdapter(StandardRegionDigraphPeristenceTests.class)); + suite.addTest(new JUnit4TestAdapter(StandardRegionDigraphTests.class)); + suite.addTest(new JUnit4TestAdapter(StandardRegionFilterTests.class)); + suite.addTest(new TestSuite(RegionSystemTests.class)); + return suite; + } +} diff --git a/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/tests/BundleInstaller.java b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/tests/BundleInstaller.java new file mode 100644 index 000000000..4986cf66c --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/tests/BundleInstaller.java @@ -0,0 +1,198 @@ +/******************************************************************************* + * Copyright (c) 2011 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.region.tests; + +import java.io.IOException; +import java.net.URL; +import java.security.*; +import java.util.*; +import org.eclipse.osgi.service.urlconversion.URLConverter; +import org.osgi.framework.*; +import org.osgi.framework.wiring.FrameworkWiring; +import org.osgi.util.tracker.ServiceTracker; + +public class BundleInstaller { + private final BundleContext context; + private final Bundle testBundle; + private String rootLocation; + private Map<String, Bundle> bundles = new HashMap<String, Bundle>(); + private final ServiceTracker<URLConverter, URLConverter> converter; + private final FrameworkWiring frameworkWiring; + + public BundleInstaller(String bundlesRoot, BundleContext context, Bundle testBundle) throws InvalidSyntaxException { + this.context = context; + frameworkWiring = context.getBundle(0).adapt(FrameworkWiring.class); + rootLocation = bundlesRoot; + converter = new ServiceTracker<URLConverter, URLConverter>(context, context.createFilter("(&(objectClass=" + URLConverter.class.getName() + ")(protocol=bundleentry))"), null); + converter.open(); + this.testBundle = testBundle; + } + + synchronized public Bundle installBundle(String name) throws BundleException { + return installBundle(name, true); + } + + synchronized public Bundle installBundle(String name, boolean track) throws BundleException { + if (bundles == null && track) + return null; + String location = getBundleLocation(name); + Bundle bundle = context.installBundle(location); + if (track) + bundles.put(name, bundle); + return bundle; + } + + public String getBundleLocation(final String name) throws BundleException { + if (System.getSecurityManager() == null) + return getBundleLocation0(name); + try { + return AccessController.doPrivileged(new PrivilegedExceptionAction<String>() { + public String run() throws Exception { + return getBundleLocation0(name); + } + }); + } catch (PrivilegedActionException e) { + throw (BundleException) e.getException(); + } + } + + String getBundleLocation0(String name) throws BundleException { + String bundleFileName = rootLocation + "/" + name; + URL bundleURL = testBundle.getEntry(bundleFileName); + if (bundleURL == null) + bundleURL = testBundle.getEntry(bundleFileName + ".jar"); + if (bundleURL == null) + throw new BundleException("Could not find bundle to install at: " + name); + try { + bundleURL = (converter.getService()).resolve(bundleURL); + } catch (IOException e) { + throw new BundleException("Converter error", e); + } + String location = bundleURL.toExternalForm(); + if ("file".equals(bundleURL.getProtocol())) + location = "reference:" + location; + return location; + } + + synchronized public Bundle updateBundle(String fromName, String toName) throws BundleException { + if (bundles == null) + return null; + Bundle fromBundle = bundles.get(fromName); + if (fromBundle == null) + throw new BundleException("The bundle to update does not exist!! " + fromName); + String bundleFileName = rootLocation + "/" + toName; + URL bundleURL = testBundle.getEntry(bundleFileName); + if (bundleURL == null) + bundleURL = testBundle.getEntry(bundleFileName + ".jar"); + try { + bundleURL = converter.getService().resolve(bundleURL); + } catch (IOException e) { + throw new BundleException("Converter error", e); + } + String location = bundleURL.toExternalForm(); + if ("file".equals(bundleURL.getProtocol())) + location = "reference:" + location; + try { + fromBundle.update(new URL(location).openStream()); + } catch (Exception e) { + throw new BundleException("Errors when updating bundle " + fromBundle, e); + } + bundles.remove(fromName); + bundles.put(toName, fromBundle); + return fromBundle; + } + + synchronized public Bundle uninstallBundle(String name) throws BundleException { + if (bundles == null) + return null; + Bundle bundle = bundles.remove(name); + if (bundle == null) + return null; + bundle.uninstall(); + return bundle; + } + + synchronized public Bundle[] uninstallAllBundles() throws BundleException { + if (bundles == null) + return null; + List<Bundle> result = new ArrayList<Bundle>(bundles.size()); + for (Iterator<Bundle> iter = bundles.values().iterator(); iter.hasNext();) { + Bundle bundle = iter.next(); + try { + bundle.uninstall(); + } catch (IllegalStateException e) { + // ignore; bundle probably already uninstalled + } + result.add(bundle); + } + bundles.clear(); + return result.toArray(new Bundle[result.size()]); + } + + synchronized public Bundle[] shutdown() throws BundleException { + if (bundles == null) + return null; + Bundle[] result = uninstallAllBundles(); + refreshPackages(result); + converter.close(); + bundles = null; + return result; + } + + synchronized public Bundle[] refreshPackages(Bundle[] refresh) { + if (bundles == null) + return null; + final boolean[] flag = new boolean[] {false}; + FrameworkListener listener = new FrameworkListener() { + public void frameworkEvent(FrameworkEvent event) { + if (event.getType() == FrameworkEvent.PACKAGES_REFRESHED) + synchronized (flag) { + flag[0] = true; + flag.notifyAll(); + } + } + }; + final Set<Bundle> refreshed = new HashSet<Bundle>(); + BundleListener refreshBundleListener = new SynchronousBundleListener() { + public void bundleChanged(BundleEvent event) { + refreshed.add(event.getBundle()); + } + }; + context.addBundleListener(refreshBundleListener); + try { + frameworkWiring.refreshBundles(Arrays.asList(refresh), listener); + synchronized (flag) { + while (!flag[0]) { + try { + flag.wait(5000); + } catch (InterruptedException e) { + // do nothing + } + } + } + } finally { + context.removeBundleListener(refreshBundleListener); + } + return refreshed.toArray(new Bundle[refreshed.size()]); + } + + synchronized public boolean resolveBundles(Bundle[] resolve) { + if (bundles == null) + return false; + return frameworkWiring.resolveBundles(Arrays.asList(resolve)); + } + + synchronized public Bundle getBundle(String name) { + if (bundles == null) + return null; + return bundles.get(name); + } +} diff --git a/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/tests/system/AbstractRegionSystemTest.java b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/tests/system/AbstractRegionSystemTest.java new file mode 100644 index 000000000..54a6b2737 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/tests/system/AbstractRegionSystemTest.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2011 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.region.tests.system; + +import java.util.Arrays; + +import java.util.List; + +import org.eclipse.virgo.kernel.osgi.region.Region; + +import org.osgi.framework.BundleContext; + +import org.osgi.framework.ServiceReference; + +import org.eclipse.virgo.kernel.osgi.region.RegionDigraph; + +import org.osgi.framework.wiring.BundleRevision; + +import org.osgi.framework.wiring.BundleWiring; + +import org.osgi.framework.Bundle; + +import org.osgi.framework.FrameworkUtil; + +import org.eclipse.equinox.region.tests.BundleInstaller; + +import junit.framework.TestCase; + +public class AbstractRegionSystemTest extends TestCase{ + public static final String PP1 = "PackageProvider1"; + public static final String SP1 = "ServiceProvider1"; + public static final String CP1 = "CapabilityProvider1"; + public static final String PP2 = "PackageProvider2"; + public static final String SP2 = "ServiceProvider2"; + public static final String CP2 = "CapabilityProvider2"; + public static final String PC1 = "PackageClient1"; + public static final String BC1 = "BundleClient1"; + public static final String SC1 = "ServiceClient1"; + public static final String CC1 = "CapabilityClient1"; + public static List<String> ALL = Arrays.asList( + PP1, + SP1, + CP1, + PP2, + SP2, + CP2, + PC1, + BC1, + SC1, + CC1); + + protected BundleInstaller bundleInstaller; + protected RegionDigraph digraph; + protected BundleContext context; + ServiceReference<RegionDigraph> digraphReference; + + @Override + protected void setUp() throws Exception { + // this is a fragment of the region impl bundle + // this line makes sure the region impl bundle is started + Bundle regionBundle = FrameworkUtil.getBundle(this.getClass()); + regionBundle.start(); + context = regionBundle.getBundleContext(); + assertNotNull("No context found", context); + + digraphReference = context.getServiceReference(RegionDigraph.class); + assertNotNull("No digraph found", digraphReference); + digraph = context.getService(digraphReference); + assertNotNull("No digraph found"); + + // fun code to get our fragment bundle + Bundle testBundle = regionBundle.adapt(BundleWiring.class).getProvidedWires(BundleRevision.HOST_NAMESPACE).get(0).getRequirerWiring().getBundle(); + bundleInstaller = new BundleInstaller("bundle_tests", regionBundle.getBundleContext(), testBundle); //$NON-NLS-1$ + } + + @Override + protected void tearDown() throws Exception { + for (Region region : digraph) { + if (!region.contains(0)) { + digraph.removeRegion(region); + for (Long bundleID : region.getBundleIds()) { + Bundle b = context.getBundle(bundleID); + b.uninstall(); + } + } + } + bundleInstaller.shutdown(); + if (digraphReference != null) + context.ungetService(digraphReference); + } + + +} diff --git a/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/tests/system/RegionSystemTests.java b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/tests/system/RegionSystemTests.java new file mode 100644 index 000000000..505fd1b7c --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/tests/system/RegionSystemTests.java @@ -0,0 +1,266 @@ +/******************************************************************************* + * Copyright (c) 2011 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.region.tests.system; + +import org.eclipse.virgo.kernel.osgi.region.RegionFilterBuilder; + +import org.osgi.framework.Constants; + +import java.util.Map; + +import java.util.HashMap; + +import org.osgi.util.tracker.ServiceTracker; + +import org.osgi.framework.InvalidSyntaxException; + +import org.eclipse.virgo.kernel.osgi.region.RegionFilter; + +import java.util.ArrayList; +import java.util.List; +import org.eclipse.virgo.kernel.osgi.region.Region; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleException; + +public class RegionSystemTests extends AbstractRegionSystemTest { + public void testBasic() throws BundleException, InvalidSyntaxException, InterruptedException{ + // get the system region + Region systemRegion = digraph.getRegion(0); + // create a disconnected test region + Region testRegion = digraph.createRegion(getName()); + List<Bundle> bundles = new ArrayList<Bundle>(); + // Install all test bundles + Bundle pp1, cp2, sc1; + bundles.add(pp1 = testRegion.installBundle(bundleInstaller.getBundleLocation(PP1))); + // should be able to start pp1 because it depends on nothing + pp1.start(); + // do a sanity check that we have no services available in the isolated region + assertNull("Found some services.", pp1.getBundleContext().getAllServiceReferences(null, null)); + assertEquals("Found extra bundles in region", 1, pp1.getBundleContext().getBundles().length); + pp1.stop(); + + bundles.add(testRegion.installBundle(bundleInstaller.getBundleLocation(SP1))); + bundles.add(testRegion.installBundle(bundleInstaller.getBundleLocation(CP1))); + bundles.add(testRegion.installBundle(bundleInstaller.getBundleLocation(PP2))); + bundles.add(testRegion.installBundle(bundleInstaller.getBundleLocation(SP2))); + bundles.add(cp2 = testRegion.installBundle(bundleInstaller.getBundleLocation(CP2))); + bundles.add(testRegion.installBundle(bundleInstaller.getBundleLocation(PC1))); + bundles.add(testRegion.installBundle(bundleInstaller.getBundleLocation(BC1))); + bundles.add(sc1 = testRegion.installBundle(bundleInstaller.getBundleLocation(SC1))); + bundles.add(testRegion.installBundle(bundleInstaller.getBundleLocation(CC1))); + + // Import the system bundle from the systemRegion + digraph.connect(testRegion, digraph.createRegionFilterBuilder().allow(RegionFilter.VISIBLE_BUNDLE_NAMESPACE, "(id=0)").build(), systemRegion); + // must import Boolean services into systemRegion to test + digraph.connect(systemRegion, digraph.createRegionFilterBuilder().allow(RegionFilter.VISIBLE_SERVICE_NAMESPACE, "(objectClass=java.lang.Boolean)").build(), testRegion); + + bundleInstaller.resolveBundles(bundles.toArray(new Bundle[bundles.size()])); + for (Bundle bundle : bundles) { + assertEquals("Bundle did not resolve: " + bundle.getSymbolicName(), Bundle.RESOLVED, bundle.getState()); + bundle.start(); + } + ServiceTracker<Boolean, Boolean> cp2Tracker = new ServiceTracker<Boolean, Boolean>(context, context.createFilter("(&(objectClass=java.lang.Boolean)(bundle.id=" + cp2.getBundleId() + "))"), null); + ServiceTracker<Boolean, Boolean> sc1Tracker = new ServiceTracker<Boolean, Boolean>(context, context.createFilter("(&(objectClass=java.lang.Boolean)(bundle.id=" + sc1.getBundleId() + "))"), null); + + cp2Tracker.open(); + sc1Tracker.open(); + + assertNotNull("The cp2 bundle never found the service.", cp2Tracker.waitForService(2000)); + assertNotNull("The sc1 bundle never found the service.", sc1Tracker.waitForService(2000)); + cp2Tracker.close(); + sc1Tracker.close(); + } + + public void testSingleBundleRegions() throws BundleException, InvalidSyntaxException, InterruptedException { + // get the system region + Region systemRegion = digraph.getRegion(0); + Map<String, Bundle> bundles = new HashMap<String, Bundle>(); + // create a disconnected test region for each test bundle + for (String location : ALL) { + Region testRegion = digraph.createRegion(location); + bundles.put(location, testRegion.installBundle(bundleInstaller.getBundleLocation(location))); + // Import the system bundle from the systemRegion + digraph.connect(testRegion, digraph.createRegionFilterBuilder().allow(RegionFilter.VISIBLE_BUNDLE_NAMESPACE, "(id=0)").build(), systemRegion); + // must import Boolean services into systemRegion to test + digraph.connect(systemRegion, digraph.createRegionFilterBuilder().allow(RegionFilter.VISIBLE_SERVICE_NAMESPACE, "(objectClass=java.lang.Boolean)").build(), testRegion); + } + + bundleInstaller.resolveBundles(bundles.values().toArray(new Bundle[bundles.size()])); + assertEquals(PP1, Bundle.RESOLVED, bundles.get(PP1).getState()); + assertEquals(SP1, Bundle.INSTALLED, bundles.get(SP1).getState()); + assertEquals(CP1, Bundle.RESOLVED, bundles.get(CP1).getState()); + assertEquals(PP2, Bundle.INSTALLED, bundles.get(PP2).getState()); + assertEquals(SP2, Bundle.INSTALLED, bundles.get(SP2).getState()); + assertEquals(CP2, Bundle.INSTALLED, bundles.get(CP2).getState()); + assertEquals(BC1, Bundle.INSTALLED, bundles.get(BC1).getState()); + assertEquals(SC1, Bundle.INSTALLED, bundles.get(SC1).getState()); + assertEquals(CC1, Bundle.INSTALLED, bundles.get(CC1).getState()); + + // now make the necessary connections + // SP1 + digraph.connect( + digraph.getRegion(SP1), + digraph.createRegionFilterBuilder().allow(RegionFilter.VISIBLE_PACKAGE_NAMESPACE, "(" + RegionFilter.VISIBLE_PACKAGE_NAMESPACE + "=pkg1.*)").build(), + digraph.getRegion(PP1)); + // PP2 + digraph.connect( + digraph.getRegion(PP2), + digraph.createRegionFilterBuilder().allow(CP1, "(name=" + CP1 + ")").build(), + digraph.getRegion(CP1)); + // SP2 + digraph.connect( + digraph.getRegion(SP2), + digraph.createRegionFilterBuilder().allow(RegionFilter.VISIBLE_PACKAGE_NAMESPACE, "(" + RegionFilter.VISIBLE_PACKAGE_NAMESPACE + "=pkg2.*)").build(), + digraph.getRegion(PP2)); + // CP2 + digraph.connect( + digraph.getRegion(CP2), + digraph.createRegionFilterBuilder().allow(RegionFilter.VISIBLE_PACKAGE_NAMESPACE, "(" + RegionFilter.VISIBLE_PACKAGE_NAMESPACE + "=pkg1.*)").build(), + digraph.getRegion(PP1)); + digraph.connect( + digraph.getRegion(CP2), + digraph.createRegionFilterBuilder().allow(RegionFilter.VISIBLE_SERVICE_NAMESPACE, "(" + Constants.OBJECTCLASS + "=pkg1.*)").build(), + digraph.getRegion(SP1)); + // PC1 + digraph.connect( + digraph.getRegion(PC1), + digraph.createRegionFilterBuilder().allow(RegionFilter.VISIBLE_PACKAGE_NAMESPACE, "(" + RegionFilter.VISIBLE_PACKAGE_NAMESPACE + "=pkg2.*)").build(), + digraph.getRegion(PP2)); + // BC1 + digraph.connect( + digraph.getRegion(BC1), + digraph.createRegionFilterBuilder().allow(RegionFilter.VISIBLE_REQUIRE_NAMESPACE, "(" + RegionFilter.VISIBLE_REQUIRE_NAMESPACE + "=" + PP2 + ")").build(), + digraph.getRegion(PP2)); + // SC1 + digraph.connect( + digraph.getRegion(SC1), + digraph.createRegionFilterBuilder().allow(RegionFilter.VISIBLE_PACKAGE_NAMESPACE, "(" + RegionFilter.VISIBLE_PACKAGE_NAMESPACE + "=pkg2.*)").build(), + digraph.getRegion(PP2)); + digraph.connect( + digraph.getRegion(SC1), + digraph.createRegionFilterBuilder().allow(RegionFilter.VISIBLE_SERVICE_NAMESPACE, "(" + Constants.OBJECTCLASS + "=pkg2.*)").build(), + digraph.getRegion(SP2)); + // CC1 + digraph.connect( + digraph.getRegion(CC1), + digraph.createRegionFilterBuilder().allow(CP2, "(name=" + CP2 + ")").build(), + digraph.getRegion(CP2)); + + bundleInstaller.resolveBundles(bundles.values().toArray(new Bundle[bundles.size()])); + for (Bundle bundle : bundles.values()) { + assertEquals("Bundle did not resolve: " + bundle.getSymbolicName(), Bundle.RESOLVED, bundle.getState()); + bundle.start(); + } + ServiceTracker<Boolean, Boolean> cp2Tracker = new ServiceTracker<Boolean, Boolean>(context, context.createFilter("(&(objectClass=java.lang.Boolean)(bundle.id=" + bundles.get(CP2).getBundleId() + "))"), null); + ServiceTracker<Boolean, Boolean> sc1Tracker = new ServiceTracker<Boolean, Boolean>(context, context.createFilter("(&(objectClass=java.lang.Boolean)(bundle.id=" + bundles.get(SC1).getBundleId() + "))"), null); + + cp2Tracker.open(); + sc1Tracker.open(); + + assertNotNull("The cp2 bundle never found the service.", cp2Tracker.waitForService(2000)); + assertNotNull("The sc1 bundle never found the service.", sc1Tracker.waitForService(2000)); + cp2Tracker.close(); + sc1Tracker.close(); + } + + public void testCyclicRegions0() throws BundleException, InvalidSyntaxException, InterruptedException { + doCyclicRegions(0); + } + + public void testCyclicRegions10() throws BundleException, InvalidSyntaxException, InterruptedException { + doCyclicRegions(10); + } + public void testCyclicRegions100() throws BundleException, InvalidSyntaxException, InterruptedException { + doCyclicRegions(100); + } + public void testCyclicRegions200() throws BundleException, InvalidSyntaxException, InterruptedException { + doCyclicRegions(200); + } + public void testCyclicRegions300() throws BundleException, InvalidSyntaxException, InterruptedException { + doCyclicRegions(300); + } + public void testCyclicRegions400() throws BundleException, InvalidSyntaxException, InterruptedException { + doCyclicRegions(400); + } + + private void doCyclicRegions(int numLevels) throws BundleException, InvalidSyntaxException, InterruptedException { + String regionName1 = getName() + "_1"; + String regionName2 = getName() + "_2"; + // get the system region + Region systemRegion = digraph.getRegion(0); + // create two regions to hold the bundles + Region testRegion1 = digraph.createRegion(regionName1); + Region testRegion2 = digraph.createRegion(regionName2); + // connect to the system bundle + testRegion1.connectRegion(systemRegion, digraph.createRegionFilterBuilder().allow(RegionFilter.VISIBLE_BUNDLE_NAMESPACE, "(id=0)").build()); + testRegion2.connectRegion(systemRegion, digraph.createRegionFilterBuilder().allow(RegionFilter.VISIBLE_BUNDLE_NAMESPACE, "(id=0)").build()); + // must import Boolean services into systemRegion to test + systemRegion.connectRegion(testRegion1, digraph.createRegionFilterBuilder().allow(RegionFilter.VISIBLE_SERVICE_NAMESPACE, "(objectClass=java.lang.Boolean)").build()); + systemRegion.connectRegion(testRegion2, digraph.createRegionFilterBuilder().allow(RegionFilter.VISIBLE_SERVICE_NAMESPACE, "(objectClass=java.lang.Boolean)").build()); + + Map<String, Bundle> bundles = new HashMap<String, Bundle>(); + // add bundles to region1 + bundles.put(PP1, testRegion1.installBundle(bundleInstaller.getBundleLocation(PP1))); + bundles.put(SP2, testRegion1.installBundle(bundleInstaller.getBundleLocation(SP2))); + bundles.put(CP2, testRegion1.installBundle(bundleInstaller.getBundleLocation(CP2))); + bundles.put(PC1, testRegion1.installBundle(bundleInstaller.getBundleLocation(PC1))); + bundles.put(BC1, testRegion1.installBundle(bundleInstaller.getBundleLocation(BC1))); + + // add bundles to region2 + bundles.put(SP1, testRegion2.installBundle(bundleInstaller.getBundleLocation(SP1))); + bundles.put(CP1, testRegion2.installBundle(bundleInstaller.getBundleLocation(CP1))); + bundles.put(PP2, testRegion2.installBundle(bundleInstaller.getBundleLocation(PP2))); + bundles.put(SC1, testRegion2.installBundle(bundleInstaller.getBundleLocation(SC1))); + bundles.put(CC1, testRegion2.installBundle(bundleInstaller.getBundleLocation(CC1))); + + RegionFilterBuilder testRegionFilter1 = digraph.createRegionFilterBuilder(); + // SP2 -> PP2 + testRegionFilter1.allow(RegionFilter.VISIBLE_PACKAGE_NAMESPACE, "(" + RegionFilter.VISIBLE_PACKAGE_NAMESPACE + "=pkg2.*)"); + // CP2 -> SP1 + testRegionFilter1.allow(RegionFilter.VISIBLE_SERVICE_NAMESPACE, "(" + Constants.OBJECTCLASS + "=pkg1.*)"); + // PC1 -> PP2 + //testRegionFilter1.allow(RegionFilter.VISIBLE_PACKAGE_NAMESPACE, "(" + RegionFilter.VISIBLE_PACKAGE_NAMESPACE + "=pkg2.*)"); + // BC1 -> PP2 + testRegionFilter1.allow(RegionFilter.VISIBLE_REQUIRE_NAMESPACE, "(" + RegionFilter.VISIBLE_REQUIRE_NAMESPACE + "=" + PP2 + ")"); + + RegionFilterBuilder testRegionFilter2 = digraph.createRegionFilterBuilder(); + //SP1 -> PP1 + testRegionFilter2.allow(RegionFilter.VISIBLE_PACKAGE_NAMESPACE, "(" + RegionFilter.VISIBLE_PACKAGE_NAMESPACE + "=pkg1.*)"); + //SC1 -> SP2 + testRegionFilter2.allow(RegionFilter.VISIBLE_SERVICE_NAMESPACE, "(" + Constants.OBJECTCLASS + "=pkg2.*)"); + //CC1 -> CP2 + testRegionFilter2.allow(CP2, "(name=" + CP2 + ")"); + + Region r1, r2 = null; + for (int i = 0; i <=numLevels; i++) { + r1 = (i > 0) ? r2 : testRegion1; + r2 = (i < numLevels) ? digraph.createRegion(getName() + "_level_" + i) : testRegion2; + r1.connectRegion(r2, testRegionFilter1.build()); + r2.connectRegion(r1, testRegionFilter2.build()); + } + + bundleInstaller.resolveBundles(bundles.values().toArray(new Bundle[bundles.size()])); + for (Bundle bundle : bundles.values()) { + assertEquals("Bundle did not resolve: " + bundle.getSymbolicName(), Bundle.RESOLVED, bundle.getState()); + bundle.start(); + } + ServiceTracker<Boolean, Boolean> cp2Tracker = new ServiceTracker<Boolean, Boolean>(context, context.createFilter("(&(objectClass=java.lang.Boolean)(bundle.id=" + bundles.get(CP2).getBundleId() + "))"), null); + ServiceTracker<Boolean, Boolean> sc1Tracker = new ServiceTracker<Boolean, Boolean>(context, context.createFilter("(&(objectClass=java.lang.Boolean)(bundle.id=" + bundles.get(SC1).getBundleId() + "))"), null); + + cp2Tracker.open(); + sc1Tracker.open(); + + assertNotNull("The cp2 bundle never found the service.", cp2Tracker.waitForService(2000)); + assertNotNull("The sc1 bundle never found the service.", sc1Tracker.waitForService(2000)); + cp2Tracker.close(); + sc1Tracker.close(); + } +} diff --git a/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionBundleEventHookTests.java b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionBundleEventHookTests.java new file mode 100644 index 000000000..7c570f817 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionBundleEventHookTests.java @@ -0,0 +1,93 @@ +/* + * This file is part of the Eclipse Virgo project. + * + * Copyright (c) 2011 VMware Inc. + * 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: + * VMware Inc. - initial contribution + */ + +package org.eclipse.virgo.kernel.osgi.region.hook; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.Collection; +import java.util.HashSet; + +import org.easymock.EasyMock; +import org.eclipse.virgo.kernel.osgi.region.Region; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraph; +import org.eclipse.virgo.teststubs.osgi.framework.StubBundle; +import org.eclipse.virgo.teststubs.osgi.framework.StubBundleContext; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleEvent; +import org.osgi.framework.hooks.bundle.EventHook; +import org.osgi.framework.hooks.bundle.FindHook; + +public class RegionBundleEventHookTests { + + private FindHook mockFindHook; + + private BundleEvent bundleEvent; + + private Collection<BundleContext> contexts; + + private Bundle eventBundle; + + private RegionDigraph mockRegionDigraph; + + private ThreadLocal<Region> threadLocal; + + @Before + public void setUp() throws Exception { + this.mockRegionDigraph = EasyMock.createMock(RegionDigraph.class); + this.mockFindHook = EasyMock.createMock(FindHook.class); + this.eventBundle = new StubBundle(); + this.bundleEvent = new BundleEvent(BundleEvent.STARTED, this.eventBundle, this.eventBundle); + this.contexts = new HashSet<BundleContext>(); + StubBundleContext stubListenerBundleContext = new StubBundleContext(); + this.contexts.add(stubListenerBundleContext); + this.threadLocal = new ThreadLocal<Region>(); + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEventAllowed() { + this.mockFindHook = new FindHook() { + + @Override + public void find(BundleContext context, Collection<Bundle> bundles) { + } + }; + EventHook eventHook = new RegionBundleEventHook(this.mockRegionDigraph, this.mockFindHook, this.threadLocal); + eventHook.event(this.bundleEvent, this.contexts); + assertEquals(1, this.contexts.size()); + } + + @Test + public void testEventNotAllowed() { + this.mockFindHook = new FindHook() { + + @Override + public void find(BundleContext context, Collection<Bundle> bundles) { + bundles.clear(); + } + }; + EventHook eventHook = new RegionBundleEventHook(this.mockRegionDigraph, this.mockFindHook, this.threadLocal); + eventHook.event(this.bundleEvent, this.contexts); + assertTrue(this.contexts.isEmpty()); + } + +} diff --git a/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionBundleFindHookTests.java b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionBundleFindHookTests.java new file mode 100644 index 000000000..cdf923dd9 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionBundleFindHookTests.java @@ -0,0 +1,263 @@ +/******************************************************************************* + * Copyright (c) 2011 VMware Inc. + * 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: + * VMware Inc. - initial contribution + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region.hook; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +import org.eclipse.virgo.kernel.osgi.region.Region; +import org.eclipse.virgo.kernel.osgi.region.RegionFilter; +import org.eclipse.virgo.kernel.osgi.region.RegionFilterBuilder; +import org.eclipse.virgo.kernel.osgi.region.internal.StandardRegionDigraph; +import org.eclipse.virgo.teststubs.osgi.framework.StubBundle; +import org.eclipse.virgo.teststubs.osgi.framework.StubBundleContext; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.Version; +import org.osgi.framework.hooks.bundle.FindHook; + +public class RegionBundleFindHookTests { + + private static final String BUNDLE_X = "X"; + + private static final Version BUNDLE_VERSION = new Version("0"); + + private long bundleId; + + private static final String REGION_A = "RegionA"; + + private static final String BUNDLE_A = "BundleA"; + + private static final String REGION_B = "RegionB"; + + private static final String BUNDLE_B = "BundleB"; + + private static final String REGION_C = "RegionC"; + + private static final String BUNDLE_C = "BundleC"; + + private static final String REGION_D = "RegionD"; + + private static final String BUNDLE_D = "BundleD"; + + private StandardRegionDigraph digraph; + + private FindHook bundleFindHook; + + private Map<String, Region> regions; + + private Map<String, Bundle> bundles; + + private Collection<Bundle> candidates; + + private ThreadLocal<Region> threadLocal; + + @Before + public void setUp() throws Exception { + this.bundleId = 1L; + this.regions = new HashMap<String, Region>(); + this.bundles = new HashMap<String, Bundle>(); + + StubBundle stubSystemBundle = new StubBundle(0L, "osgi.framework", new Version("0"), "loc"); + StubBundleContext stubBundleContext = new StubBundleContext(); + stubBundleContext.addInstalledBundle(stubSystemBundle); + this.threadLocal = new ThreadLocal<Region>(); + this.digraph = new StandardRegionDigraph(stubBundleContext, this.threadLocal); + this.bundleFindHook = new RegionBundleFindHook(this.digraph, stubSystemBundle.getBundleId()); + this.candidates = new HashSet<Bundle>(); + + // Create regions A, B, C, D containing bundles A, B, C, D, respectively. + createRegion(REGION_A, BUNDLE_A); + createRegion(REGION_B, BUNDLE_B); + createRegion(REGION_C, BUNDLE_C); + createRegion(REGION_D, BUNDLE_D); + + createBundle(BUNDLE_X); + + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testFindInSameRegion() { + this.candidates.add(bundle(BUNDLE_A)); + this.bundleFindHook.find(bundleContext(BUNDLE_A), this.candidates); + assertTrue(this.candidates.contains(bundle(BUNDLE_A))); + } + + @Test + public void testFindInDisconnectedRegion() { + this.candidates.add(bundle(BUNDLE_B)); + this.bundleFindHook.find(bundleContext(BUNDLE_A), this.candidates); + assertFalse(this.candidates.contains(bundle(BUNDLE_B))); + } + + @Test + public void testFindConnectedRegionAllowed() throws BundleException, InvalidSyntaxException { + RegionFilter filter = createFilter(BUNDLE_B); + region(REGION_A).connectRegion(region(REGION_B), filter); + + this.candidates.add(bundle(BUNDLE_B)); + this.bundleFindHook.find(bundleContext(BUNDLE_A), this.candidates); + assertTrue(this.candidates.contains(bundle(BUNDLE_B))); + } + + @Test + public void testFindConnectedRegionFiltering() throws BundleException, InvalidSyntaxException { + region(REGION_A).connectRegion(region(REGION_B), createFilter(BUNDLE_B)); + Bundle x = createBundle(BUNDLE_X); + region(REGION_B).addBundle(x); + + this.candidates.add(bundle(BUNDLE_B)); + this.candidates.add(x); + this.bundleFindHook.find(bundleContext(BUNDLE_A), this.candidates); + assertTrue(this.candidates.contains(bundle(BUNDLE_B))); + assertFalse(this.candidates.contains(x)); + } + + @Test + public void testFindTransitive() throws BundleException, InvalidSyntaxException { + region(REGION_A).connectRegion(region(REGION_B), createFilter(BUNDLE_C)); + region(REGION_B).connectRegion(region(REGION_C), createFilter(BUNDLE_C)); + region(REGION_C).addBundle(bundle(BUNDLE_X)); + + this.candidates.add(bundle(BUNDLE_B)); + this.candidates.add(bundle(BUNDLE_C)); + this.candidates.add(bundle(BUNDLE_X)); + this.bundleFindHook.find(bundleContext(BUNDLE_A), this.candidates); + assertTrue(this.candidates.contains(bundle(BUNDLE_C))); + assertFalse(this.candidates.contains(bundle(BUNDLE_B))); + assertFalse(this.candidates.contains(bundle(BUNDLE_X))); + + } + + @Test + public void testFindInCyclicGraph() throws BundleException, InvalidSyntaxException { + region(REGION_D).addBundle(bundle(BUNDLE_X)); + + region(REGION_A).connectRegion(region(REGION_B), createFilter(BUNDLE_D, BUNDLE_X)); + region(REGION_B).connectRegion(region(REGION_A), createFilter()); + + region(REGION_B).connectRegion(region(REGION_D), createFilter(BUNDLE_D)); + region(REGION_D).connectRegion(region(REGION_B), createFilter()); + + region(REGION_B).connectRegion(region(REGION_C), createFilter(BUNDLE_X)); + region(REGION_C).connectRegion(region(REGION_B), createFilter()); + + region(REGION_C).connectRegion(region(REGION_D), createFilter(BUNDLE_X)); + region(REGION_D).connectRegion(region(REGION_C), createFilter()); + + region(REGION_A).connectRegion(region(REGION_C), createFilter()); + region(REGION_C).connectRegion(region(REGION_A), createFilter()); + + region(REGION_D).connectRegion(region(REGION_A), createFilter()); + region(REGION_A).connectRegion(region(REGION_D), createFilter()); + + // Find from region A. + this.candidates.add(bundle(BUNDLE_B)); + this.candidates.add(bundle(BUNDLE_C)); + this.candidates.add(bundle(BUNDLE_D)); + this.candidates.add(bundle(BUNDLE_X)); + + this.bundleFindHook.find(bundleContext(BUNDLE_A), this.candidates); + assertEquals(2, this.candidates.size()); + assertTrue(this.candidates.contains(bundle(BUNDLE_D))); + assertTrue(this.candidates.contains(bundle(BUNDLE_X))); + + // Find from region B + this.candidates.add(bundle(BUNDLE_B)); + this.candidates.add(bundle(BUNDLE_C)); + this.candidates.add(bundle(BUNDLE_D)); + this.candidates.add(bundle(BUNDLE_X)); + + this.bundleFindHook.find(bundleContext(BUNDLE_B), this.candidates); + assertEquals(3, this.candidates.size()); + assertTrue(this.candidates.contains(bundle(BUNDLE_B))); + assertTrue(this.candidates.contains(bundle(BUNDLE_D))); + assertTrue(this.candidates.contains(bundle(BUNDLE_X))); + } + + @Test + public void testFindFromSystemBundle() { + this.candidates.add(bundle(BUNDLE_A)); + + Bundle stubBundle = new StubBundle(0L, "sys", BUNDLE_VERSION, ""); + this.bundleFindHook.find(stubBundle.getBundleContext(), this.candidates); + assertEquals(1, this.candidates.size()); + assertTrue(this.candidates.contains(bundle(BUNDLE_A))); + } + + @Test + public void testFindFromBundleInNoRegion() { + this.candidates.add(bundle(BUNDLE_A)); + + Bundle stranger = createBundle("stranger"); + this.bundleFindHook.find(stranger.getBundleContext(), this.candidates); + assertEquals(0, this.candidates.size()); + } + + private Region createRegion(String regionName, String... bundleSymbolicNames) throws BundleException { + Region region = this.digraph.createRegion(regionName); + for (String bundleSymbolicName : bundleSymbolicNames) { + Bundle stubBundle = createBundle(bundleSymbolicName); + region.addBundle(stubBundle); + } + this.regions.put(regionName, region); + return region; + } + + private Region region(String regionName) { + return this.regions.get(regionName); + } + + private RegionFilter createFilter(String... bundleSymbolicNames) throws InvalidSyntaxException { + Collection<String> filters = new ArrayList<String>(bundleSymbolicNames.length); + for (String bundleSymbolicName : bundleSymbolicNames) { + filters.add('(' + RegionFilter.VISIBLE_BUNDLE_NAMESPACE + '=' + bundleSymbolicName + ')'); + } + RegionFilterBuilder builder = digraph.createRegionFilterBuilder(); + for (String filter : filters) { + builder.allow(RegionFilter.VISIBLE_BUNDLE_NAMESPACE, filter); + } + return builder.build(); + } + + private Bundle createBundle(String bundleSymbolicName) { + Bundle stubBundle = new StubBundle(this.bundleId++, bundleSymbolicName, BUNDLE_VERSION, "loc:" + bundleSymbolicName); + this.bundles.put(bundleSymbolicName, stubBundle); + return stubBundle; + } + + private BundleContext bundleContext(String bundleSymbolicName) { + return bundle(bundleSymbolicName).getBundleContext(); + } + + private Bundle bundle(String bundleSymbolicName) { + Bundle bundleA = this.bundles.get(bundleSymbolicName); + return bundleA; + } + +} diff --git a/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionResolverHookTests.java b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionResolverHookTests.java new file mode 100644 index 000000000..b1337ce76 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionResolverHookTests.java @@ -0,0 +1,580 @@ +/******************************************************************************* + * Copyright (c) 2011 VMware Inc. + * 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: + * VMware Inc. - initial contribution + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region.hook; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +import org.eclipse.virgo.kernel.osgi.region.Region; +import org.eclipse.virgo.kernel.osgi.region.RegionFilter; +import org.eclipse.virgo.kernel.osgi.region.RegionFilterBuilder; +import org.eclipse.virgo.kernel.osgi.region.internal.StandardRegionDigraph; +import org.eclipse.virgo.teststubs.osgi.framework.StubBundle; +import org.eclipse.virgo.teststubs.osgi.framework.StubBundleContext; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleException; +import org.osgi.framework.Constants; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.Version; +import org.osgi.framework.hooks.resolver.ResolverHook; +import org.osgi.framework.wiring.BundleCapability; +import org.osgi.framework.wiring.BundleRequirement; +import org.osgi.framework.wiring.BundleRevision; +import org.osgi.framework.wiring.BundleWiring; + +public class RegionResolverHookTests { + + private static final String PACKAGE_A = "package.a"; + + private static final String PACKAGE_B = "package.b"; + + private static final String PACKAGE_C = "package.c"; + + private static final String PACKAGE_D = "package.d"; + + private static final String PACKAGE_X = "package.x"; + + private static final String PACKAGE_DUP = "duplicate"; + + private static final String BUNDLE_X = "X"; + + private static final Version BUNDLE_VERSION = new Version("0"); + + private long bundleId; + + private static final String REGION_A = "RegionA"; + + private static final String BUNDLE_A = "BundleA"; + + private static final String REGION_B = "RegionB"; + + private static final String BUNDLE_B = "BundleB"; + + private static final String REGION_C = "RegionC"; + + private static final String BUNDLE_C = "BundleC"; + + private static final String REGION_D = "RegionD"; + + private static final String BUNDLE_D = "BundleD"; + + + + private StandardRegionDigraph digraph; + + private ResolverHook resolverHook; + + private Map<String, Region> regions; + + private Map<String, Bundle> bundles; + + private Collection<BundleCapability> candidates; + + private ThreadLocal<Region> threadLocal; + + @Before + public void setUp() throws Exception { + this.bundleId = 1L; + this.regions = new HashMap<String, Region>(); + this.bundles = new HashMap<String, Bundle>(); + this.threadLocal = new ThreadLocal<Region>(); + StubBundle stubSystemBundle = new StubBundle(0L, "osgi.framework", new Version("0"), "loc"); + StubBundleContext stubBundleContext = new StubBundleContext(); + stubBundleContext.addInstalledBundle(stubSystemBundle); + this.digraph = new StandardRegionDigraph(stubBundleContext, this.threadLocal); + this.resolverHook = new RegionResolverHook(this.digraph); + this.candidates = new HashSet<BundleCapability>(); + + // Create regions A, B, C, D containing bundles A, B, C, D, respectively. + createRegion(REGION_A, BUNDLE_A); + createRegion(REGION_B, BUNDLE_B); + createRegion(REGION_C, BUNDLE_C); + createRegion(REGION_D, BUNDLE_D); + + createBundle(BUNDLE_X); + + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testResolveInSameRegion() { + this.candidates.add(packageCapability(BUNDLE_A, PACKAGE_A)); + this.resolverHook.filterMatches(bundleRequirement(BUNDLE_A), this.candidates); + assertTrue(this.candidates.contains(packageCapability(BUNDLE_A, PACKAGE_A))); + } + + @Test + public void testResolveInDisconnectedRegion() { + this.candidates.add(packageCapability(BUNDLE_B, PACKAGE_B)); + this.resolverHook.filterMatches(bundleRequirement(BUNDLE_A), this.candidates); + assertFalse(this.candidates.contains(packageCapability(BUNDLE_B, PACKAGE_B))); + } + + @Test + public void testResolveConnectedRegionAllowed() throws BundleException, InvalidSyntaxException { + RegionFilter filter = createFilter(PACKAGE_B); + region(REGION_A).connectRegion(region(REGION_B), filter); + + this.candidates.add(packageCapability(BUNDLE_B, PACKAGE_B)); + this.resolverHook.filterMatches(bundleRequirement(BUNDLE_A), this.candidates); + assertTrue(this.candidates.contains(packageCapability(BUNDLE_B, PACKAGE_B))); + } + + @Test + public void testResolveBundleCapabilityConnectedRegionAllowed() throws BundleException, InvalidSyntaxException { + RegionFilter filter = createBundleFilter(BUNDLE_B, BUNDLE_VERSION); + region(REGION_A).connectRegion(region(REGION_B), filter); + + this.candidates.add(bundleCapability(BUNDLE_B)); + this.resolverHook.filterMatches(bundleRequirement(BUNDLE_A), this.candidates); + assertTrue(this.candidates.contains(bundleCapability(BUNDLE_B))); + } + + @Test + public void testResolveConnectedRegionFiltering() throws BundleException, InvalidSyntaxException { + region(REGION_A).connectRegion(region(REGION_B), createFilter(PACKAGE_B)); + Bundle x = createBundle(BUNDLE_X); + region(REGION_B).addBundle(x); + + this.candidates.add(packageCapability(BUNDLE_B, PACKAGE_B)); + this.candidates.add(packageCapability(BUNDLE_X, PACKAGE_X)); + this.resolverHook.filterMatches(bundleRequirement(BUNDLE_A), this.candidates); + assertTrue(this.candidates.contains(packageCapability(BUNDLE_B, PACKAGE_B))); + assertFalse(this.candidates.contains(packageCapability(BUNDLE_X, PACKAGE_X))); + } + + @Test + public void testResolveBundleConnectedRegionFiltering() throws BundleException, InvalidSyntaxException { + RegionFilter filter = createBundleFilter(BUNDLE_B, BUNDLE_VERSION); + region(REGION_A).connectRegion(region(REGION_B), filter); + Bundle x = createBundle(BUNDLE_X); + region(REGION_B).addBundle(x); + + this.candidates.add(bundleCapability(BUNDLE_B)); + this.candidates.add(bundleCapability(BUNDLE_X)); + this.resolverHook.filterMatches(bundleRequirement(BUNDLE_A), this.candidates); + assertTrue(this.candidates.contains(bundleCapability(BUNDLE_B))); + assertFalse(this.candidates.contains(bundleCapability(BUNDLE_X))); + } + + @Test + public void testResolveTransitive() throws BundleException, InvalidSyntaxException { + region(REGION_A).connectRegion(region(REGION_B), createFilter(PACKAGE_C)); + region(REGION_B).connectRegion(region(REGION_C), createFilter(PACKAGE_C)); + region(REGION_C).addBundle(bundle(BUNDLE_X)); + + this.candidates.add(packageCapability(BUNDLE_B, PACKAGE_B)); + this.candidates.add(packageCapability(BUNDLE_C, PACKAGE_C)); + this.candidates.add(packageCapability(BUNDLE_X, PACKAGE_X)); + this.resolverHook.filterMatches(bundleRequirement(BUNDLE_A), this.candidates); + assertTrue(this.candidates.contains(packageCapability(BUNDLE_C, PACKAGE_C))); + assertFalse(this.candidates.contains(packageCapability(BUNDLE_B, PACKAGE_B))); + assertFalse(this.candidates.contains(packageCapability(BUNDLE_X, PACKAGE_X))); + } + + @Test + public void testResolveTransitiveDups() throws BundleException, InvalidSyntaxException { + region(REGION_A).connectRegion(region(REGION_B), createFilter(PACKAGE_B)); + region(REGION_A).connectRegion(region(REGION_C), createFilter(PACKAGE_DUP)); + region(REGION_A).connectRegion(region(REGION_D), createFilter(PACKAGE_DUP)); + region(REGION_B).connectRegion(region(REGION_C), createFilter(PACKAGE_DUP)); + region(REGION_C).connectRegion(region(REGION_D), createFilter(PACKAGE_DUP)); + region(REGION_D).connectRegion(region(REGION_A), createFilter(PACKAGE_DUP)); + + this.candidates.add(packageCapability(BUNDLE_A, PACKAGE_DUP)); + this.candidates.add(packageCapability(BUNDLE_B, PACKAGE_DUP)); + this.candidates.add(packageCapability(BUNDLE_C, PACKAGE_DUP)); + this.candidates.add(packageCapability(BUNDLE_D, PACKAGE_DUP)); + + Collection<BundleCapability> testCandidates = new ArrayList<BundleCapability>(this.candidates); + this.resolverHook.filterMatches(bundleRequirement(BUNDLE_A), testCandidates); + assertTrue(testCandidates.contains(packageCapability(BUNDLE_A, PACKAGE_DUP))); + assertFalse(testCandidates.contains(packageCapability(BUNDLE_B, PACKAGE_DUP))); + assertTrue(testCandidates.contains(packageCapability(BUNDLE_C, PACKAGE_DUP))); + assertTrue(testCandidates.contains(packageCapability(BUNDLE_D, PACKAGE_DUP))); + + testCandidates = new ArrayList<BundleCapability>(this.candidates); + this.resolverHook.filterMatches(bundleRequirement(BUNDLE_B), testCandidates); + assertTrue(testCandidates.contains(packageCapability(BUNDLE_A, PACKAGE_DUP))); + assertTrue(testCandidates.contains(packageCapability(BUNDLE_B, PACKAGE_DUP))); + assertTrue(testCandidates.contains(packageCapability(BUNDLE_C, PACKAGE_DUP))); + assertTrue(testCandidates.contains(packageCapability(BUNDLE_D, PACKAGE_DUP))); + + } + + @Test + public void testResolveInCyclicGraph() throws BundleException, InvalidSyntaxException { + region(REGION_D).addBundle(bundle(BUNDLE_X)); + + region(REGION_A).connectRegion(region(REGION_B), createFilter(PACKAGE_D, PACKAGE_X)); + region(REGION_B).connectRegion(region(REGION_A), createFilter()); + + region(REGION_B).connectRegion(region(REGION_D), createFilter(PACKAGE_D)); + region(REGION_D).connectRegion(region(REGION_B), createFilter()); + + region(REGION_B).connectRegion(region(REGION_C), createFilter(PACKAGE_X)); + region(REGION_C).connectRegion(region(REGION_B), createFilter()); + + region(REGION_C).connectRegion(region(REGION_D), createFilter(PACKAGE_X)); + region(REGION_D).connectRegion(region(REGION_C), createFilter()); + + region(REGION_A).connectRegion(region(REGION_C), createFilter()); + region(REGION_C).connectRegion(region(REGION_A), createFilter()); + + region(REGION_D).connectRegion(region(REGION_A), createFilter()); + region(REGION_A).connectRegion(region(REGION_D), createFilter()); + + // Find from region A. + this.candidates.add(packageCapability(BUNDLE_B, PACKAGE_B)); + this.candidates.add(packageCapability(BUNDLE_C, PACKAGE_C)); + this.candidates.add(packageCapability(BUNDLE_D, PACKAGE_D)); + this.candidates.add(packageCapability(BUNDLE_X, PACKAGE_X)); + + this.resolverHook.filterMatches(bundleRequirement(BUNDLE_A), this.candidates); + assertEquals(2, this.candidates.size()); + assertTrue(this.candidates.contains(packageCapability(BUNDLE_D, PACKAGE_D))); + assertTrue(this.candidates.contains(packageCapability(BUNDLE_X, PACKAGE_X))); + + // Find from region B + this.candidates.add(packageCapability(BUNDLE_B, PACKAGE_B)); + this.candidates.add(packageCapability(BUNDLE_C, PACKAGE_C)); + this.candidates.add(packageCapability(BUNDLE_D, PACKAGE_D)); + this.candidates.add(packageCapability(BUNDLE_X, PACKAGE_X)); + + this.resolverHook.filterMatches(bundleRequirement(BUNDLE_B), this.candidates); + assertEquals(3, this.candidates.size()); + assertTrue(this.candidates.contains(packageCapability(BUNDLE_B, PACKAGE_B))); + assertTrue(this.candidates.contains(packageCapability(BUNDLE_D, PACKAGE_D))); + assertTrue(this.candidates.contains(packageCapability(BUNDLE_X, PACKAGE_X))); + } + + @Test + public void testResolveFromSystemBundle() { + this.candidates.add(packageCapability(BUNDLE_A, PACKAGE_A)); + + Bundle stubBundle = new StubBundle(0L, "sys", BUNDLE_VERSION, ""); + this.resolverHook.filterMatches(new StubBundleRequirement(stubBundle), this.candidates); + assertEquals(1, this.candidates.size()); + assertTrue(this.candidates.contains(packageCapability(BUNDLE_A, PACKAGE_A))); + } + + @Test + public void testResolveFromBundleInNoRegion() { + this.candidates.add(packageCapability(BUNDLE_A, PACKAGE_A)); + + Bundle stranger = createBundle("stranger"); + this.resolverHook.filterMatches(new StubBundleRequirement(stranger), this.candidates); + assertEquals(0, this.candidates.size()); + } + + @Test + public void testUnimplementedMethods() { + this.resolverHook.filterResolvable(null); + this.resolverHook.end(); + } + + private BundleCapability packageCapability(final String bundleSymbolicName, String packageName) { + return new StubPackageCapability(bundleSymbolicName, packageName); + } + + private BundleCapability bundleCapability(String bundleSymbolicName) { + return new StubBundleCapability(bundleSymbolicName); + } + + private Region createRegion(String regionName, String... bundleSymbolicNames) throws BundleException { + Region region = this.digraph.createRegion(regionName); + for (String bundleSymbolicName : bundleSymbolicNames) { + Bundle stubBundle = createBundle(bundleSymbolicName); + region.addBundle(stubBundle); + } + this.regions.put(regionName, region); + return region; + } + + private Region region(String regionName) { + return this.regions.get(regionName); + } + + private RegionFilter createFilter(final String... packageNames) throws InvalidSyntaxException { + Collection<String> filters = new ArrayList<String>(packageNames.length); + for (String pkg : packageNames) { + filters.add('(' + RegionFilter.VISIBLE_PACKAGE_NAMESPACE + '=' + pkg + ')'); + } + RegionFilterBuilder builder = digraph.createRegionFilterBuilder(); + for (String filter : filters) { + builder.allow(RegionFilter.VISIBLE_PACKAGE_NAMESPACE, filter); + } + return builder.build(); + } + + private RegionFilter createBundleFilter(String bundleSymbolicName, Version bundleVersion) throws InvalidSyntaxException { + String bundleFilter = "(&(" + RegionFilter.VISIBLE_BUNDLE_NAMESPACE + '=' + bundleSymbolicName + ')' + '(' + + Constants.BUNDLE_VERSION_ATTRIBUTE + ">=" + (bundleVersion == null ? "0" : bundleVersion.toString()) + "))"; + RegionFilterBuilder builder = digraph.createRegionFilterBuilder(); + return builder.allow(RegionFilter.VISIBLE_BUNDLE_NAMESPACE, bundleFilter).build(); + } + + private Bundle createBundle(String bundleSymbolicName) { + Bundle stubBundle = new StubBundle(this.bundleId++, bundleSymbolicName, BUNDLE_VERSION, "loc:" + bundleSymbolicName); + this.bundles.put(bundleSymbolicName, stubBundle); + return stubBundle; + } + + private BundleRequirement bundleRequirement(String bundleSymbolicName) { + return new StubBundleRequirement(bundle(bundleSymbolicName)); + } + + private Bundle bundle(String bundleSymbolicName) { + Bundle bundleA = this.bundles.get(bundleSymbolicName); + return bundleA; + } + + private final class StubPackageCapability implements BundleCapability { + + private final String bundleSymbolicName; + + private final String packageName; + + private StubPackageCapability(String bundleSymbolicName, String packageName) { + this.bundleSymbolicName = bundleSymbolicName; + this.packageName = packageName; + } + + @Override + public String getNamespace() { + return BundleRevision.PACKAGE_NAMESPACE; + } + + @Override + public Map<String, String> getDirectives() { + return new HashMap<String, String>(); + } + + @Override + public Map<String, Object> getAttributes() { + HashMap<String, Object> attributes = new HashMap<String, Object>(); + attributes.put(BundleRevision.PACKAGE_NAMESPACE, this.packageName); + return attributes; + } + + @Override + public BundleRevision getRevision() { + return new StubBundleRevision(bundle(this.bundleSymbolicName)); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + getOuterType().hashCode(); + result = prime * result + (this.bundleSymbolicName == null ? 0 : this.bundleSymbolicName.hashCode()); + result = prime * result + (this.packageName == null ? 0 : this.packageName.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof StubPackageCapability)) { + return false; + } + StubPackageCapability other = (StubPackageCapability) obj; + if (!getOuterType().equals(other.getOuterType())) { + return false; + } + if (this.bundleSymbolicName == null) { + if (other.bundleSymbolicName != null) { + return false; + } + } else if (!this.bundleSymbolicName.equals(other.bundleSymbolicName)) { + return false; + } + if (this.packageName == null) { + if (other.packageName != null) { + return false; + } + } else if (!this.packageName.equals(other.packageName)) { + return false; + } + return true; + } + + private RegionResolverHookTests getOuterType() { + return RegionResolverHookTests.this; + } + + } + + private final class StubBundleCapability implements BundleCapability { + + private final String bundleSymbolicName; + + private StubBundleCapability(String bundleSymbolicName) { + this.bundleSymbolicName = bundleSymbolicName; + } + + @Override + public String getNamespace() { + return BundleRevision.BUNDLE_NAMESPACE; + } + + @Override + public Map<String, String> getDirectives() { + return new HashMap<String, String>(); + } + + @Override + public Map<String, Object> getAttributes() { + HashMap<String, Object> attributes = new HashMap<String, Object>(); + attributes.put(BundleRevision.BUNDLE_NAMESPACE, bundleSymbolicName); + return attributes; + } + + @Override + public BundleRevision getRevision() { + return new StubBundleRevision(bundle(this.bundleSymbolicName)); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + getOuterType().hashCode(); + result = prime * result + ((bundleSymbolicName == null) ? 0 : bundleSymbolicName.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (!(obj instanceof StubBundleCapability)) + return false; + StubBundleCapability other = (StubBundleCapability) obj; + if (!getOuterType().equals(other.getOuterType())) + return false; + if (bundleSymbolicName == null) { + if (other.bundleSymbolicName != null) + return false; + } else if (!bundleSymbolicName.equals(other.bundleSymbolicName)) + return false; + return true; + } + + private RegionResolverHookTests getOuterType() { + return RegionResolverHookTests.this; + } + + } + + private final class StubBundleRequirement implements BundleRequirement { + + private final StubBundleRevision bundleRevision; + + private StubBundleRequirement(Bundle bundle) { + this.bundleRevision = new StubBundleRevision(bundle); + } + + @Override + public String getNamespace() { + throw new UnsupportedOperationException(); + } + + @Override + public Map<String, String> getDirectives() { + throw new UnsupportedOperationException(); + } + + @Override + public Map<String, Object> getAttributes() { + throw new UnsupportedOperationException(); + } + + @Override + public BundleRevision getRevision() { + return this.bundleRevision; + } + + @Override + public boolean matches(BundleCapability capability) { + throw new UnsupportedOperationException(); + } + + } + + private final class StubBundleRevision implements BundleRevision { + + private final Bundle bundle; + + private StubBundleRevision(Bundle bundle) { + this.bundle = bundle; + } + + @Override + public Bundle getBundle() { + return this.bundle; + } + + @Override + public String getSymbolicName() { + return this.bundle.getSymbolicName(); + } + + @Override + public Version getVersion() { + return this.bundle.getVersion(); + } + + @Override + public List<BundleCapability> getDeclaredCapabilities(String namespace) { + throw new UnsupportedOperationException(); + } + + @Override + public int getTypes() { + throw new UnsupportedOperationException(); + } + + @Override + public List<BundleRequirement> getDeclaredRequirements(String namespace) { + throw new UnsupportedOperationException(); + } + + @Override + public BundleWiring getWiring() { + throw new UnsupportedOperationException(); + } + + } + +} diff --git a/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionServiceEventHookTests.java b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionServiceEventHookTests.java new file mode 100644 index 000000000..40553936c --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionServiceEventHookTests.java @@ -0,0 +1,91 @@ +/* + * This file is part of the Eclipse Virgo project. + * + * Copyright (c) 2011 VMware Inc. + * 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: + * VMware Inc. - initial contribution + */ + +package org.eclipse.virgo.kernel.osgi.region.hook; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.Collection; +import java.util.HashSet; + +import org.easymock.EasyMock; +import org.eclipse.virgo.teststubs.osgi.framework.StubBundle; +import org.eclipse.virgo.teststubs.osgi.framework.StubBundleContext; +import org.eclipse.virgo.teststubs.osgi.framework.StubServiceReference; +import org.eclipse.virgo.teststubs.osgi.framework.StubServiceRegistration; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceEvent; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.hooks.service.EventHook; +import org.osgi.framework.hooks.service.FindHook; + +@SuppressWarnings("deprecation") +public class RegionServiceEventHookTests { + + private FindHook mockFindHook; + + private ServiceEvent serviceEvent; + + private Collection<BundleContext> contexts; + + private Bundle eventBundle; + + @Before + public void setUp() throws Exception { + this.mockFindHook = EasyMock.createMock(FindHook.class); + this.eventBundle = new StubBundle(); + StubServiceReference<Object> stubServiceReference = new StubServiceReference<Object>(new StubServiceRegistration<Object>( + (StubBundleContext) this.eventBundle.getBundleContext(), Object.class.getName())); + this.serviceEvent = new ServiceEvent(ServiceEvent.REGISTERED, stubServiceReference); + this.contexts = new HashSet<BundleContext>(); + StubBundleContext stubListenerBundleContext = new StubBundleContext(); + this.contexts.add(stubListenerBundleContext); + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEventAllowed() { + this.mockFindHook = new FindHook() { + + @Override + public void find(BundleContext context, String name, String filter, boolean allServices, Collection<ServiceReference<?>> references) { + } + }; + EventHook eventHook = new RegionServiceEventHook(this.mockFindHook); + eventHook.event(this.serviceEvent, this.contexts); + assertEquals(1, this.contexts.size()); + } + + @Test + public void testEventNotAllowed() { + this.mockFindHook = new FindHook() { + + @Override + public void find(BundleContext context, String name, String filter, boolean allServices, Collection<ServiceReference<?>> references) { + references.clear(); + } + }; + EventHook eventHook = new RegionServiceEventHook(this.mockFindHook); + eventHook.event(this.serviceEvent, this.contexts); + assertTrue(this.contexts.isEmpty()); + } + +} diff --git a/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionServiceFindHookTests.java b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionServiceFindHookTests.java new file mode 100644 index 000000000..83839ca61 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionServiceFindHookTests.java @@ -0,0 +1,305 @@ +/******************************************************************************* + * Copyright (c) 2011 VMware Inc. + * 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: + * VMware Inc. - initial contribution + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region.hook; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.*; +import org.eclipse.virgo.kernel.osgi.region.*; +import org.eclipse.virgo.kernel.osgi.region.internal.StandardRegionDigraph; +import org.eclipse.virgo.teststubs.osgi.framework.*; +import org.junit.*; +import org.osgi.framework.*; +import org.osgi.framework.hooks.service.FindHook; + +/** + * This testcase was based on {@link RegionBundleFindHookTests}. + */ +public class RegionServiceFindHookTests { + + private static final String BUNDLE_X = "X"; + + private static final Version BUNDLE_VERSION = new Version("0"); + + private long bundleId; + + private static final String REGION_A = "RegionA"; + + private static final String BUNDLE_A = "BundleA"; + + private static final String REGION_B = "RegionB"; + + private static final String BUNDLE_B = "BundleB"; + + private static final String REGION_C = "RegionC"; + + private static final String BUNDLE_C = "BundleC"; + + private static final String REGION_D = "RegionD"; + + private static final String BUNDLE_D = "BundleD"; + + private static final String DUPLICATE = "Duplicate"; + private static final String DUPLICATE_FIlTER = DUPLICATE + "*"; + + private StandardRegionDigraph digraph; + + private FindHook bundleFindHook; + + private Map<String, Region> regions; + + private Map<String, Bundle> bundles; + + private Map<String, ServiceReference<Object>> serviceReferences; + + private Collection<ServiceReference<?>> candidates; + + private ThreadLocal<Region> threadLocal; + + @Before + public void setUp() throws Exception { + this.bundleId = 1L; + this.regions = new HashMap<String, Region>(); + this.bundles = new HashMap<String, Bundle>(); + this.serviceReferences = new HashMap<String, ServiceReference<Object>>(); + + StubBundle stubSystemBundle = new StubBundle(0L, "osgi.framework", new Version("0"), "loc"); + StubBundleContext stubBundleContext = new StubBundleContext(); + stubBundleContext.addInstalledBundle(stubSystemBundle); + this.threadLocal = new ThreadLocal<Region>(); + this.digraph = new StandardRegionDigraph(stubBundleContext, this.threadLocal); + this.bundleFindHook = new RegionServiceFindHook(this.digraph); + this.candidates = new HashSet<ServiceReference<?>>(); + + // Create regions A, B, C, D containing bundles A, B, C, D, respectively. + createRegion(REGION_A, BUNDLE_A); + createRegion(REGION_B, BUNDLE_B); + createRegion(REGION_C, BUNDLE_C); + createRegion(REGION_D, BUNDLE_D); + + createBundle(BUNDLE_X); + + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testFindInSameRegion() { + this.candidates.add(serviceReference(BUNDLE_A)); + this.bundleFindHook.find(bundleContext(BUNDLE_A), "", "", false, this.candidates); + assertTrue(this.candidates.contains(serviceReference(BUNDLE_A))); + } + + @Test + public void testFindInDisconnectedRegion() { + this.candidates.add(serviceReference(BUNDLE_B)); + this.bundleFindHook.find(bundleContext(BUNDLE_A), "", "", false, this.candidates); + assertFalse(this.candidates.contains(serviceReference(BUNDLE_B))); + } + + @Test + public void testFindConnectedRegionAllowed() throws BundleException, InvalidSyntaxException { + RegionFilter filter = createFilter(BUNDLE_B); + region(REGION_A).connectRegion(region(REGION_B), filter); + + this.candidates.add(serviceReference(BUNDLE_B)); + this.bundleFindHook.find(bundleContext(BUNDLE_A), "", "", false, this.candidates); + assertTrue(this.candidates.contains(serviceReference(BUNDLE_B))); + } + + @Test + public void testFindConnectedRegionFiltering() throws BundleException, InvalidSyntaxException { + region(REGION_A).connectRegion(region(REGION_B), createFilter(BUNDLE_B)); + Bundle x = createBundle(BUNDLE_X); + region(REGION_B).addBundle(x); + + this.candidates.add(serviceReference(BUNDLE_B)); + this.candidates.add(serviceReference(BUNDLE_X)); + this.bundleFindHook.find(bundleContext(BUNDLE_A), "", "", false, this.candidates); + assertTrue(this.candidates.contains(serviceReference(BUNDLE_B))); + assertFalse(this.candidates.contains(serviceReference(BUNDLE_X))); + } + + @Test + public void testFindTransitive() throws BundleException, InvalidSyntaxException { + region(REGION_A).connectRegion(region(REGION_B), createFilter(BUNDLE_C)); + region(REGION_B).connectRegion(region(REGION_C), createFilter(BUNDLE_C)); + region(REGION_C).addBundle(bundle(BUNDLE_X)); + + this.candidates.add(serviceReference(BUNDLE_B)); + this.candidates.add(serviceReference(BUNDLE_C)); + this.bundleFindHook.find(bundleContext(BUNDLE_A), "", "", false, this.candidates); + assertTrue(this.candidates.contains(serviceReference(BUNDLE_C))); + assertFalse(this.candidates.contains(serviceReference(BUNDLE_B))); + assertFalse(this.candidates.contains(serviceReference(BUNDLE_X))); + + } + + @Test + public void testFindTransitiveDups() throws BundleException, InvalidSyntaxException { + region(REGION_A).connectRegion(region(REGION_B), createFilter(BUNDLE_C)); + region(REGION_A).connectRegion(region(REGION_C), createFilter(DUPLICATE_FIlTER)); + region(REGION_A).connectRegion(region(REGION_D), createFilter(DUPLICATE_FIlTER)); + region(REGION_B).connectRegion(region(REGION_C), createFilter(DUPLICATE_FIlTER)); + region(REGION_C).connectRegion(region(REGION_D), createFilter(DUPLICATE_FIlTER)); + region(REGION_D).connectRegion(region(REGION_A), createFilter(DUPLICATE_FIlTER)); + + this.candidates.add(serviceReference(DUPLICATE + bundle(BUNDLE_A).getBundleId())); + this.candidates.add(serviceReference(DUPLICATE + bundle(BUNDLE_B).getBundleId())); + this.candidates.add(serviceReference(DUPLICATE + bundle(BUNDLE_C).getBundleId())); + this.candidates.add(serviceReference(DUPLICATE + bundle(BUNDLE_D).getBundleId())); + + Collection<ServiceReference<?>> testCandidates = new ArrayList<ServiceReference<?>>(this.candidates); + this.bundleFindHook.find(bundleContext(BUNDLE_A), "", "", false, testCandidates); + assertTrue(testCandidates.contains(serviceReference(DUPLICATE + bundle(BUNDLE_A).getBundleId()))); + assertFalse(testCandidates.contains(serviceReference(DUPLICATE + bundle(BUNDLE_B).getBundleId()))); + assertTrue(testCandidates.contains(serviceReference(DUPLICATE + bundle(BUNDLE_C).getBundleId()))); + assertTrue(testCandidates.contains(serviceReference(DUPLICATE + bundle(BUNDLE_D).getBundleId()))); + + testCandidates = new ArrayList<ServiceReference<?>>(this.candidates); + this.bundleFindHook.find(bundleContext(BUNDLE_A), "", "", false, testCandidates); + assertTrue(testCandidates.contains(serviceReference(DUPLICATE + bundle(BUNDLE_A).getBundleId()))); + assertFalse(testCandidates.contains(serviceReference(DUPLICATE + bundle(BUNDLE_B).getBundleId()))); + assertTrue(testCandidates.contains(serviceReference(DUPLICATE + bundle(BUNDLE_C).getBundleId()))); + assertTrue(testCandidates.contains(serviceReference(DUPLICATE + bundle(BUNDLE_D).getBundleId()))); + + } + + @Test + public void testFindInCyclicGraph() throws BundleException, InvalidSyntaxException { + region(REGION_D).addBundle(bundle(BUNDLE_X)); + + region(REGION_A).connectRegion(region(REGION_B), createFilter(BUNDLE_D, BUNDLE_X)); + region(REGION_B).connectRegion(region(REGION_A), createFilter()); + + region(REGION_B).connectRegion(region(REGION_D), createFilter(BUNDLE_D)); + region(REGION_D).connectRegion(region(REGION_B), createFilter()); + + region(REGION_B).connectRegion(region(REGION_C), createFilter(BUNDLE_X)); + region(REGION_C).connectRegion(region(REGION_B), createFilter()); + + region(REGION_C).connectRegion(region(REGION_D), createFilter(BUNDLE_X)); + region(REGION_D).connectRegion(region(REGION_C), createFilter()); + + region(REGION_A).connectRegion(region(REGION_C), createFilter()); + region(REGION_C).connectRegion(region(REGION_A), createFilter()); + + region(REGION_D).connectRegion(region(REGION_A), createFilter()); + region(REGION_A).connectRegion(region(REGION_D), createFilter()); + + // Find from region A. + this.candidates.add(serviceReference(BUNDLE_B)); + this.candidates.add(serviceReference(BUNDLE_C)); + this.candidates.add(serviceReference(BUNDLE_D)); + this.candidates.add(serviceReference(BUNDLE_X)); + + this.bundleFindHook.find(bundleContext(BUNDLE_A), "", "", false, this.candidates); + assertEquals(2, this.candidates.size()); + assertTrue(this.candidates.contains(serviceReference(BUNDLE_D))); + assertTrue(this.candidates.contains(serviceReference(BUNDLE_X))); + + // Find from region B + this.candidates.add(serviceReference(BUNDLE_B)); + this.candidates.add(serviceReference(BUNDLE_C)); + this.candidates.add(serviceReference(BUNDLE_D)); + this.candidates.add(serviceReference(BUNDLE_X)); + + this.bundleFindHook.find(bundleContext(BUNDLE_B), "", "", false, this.candidates); + assertEquals(3, this.candidates.size()); + assertTrue(this.candidates.contains(serviceReference(BUNDLE_B))); + assertTrue(this.candidates.contains(serviceReference(BUNDLE_D))); + assertTrue(this.candidates.contains(serviceReference(BUNDLE_X))); + } + + @Test + public void testFindFromSystemBundle() { + this.candidates.add(serviceReference(BUNDLE_A)); + + Bundle stubBundle = new StubBundle(0L, "sys", BUNDLE_VERSION, ""); + this.bundleFindHook.find(stubBundle.getBundleContext(), "", "", false, this.candidates); + assertEquals(1, this.candidates.size()); + assertTrue(this.candidates.contains(serviceReference(BUNDLE_A))); + } + + @Test + public void testFindFromBundleInNoRegion() { + this.candidates.add(serviceReference(BUNDLE_A)); + + Bundle stranger = createBundle("stranger"); + this.bundleFindHook.find(stranger.getBundleContext(), "", "", false, this.candidates); + assertEquals(0, this.candidates.size()); + } + + private Region createRegion(String regionName, String... bundleSymbolicNames) throws BundleException { + Region region = this.digraph.createRegion(regionName); + for (String bundleSymbolicName : bundleSymbolicNames) { + Bundle stubBundle = createBundle(bundleSymbolicName); + region.addBundle(stubBundle); + } + this.regions.put(regionName, region); + return region; + } + + private Region region(String regionName) { + return this.regions.get(regionName); + } + + private RegionFilter createFilter(final String... referenceNames) throws InvalidSyntaxException { + Collection<String> filters = new ArrayList<String>(referenceNames.length); + for (String referenceName : referenceNames) { + filters.add('(' + Constants.OBJECTCLASS + '=' + referenceName + ')'); + } + RegionFilterBuilder builder = digraph.createRegionFilterBuilder(); + for (String filter : filters) { + builder.allow(RegionFilter.VISIBLE_SERVICE_NAMESPACE, filter); + } + return builder.build(); + } + + private Bundle createBundle(String bundleSymbolicName) { + Bundle stubBundle = new StubBundle(this.bundleId++, bundleSymbolicName, BUNDLE_VERSION, "loc:" + bundleSymbolicName); + this.bundles.put(bundleSymbolicName, stubBundle); + createServiceReference(stubBundle, bundleSymbolicName); + return stubBundle; + } + + private StubServiceReference<Object> createServiceReference(Bundle stubBundle, String referenceName) { + StubServiceRegistration<Object> stubServiceRegistration = new StubServiceRegistration<Object>( + (StubBundleContext) stubBundle.getBundleContext(), referenceName); + StubServiceReference<Object> stubServiceReference = new StubServiceReference<Object>(stubServiceRegistration); + this.serviceReferences.put(referenceName, stubServiceReference); + + StubServiceRegistration<Object> dupServiceRegistration = new StubServiceRegistration<Object>( + (StubBundleContext) stubBundle.getBundleContext(), DUPLICATE + stubBundle.getBundleId()); + StubServiceReference<Object> dupServiceReference = new StubServiceReference<Object>(dupServiceRegistration); + this.serviceReferences.put(DUPLICATE + stubBundle.getBundleId(), dupServiceReference); + return stubServiceReference; + } + + private BundleContext bundleContext(String bundleSymbolicName) { + return bundle(bundleSymbolicName).getBundleContext(); + } + + private Bundle bundle(String bundleSymbolicName) { + Bundle bundleA = this.bundles.get(bundleSymbolicName); + return bundleA; + } + + private ServiceReference<Object> serviceReference(String referenceName) { + return this.serviceReferences.get(referenceName); + } + +} diff --git a/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/internal/BundleIdBasedRegionTests.java b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/internal/BundleIdBasedRegionTests.java new file mode 100644 index 000000000..3af2eb7e8 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/internal/BundleIdBasedRegionTests.java @@ -0,0 +1,307 @@ +/******************************************************************************* + * Copyright (c) 2011 VMware Inc. + * 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: + * VMware Inc. - initial contribution + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.easymock.EasyMock; +import org.eclipse.virgo.kernel.osgi.region.Region; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraph; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraph.FilteredRegion; +import org.eclipse.virgo.kernel.osgi.region.RegionFilter; +import org.eclipse.virgo.util.math.OrderedPair; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; +import org.osgi.framework.Version; + +public class BundleIdBasedRegionTests { + + private static final String OTHER_REGION_NAME = "other"; + + private static final String BUNDLE_SYMBOLIC_NAME = "b"; + + private static final String BUNDLE_SYMBOLIC_NAME_2 = "c"; + + private static final Version BUNDLE_VERSION = new Version("1"); + + private static final long BUNDLE_ID = 1L; + + private static final long BUNDLE_ID_2 = 2L; + + private static final String REGION_NAME = "reg"; + + private static final long TEST_BUNDLE_ID = 99L; + + private Bundle mockBundle; + + private RegionDigraph mockGraph; + + private Iterator<Region> regionIterator; + + private BundleContext mockBundleContext; + + private Region mockRegion; + + private Region mockRegion2; + + private RegionFilter mockRegionFilter; + + private ThreadLocal<Region> threadLocal; + + @Before + public void setUp() throws Exception { + this.threadLocal = new ThreadLocal<Region>(); + this.mockBundle = EasyMock.createMock(Bundle.class); + EasyMock.expect(this.mockBundle.getSymbolicName()).andReturn(BUNDLE_SYMBOLIC_NAME).anyTimes(); + EasyMock.expect(this.mockBundle.getVersion()).andReturn(BUNDLE_VERSION).anyTimes(); + EasyMock.expect(this.mockBundle.getBundleId()).andReturn(BUNDLE_ID).anyTimes(); + + this.mockBundleContext = EasyMock.createMock(BundleContext.class); + EasyMock.expect(this.mockBundleContext.getBundle(BUNDLE_ID)).andReturn(this.mockBundle).anyTimes(); + + this.mockRegion = EasyMock.createMock(Region.class); + this.mockRegion2 = EasyMock.createMock(Region.class); + + this.mockRegionFilter = EasyMock.createMock(RegionFilter.class); + + this.regionIterator = new Iterator<Region>() { + + @Override + public boolean hasNext() { + return false; + } + + @Override + public Region next() { + return null; + } + + @Override + public void remove() { + } + }; + this.mockGraph = EasyMock.createMock(RegionDigraph.class); + this.mockGraph.connect(EasyMock.isA(Region.class), EasyMock.eq(this.mockRegionFilter), EasyMock.eq(this.mockRegion)); + EasyMock.expectLastCall().anyTimes(); + } + + private void replayMocks() { + EasyMock.replay(this.mockBundleContext, this.mockBundle, this.mockRegion, this.mockRegion2, this.mockRegionFilter, this.mockGraph); + } + + @After + public void tearDown() throws Exception { + EasyMock.verify(this.mockBundleContext, this.mockBundle, this.mockRegion, this.mockRegion2, this.mockRegionFilter, this.mockGraph); + } + + @Test + public void testGetName() { + defaultSetUp(); + + Region r = new BundleIdBasedRegion(REGION_NAME, this.mockGraph, this.mockBundleContext, this.threadLocal); + assertEquals(REGION_NAME, r.getName()); + } + + private void defaultSetUp() { + EasyMock.expect(this.mockGraph.iterator()).andReturn(this.regionIterator).anyTimes(); + EasyMock.expect(this.mockGraph.getEdges(EasyMock.isA(Region.class))).andReturn(new HashSet<FilteredRegion>()).anyTimes(); + replayMocks(); + } + + @Test + public void testAddBundle() throws BundleException { + EasyMock.expect(this.mockGraph.iterator()).andReturn(this.regionIterator).anyTimes(); + + HashSet<FilteredRegion> edges = new HashSet<FilteredRegion>(); + edges.add(new FilteredRegion() { + + @Override + public Region getRegion() { + // TODO Auto-generated method stub + return null; + } + + @Override + public RegionFilter getFilter() { + return mockRegionFilter; + } + }); + EasyMock.expect(this.mockGraph.getEdges(EasyMock.isA(Region.class))).andReturn(edges).anyTimes(); + Set<OrderedPair<String, Version>> allowedBundles = new HashSet<OrderedPair<String, Version>>(); + allowedBundles.add(new OrderedPair<String, Version>(BUNDLE_SYMBOLIC_NAME_2, BUNDLE_VERSION)); + replayMocks(); + + Region r = new BundleIdBasedRegion(REGION_NAME, this.mockGraph, this.mockBundleContext, this.threadLocal); + r.addBundle(this.mockBundle); + } + + @Test + public void testAddExistingBundle() throws BundleException { + defaultSetUp(); + + Region r = new BundleIdBasedRegion(REGION_NAME, this.mockGraph, this.mockBundleContext, this.threadLocal); + r.addBundle(this.mockBundle); + r.addBundle(this.mockBundle); + } + + // This restriction was removed, so no exception should be thrown. + public void testAddConflictingBundle() throws BundleException { + defaultSetUp(); + + Bundle mockBundle2 = EasyMock.createMock(Bundle.class); + EasyMock.expect(mockBundle2.getSymbolicName()).andReturn(BUNDLE_SYMBOLIC_NAME).anyTimes(); + EasyMock.expect(mockBundle2.getVersion()).andReturn(BUNDLE_VERSION).anyTimes(); + EasyMock.expect(mockBundle2.getBundleId()).andReturn(BUNDLE_ID_2).anyTimes(); + EasyMock.replay(mockBundle2); + + Region r = new BundleIdBasedRegion(REGION_NAME, this.mockGraph, this.mockBundleContext, this.threadLocal); + r.addBundle(this.mockBundle); + r.addBundle(mockBundle2); + } + + @Test(expected = BundleException.class) + public void testAddBundlePresentInAnotherRegion() throws BundleException { + this.regionIterator = new Iterator<Region>() { + + private int next = 2; + + @Override + public boolean hasNext() { + return this.next > 0; + } + + @Override + public Region next() { + switch (next--) { + case 2: + return mockRegion; + default: + return mockRegion2; + } + } + + @Override + public void remove() { + } + }; + EasyMock.expect(this.mockGraph.iterator()).andReturn(this.regionIterator).anyTimes(); + EasyMock.expect(this.mockGraph.getEdges(EasyMock.isA(Region.class))).andReturn(new HashSet<FilteredRegion>()).anyTimes(); + EasyMock.expect(this.mockRegion.contains(EasyMock.eq(this.mockBundle))).andReturn(true).anyTimes(); + EasyMock.expect(this.mockRegion2.contains(EasyMock.eq(this.mockBundle))).andReturn(false).anyTimes(); + + replayMocks(); + + Region r = new BundleIdBasedRegion(REGION_NAME, this.mockGraph, this.mockBundleContext, this.threadLocal); + r.addBundle(this.mockBundle); + } + + @Test + public void testInstallBundleStringInputStream() { + defaultSetUp(); + + // TODO + } + + @Test + public void testInstallBundleString() { + defaultSetUp(); + + // TODO + } + + @Test + public void testContains() throws BundleException { + defaultSetUp(); + + Region r = new BundleIdBasedRegion(REGION_NAME, this.mockGraph, this.mockBundleContext, this.threadLocal); + r.addBundle(this.mockBundle); + assertTrue(r.contains(this.mockBundle)); + } + + @Test + public void testDoesNotContain() throws BundleException { + defaultSetUp(); + + Region r = new BundleIdBasedRegion(REGION_NAME, this.mockGraph, this.mockBundleContext, this.threadLocal); + assertFalse(r.contains(this.mockBundle)); + } + + @Test + public void testGetBundle() throws BundleException { + defaultSetUp(); + + Region r = new BundleIdBasedRegion(REGION_NAME, this.mockGraph, this.mockBundleContext, this.threadLocal); + r.addBundle(this.mockBundle); + assertEquals(this.mockBundle, r.getBundle(BUNDLE_SYMBOLIC_NAME, BUNDLE_VERSION)); + } + + @Test + public void testGetBundleNotFound() throws BundleException { + defaultSetUp(); + + Region r = new BundleIdBasedRegion(REGION_NAME, this.mockGraph, this.mockBundleContext, this.threadLocal); + r.addBundle(this.mockBundle); + assertNull(r.getBundle(BUNDLE_SYMBOLIC_NAME_2, BUNDLE_VERSION)); + } + + @Test + public void testConnectRegion() throws BundleException { + defaultSetUp(); + + Region r = new BundleIdBasedRegion(REGION_NAME, this.mockGraph, this.mockBundleContext, this.threadLocal); + r.connectRegion(this.mockRegion, this.mockRegionFilter); + } + + @Test + public void testEquals() { + defaultSetUp(); + + Region r = new BundleIdBasedRegion(REGION_NAME, this.mockGraph, this.mockBundleContext, this.threadLocal); + Region s = new BundleIdBasedRegion(REGION_NAME, this.mockGraph, this.mockBundleContext, this.threadLocal); + assertEquals(r, r); + assertEquals(r, s); + assertEquals(r.hashCode(), s.hashCode()); + } + + @Test + public void testNotEqual() { + defaultSetUp(); + + Region r = new BundleIdBasedRegion(REGION_NAME, this.mockGraph, this.mockBundleContext, this.threadLocal); + Region s = new BundleIdBasedRegion(OTHER_REGION_NAME, this.mockGraph, this.mockBundleContext, this.threadLocal); + assertFalse(r.equals(s)); + assertFalse(r.equals(null)); + } + + @Test + public void testAddRemoveBundleId() { + defaultSetUp(); + Region r = new BundleIdBasedRegion(REGION_NAME, this.mockGraph, this.mockBundleContext, this.threadLocal); + r.addBundle(TEST_BUNDLE_ID); + assertTrue(r.contains(TEST_BUNDLE_ID)); + r.removeBundle(TEST_BUNDLE_ID); + assertFalse(r.contains(TEST_BUNDLE_ID)); + + } + +} diff --git a/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraphPeristenceTests.java b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraphPeristenceTests.java new file mode 100644 index 000000000..e42b8c27b --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraphPeristenceTests.java @@ -0,0 +1,283 @@ +/******************************************************************************* + * This file is part of the Virgo Web Server. + * + * Copyright (c) 2011 VMware Inc. + * 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: + * SpringSource, a division of VMware - initial API and implementation and/or initial documentation + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region.internal; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.virgo.kernel.osgi.region.Region; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraph; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraph.FilteredRegion; +import org.eclipse.virgo.kernel.osgi.region.RegionFilter; +import org.eclipse.virgo.kernel.osgi.region.RegionFilterBuilder; +import org.eclipse.virgo.teststubs.osgi.framework.StubBundle; +import org.eclipse.virgo.teststubs.osgi.framework.StubBundleContext; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleException; +import org.osgi.framework.Constants; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.Version; + +public class StandardRegionDigraphPeristenceTests { + + private RegionDigraph digraph; + + private StubBundleContext systemBundleContext; + + private ThreadLocal<Region> threadLocal; + + private static final String BOOT_REGION = "boot"; + + private static final Collection<String> regionNames = Arrays.asList("r0", "r1", "r2", "r3"); + + @Before + public void setUp() throws Exception { + StubBundle stubSystemBundle = new StubBundle(0L, "osgi.framework", new Version("0"), "loc"); + systemBundleContext = (StubBundleContext) stubSystemBundle.getBundleContext(); + systemBundleContext.addInstalledBundle(stubSystemBundle); + threadLocal = new ThreadLocal<Region>(); + this.digraph = new StandardRegionDigraph(systemBundleContext, threadLocal); + Region boot = digraph.createRegion(BOOT_REGION); + boot.addBundle(stubSystemBundle); + + for (String regionName : regionNames) { + Region region = digraph.createRegion(regionName); + for (int i = 0; i < 10; i++) { + String bsn = region.getName() + "." + i; + StubBundle b = (StubBundle) systemBundleContext.installBundle(bsn); + systemBundleContext.addInstalledBundle(b); + region.addBundle(b); + } + } + } + + @After + public void tearDown() throws Exception { + + } + + @Test + public void testBasic() throws IOException, InvalidSyntaxException, BundleException { + doTest(); + } + + @Test + public void testSingleConnection() throws InvalidSyntaxException, BundleException, IOException { + Region tail = null; + // create a single connection between each region + for (Region head : digraph) { + if (tail != null) { + String name = head.getName(); + tail.connectRegion(head, createFilter(name + "A", name + "B", name + "C")); + } + tail = head; + } + doTest(); + } + + @Test + public void testMultiConnection() throws BundleException, InvalidSyntaxException, IOException { + List<Region> tails = new ArrayList<Region>(); + // create multiple connections between each region + for (Region head : digraph) { + for (Region tail : tails) { + String name = head.getName(); + tail.connectRegion(head, createFilter(name + "A", name + "B", name + "C")); + } + tails.add(head); + } + doTest(); + } + + @Test + public void testMultiConnectionCycle() throws BundleException, InvalidSyntaxException, IOException { + List<Region> tails = new ArrayList<Region>(); + for (Region region : digraph) { + tails.add(region); + } + // create multiple connections between each region with cycles + for (Region head : digraph) { + for (Region tail : tails) { + if (head == tail) + continue; + String name = head.getName(); + tail.connectRegion(head, createFilter(name + "A", name + "B", name + "C")); + } + } + doTest(); + } + + @Test + public void testInvalidOperations() throws IOException, InvalidSyntaxException, BundleException { + Region boot = digraph.getRegion(BOOT_REGION); + Bundle b = boot.installBundle("dynamic.add.a.1", null); + // needed because we don't have a bundle hook to add it for us + boot.addBundle(b); + // needed because StubBundleContext.installBundle does not do this! + systemBundleContext.addInstalledBundle((StubBundle) b); + Bundle p = boot.getBundle(b.getSymbolicName(), b.getVersion()); + Assert.assertEquals(b, p); + // TODO seems testing this will require a reference handler to be present + // b = boot.installBundle("file:dynamic.add.a.2"); + // boot.addBundle(b); // needed because we don't have a bundle hook to add it for us + + RegionDigraph copy = copy(digraph); + Region bootCopy = copy.getRegion(BOOT_REGION); + p = bootCopy.getBundle(b.getSymbolicName(), b.getVersion()); + Assert.assertNull(p); + try { + bootCopy.installBundle("dynamic.add.b.1", null); + } catch (BundleException e) { + // expected + } + try { + bootCopy.installBundle("dynamic.add.b.2"); + } catch (BundleException e) { + // expected + } + + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidPersistentName() throws IOException, InvalidSyntaxException, BundleException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + DataOutputStream dataOut = new DataOutputStream(output); + dataOut.writeUTF("test"); + dataOut.close(); + byte[] byteArray = output.toByteArray(); + readDigraph(byteArray); + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidPersistentVersion() throws IOException, InvalidSyntaxException, BundleException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + DataOutputStream dataOut = new DataOutputStream(output); + dataOut.writeUTF("virgo region digraph"); + dataOut.writeInt(-1); + dataOut.close(); + byte[] byteArray = output.toByteArray(); + readDigraph(byteArray); + } + + private void readDigraph(byte[] byteArray) throws IOException, InvalidSyntaxException, BundleException { + ByteArrayInputStream input = new ByteArrayInputStream(byteArray); + DataInputStream dataIn = new DataInputStream(input); + try { + StandardRegionDigraphPersistence.readRegionDigraph(dataIn); + } finally { + dataIn.close(); + } + } + + private void doTest() throws IOException, InvalidSyntaxException, BundleException { + // test a single write + doTest(1); + // test writing and reading the digraph multiple times to same stream + doTest(10); + } + + private RegionDigraph copy(RegionDigraph toCopy) throws IOException, InvalidSyntaxException, BundleException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + DataOutputStream dataOut = new DataOutputStream(output); + StandardRegionDigraphPersistence.writeRegionDigraph(new DataOutputStream(output), digraph); + dataOut.close(); + + DataInputStream dataIn = new DataInputStream(new ByteArrayInputStream(output.toByteArray())); + RegionDigraph copy = StandardRegionDigraphPersistence.readRegionDigraph(dataIn); + dataIn.close(); + return copy; + } + + private void doTest(int iterations) throws IOException, InvalidSyntaxException, BundleException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + DataOutputStream dataOut = new DataOutputStream(output); + for (int i = 0; i < iterations; i++) { + StandardRegionDigraphPersistence.writeRegionDigraph(new DataOutputStream(output), digraph); + } + dataOut.close(); + + DataInputStream dataIn = new DataInputStream(new ByteArrayInputStream(output.toByteArray())); + for (int i = 0; i < iterations; i++) { + RegionDigraph copy = StandardRegionDigraphPersistence.readRegionDigraph(dataIn); + assertEquals(digraph, copy); + } + dataIn.close(); + } + + private RegionFilter createFilter(String... input) throws InvalidSyntaxException { + RegionFilterBuilder builder = digraph.createRegionFilterBuilder(); + for (String param : input) { + builder.allow(RegionFilter.VISIBLE_BUNDLE_NAMESPACE, "(bundle-symbolic-name=" + param + ")"); + builder.allow(RegionFilter.VISIBLE_HOST_NAMESPACE, "(" + RegionFilter.VISIBLE_HOST_NAMESPACE + "=" + param + ")"); + builder.allow(RegionFilter.VISIBLE_PACKAGE_NAMESPACE, "(" + RegionFilter.VISIBLE_PACKAGE_NAMESPACE + "=" + param + ")"); + builder.allow(RegionFilter.VISIBLE_REQUIRE_NAMESPACE, "(" + RegionFilter.VISIBLE_REQUIRE_NAMESPACE + "=" + param + ")"); + builder.allow(RegionFilter.VISIBLE_SERVICE_NAMESPACE, "(" + Constants.OBJECTCLASS + "=" + param + ")"); + } + return builder.build(); + } + + static void assertEquals(RegionDigraph d1, RegionDigraph d2) { + int rCnt1 = countRegions(d1); + int rCnt2 = countRegions(d2); + Assert.assertEquals(rCnt1, rCnt2); + for (Region r1 : d1) { + Region r2 = d2.getRegion(r1.getName()); + assertEquals(r1, r2); + } + } + + static int countRegions(RegionDigraph digraph) { + return digraph.getRegions().size(); + } + + static void assertEquals(Region r1, Region r2) { + Assert.assertNotNull(r1); + Assert.assertNotNull(r2); + Assert.assertEquals("Wrong name", r1.getName(), r2.getName()); + Set<Long> r1IDs = r1.getBundleIds(); + Set<Long> r2IDs = r2.getBundleIds(); + Assert.assertEquals(r1IDs.size(), r2IDs.size()); + for (Long id : r1IDs) { + Assert.assertTrue("Missing id: " + id, r2IDs.contains(id)); + } + assertEquals(r1.getEdges(), r2.getEdges()); + } + + static void assertEquals(Set<FilteredRegion> edges1, Set<FilteredRegion> edges2) { + Assert.assertEquals(edges1.size(), edges2.size()); + Map<String, RegionFilter> edges2Map = new HashMap<String, RegionFilter>(); + for (FilteredRegion edge2 : edges2) { + edges2Map.put(edge2.getRegion().getName(), edge2.getFilter()); + } + for (FilteredRegion edge1 : edges1) { + RegionFilter filter2 = edges2Map.get(edge1.getRegion().getName()); + Assert.assertNotNull("No filter found: " + edge1.getRegion().getName(), filter2); + Assert.assertEquals(edge1.getFilter().getSharingPolicy(), filter2.getSharingPolicy()); + } + } +} diff --git a/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraphTests.java b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraphTests.java new file mode 100644 index 000000000..64de3fec5 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraphTests.java @@ -0,0 +1,190 @@ +/******************************************************************************* + * This file is part of the Virgo Web Server. + * + * Copyright (c) 2011 VMware Inc. + * 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: + * SpringSource, a division of VMware - initial API and implementation and/or initial documentation + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.Set; + +import org.easymock.EasyMock; +import org.eclipse.virgo.kernel.osgi.region.Region; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraph; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraph.FilteredRegion; +import org.eclipse.virgo.kernel.osgi.region.RegionFilter; +import org.eclipse.virgo.teststubs.osgi.framework.StubBundle; +import org.eclipse.virgo.teststubs.osgi.framework.StubBundleContext; +import org.eclipse.virgo.util.math.OrderedPair; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleException; +import org.osgi.framework.Constants; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.Version; + +public class StandardRegionDigraphTests { + + private RegionDigraph digraph; + + private Region mockRegion1; + + private Region mockRegion2; + + private Region mockRegion3; + + private RegionFilter regionFilter1; + + private RegionFilter regionFilter2; + + private Bundle mockBundle; + + @Before + public void setUp() throws Exception { + StubBundle stubSystemBundle = new StubBundle(0L, "osgi.framework", new Version("0"), "loc"); + StubBundleContext stubBundleContext = new StubBundleContext(); + stubBundleContext.addInstalledBundle(stubSystemBundle); + this.digraph = new StandardRegionDigraph(stubBundleContext, new ThreadLocal<Region>()); + + this.mockRegion1 = EasyMock.createMock(Region.class); + EasyMock.expect(this.mockRegion1.getName()).andReturn("mockRegion1").anyTimes(); + + this.mockRegion2 = EasyMock.createMock(Region.class); + EasyMock.expect(this.mockRegion2.getName()).andReturn("mockRegion2").anyTimes(); + + this.mockRegion3 = EasyMock.createMock(Region.class); + EasyMock.expect(this.mockRegion3.getName()).andReturn("mockRegion3").anyTimes(); + + this.mockBundle = EasyMock.createMock(Bundle.class); + } + + private void setDefaultFilters() throws InvalidSyntaxException { + this.regionFilter1 = digraph.createRegionFilterBuilder().build(); + this.regionFilter2 = digraph.createRegionFilterBuilder().build(); + } + + private void setAllowedFilters(OrderedPair<String, Version> b1, OrderedPair<String, Version> b2) throws InvalidSyntaxException { + String filter1 = "(&(" + RegionFilter.VISIBLE_BUNDLE_NAMESPACE + "=" + b1.getFirst() + ")(" + Constants.BUNDLE_VERSION_ATTRIBUTE + "=" + + b1.getSecond() + "))"; + regionFilter1 = digraph.createRegionFilterBuilder().allow(RegionFilter.VISIBLE_BUNDLE_NAMESPACE, filter1).build(); + + String filter2 = "(&(" + RegionFilter.VISIBLE_BUNDLE_NAMESPACE + "=" + b1.getFirst() + ")(" + Constants.BUNDLE_VERSION_ATTRIBUTE + "=" + + b1.getSecond() + "))"; + regionFilter2 = digraph.createRegionFilterBuilder().allow(RegionFilter.VISIBLE_BUNDLE_NAMESPACE, filter2).build(); + + } + + private void replayMocks() { + EasyMock.replay(this.mockRegion1, this.mockRegion2, this.mockRegion3, this.mockBundle); + } + + @After + public void tearDown() throws Exception { + EasyMock.verify(this.mockRegion1, this.mockRegion2, this.mockRegion3, this.mockBundle); + } + + @Test + public void testConnect() throws BundleException, InvalidSyntaxException { + setDefaultFilters(); + replayMocks(); + + this.digraph.connect(this.mockRegion1, this.regionFilter1, this.mockRegion2); + } + + @Test + public void testConnectWithFilterContents() throws BundleException, InvalidSyntaxException { + OrderedPair<String, Version> b1 = new OrderedPair<String, Version>("b1", new Version("0")); + OrderedPair<String, Version> b2 = new OrderedPair<String, Version>("b2", new Version("0")); + setAllowedFilters(b1, b2); + EasyMock.expect(this.mockRegion1.getBundle(b1.getFirst(), b1.getSecond())).andReturn(null).anyTimes(); + EasyMock.expect(this.mockRegion1.getBundle(b2.getFirst(), b2.getSecond())).andReturn(null).anyTimes(); + + replayMocks(); + + this.digraph.connect(this.mockRegion1, this.regionFilter1, this.mockRegion2); + this.digraph.connect(this.mockRegion1, this.regionFilter2, this.mockRegion3); + } + + @Test(expected = BundleException.class) + public void testConnectLoop() throws BundleException, InvalidSyntaxException { + setDefaultFilters(); + replayMocks(); + + this.digraph.connect(this.mockRegion1, this.regionFilter1, this.mockRegion1); + } + + @Test(expected = BundleException.class) + public void testDuplicateConnection() throws BundleException, InvalidSyntaxException { + setDefaultFilters(); + replayMocks(); + + this.digraph.connect(this.mockRegion1, this.regionFilter1, this.mockRegion2); + this.digraph.connect(this.mockRegion1, this.regionFilter2, this.mockRegion2); + } + + @Test + public void testGetEdges() throws BundleException, InvalidSyntaxException { + setDefaultFilters(); + replayMocks(); + + this.digraph.connect(this.mockRegion1, this.regionFilter1, this.mockRegion2); + this.digraph.connect(this.mockRegion1, this.regionFilter2, this.mockRegion3); + this.digraph.connect(this.mockRegion2, this.regionFilter2, this.mockRegion1); + + Set<FilteredRegion> edges = this.digraph.getEdges(this.mockRegion1); + + assertEquals(2, edges.size()); + + for (FilteredRegion edge : edges) { + if (edge.getRegion().equals(this.mockRegion2)) { + assertEquals(this.regionFilter1, edge.getFilter()); + } else if (edge.getRegion().equals(this.mockRegion3)) { + assertEquals(this.regionFilter2, edge.getFilter()); + } else { + fail("unexpected edge"); + } + } + } + + @Test + public void testRemoveRegion() throws BundleException, InvalidSyntaxException { + setDefaultFilters(); + replayMocks(); + + this.digraph.connect(this.mockRegion1, this.regionFilter1, this.mockRegion2); + this.digraph.connect(this.mockRegion2, this.regionFilter2, this.mockRegion1); + assertNotNull(this.digraph.getRegion("mockRegion1")); + assertNotNull(this.digraph.getRegion("mockRegion2")); + this.digraph.removeRegion(this.mockRegion1); + assertNull(this.digraph.getRegion("mockRegion1")); + assertNotNull(this.digraph.getRegion("mockRegion2")); + } + + @Test + public void testGetRegions() throws BundleException, InvalidSyntaxException { + setDefaultFilters(); + replayMocks(); + + this.digraph.connect(this.mockRegion1, this.regionFilter1, this.mockRegion2); + Set<Region> regions = this.digraph.getRegions(); + assertEquals(2, regions.size()); + assertTrue(regions.contains(this.mockRegion1)); + assertTrue(regions.contains(this.mockRegion2)); + } + +} diff --git a/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionFilterTests.java b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionFilterTests.java new file mode 100644 index 000000000..5945f7da2 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionFilterTests.java @@ -0,0 +1,191 @@ +/* + * This file is part of the Eclipse Virgo project. + * + * Copyright (c) 2011 VMware Inc. + * 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: + * VMware Inc. - initial contribution + */ + +package org.eclipse.virgo.kernel.osgi.region.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.easymock.EasyMock; +import org.eclipse.virgo.kernel.osgi.region.RegionFilter; +import org.eclipse.virgo.teststubs.osgi.framework.StubBundle; +import org.eclipse.virgo.teststubs.osgi.framework.StubBundleContext; +import org.eclipse.virgo.teststubs.osgi.framework.StubServiceRegistration; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.osgi.framework.Constants; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceRegistration; +import org.osgi.framework.Version; +import org.osgi.framework.wiring.BundleCapability; +import org.osgi.framework.wiring.BundleRevision; + +public class StandardRegionFilterTests { + + private static final String BUNDLE_SYMBOLIC_NAME = "A"; + + private static final Version BUNDLE_VERSION = new Version("0"); + + private StubBundle stubBundle; + + private String packageImportPolicy = "(" + BundleRevision.PACKAGE_NAMESPACE + "=foo)"; + + private String serviceImportPolicy = "(" + Constants.OBJECTCLASS + "=foo.Service)"; + + private BundleCapability fooPackage; + + private BundleCapability barPackage; + + private ServiceRegistration<Object> fooService; + + private ServiceRegistration<Object> barService; + + @Before + public void setUp() throws Exception { + this.stubBundle = new StubBundle(BUNDLE_SYMBOLIC_NAME, BUNDLE_VERSION); + this.fooService = new StubServiceRegistration<Object>(new StubBundleContext(), "foo.Service"); + this.barService = new StubServiceRegistration<Object>(new StubBundleContext(), "bar.Service"); + + this.fooPackage = EasyMock.createMock(BundleCapability.class); + Map<String, Object> fooAttrs = new HashMap<String, Object>(); + fooAttrs.put(BundleRevision.PACKAGE_NAMESPACE, "foo"); + EasyMock.expect(fooPackage.getNamespace()).andReturn(BundleRevision.PACKAGE_NAMESPACE).anyTimes(); + EasyMock.expect(fooPackage.getAttributes()).andReturn(fooAttrs).anyTimes(); + EasyMock.replay(fooPackage); + + this.barPackage = EasyMock.createMock(BundleCapability.class); + Map<String, Object> barAttrs = new HashMap<String, Object>(); + barAttrs.put(BundleRevision.PACKAGE_NAMESPACE, "bar"); + EasyMock.expect(barPackage.getNamespace()).andReturn(BundleRevision.PACKAGE_NAMESPACE).anyTimes(); + EasyMock.expect(barPackage.getAttributes()).andReturn(barAttrs).anyTimes(); + EasyMock.replay(barPackage); + } + + @After + public void tearDown() throws Exception { + } + + private RegionFilter createBundleFilter(String bundleSymbolicName, Version bundleVersion) throws InvalidSyntaxException { + String filter = "(&(" + RegionFilter.VISIBLE_BUNDLE_NAMESPACE + "=" + bundleSymbolicName + ")(" + Constants.BUNDLE_VERSION_ATTRIBUTE + ">=" + + bundleVersion + "))"; + return new StandardRegionFilterBuilder().allow(RegionFilter.VISIBLE_BUNDLE_NAMESPACE, filter).build(); + } + + private RegionFilter createRegionFilter(String namespace, Collection<String> filters) throws InvalidSyntaxException { + StandardRegionFilterBuilder builder = new StandardRegionFilterBuilder(); + for (String filter : filters) { + builder.allow(namespace, filter); + } + return builder.build(); + } + + @Test + public void testBundleAllow() throws InvalidSyntaxException { + RegionFilter regionFilter = createBundleFilter(BUNDLE_SYMBOLIC_NAME, BUNDLE_VERSION); + assertTrue(regionFilter.isAllowed(stubBundle)); + } + + @Test + public void testBundleAllNotAllowed() { + RegionFilter regionFilter = new StandardRegionFilterBuilder().build(); + assertFalse(regionFilter.isAllowed(stubBundle)); + } + + @Test + public void testBundleAllAllowed() { + RegionFilter regionFilter = new StandardRegionFilterBuilder().allowAll(RegionFilter.VISIBLE_BUNDLE_NAMESPACE).build(); + assertTrue(regionFilter.isAllowed(stubBundle)); + } + + @Test + public void testBundleNotAllowedInRange() throws InvalidSyntaxException { + RegionFilter regionFilter = createBundleFilter(BUNDLE_SYMBOLIC_NAME, new Version(1, 0, 0)); + assertFalse(regionFilter.isAllowed(stubBundle)); + } + + @Test + public void testCapabilityAllowed() throws InvalidSyntaxException { + RegionFilter regionFilter = createRegionFilter(RegionFilter.VISIBLE_PACKAGE_NAMESPACE, Arrays.asList(packageImportPolicy)); + assertTrue(regionFilter.isAllowed(fooPackage)); + assertEquals(Arrays.asList(this.packageImportPolicy), regionFilter.getSharingPolicy().get(RegionFilter.VISIBLE_PACKAGE_NAMESPACE)); + } + + @Test + public void testCapabilityAllNotAllowed() { + RegionFilter regionFilter = new StandardRegionFilterBuilder().build(); + assertFalse(regionFilter.isAllowed(barPackage)); + } + + @Test + public void testCapabilityAllAllowed() { + RegionFilter regionFilter = new StandardRegionFilterBuilder().allowAll(RegionFilter.VISIBLE_PACKAGE_NAMESPACE).build(); + assertTrue(regionFilter.isAllowed(barPackage)); + } + + @Test + public void testCapabilityNotAllowed() throws InvalidSyntaxException { + RegionFilter regionFilter = createRegionFilter(RegionFilter.VISIBLE_PACKAGE_NAMESPACE, Arrays.asList(packageImportPolicy)); + assertFalse(regionFilter.isAllowed(barPackage)); + assertEquals(Arrays.asList(this.packageImportPolicy), regionFilter.getSharingPolicy().get(RegionFilter.VISIBLE_PACKAGE_NAMESPACE)); + } + + @Test + public void testServiceAllowed() throws InvalidSyntaxException { + RegionFilter regionFilter = createRegionFilter(RegionFilter.VISIBLE_SERVICE_NAMESPACE, Arrays.asList(serviceImportPolicy)); + assertTrue(regionFilter.isAllowed(fooService.getReference())); + assertEquals(Arrays.asList(serviceImportPolicy), regionFilter.getSharingPolicy().get(RegionFilter.VISIBLE_SERVICE_NAMESPACE)); + } + + @Test + public void testServiceAllNotAllowed() { + RegionFilter regionFilter = new StandardRegionFilterBuilder().build(); + assertFalse(regionFilter.isAllowed(fooService.getReference())); + } + + @Test + public void testServiceAllAllowed() { + RegionFilter regionFilter = new StandardRegionFilterBuilder().allowAll(RegionFilter.VISIBLE_SERVICE_NAMESPACE).build(); + assertTrue(regionFilter.isAllowed(fooService.getReference())); + } + + @Test + public void testServiceNotAllowed() throws InvalidSyntaxException { + RegionFilter regionFilter = createRegionFilter(RegionFilter.VISIBLE_SERVICE_NAMESPACE, Arrays.asList(serviceImportPolicy)); + assertFalse(regionFilter.isAllowed(barService.getReference())); + assertEquals(Arrays.asList(serviceImportPolicy), regionFilter.getSharingPolicy().get(RegionFilter.VISIBLE_SERVICE_NAMESPACE)); + } + + @Test + public void testAllNamespace() throws InvalidSyntaxException { + RegionFilter regionFilterNotAllowed = new StandardRegionFilterBuilder().allow(RegionFilter.VISIBLE_ALL_NAMESPACE, "(all=namespace)").build(); + assertFalse(regionFilterNotAllowed.isAllowed(stubBundle)); + assertFalse(regionFilterNotAllowed.isAllowed(fooPackage)); + assertFalse(regionFilterNotAllowed.isAllowed(barPackage)); + assertFalse(regionFilterNotAllowed.isAllowed(fooService.getReference())); + assertFalse(regionFilterNotAllowed.isAllowed(barService.getReference())); + + RegionFilter regionFilterAllAllowed = new StandardRegionFilterBuilder().allowAll(RegionFilter.VISIBLE_ALL_NAMESPACE).build(); + assertTrue(regionFilterAllAllowed.isAllowed(stubBundle)); + assertTrue(regionFilterAllAllowed.isAllowed(fooPackage)); + assertTrue(regionFilterAllAllowed.isAllowed(barPackage)); + assertTrue(regionFilterAllAllowed.isAllowed(fooService.getReference())); + assertTrue(regionFilterAllAllowed.isAllowed(barService.getReference())); + } +} diff --git a/bundles/org.eclipse.equinox.region.tests/stubs/README b/bundles/org.eclipse.equinox.region.tests/stubs/README new file mode 100644 index 000000000..d5f9156d2 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/stubs/README @@ -0,0 +1,3 @@ +The teststubs are built out of the virgo project. +Note that the source for this jar is dependent on the org.osgi API and implements stubs for many org.osgi.* types. +If and when the org.osgi.* types are modified, this jar will have to be updated and recompiled. diff --git a/bundles/org.eclipse.equinox.region.tests/stubs/org.eclipse.virgo.teststubs.osgi-sources.jar b/bundles/org.eclipse.equinox.region.tests/stubs/org.eclipse.virgo.teststubs.osgi-sources.jar Binary files differnew file mode 100644 index 000000000..baf9e683a --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/stubs/org.eclipse.virgo.teststubs.osgi-sources.jar diff --git a/bundles/org.eclipse.equinox.region.tests/stubs/org.eclipse.virgo.teststubs.osgi.jar b/bundles/org.eclipse.equinox.region.tests/stubs/org.eclipse.virgo.teststubs.osgi.jar Binary files differnew file mode 100644 index 000000000..a2730a2a7 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/stubs/org.eclipse.virgo.teststubs.osgi.jar diff --git a/bundles/org.eclipse.equinox.region.tests/test.xml b/bundles/org.eclipse.equinox.region.tests/test.xml new file mode 100644 index 000000000..2a893b445 --- /dev/null +++ b/bundles/org.eclipse.equinox.region.tests/test.xml @@ -0,0 +1,63 @@ +<?xml version="1.0"?> +<project name="Equinox Region Automated Tests" default="run" basedir="."> + + <!-- The property ${eclipse-home} should be passed into this script --> + <!-- sets the properties eclipse-home, and library-file --> + <property name="eclipse-home" value="${basedir}/../../"/> + <property name="library-file" value="${eclipse-home}/plugins/org.eclipse.test/library.xml"/> + <property name="osgi_location" value="${eclipse-home}/region_sniff_folder"/> + <property name="plugin-name" value="org.eclipse.equinox.region.tests"/> + + <!-- This target holds all initialization code that needs to be done for --> + <!-- all tests that are to be run. Initialization for individual tests --> + <!-- should be done within the body of the suite target. --> + <target name="init"> + <tstamp/> + </target> + + <!-- This target holds code to cleanup the testing environment after the tests --> + <!-- have been run. You can use this to delete temporary files that are created. --> + <target name="cleanup"> + <delete dir="${osgi_location}" quiet="true"/> + </target> + + <!-- This target runs the test suite. Any actions that need to happen after all --> + <!-- the tests have been run should go here. --> + <target name="run" depends="init,suite,cleanup"> + <ant target="collect" antfile="${library-file}" dir="${eclipse-home}"> + <property name="includes" value="org*.xml"/> + <property name="output-file" value="${plugin-name}.xml"/> + </ant> + </target> + + <!-- This target runs the performance test suites. Any actions that need to happen after all --> + <!-- the tests have been run should go here. --> + <!-- + <target name="performance" depends="init,performance-suite,cleanup"> + <ant target="collect" antfile="${library-file}" dir="${eclipse-home}"> + <property name="includes" value="org*.xml"/> + <property name="output-file" value="${plugin-name}.xml"/> + </ant> + </target> + --> + + <target name="RegionTests" depends="init,cleanup"> + <ant target="core-test" antfile="${library-file}" dir="${eclipse-home}"> + <property name="data-dir" value="${osgi_location}"/> + <property name="plugin-name" value="org.eclipse.equinox.region.tests"/> + <property name="classname" value="org.eclipse.equinox.region.tests.AllTests"/> + </ant> + </target> + + <target name="DSPerformanceTests"> + <!-- TODO --> + </target> + + <!-- This target defines the tests that need to be run. --> + <target name="suite" depends="RegionTests"/> + + <!-- This target defines the performance tests that need to be run. --> + <!-- + <target name="performance-suite" depends="DSPerformanceTests"/> + --> + </project> diff --git a/bundles/org.eclipse.equinox.region/.classpath b/bundles/org.eclipse.equinox.region/.classpath new file mode 100644 index 000000000..ad32c83a7 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/.classpath @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="src" path="src"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/bundles/org.eclipse.equinox.region/.project b/bundles/org.eclipse.equinox.region/.project new file mode 100644 index 000000000..269c1e5cb --- /dev/null +++ b/bundles/org.eclipse.equinox.region/.project @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.equinox.region</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.region/.settings/org.eclipse.core.resources.prefs b/bundles/org.eclipse.equinox.region/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 000000000..16532b29e --- /dev/null +++ b/bundles/org.eclipse.equinox.region/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,3 @@ +#Tue May 25 15:00:03 EDT 2004 +encoding/<project>=ISO-8859-1 +eclipse.preferences.version=1 diff --git a/bundles/org.eclipse.equinox.region/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.equinox.region/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..60fec9e81 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,329 @@ +#Fri Apr 08 08:55:56 CDT 2011 +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=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +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=error +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=error +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.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.6 +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_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.region/.settings/org.eclipse.jdt.ui.prefs b/bundles/org.eclipse.equinox.region/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 000000000..614ff2ccd --- /dev/null +++ b/bundles/org.eclipse.equinox.region/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,61 @@ +#Thu Mar 31 16:02:27 CDT 2011 +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=false +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=99 +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_methods=false +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_missing_override_annotations_interface_methods=false +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.format_source_code_changes_only=false +sp_cleanup.make_local_variable_final=false +sp_cleanup.make_parameters_final=false +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_type_abstract_if_missing_method=false +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.region/.settings/org.eclipse.pde.core.prefs b/bundles/org.eclipse.equinox.region/.settings/org.eclipse.pde.core.prefs new file mode 100644 index 000000000..cd216df0d --- /dev/null +++ b/bundles/org.eclipse.equinox.region/.settings/org.eclipse.pde.core.prefs @@ -0,0 +1,4 @@ +#Wed Mar 23 12:53:23 CDT 2011 +eclipse.preferences.version=1 +pluginProject.extensions=false +resolve.requirebundle=false diff --git a/bundles/org.eclipse.equinox.region/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.region/META-INF/MANIFEST.MF new file mode 100644 index 000000000..122b3248b --- /dev/null +++ b/bundles/org.eclipse.equinox.region/META-INF/MANIFEST.MF @@ -0,0 +1,17 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %Bundle-Name +Bundle-SymbolicName: org.eclipse.equinox.region +Bundle-Version: 1.0.0.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Import-Package: javax.management, + org.eclipse.osgi.service.resolver;version="1.5.0", + org.osgi.framework;version="1.6.0", + org.osgi.framework.hooks.bundle;version="1.0.0", + org.osgi.framework.hooks.resolver;version="1.0.0", + org.osgi.framework.hooks.service;version="1.1.0", + org.osgi.framework.wiring;version="1.0.0", + org.osgi.util.tracker;version="1.5.0" +Bundle-Activator: org.eclipse.virgo.kernel.osgi.region.internal.RegionManager +Export-Package: org.eclipse.virgo.kernel.osgi.region;version="1.0.0" +Bundle-Vendor: %Bundle-Vendor diff --git a/bundles/org.eclipse.equinox.region/OSGI-INF/l10n/bundle.properties b/bundles/org.eclipse.equinox.region/OSGI-INF/l10n/bundle.properties new file mode 100644 index 000000000..4d75fd9c0 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/OSGI-INF/l10n/bundle.properties @@ -0,0 +1,12 @@ +############################################################################### +# Copyright (c) 2011 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 +############################################################################### +Bundle-Vendor = Eclipse.org - Equinox +Bundle-Name = Region Digraph
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.region/about.html b/bundles/org.eclipse.equinox.region/about.html new file mode 100644 index 000000000..460233046 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/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>June 2, 2006</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.region/build.properties b/bundles/org.eclipse.equinox.region/build.properties new file mode 100644 index 000000000..04fa2df49 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/build.properties @@ -0,0 +1,7 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + about.html,\ + OSGI-INF/l10n/bundle.properties +src.includes = about.html diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/Region.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/Region.java new file mode 100644 index 000000000..4d4c0c110 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/Region.java @@ -0,0 +1,192 @@ +/******************************************************************************* + * Copyright (c) 2008, 2011 VMware Inc. + * 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: + * VMware Inc. - initial contribution + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region; + +import java.io.InputStream; +import java.util.Set; + +import org.eclipse.virgo.kernel.osgi.region.RegionDigraph.FilteredRegion; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; +import org.osgi.framework.Version; + +/** + * A <i>region</i> is a subset of the bundles of an OSGi framework. A regions is "weakly" isolated from other regions + * except that is has full visibility of certain (subject to a {@link RegionFilter}) bundles, packages, and services + * from other regions to which it is connected. However a bundle running in a region is not protected from discovering + * bundles in other regions, e.g. by following wires using Wire Admin or similar services, so this is why regions are + * only weakly isolated from each other. + * <p /> + * + * <strong>Concurrent Semantics</strong><br /> + * + * Implementations must be thread safe. + * + */ +public interface Region { + + /** + * Returns the name of the region. + * + * @return the region name + */ + String getName(); + + /** + * Associates a given bundle, which has therefore already been installed, with this region. + * <p> + * This method is typically used to associate the system bundle with a region. Note that the system bundle is not + * treated specially and in order to be fully visible in a region, it must either be associated with the region or + * imported from another region via a connection. + * <p> + * If the bundle is already associated with this region, takes no action and returns normally. + * <p> + * If the bundle is already associated with another region, throws BundleException with exception type + * INVALID_OPERATION. + * <p> + * If the bundle has the same bundle symbolic name and version as a bundle already present in the region or as a + * bundle import specified on a connection to another region, then BundleException with exception type + * DUPLICATE_BUNDLE_ERROR is thrown. + * + * @param bundle the bundle to be associated with this region + * @throws BundleException if the bundle cannot be associated with the region + */ + void addBundle(Bundle bundle) throws BundleException; + + /** + * Associates the given bundle id with this region. If the given bundle id is already associated with this region, + * this is not an error and there is no effect. + * <p> + * This is useful when manipulating offline resolver states and bundle descriptions which do not correspond to + * bundles. + * + * @param bundleId the bundle id to be associated with this region + */ + void addBundle(long bundleId); + + /** + * Installs a bundle and associates the bundle with this region. The bundle's location will have the region name + * prepended to the given location to ensure the location is unique across regions. + * <p> + * If the bundle has the same bundle symbolic name and version as a bundle already present in the region or as a + * bundle import specified on a connection to another region, then BundleException with exception type + * DUPLICATE_BUNDLE_ERROR is thrown. + * + * @param location the bundle location string + * @param input a stream of the bundle's contents or <code>null</code> + * @return the installed Bundle + * @throws BundleException if the install fails + * @see BundleContext#installBundle(String, InputStream) + */ + Bundle installBundle(String location, InputStream input) throws BundleException; + + /** + * Installs a bundle and associates the bundle with this region. The bundle's location will have the region name + * prepended to the given location to ensure the location is unique across regions. + * <p> + * If the bundle has the same bundle symbolic name and version as a bundle already present in the region or as a + * bundle import specified on a connection to another region, then BundleException with exception type + * DUPLICATE_BUNDLE_ERROR is thrown. + * + * + * @param location the bundle location string + * @return the installed Bundle + * @throws BundleException if the install fails + * @see BundleContext#installBundle(String) + */ + Bundle installBundle(String location) throws BundleException; + + /** + * + * Gets the bundle ids of the bundles associated with this region. + * + * @return a set of bundle ids + */ + Set<Long> getBundleIds(); + + /** + * Returns <code>true</code> if and only if the given bundle belongs to this region. + * + * @param bundle a {@link Bundle} + * @return <code>true</code> if the given bundle belongs to this region and <code>false</code> otherwise + */ + boolean contains(Bundle bundle); + + /** + * Returns <code>true</code> if and only if a bundle with the given bundle id belongs to this region. + * + * @param bundleId a bundle id + * @return <code>true</code> if a bundle with the given bundle id belongs to this region and <code>false</code> + * otherwise + */ + boolean contains(long bundleId); + + /** + * Get the bundle in this region with the given symbolic name and version. + * + * @param symbolicName + * @param version + * @return the bundle or <code>null</code> if there is no such bundle + */ + Bundle getBundle(String symbolicName, Version version); + + /** + * Connects this region to the given head region and associates the given {@link RegionFilter} with the connection. + * This region may then, subject to the region filter, see bundles, packages, and services visible in the head + * region. + * <p> + * If the filter allows the same bundle symbolic name and version as a bundle already present in this region or a + * filter connecting this region to a region other than the tail region, then BundleException with exception type + * DUPLICATE_BUNDLE_ERROR is thrown. + * <p> + * If the given source region is already connected to the given tail region, then BundleException with exception + * type UNSUPPORTED_OPERATION is thrown. + * + * @param headRegion the region to connect this region to + * @param filter a {@link RegionFilter} which controls what is visible across the connection + * @throws BundleException if the connection was not created + */ + void connectRegion(Region headRegion, RegionFilter filter) throws BundleException; + + /** + * Removes the given bundle from this region. If the given bundle does not belong to this region, this is not an + * error and there is no effect. + * + * @param bundle the bundle to be removed + */ + void removeBundle(Bundle bundle); + + /** + * Removes the given bundle id from this region. If the given bundle id is not associated with this region, this is + * not an error and there is no effect. + * + * @param bundleId the bundle id to be removed + */ + void removeBundle(long bundleId); + + /** + * Gets a {@link Set} containing a snapshot of the {@link FilteredRegion FilteredRegions} attached to this tail + * region. + * + * @return a {@link Set} of {@link FilteredRegion FilteredRegions} of head regions and region filters + */ + Set<FilteredRegion> getEdges(); + + /** + * Visit the subgraph connected to this region. + * + * @param visitor a {@link RegionDigraphVisitor} to be called as the subgraph is navigated + */ + void visitSubgraph(RegionDigraphVisitor visitor); + +} diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/RegionDigraph.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/RegionDigraph.java new file mode 100644 index 000000000..f372f2f80 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/RegionDigraph.java @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright (c) 2011 VMware Inc. + * 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: + * SpringSource, a division of VMware - initial API and implementation and/or initial documentation + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region; + +import java.util.Set; + +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleException; + +/** + * {@link RegionDigraph} is a <a href="http://en.wikipedia.org/wiki/Directed_graph">directed graph</a>, or + * <i>digraph</i>, of {@link Region Regions}. The regions form the nodes of the graph and the edges connect regions to + * other regions. + * <p> + * Each edge (r, s) of the digraph is directed from region r, known as the <i>tail</i> of the edge, to region s, known + * as the <i>head</i> of the edge. + * <p> + * Each edge is associated with a {@link RegionFilter}, making the digraph a <i>labelled</i> digraph. The region filter + * for edge (r, s) allows region r to see certain bundles, packages, and services visible in region s. + * <p> + * Although the digraph may contain cycles it does not contain any <i>loops</i> which are edges of the form (r, r) for + * some region r. Loopless digraphs are known as <i>simple</i> digraphs. So the digraph is a simple, labelled digraph. + * <p> + * The region digraph extends <code>Iterable<Region></code> and so a foreach statement may be used to iterate over (a + * snapshot of) the regions in the digraph, e.g. + * + * <pre> + * for (Region r : regionDigraph) { + * ... + * } + * </pre> + * <p> + * <strong>Concurrent Semantics</strong><br /> + * + * Implementations of this interface must be thread safe. + * + */ +public interface RegionDigraph extends Iterable<Region> { + public interface FilteredRegion { + + Region getRegion(); + + RegionFilter getFilter(); + } + + /** + * Create a {@link Region} with the given name. If a region with the given name already exists, then BundleException + * with exception type UNSUPPORTED_OPERATION is thrown. + * + * @param regionName the name of the region + * @return the {@link Region} created + * @throws BundleException if the region was not created + */ + Region createRegion(String regionName) throws BundleException; + + /** + * Create a {@link RegionFilterBuilder} instance. + * + * @return a region filter builder + */ + RegionFilterBuilder createRegionFilterBuilder(); + + /** + * Removes the given {@link Region} from the digraph along with any edges which have the given region as head or + * tail. If the given region is not present in the digraph, this is not an error and there is no effect. + * + * @param region the {@link Region} to be removed + */ + void removeRegion(Region region); + + /** + * Gets all the {@link Region Regions} in the digraph. + * + * @return a set of {@link Region Regions} + */ + Set<Region> getRegions(); + + /** + * Gets the {@link Region} in the digraph with the given name. + * + * @param regionName the name of the region + * @return the {@link Region} or <code>null</code> if no such region is present in the digraph + */ + Region getRegion(String regionName); + + /** + * Gets the {@link Region} in the digraph containing the given bundle. + * + * @param bundle the bundle to search for + * @return the {@link Region} which contains the given bundle or <code>null</code> if there is no such region + */ + Region getRegion(Bundle bundle); + + /** + * Gets the {@link Region} in the digraph containing a bundle with the given bundle id. + * + * @param bundleId the bundleId of the bundle to search for + * @return the {@link Region} which contains a bundle with the given bundle or <code>null</code> if there is no such + * region + */ + Region getRegion(long bundleId); + + /** + * Connects a given tail region to a given head region via an edge labelled with the given {@link RegionFilter}. The + * tail region may then, subject to the region filter, see bundles, packages, and services visible in the head + * region. + * <p> + * The given head and tail regions are added to the digraph if they are not already present. + * <p> + * If the given tail region is already connected to the given head region, then BundleException with exception type + * UNSUPPORTED_OPERATION is thrown. + * <p> + * If the given head and the given tail are identical, then BundleException with exception type + * UNSUPPORTED_OPERATION is thrown. + * + * @param tailRegion the region at the tail of the new edge + * @param filter a {@link RegionFilter} which labels the new edge + * @param headRegion the region at the head of the new edge + * @throws BundleException if the edge was not created + */ + void connect(Region tailRegion, RegionFilter filter, Region headRegion) throws BundleException; + + /** + * Gets a {@link Set} containing a snapshot of the {@link FilteredRegion FilteredRegions} attached to the given tail + * region. + * + * @param tailRegion the tail region whose edges are gotten + * @return a {@link Set} of {@link FilteredRegion FilteredRegions} of head regions and region filters + */ + Set<FilteredRegion> getEdges(Region tailRegion); + + /** + * Visit the subgraph connected to the given region. + * + * @param startingRegion the region at which to start + * @param visitor a {@link RegionDigraphVisitor} to be called as the subgraph is navigated + */ + void visitSubgraph(Region startingRegion, RegionDigraphVisitor visitor); + + /** + * Gets a {@link RegionDigraphPersistence} object which can be used to save and load a {@link RegionDigraph} to and + * from persistent storage. + * + * @return a {@link RegionDigraphPersistence} object. + */ + RegionDigraphPersistence getRegionDigraphPersistence(); +} diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/RegionDigraphPersistence.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/RegionDigraphPersistence.java new file mode 100644 index 000000000..d9cd78894 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/RegionDigraphPersistence.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2011 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.virgo.kernel.osgi.region; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * A region digraph persistence is used to persist the state of a {@link RegionDigraph}. + * <p /> + * <strong>Concurrent Semantics</strong><br /> + * + * Implementations of this interface must be thread safe. + */ +public interface RegionDigraphPersistence { + + /** + * Creates a new digraph and reads the content of the digraph from the provided input. The provided input must have + * been persisted using the {@link #save(RegionDigraph, OutputStream)} method. + * <p /> + * Note that the returned digraph is disconnected from the OSGi runtime. Any modifications made to the returned + * digraph will not affect the OSGi runtime behavior of the bundles installed in the running framework. + * <p /> + * The specified stream remains open after this method returns. + * + * @param input an input stream to read a digraph from. + * @return the new digraph + * @throws IOException if error occurs reading the digraph. + * @throws IllegalArgumentException if the input stream is not a digraph or has an incompatible persistent version + */ + RegionDigraph load(InputStream input) throws IOException; + + /** + * Writes the specified {@link RegionDigraph} to the provided output in a form suitable for using the + * {@link #load(InputStream)} method. + * <p /> + * After the digraph has been written, the output stream is flushed. The output stream remains open after this + * method returns. + * + * @param digraph a digraph to be written. + * @param output an output stream to write a digraph to. + * @throws IOException if error occurs writing the digraph. + */ + void save(RegionDigraph digraph, OutputStream output) throws IOException; +} diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/RegionDigraphVisitor.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/RegionDigraphVisitor.java new file mode 100644 index 000000000..c4f737123 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/RegionDigraphVisitor.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2011 VMware Inc. + * 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: + * SpringSource, a division of VMware - initial API and implementation and/or initial documentation + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region; + +/** + * {@link RegionDigraphVisitor} is used to traverse a subgraph of a {@link RegionDigraph}. + * <p /> + * + * <strong>Concurrent Semantics</strong><br /> + * + * Implementations of this interface must be thread safe. + */ +public interface RegionDigraphVisitor { + + /** + * Visits the given region and determines whether or not to continue traversing. + * + * @param region the region to visit + * @return <code>true</code> if the traversal is to continue and <code>false</code> otherwise + */ + boolean visit(Region region); + + /** + * Prepares to traverse an edge with the given {@link RegionFilter} and determines whether or not to traverse the + * edge. + * + * @param regionFilter the {@link RegionFilter} of the edge to be traversed + * @return <code>true</code> if the edge is to be traversed and <code>false</code> otherwise + */ + boolean preEdgeTraverse(RegionFilter regionFilter); + + /** + * This is called after traversing an edge with the given {@link RegionFilter}. + * + * @param regionFilter the {@link RegionFilter} of the edge that has just been traversed + */ + void postEdgeTraverse(RegionFilter regionFilter); + +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/RegionFilter.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/RegionFilter.java new file mode 100644 index 000000000..49fc43cd2 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/RegionFilter.java @@ -0,0 +1,118 @@ +/******************************************************************************* + * Copyright (c) 2010 VMware Inc. + * 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: + * SpringSource, a division of VMware - initial API and implementation and/or initial documentation + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region; + +import java.util.Collection; +import java.util.Map; + +import org.osgi.framework.Bundle; +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.wiring.BundleCapability; +import org.osgi.framework.wiring.BundleRevision; + +/** + * A {@link RegionFilter} is associated with a connection from one region to another and determines the bundles, + * packages, services and other capabilities which are visible across the connection. A region filter is constant; its + * sharing policy cannot be changed after construction. Instances of region filters can be created with a + * {@link RegionFilterBuilder}. + * <p /> + * + * <strong>Concurrent Semantics</strong><br /> + * + * Implementations must be thread safe. + * + */ +public interface RegionFilter { + + /** + * Name space for sharing package capabilities. + * + * @see BundleRevision#PACKAGE_NAMESPACE + */ + public static final String VISIBLE_PACKAGE_NAMESPACE = BundleRevision.PACKAGE_NAMESPACE; + + /** + * Name space for sharing bundle capabilities for require bundle constraints. + * + * @see BundleRevision#BUNDLE_NAMESPACE + */ + public static final String VISIBLE_REQUIRE_NAMESPACE = BundleRevision.BUNDLE_NAMESPACE; + + /** + * Name space for sharing host capabilities. + * + * @see BundleRevision#HOST_NAMESPACE + */ + public static final String VISIBLE_HOST_NAMESPACE = BundleRevision.HOST_NAMESPACE; + + /** + * Name space for sharing services. The filters specified in this name space will be used to match + * {@link ServiceReference services}. + */ + public static final String VISIBLE_SERVICE_NAMESPACE = "org.eclipse.equinox.allow.service"; + + /** + * Name space for sharing bundles. The filters specified in this name space will be use to match against a bundle's + * symbolic name and version. The attribute {@link Constants#BUNDLE_SYMBOLICNAME_ATTRIBUTE bundle-symbolic-name} is + * used for the symbolic name and the attribute {@link Constants#BUNDLE_VERSION_ATTRIBUTE bundle-version} is used + * for the bundle version. + */ + public static final String VISIBLE_BUNDLE_NAMESPACE = "org.eclipse.equinox.allow.bundle"; + + /** + * Name space for matching against all capabilities. The filters specified in this name space will be used to match + * all capabilities. + */ + public static final String VISIBLE_ALL_NAMESPACE = "org.eclipse.equinox.allow.all"; + + /** + * Determines whether this filter allows the given bundle + * + * @param bundle the bundle + * @return <code>true</code> if the bundle is allowed and <code>false</code>otherwise + */ + public boolean isAllowed(Bundle bundle); + + /** + * Determines whether this filter allows the given bundle + * + * @param bundle the bundle revision + * @return <code>true</code> if the bundle is allowed and <code>false</code>otherwise + */ + public boolean isAllowed(BundleRevision bundle); + + /** + * Determines whether this filter allows the given service reference. + * + * @param service the service reference of the service + * @return <code>true</code> if the service is allowed and <code>false</code>otherwise + */ + public boolean isAllowed(ServiceReference<?> service); + + /** + * Determines whether this filter allows the given capability. + * + * @param capability the bundle capability + * @return <code>true</code> if the capability is allowed and <code>false</code>otherwise + */ + public boolean isAllowed(BundleCapability capability); + + /** + * Returns a map of the filters used by each name space for this region filter. The may key is the name space and + * the value is a collection of filters for the name space. The returned map is a snapshot of the sharing policy. + * Changes made to the returned map have no affect on this region filter. + * + * @return a map containing the sharing policy used by this region filter + */ + public Map<String, Collection<String>> getSharingPolicy(); +} diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/RegionFilterBuilder.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/RegionFilterBuilder.java new file mode 100644 index 000000000..6b95fea90 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/RegionFilterBuilder.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2011 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.virgo.kernel.osgi.region; + +import org.osgi.framework.InvalidSyntaxException; + +/** + * A builder for creating {@link RegionFilter} instances. A builder instance can be obtained from the + * {@link RegionDigraph#createRegionFilterBuilder()} method. + * <p /> + * <strong>Concurrent Semantics</strong><br /> + * + * Implementations of this interface must be thread safe. + */ +public interface RegionFilterBuilder { + + /** + * Allow capabilities with the given name space matching the given filter. + * + * @param namespace the name space of the capabilities to be allowed + * @param filter the filter matching the capabilities to be allowed + * @return this builder (for method chaining) + */ + RegionFilterBuilder allow(String namespace, String filter) throws InvalidSyntaxException; + + /** + * Allow all capabilities with the given name space. + * + * @param namespace the name space of the capabilities to be allowed + * @return this builder (for method chaining) + */ + RegionFilterBuilder allowAll(String namespace); + + /** + * Build a {@link RegionFilter} from the current state of this builder. + * + * @return the {@link RegionFilter} built + */ + RegionFilter build(); +} diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionBundleEventHook.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionBundleEventHook.java new file mode 100644 index 000000000..a1f4c36e9 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionBundleEventHook.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * Copyright (c) 2011 VMware Inc. + * 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: + * VMware Inc. - initial contribution + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region.hook; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; + +import org.eclipse.virgo.kernel.osgi.region.Region; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraph; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleEvent; +import org.osgi.framework.BundleException; +import org.osgi.framework.hooks.bundle.EventHook; +import org.osgi.framework.hooks.bundle.FindHook; + +/** + * {@link RegionBundleEventHook} manages the visibility of bundle events across regions according to the + * {@link RegionDigraph}. + * <p> + * The current implementation delegates to {@link RegionBundleFindHook}. This is likely to perform adequately because of + * the low frequency of bundle events and the typically small number of bundle listeners. + * <p /> + * + * <strong>Concurrent Semantics</strong><br /> + * Thread safe. + */ +public final class RegionBundleEventHook implements EventHook { + + private final RegionDigraph regionDigraph; + + private final FindHook bundleFindHook; + + private final ThreadLocal<Region> threadLocal; + + public RegionBundleEventHook(RegionDigraph regionDigraph, FindHook bundleFindBook, ThreadLocal<Region> threadLocal) { + this.regionDigraph = regionDigraph; + this.bundleFindHook = bundleFindBook; + this.threadLocal = threadLocal; + } + + /** + * {@inheritDoc} + */ + @Override + public void event(BundleEvent event, Collection<BundleContext> contexts) { + Bundle eventBundle = event.getBundle(); + if (event.getType() == BundleEvent.INSTALLED) { + bundleInstalled(eventBundle, event.getOrigin()); + } + Iterator<BundleContext> i = contexts.iterator(); + while (i.hasNext()) { + if (!find(i.next(), eventBundle)) { + i.remove(); + } + } + if (event.getType() == BundleEvent.UNINSTALLED) { + bundleUninstalled(eventBundle); + } + } + + private boolean find(BundleContext finderBundleContext, Bundle candidateBundle) { + Collection<Bundle> candidates = new ArrayList<Bundle>(1); + candidates.add(candidateBundle); + this.bundleFindHook.find(finderBundleContext, candidates); + return !candidates.isEmpty(); + } + + private void bundleInstalled(Bundle eventBundle, Bundle originBundle) { + /* + * BundleIdBasedRegion sets thread local to install bundles into arbitrary regions. If this is not set, the + * bundle inherits the region of the origin bundle. + */ + Region installRegion = this.threadLocal.get(); + if (installRegion != null) { + try { + installRegion.addBundle(eventBundle); + } catch (BundleException e) { + e.printStackTrace(); + throw new RuntimeException("Bundle could not be added to region", e); + } + } else { + Region originRegion = this.regionDigraph.getRegion(originBundle); + if (originRegion != null) { + try { + originRegion.addBundle(eventBundle); + } catch (BundleException e) { + e.printStackTrace(); + throw new RuntimeException("Bundle could not be added to region", e); + } + } + } + } + + private void bundleUninstalled(Bundle eventBundle) { + Region region = this.regionDigraph.getRegion(eventBundle); + if (region != null) { + region.removeBundle(eventBundle); + } + } + +} diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionBundleFindHook.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionBundleFindHook.java new file mode 100644 index 000000000..58177a955 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionBundleFindHook.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright (c) 2011 VMware Inc. + * 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: + * VMware Inc. - initial contribution + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region.hook; + +import java.util.Collection; +import org.eclipse.virgo.kernel.osgi.region.*; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.hooks.bundle.FindHook; + +/** + * {@link RegionBundleFindHook} manages the visibility of bundles across regions according to the {@link RegionDigraph}. + * <p /> + * + * <strong>Concurrent Semantics</strong><br /> + * Thread safe. + */ +public final class RegionBundleFindHook implements FindHook { + + private final RegionDigraph regionDigraph; + + private final long hookImplID; + + public RegionBundleFindHook(RegionDigraph regionDigraph, long hookImplID) { + this.regionDigraph = regionDigraph; + this.hookImplID = hookImplID; + } + + /** + * {@inheritDoc} + */ + @Override + public void find(BundleContext context, Collection<Bundle> bundles) { + long bundleID = context.getBundle().getBundleId(); + + if (bundleID == 0 || bundleID == hookImplID) { + // The system bundle and the hook impl bundle can see all bundles + return; + } + + Region finderRegion = getRegion(context); + if (finderRegion == null) { + bundles.clear(); + return; + } + + Visitor visitor = new Visitor(bundles); + finderRegion.visitSubgraph(visitor); + Collection<Bundle> allowed = visitor.getAllowed(); + + bundles.retainAll(allowed); + } + + private class Visitor extends RegionDigraphVisitorBase<Bundle> { + + private Visitor(Collection<Bundle> candidates) { + super(candidates); + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean contains(Region region, Bundle candidate) { + return region.contains(candidate); + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean isAllowed(Bundle candidate, RegionFilter filter) { + return filter.isAllowed(candidate); + } + + } + + private Region getRegion(BundleContext context) { + return this.regionDigraph.getRegion(context.getBundle()); + } +} diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionDigraphVisitorBase.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionDigraphVisitorBase.java new file mode 100644 index 000000000..92e232194 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionDigraphVisitorBase.java @@ -0,0 +1,165 @@ +/******************************************************************************* + * Copyright (c) 2011 VMware Inc. + * 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: + * SpringSource, a division of VMware - initial API and implementation and/or initial documentation + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region.hook; + +import java.util.*; +import org.eclipse.virgo.kernel.osgi.region.*; + +/** + * {@link RegionDigraphVisitorBase} is an abstract base class for {@link RegionDigraphVisitor} implementations in the + * framework hooks. + * <p /> + * + * <strong>Concurrent Semantics</strong><br /> + * This class is thread safe. + */ +abstract class RegionDigraphVisitorBase<C> implements RegionDigraphVisitor { + + private final Collection<C> allCandidates; + + private final Stack<Set<C>> allowedStack = new Stack<Set<C>>(); + private final Stack<Collection<C>> filteredStack = new Stack<Collection<C>>(); + + private Object monitor = new Object(); + + private Set<C> allowed; + + protected RegionDigraphVisitorBase(Collection<C> candidates) { + this.allCandidates = candidates; + synchronized (this.monitor) { + this.allowed = new HashSet<C>(); + } + } + + Collection<C> getAllowed() { + synchronized (this.monitor) { + return this.allowed; + } + } + + private void allow(C candidate) { + synchronized (this.monitor) { + this.allowed.add(candidate); + } + } + + private void allow(Collection<C> candidates) { + synchronized (this.monitor) { + this.allowed.addAll(candidates); + } + } + + private void pushAllowed() { + synchronized (this.monitor) { + this.allowedStack.push(this.allowed); + this.allowed = new HashSet<C>(); + } + } + + private Collection<C> popAllowed() { + synchronized (this.monitor) { + Collection<C> a = this.allowed; + this.allowed = this.allowedStack.pop(); + return a; + } + } + + private void pushFiltered(Collection<C> filtered) { + synchronized (this.monitor) { + this.filteredStack.push(filtered); + } + } + + private Collection<C> popFiltered() { + synchronized (this.monitor) { + return this.filteredStack.isEmpty() ? allCandidates : this.filteredStack.pop(); + } + } + + private Collection<C> peekFiltered() { + synchronized (this.monitor) { + return this.filteredStack.isEmpty() ? allCandidates : this.filteredStack.peek(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean visit(Region region) { + Collection<C> candidates = peekFiltered(); + for (C candidate : candidates) { + if (contains(region, candidate)) { + allow(candidate); + } + } + return true; + } + + /** + * Determines whether the given region contains the given candidate. + * + * @param region the {@link Region} + * @param candidate the candidate + * @return <code>true</code> if and only if the given region contains the given candidate + */ + protected abstract boolean contains(Region region, C candidate); + + /** + * {@inheritDoc} + */ + @Override + public boolean preEdgeTraverse(RegionFilter regionFilter) { + // Find the candidates filtered by the previous edge + Collection<C> candidates = new ArrayList<C>(peekFiltered()); + // remove any candidates contained in the current region + candidates.removeAll(allowed); + // apply the filter across remaining candidates + filter(candidates, regionFilter); + if (candidates.isEmpty()) + return false; // this filter does not apply; avoid traversing this edge + // push the filtered candidates for the next region + pushFiltered(candidates); + // push the allowed + pushAllowed(); + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public void postEdgeTraverse(RegionFilter regionFilter) { + popFiltered(); + Collection<C> candidates = popAllowed(); + allow(candidates); + } + + private void filter(Collection<C> candidates, RegionFilter filter) { + Iterator<C> i = candidates.iterator(); + while (i.hasNext()) { + C candidate = i.next(); + if (!isAllowed(candidate, filter)) { + i.remove(); + } + } + } + + /** + * Determines whether the given candidate is allowed by the given {@link RegionFilter}. + * + * @param candidate the candidate + * @param filter the filter + * @return <code>true</code> if and only if the given candidate is allowed by the given filter + */ + protected abstract boolean isAllowed(C candidate, RegionFilter filter); +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionResolverHook.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionResolverHook.java new file mode 100644 index 000000000..849ae6af3 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionResolverHook.java @@ -0,0 +1,174 @@ +/******************************************************************************* + * Copyright (c) 2011 VMware Inc. + * 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: + * VMware Inc. - initial contribution + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region.hook; + +import java.util.Collection; +import java.util.Iterator; +import org.eclipse.osgi.service.resolver.BundleDescription; +import org.eclipse.virgo.kernel.osgi.region.*; +import org.osgi.framework.Bundle; +import org.osgi.framework.hooks.resolver.ResolverHook; +import org.osgi.framework.wiring.*; + +/** + * {@link RegionResolverHook} manages the visibility of bundles across regions according to the {@link RegionDigraph}. + * <p /> + * + * <strong>Concurrent Semantics</strong><br /> + * Thread safe. + */ +final class RegionResolverHook implements ResolverHook { + + private static final Boolean DEBUG = false; + + private final RegionDigraph regionDigraph; + + RegionResolverHook(RegionDigraph regionDigraph) { + this.regionDigraph = regionDigraph; + } + + @Override + public void filterMatches(BundleRequirement requirement, Collection<BundleCapability> candidates) { + BundleRevision requirer = requirement.getRevision(); + try { + if (DEBUG) { + debugEntry(requirer, candidates); + } + + if (getBundleId(requirer) == 0L) { + return; + } + + Region requirerRegion = getRegion(requirer); + if (requirerRegion == null) { + candidates.clear(); + return; + } + + Visitor visitor = new Visitor(candidates); + requirerRegion.visitSubgraph(visitor); + Collection<BundleCapability> allowed = visitor.getAllowed(); + + candidates.retainAll(allowed); + } finally { + if (DEBUG) { + debugExit(requirer, candidates); + } + } + } + + private class Visitor extends RegionDigraphVisitorBase<BundleCapability> { + + private Visitor(Collection<BundleCapability> candidates) { + super(candidates); + } + + @Override + protected boolean contains(Region region, BundleCapability candidate) { + return region.equals(getRegion(candidate.getRevision())); + } + + @Override + protected boolean isAllowed(BundleCapability candidate, RegionFilter filter) { + return filter.isAllowed(candidate) || filter.isAllowed(candidate.getRevision()); + } + + } + + private Region getRegion(BundleRevision bundleRevision) { + Bundle bundle = bundleRevision.getBundle(); + if (bundle != null) { + return getRegion(bundle); + } + Long bundleId = getBundleId(bundleRevision); + return getRegion(bundleId); + } + + private Region getRegion(Long bundleId) { + return this.regionDigraph.getRegion(bundleId); + } + + private Long getBundleId(BundleRevision bundleRevision) { + // For testability, use the bundle revision's bundle before casting to ResolverBundle. + Bundle bundle = bundleRevision.getBundle(); + if (bundle != null) { + return bundle.getBundleId(); + } + if (bundleRevision instanceof BundleDescription) { + BundleDescription bundleDescription = (BundleDescription) bundleRevision; + return bundleDescription.getBundleId(); + } + throw new RuntimeException(String.format("Cannot determine bundle id of BundleRevision '%s'", bundleRevision)); + } + + private Region getRegion(Bundle bundle) { + return this.regionDigraph.getRegion(bundle); + } + + @Override + public void end() { + } + + @Override + public void filterResolvable(Collection<BundleRevision> candidates) { + } + + @Override + public void filterSingletonCollisions(BundleCapability singleton, Collection<BundleCapability> collisionCandidates) { + collisionCandidates.clear(); // XXX temporary hack in lieu of Borislav's changes + } + + private void debugEntry(BundleRevision requirer, Collection<BundleCapability> candidates) { + System.out.println("Requirer: " + requirer.getSymbolicName() + "_" + requirer.getVersion() + "[" + getBundleId(requirer) + "]"); + System.out.println(" Candidates: "); + Iterator<BundleCapability> i = candidates.iterator(); + while (i.hasNext()) { + BundleCapability c = i.next(); + String namespace = c.getNamespace(); + if (BundleRevision.PACKAGE_NAMESPACE.equals(namespace)) { + BundleRevision providerRevision = c.getRevision(); + String pkg = (String) c.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE); + System.out.println(" Package " + pkg + " from provider " + providerRevision.getSymbolicName() + "_" + + providerRevision.getVersion() + "[" + getBundleId(providerRevision) + "]"); + if (pkg.equals("slow")) { + System.out.println(">>> put breakpoint here <<<"); + } + } else { + BundleRevision providerRevision = c.getRevision(); + System.out.println(" Bundle from provider " + providerRevision.getSymbolicName() + "_" + providerRevision.getVersion() + "[" + + getBundleId(providerRevision) + "]"); + } + } + } + + private void debugExit(BundleRevision requirer, Collection<BundleCapability> candidates) { + System.out.println(" Filtered candidates: "); + Iterator<BundleCapability> i = candidates.iterator(); + while (i.hasNext()) { + BundleCapability c = i.next(); + String namespace = c.getNamespace(); + if (BundleRevision.PACKAGE_NAMESPACE.equals(namespace)) { + BundleRevision providerRevision = c.getRevision(); + String pkg = (String) c.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE); + System.out.println(" Package " + pkg + " from provider " + providerRevision.getSymbolicName() + "_" + + providerRevision.getVersion() + "[" + getBundleId(providerRevision) + "]"); + if (pkg.equals("slow")) { + System.out.println(">>> put breakpoint here <<<"); + } + } else { + BundleRevision providerRevision = c.getRevision(); + System.out.println(" Bundle from provider " + providerRevision.getSymbolicName() + "_" + providerRevision.getVersion() + "[" + + getBundleId(providerRevision) + "]"); + } + } + } +} diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionResolverHookFactory.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionResolverHookFactory.java new file mode 100644 index 000000000..1f48babb5 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionResolverHookFactory.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2010 VMware Inc. + * 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: + * SpringSource, a division of VMware - initial API and implementation and/or initial documentation + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region.hook; + +import java.util.Collection; + +import org.eclipse.virgo.kernel.osgi.region.RegionDigraph; +import org.osgi.framework.hooks.resolver.ResolverHook; +import org.osgi.framework.hooks.resolver.ResolverHookFactory; +import org.osgi.framework.wiring.BundleRevision; + +/** + * {@link RegionResolverHook} constructs an instance of {@link RegionResolverHook} for a particular resolution + * operation. + * <p /> + * + * <strong>Concurrent Semantics</strong><br /> + * + * Thread safe. + */ +public final class RegionResolverHookFactory implements ResolverHookFactory { + + private final RegionDigraph regionDigraph; + + public RegionResolverHookFactory(RegionDigraph regionDigraph) { + this.regionDigraph = regionDigraph; + } + + public ResolverHook begin(Collection<BundleRevision> triggers) { + return new RegionResolverHook(this.regionDigraph); + } + +} diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionServiceEventHook.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionServiceEventHook.java new file mode 100644 index 000000000..17b869144 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionServiceEventHook.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2011 VMware Inc. + * 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: + * VMware Inc. - initial contribution + *******************************************************************************/ + + +package org.eclipse.virgo.kernel.osgi.region.hook; + +import java.util.*; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraph; +import org.osgi.framework.*; +import org.osgi.framework.hooks.service.EventHook; +import org.osgi.framework.hooks.service.FindHook; + +/** + * {@link RegionServiceEventHook} manages the visibility of service events across regions according to the + * {@link RegionDigraph}. + * <p> + * The current implementation delegates to {@link RegionServiceFindHook}. This is likely to perform adequately because + * of the relatively low frequency (compared to service lookups) of service events and the typically small number of + * service listeners. + * <p /> + * + * <strong>Concurrent Semantics</strong><br /> + * Thread safe. + */ +@SuppressWarnings("deprecation") +public final class RegionServiceEventHook implements EventHook { + + private final FindHook serviceFindHook; + + public RegionServiceEventHook(FindHook bundleFindBook) { + this.serviceFindHook = bundleFindBook; + } + + /** + * {@inheritDoc} + */ + public void event(ServiceEvent event, Collection<BundleContext> contexts) { + ServiceReference<?> eventBundle = event.getServiceReference(); + Iterator<BundleContext> i = contexts.iterator(); + while (i.hasNext()) { + if (!find(i.next(), eventBundle)) { + i.remove(); + } + } + } + + private boolean find(BundleContext finderBundleContext, ServiceReference<?> candidateServiceReference) { + Collection<ServiceReference<?>> candidates = new ArrayList<ServiceReference<?>>(); + candidates.add(candidateServiceReference); + this.serviceFindHook.find(finderBundleContext, "", "", false, candidates); + return !candidates.isEmpty(); + } + +} diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionServiceFindHook.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionServiceFindHook.java new file mode 100644 index 000000000..8f5b939b9 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionServiceFindHook.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2011 VMware Inc. + * 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: + * VMware Inc. - initial contribution + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region.hook; + +import java.util.Collection; +import org.eclipse.virgo.kernel.osgi.region.*; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.hooks.service.FindHook; + +/** + * {@link RegionServiceFindHook} manages the visibility of services across regions according to the + * {@link RegionDigraph}. + * <p /> + * + * <strong>Concurrent Semantics</strong><br /> + * Thread safe. + */ +public final class RegionServiceFindHook implements FindHook { + + private final RegionDigraph regionDigraph; + + public RegionServiceFindHook(RegionDigraph regionDigraph) { + this.regionDigraph = regionDigraph; + } + + /** + * {@inheritDoc} + */ + public void find(BundleContext context, String name, String filter, boolean allServices, Collection<ServiceReference<?>> references) { + if (context.getBundle().getBundleId() == 0L) { + return; + } + + Region finderRegion = getRegion(context); + if (finderRegion == null) { + references.clear(); + return; + } + + Visitor visitor = new Visitor(references); + finderRegion.visitSubgraph(visitor); + Collection<ServiceReference<?>> allowed = visitor.getAllowed(); + + references.retainAll(allowed); + } + + private class Visitor extends RegionDigraphVisitorBase<ServiceReference<?>> { + + private Visitor(Collection<ServiceReference<?>> candidates) { + super(candidates); + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean contains(Region region, ServiceReference<?> candidate) { + return region.contains(candidate.getBundle()); + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean isAllowed(ServiceReference<?> candidate, RegionFilter filter) { + return filter.isAllowed(candidate) || filter.isAllowed(candidate.getBundle()); + } + + } + + private Region getRegion(BundleContext context) { + return this.regionDigraph.getRegion(context.getBundle()); + } + +} diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/BundleIdBasedRegion.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/BundleIdBasedRegion.java new file mode 100644 index 000000000..455a4bb11 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/BundleIdBasedRegion.java @@ -0,0 +1,280 @@ +/******************************************************************************* + * Copyright (c) 2011 VMware Inc. + * 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: + * VMware Inc. - initial contribution + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region.internal; + +import java.util.concurrent.ConcurrentHashMap; + +import java.util.concurrent.ConcurrentMap; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.virgo.kernel.osgi.region.Region; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraph; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraph.FilteredRegion; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraphVisitor; +import org.eclipse.virgo.kernel.osgi.region.RegionFilter; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; +import org.osgi.framework.Version; + +/** + * {@link BundleIdBasedRegion} is an implementation of {@link Region} which keeps a track of the bundles in the region + * by recording their bundle identifiers. + * <p /> + * + * <strong>Concurrent Semantics</strong><br /> + * Thread safe. + */ +final class BundleIdBasedRegion implements Region { + + private static final String REGION_LOCATION_DELIMITER = "@"; + + private static final String REFERENCE_SCHEME = "reference:"; + + private static final String FILE_SCHEME = "file:"; + + // A concurrent data structure ensures the contains method does not need synchronisation. + private final ConcurrentMap<Long, Boolean> bundleIds = new ConcurrentHashMap<Long, Boolean>(); + + // Updates do need synchronising to avoid races. + private final Object updateMonitor = new Object(); + + private final String regionName; + + private final RegionDigraph regionDigraph; + + private final BundleContext bundleContext; + + private final ThreadLocal<Region> threadLocal; + + BundleIdBasedRegion(String regionName, RegionDigraph regionDigraph, BundleContext bundleContext, ThreadLocal<Region> threadLocal) { + if (regionName == null) + throw new IllegalArgumentException("The region name must not be null"); + if (regionDigraph == null) + throw new IllegalArgumentException("The region digraph must not be null"); + this.regionName = regionName; + this.regionDigraph = regionDigraph; + this.bundleContext = bundleContext; + this.threadLocal = threadLocal; + } + + /** + * {@inheritDoc} + */ + public String getName() { + return this.regionName; + } + + /** + * {@inheritDoc} + */ + public void addBundle(Bundle bundle) throws BundleException { + synchronized (this.updateMonitor) { + checkBundleNotAssociatedWithAnotherRegion(bundle); + + this.bundleIds.putIfAbsent(bundle.getBundleId(), Boolean.TRUE); + } + } + + private void checkBundleNotAssociatedWithAnotherRegion(Bundle bundle) throws BundleException { + for (Region r : this.regionDigraph) { + if (!this.equals(r) && r.contains(bundle)) { + throw new BundleException("Bundle '" + bundle + "' is already associated with region '" + r + "'", BundleException.INVALID_OPERATION); + } + } + } + + /** + * {@inheritDoc} + */ + public void addBundle(long bundleId) { + synchronized (this.updateMonitor) { + this.bundleIds.putIfAbsent(bundleId, Boolean.TRUE); + } + } + + /** + * {@inheritDoc} + */ + public Bundle installBundle(String location, InputStream input) throws BundleException { + if (this.bundleContext == null) + throw new BundleException("This region is not connected to an OSGi Framework.", BundleException.INVALID_OPERATION); + setRegionThreadLocal(); + try { + return this.bundleContext.installBundle(this.regionName + REGION_LOCATION_DELIMITER + location, input); + } finally { + removeRegionThreadLocal(); + } + } + + /** + * {@inheritDoc} + */ + public Bundle installBundle(String location) throws BundleException { + if (this.bundleContext == null) + throw new BundleException("This region is not connected to an OSGi Framework.", BundleException.INVALID_OPERATION); + setRegionThreadLocal(); + try { + return this.bundleContext.installBundle(this.regionName + REGION_LOCATION_DELIMITER + location, openBundleStream(location)); + } finally { + removeRegionThreadLocal(); + } + } + + private void setRegionThreadLocal() { + if (this.threadLocal != null) + this.threadLocal.set(this); + } + + private void removeRegionThreadLocal() { + if (this.threadLocal != null) + this.threadLocal.remove(); + } + + private InputStream openBundleStream(String location) throws BundleException { + String absoluteBundleReferenceUriString; + if (location.startsWith(REFERENCE_SCHEME)) + absoluteBundleReferenceUriString = location; + else + absoluteBundleReferenceUriString = REFERENCE_SCHEME + getAbsoluteUriString(location); + + try { + // Use the reference: scheme to obtain an InputStream for either a file or a directory. + return new URL(absoluteBundleReferenceUriString).openStream(); + + } catch (MalformedURLException e) { + throw new BundleException("Location '" + location + "' resulted in an invalid bundle URI '" + absoluteBundleReferenceUriString + "'", e); + } catch (IOException e) { + throw new BundleException("Location '" + location + "' referred to an invalid bundle at URI '" + absoluteBundleReferenceUriString + "'", e); + } + } + + private String getAbsoluteUriString(String location) throws BundleException { + if (!location.startsWith(FILE_SCHEME)) { + throw new BundleException("Cannot install from location '" + location + "' which did not start with '" + FILE_SCHEME + "'"); + } + + String filePath = location.substring(FILE_SCHEME.length()); + + return FILE_SCHEME + new File(filePath).getAbsolutePath(); + } + + /** + * {@inheritDoc} + */ + public Bundle getBundle(String symbolicName, Version version) { + if (bundleContext == null) + return null; // this region is not connected to an OSGi framework + + // The following iteration is weakly consistent and will never throw ConcurrentModificationException. + for (long bundleId : this.bundleIds.keySet()) { + Bundle bundle = bundleContext.getBundle(bundleId); + if (bundle != null && symbolicName.equals(bundle.getSymbolicName()) && version.equals(bundle.getVersion())) { + return bundle; + } + } + return null; + } + + /** + * {@inheritDoc} + */ + public void connectRegion(Region headRegion, RegionFilter filter) throws BundleException { + synchronized (this.updateMonitor) { + this.regionDigraph.connect(this, filter, headRegion); + } + } + + /** + * {@inheritDoc} + */ + public boolean contains(Bundle bundle) { + return this.bundleIds.containsKey(bundle.getBundleId()); + } + + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + this.regionName.hashCode(); + return result; + } + + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof BundleIdBasedRegion)) { + return false; + } + BundleIdBasedRegion other = (BundleIdBasedRegion) obj; + return this.regionName.equals(other.regionName); + } + + /** + * {@inheritDoc} + */ + public boolean contains(long bundleId) { + return this.bundleIds.containsKey(bundleId); + } + + /** + * {@inheritDoc} + */ + public void removeBundle(Bundle bundle) { + removeBundle(bundle.getBundleId()); + + } + + /** + * {@inheritDoc} + */ + public void removeBundle(long bundleId) { + synchronized (this.updateMonitor) { + this.bundleIds.remove(bundleId); + } + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return getName(); + } + + public Set<Long> getBundleIds() { + Set<Long> bundleIds = new HashSet<Long>(); + synchronized (this.updateMonitor) { + bundleIds.addAll(this.bundleIds.keySet()); + } + return bundleIds; + } + + public Set<FilteredRegion> getEdges() { + return this.regionDigraph.getEdges(this); + } + + public void visitSubgraph(RegionDigraphVisitor visitor) { + this.regionDigraph.visitSubgraph(this, visitor); + } + +} diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/RegionLifecycleListener.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/RegionLifecycleListener.java new file mode 100644 index 000000000..c12f0b8d8 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/RegionLifecycleListener.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2011 VMware Inc. + * 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: + * VMware Inc. - initial contribution + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region.internal; + +import org.eclipse.virgo.kernel.osgi.region.Region; + +/** + * {@link RegionLifecycleListener} is a service interface to listen for regions being added to and deleted from the + * region digraph. + * <p /> + * Note that this is an internal interface and is not intended for external use. + * <p /> + * + * <strong>Concurrent Semantics</strong><br /> + * Implementations of this interface must be thread safe. + */ +public interface RegionLifecycleListener { + + /** + * Called after the given region is added to the digraph. + * + * @param region the region which has been added + */ + void regionAdded(Region region); + + /** + * Called before the given region is removed from the digraph. + * + * @param region the region which is about to be removed + */ + void regionRemoving(Region region); + +} diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/RegionManager.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/RegionManager.java new file mode 100644 index 000000000..e94657f15 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/RegionManager.java @@ -0,0 +1,155 @@ +/******************************************************************************* + * Copyright (c) 2008, 2011 VMware Inc. + * 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: + * VMware Inc. - initial contribution + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region.internal; + +import java.io.*; +import java.util.ArrayList; +import java.util.Collection; +import org.eclipse.virgo.kernel.osgi.region.Region; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraph; +import org.eclipse.virgo.kernel.osgi.region.hook.*; +import org.eclipse.virgo.kernel.osgi.region.management.internal.StandardManageableRegionDigraph; +import org.osgi.framework.*; +import org.osgi.framework.hooks.bundle.EventHook; +import org.osgi.framework.hooks.bundle.FindHook; +import org.osgi.framework.hooks.resolver.ResolverHookFactory; + +/** + * Creates and manages the {@link RegionDigraph} associated + * with the running framework. + * <p /> + * + * <strong>Concurrent Semantics</strong><br /> + * + * Threadsafe. + * + */ +public final class RegionManager implements BundleActivator { + + private static final String REGION_KERNEL = "org.eclipse.equinox.region.kernel"; + private static final String REGION_DOMAIN_PROP = "org.eclipse.equinox.region.domain"; + private static final String DIGRAPH_FILE = "digraph"; + + Collection<ServiceRegistration<?>> registrations = new ArrayList<ServiceRegistration<?>>(); + + private BundleContext bundleContext; + + private final ThreadLocal<Region> threadLocal = new ThreadLocal<Region>(); + + private String domain; + + private RegionDigraph digraph; + + public void start(BundleContext bc) throws BundleException, IOException, InvalidSyntaxException { + this.bundleContext = bc; + this.domain = bc.getProperty(REGION_DOMAIN_PROP); + if (this.domain == null) + this.domain = REGION_DOMAIN_PROP; + digraph = loadRegionDigraph(); + registerRegionHooks(digraph); + registerDigraphMbean(digraph); + registerRegionDigraph(digraph); + } + + public void stop(BundleContext bc) throws IOException { + for (ServiceRegistration<?> registration : registrations) + registration.unregister(); + saveDigraph(); + } + + private RegionDigraph loadRegionDigraph() throws BundleException, IOException, InvalidSyntaxException { + File digraphFile = bundleContext.getDataFile(DIGRAPH_FILE); + if (digraphFile == null || !digraphFile.exists()) { + // no persistent digraph available, create a new one + return createRegionDigraph(); + } + FileInputStream in = new FileInputStream(digraphFile); + try { + // TODO need to validate bundle IDs to make sure they are consistent with current bundles + return StandardRegionDigraphPersistence.readRegionDigraph(new DataInputStream(in)); + } finally { + try { + in.close(); + } catch (IOException e) { + // We tried our best to clean up + } + } + } + + private RegionDigraph createRegionDigraph() throws BundleException { + RegionDigraph regionDigraph = new StandardRegionDigraph(this.bundleContext, this.threadLocal); + Region kernelRegion = regionDigraph.createRegion(REGION_KERNEL); + for (Bundle bundle : this.bundleContext.getBundles()) { + kernelRegion.addBundle(bundle); + } + return regionDigraph; + } + + private void saveDigraph() throws IOException { + FileOutputStream digraphFile = new FileOutputStream(bundleContext.getDataFile(DIGRAPH_FILE)); + try { + digraph.getRegionDigraphPersistence().save(digraph, digraphFile); + } finally { + try { + digraphFile.close(); + } catch (IOException e) { + // ignore; + } + } + + } + + private void registerDigraphMbean(RegionDigraph regionDigraph) { + StandardManageableRegionDigraph standardManageableRegionDigraph = new StandardManageableRegionDigraph(regionDigraph, this.domain, + this.bundleContext); + standardManageableRegionDigraph.registerMBean(); + } + + private void registerRegionHooks(RegionDigraph regionDigraph) { + registerResolverHookFactory(new RegionResolverHookFactory(regionDigraph)); + + RegionBundleFindHook bundleFindHook = new RegionBundleFindHook(regionDigraph, bundleContext.getBundle().getBundleId()); + registerBundleFindHook(bundleFindHook); + registerBundleEventHook(new RegionBundleEventHook(regionDigraph, bundleFindHook, this.threadLocal)); + + RegionServiceFindHook serviceFindHook = new RegionServiceFindHook(regionDigraph); + registerServiceFindHook(serviceFindHook); + registerServiceEventHook(new RegionServiceEventHook(serviceFindHook)); + } + + private void registerRegionDigraph(RegionDigraph regionDigraph) { + this.registrations.add(this.bundleContext.registerService(RegionDigraph.class, regionDigraph, null)); + } + + private void registerServiceFindHook(org.osgi.framework.hooks.service.FindHook serviceFindHook) { + this.registrations.add(this.bundleContext.registerService(org.osgi.framework.hooks.service.FindHook.class, serviceFindHook, null)); + } + + @SuppressWarnings("deprecation") + private void registerServiceEventHook(org.osgi.framework.hooks.service.EventHook serviceEventHook) { + this.registrations.add(this.bundleContext.registerService(org.osgi.framework.hooks.service.EventHook.class, serviceEventHook, null)); + } + + private void registerBundleFindHook(FindHook findHook) { + this.registrations.add(this.bundleContext.registerService(FindHook.class, findHook, null)); + } + + private void registerBundleEventHook(EventHook eventHook) { + this.registrations.add(this.bundleContext.registerService(EventHook.class, eventHook, null)); + + } + + private void registerResolverHookFactory(ResolverHookFactory resolverHookFactory) { + this.registrations.add(this.bundleContext.registerService(ResolverHookFactory.class, resolverHookFactory, null)); + } + +} diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraph.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraph.java new file mode 100644 index 000000000..2882c6511 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraph.java @@ -0,0 +1,330 @@ +/******************************************************************************* + * Copyright (c) 2011 VMware Inc. + * 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: + * SpringSource, a division of VMware - initial API and implementation and/or initial documentation + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region.internal; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.eclipse.virgo.kernel.osgi.region.Region; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraph; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraphPersistence; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraphVisitor; +import org.eclipse.virgo.kernel.osgi.region.RegionFilter; +import org.eclipse.virgo.kernel.osgi.region.RegionFilterBuilder; +import org.eclipse.virgo.util.math.OrderedPair; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; + +/** + * {@link StandardRegionDigraph} is the default implementation of {@link RegionDigraph}. + * <p /> + * + * <strong>Concurrent Semantics</strong><br /> + * + * Thread safe. + * + */ +public final class StandardRegionDigraph implements RegionDigraph { + + private final Object monitor = new Object(); + + private final Set<Region> regions = new HashSet<Region>(); + + private final Map<OrderedPair<Region, Region>, RegionFilter> filter = new HashMap<OrderedPair<Region, Region>, RegionFilter>(); + + private final BundleContext bundleContext; + + private final ThreadLocal<Region> threadLocal; + + private final SubgraphTraverser subgraphTraverser; + + StandardRegionDigraph() { + this(null, null); + } + + public StandardRegionDigraph(BundleContext bundleContext, ThreadLocal<Region> threadLocal) { + this.subgraphTraverser = new SubgraphTraverser(); + this.bundleContext = bundleContext; + this.threadLocal = threadLocal; + } + + /** + * {@inheritDoc} + */ + public Region createRegion(String regionName) throws BundleException { + Region region = new BundleIdBasedRegion(regionName, this, this.bundleContext, this.threadLocal); + synchronized (this.monitor) { + if (getRegion(regionName) != null) { + throw new BundleException("Region '" + regionName + "' already exists", BundleException.UNSUPPORTED_OPERATION); + } + this.regions.add(region); + } + notifyAdded(region); + return region; + } + + /** + * {@inheritDoc} + */ + public void connect(Region tailRegion, RegionFilter filter, Region headRegion) throws BundleException { + if (tailRegion == null) + throw new IllegalArgumentException("The tailRegion must not be null."); + if (filter == null) + throw new IllegalArgumentException("The filter must not be null."); + if (headRegion == null) + throw new IllegalArgumentException("The headRegion must not be null."); + if (headRegion.equals(tailRegion)) { + throw new BundleException("Cannot connect region '" + headRegion + "' to itself", BundleException.UNSUPPORTED_OPERATION); + } + OrderedPair<Region, Region> nodePair = new OrderedPair<Region, Region>(tailRegion, headRegion); + boolean tailAdded = false; + boolean headAdded = false; + synchronized (this.monitor) { + if (this.filter.containsKey(nodePair)) { + throw new BundleException("Region '" + tailRegion + "' is already connected to region '" + headRegion, + BundleException.UNSUPPORTED_OPERATION); + } else { + checkFilterDoesNotAllowExistingBundle(tailRegion, filter); + tailAdded = this.regions.add(tailRegion); + headAdded = this.regions.add(headRegion); + this.filter.put(nodePair, filter); + } + } + if (tailAdded) { + notifyAdded(tailRegion); + } + if (headAdded) { + notifyAdded(headRegion); + } + } + + private void checkFilterDoesNotAllowExistingBundle(Region tailRegion, RegionFilter filter) throws BundleException { + // TODO: enumerate the bundles in the region and check the filter does not allow any of them + } + + /** + * {@inheritDoc} + */ + public Iterator<Region> iterator() { + synchronized (this.monitor) { + Set<Region> snapshot = new HashSet<Region>(this.regions.size()); + snapshot.addAll(this.regions); + return snapshot.iterator(); + } + } + + /** + * {@inheritDoc} + */ + public Set<FilteredRegion> getEdges(Region tailRegion) { + Set<FilteredRegion> edges = new HashSet<FilteredRegion>(); + synchronized (this.monitor) { + Set<OrderedPair<Region, Region>> regionPairs = this.filter.keySet(); + for (OrderedPair<Region, Region> regionPair : regionPairs) { + if (tailRegion.equals(regionPair.getFirst())) { + edges.add(new StandardFilteredRegion(regionPair.getSecond(), this.filter.get(regionPair))); + } + } + } + return edges; + } + + private static class StandardFilteredRegion implements FilteredRegion { + + private Region region; + + private RegionFilter regionFilter; + + private StandardFilteredRegion(Region region, RegionFilter regionFilter) { + this.region = region; + this.regionFilter = regionFilter; + } + + public Region getRegion() { + return this.region; + } + + public RegionFilter getFilter() { + return this.regionFilter; + } + + } + + /** + * {@inheritDoc} + */ + public Region getRegion(String regionName) { + synchronized (this.monitor) { + for (Region region : this) { + if (regionName.equals(region.getName())) { + return region; + } + } + return null; + } + } + + /** + * {@inheritDoc} + */ + public Region getRegion(Bundle bundle) { + synchronized (this.monitor) { + for (Region region : this) { + if (region.contains(bundle)) { + return region; + } + } + return null; + } + } + + /** + * {@inheritDoc} + */ + public Region getRegion(long bundleId) { + synchronized (this.monitor) { + for (Region region : this) { + if (region.contains(bundleId)) { + return region; + } + } + return null; + } + } + + /** + * {@inheritDoc} + */ + public void removeRegion(Region region) { + if (region == null) + throw new IllegalArgumentException("The region cannot be null."); + notifyRemoving(region); + synchronized (this.monitor) { + this.regions.remove(region); + Iterator<OrderedPair<Region, Region>> i = this.filter.keySet().iterator(); + while (i.hasNext()) { + OrderedPair<Region, Region> regionPair = i.next(); + if (region.equals(regionPair.getFirst()) || region.equals(regionPair.getSecond())) { + i.remove(); + } + } + } + } + + /** + * {@inheritDoc} + */ + public String toString() { + synchronized (this.monitor) { + StringBuffer s = new StringBuffer(); + boolean first = true; + s.append("RegionDigraph{"); + for (Region r : this) { + if (!first) { + s.append(", "); + } + s.append(r); + first = false; + } + s.append("}"); + s.append("["); + first = true; + for (OrderedPair<Region, Region> regionPair : this.filter.keySet()) { + if (!first) { + s.append(", "); + } + s.append(regionPair.getFirst() + "->" + regionPair.getSecond()); + first = false; + } + s.append("]"); + return s.toString(); + } + } + + public Set<Region> getRegions() { + Set<Region> result = new HashSet<Region>(); + synchronized (this.monitor) { + result.addAll(this.regions); + } + return result; + } + + public RegionFilterBuilder createRegionFilterBuilder() { + return new StandardRegionFilterBuilder(); + } + + private void notifyAdded(Region region) { + Set<RegionLifecycleListener> listeners = getListeners(); + for (RegionLifecycleListener listener : listeners) { + listener.regionAdded(region); + } + } + + private void notifyRemoving(Region region) { + Set<RegionLifecycleListener> listeners = getListeners(); + for (RegionLifecycleListener listener : listeners) { + listener.regionRemoving(region); + } + } + + private Set<RegionLifecycleListener> getListeners() { + Set<RegionLifecycleListener> listeners = new HashSet<RegionLifecycleListener>(); + if (this.bundleContext == null) + return listeners; + try { + Collection<ServiceReference<RegionLifecycleListener>> listenerServiceReferences = this.bundleContext.getServiceReferences( + RegionLifecycleListener.class, null); + for (ServiceReference<RegionLifecycleListener> listenerServiceReference : listenerServiceReferences) { + RegionLifecycleListener regionLifecycleListener = this.bundleContext.getService(listenerServiceReference); + if (regionLifecycleListener != null) { + listeners.add(regionLifecycleListener); + } + } + } catch (InvalidSyntaxException e) { + e.printStackTrace(); + } + return listeners; + } + + /** + * {@inheritDoc} + */ + public void visitSubgraph(Region startingRegion, RegionDigraphVisitor visitor) { + this.subgraphTraverser.visitSubgraph(startingRegion, visitor); + } + + /** + * Returns a snapshot of filtered regions + * + * @return a snapshot of filtered regions + */ + Map<Region, Set<FilteredRegion>> getFilteredRegions() { + Map<Region, Set<FilteredRegion>> result = new HashMap<Region, Set<FilteredRegion>>(); + synchronized (this.monitor) { + for (Region region : regions) { + result.put(region, getEdges(region)); + } + } + return result; + } + + public RegionDigraphPersistence getRegionDigraphPersistence() { + return new StandardRegionDigraphPersistence(); + } +} diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraphPersistence.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraphPersistence.java new file mode 100644 index 000000000..03716b302 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraphPersistence.java @@ -0,0 +1,210 @@ +/******************************************************************************* + * Copyright (c) 2011 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.virgo.kernel.osgi.region.internal; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +import org.eclipse.virgo.kernel.osgi.region.Region; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraph; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraph.FilteredRegion; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraphPersistence; +import org.eclipse.virgo.kernel.osgi.region.RegionFilter; +import org.eclipse.virgo.kernel.osgi.region.RegionFilterBuilder; +import org.osgi.framework.BundleException; +import org.osgi.framework.InvalidSyntaxException; + +/** + * + * Class used for reading and writing a region digraph to persistent storage. + * <p /> + * + * <strong>Concurrent Semantics</strong><br /> + * Thread safe. + */ +final class StandardRegionDigraphPersistence implements RegionDigraphPersistence { + + private static final String PERSISTENT_NAME = "virgo region digraph"; + + private static final int PERSISTENT_VERSION = 1; + + static void writeRegionDigraph(DataOutputStream out, RegionDigraph digraph) throws IOException { + if (!(digraph instanceof StandardRegionDigraph)) + throw new IllegalArgumentException("Only digraphs of type '" + StandardRegionDigraph.class.getName() + "' are allowed: " + + digraph.getClass().getName()); + Map<Region, Set<FilteredRegion>> filteredRegions = ((StandardRegionDigraph) digraph).getFilteredRegions(); + + try { + // write the persistent name and version + out.writeUTF(PERSISTENT_NAME); + out.writeInt(PERSISTENT_VERSION); + // write the number of regions + out.writeInt(filteredRegions.size()); + // write each region + for (Region region : filteredRegions.keySet()) { + writeRegion(out, region); + } + // write each edge + // write number of tail regions + out.writeInt(filteredRegions.size()); + for (Map.Entry<Region, Set<FilteredRegion>> edges : filteredRegions.entrySet()) { + // write the number of edges for this tail + out.writeInt(edges.getValue().size()); + for (FilteredRegion edge : edges.getValue()) { + writeEdge(out, edges.getKey(), edge.getFilter(), edge.getRegion()); + } + } + } finally { + // note that the output is flushed even on exception + out.flush(); + } + } + + private static void writeRegion(DataOutputStream out, Region region) throws IOException { + // write region name + out.writeUTF(region.getName()); + + Set<Long> ids = region.getBundleIds(); + // write number of bundles + out.writeInt(ids.size()); + for (Long id : ids) { + // write each bundle id + out.writeLong(id); + } + } + + private static void writeEdge(DataOutputStream out, Region tail, RegionFilter filter, Region head) throws IOException { + // write tail region name + out.writeUTF(tail.getName()); + // write head region name + out.writeUTF(head.getName()); + // save the sharing policy + Map<String, Collection<String>> policy = filter.getSharingPolicy(); + // write the number of name spaces + out.writeInt(policy.size()); + // write each name space policy + for (Map.Entry<String, Collection<String>> namespace : policy.entrySet()) { + // write the name space name + out.writeUTF(namespace.getKey()); + Collection<String> filters = namespace.getValue(); + // write the number of filters + out.writeInt(filters.size()); + for (String filterSpec : filters) { + // write each filter + out.writeUTF(filterSpec); + } + } + } + + static RegionDigraph readRegionDigraph(DataInputStream in) throws IOException, InvalidSyntaxException, BundleException { + RegionDigraph digraph = new StandardRegionDigraph(); + + // Read and check the persistent name and version + String persistentName = in.readUTF(); + if (!PERSISTENT_NAME.equals(persistentName)) { + throw new IllegalArgumentException("Input stream does not represent a digraph"); + } + int persistentVersion = in.readInt(); + if (PERSISTENT_VERSION != persistentVersion) { + throw new IllegalArgumentException("Input stream contains a digraph with an incompatible version '" + persistentVersion + "'"); + } + // read the number of regions + int numRegions = in.readInt(); + for (int i = 0; i < numRegions; i++) { + readRegion(in, digraph); + } + // read each edge + // read number of tail regions + int numTails = in.readInt(); + for (int i = 0; i < numTails; i++) { + // read the number of edges for this tail + int numEdges = in.readInt(); + for (int j = 0; j < numEdges; j++) { + readEdge(in, digraph); + } + } + + return digraph; + } + + private static Region readRegion(DataInputStream in, RegionDigraph digraph) throws IOException, BundleException { + // read region name + String name = in.readUTF(); + Region region = digraph.createRegion(name); + + // read number of bundles + int numIds = in.readInt(); + for (int i = 0; i < numIds; i++) { + region.addBundle(in.readLong()); + } + return region; + } + + private static void readEdge(DataInputStream in, RegionDigraph digraph) throws IOException, InvalidSyntaxException, BundleException { + // read tail region name + String tailName = in.readUTF(); + Region tail = digraph.getRegion(tailName); + if (tail == null) + throw new IOException("Could not find tail region: " + tailName); + // read head region name + String headName = in.readUTF(); + Region head = digraph.getRegion(headName); + if (head == null) + throw new IOException("Could not find head region: " + headName); + // read the sharing policy + RegionFilterBuilder builder = digraph.createRegionFilterBuilder(); + // read the number of name spaces + int numSpaces = in.readInt(); + // read each name space policy + for (int i = 0; i < numSpaces; i++) { + // read the name space name + String namespace = in.readUTF(); + // read the number of filters + int numFilters = in.readInt(); + for (int j = 0; j < numFilters; j++) { + String filter = in.readUTF(); + builder.allow(namespace, filter); + } + } + digraph.connect(tail, builder.build(), head); + } + + /** + * {@inheritDoc} + */ + public RegionDigraph load(InputStream input) throws IOException { + try { + return readRegionDigraph(new DataInputStream(input)); + } catch (InvalidSyntaxException e) { + // This should never happen since the filters were valid on save + // propagate as IllegalStateException + throw new IllegalStateException("Internal error reading a filter", e); + } catch (BundleException e) { + // This should never happen since the digraph was valid on save + // propagate as IllegalStateException + throw new IllegalStateException("Internal error creating the digraph", e); + } + } + + /** + * {@inheritDoc} + */ + public void save(RegionDigraph digraph, OutputStream output) throws IOException { + writeRegionDigraph(new DataOutputStream(output), digraph); + } +} diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionFilter.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionFilter.java new file mode 100644 index 000000000..38e6c81bc --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionFilter.java @@ -0,0 +1,159 @@ +/******************************************************************************* + * Copyright (c) 2011 VMware Inc. + * 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: + * VMware Inc. - initial contribution + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region.internal; + +import java.util.*; +import org.eclipse.osgi.service.resolver.BundleDescription; +import org.eclipse.virgo.kernel.osgi.region.RegionFilter; +import org.osgi.framework.*; +import org.osgi.framework.wiring.BundleCapability; +import org.osgi.framework.wiring.BundleRevision; + +final class StandardRegionFilter implements RegionFilter { + private static final String BUNDLE_ID_ATTR = "id"; + private final Map<String, Collection<Filter>> filters; + + StandardRegionFilter(Map<String, Collection<Filter>> filters) { + if (filters == null) { + throw new IllegalArgumentException("filters must not be null."); + } + // must perform deep copy to avoid external changes + this.filters = new HashMap<String, Collection<Filter>>((int) ((filters.size() / 0.75) + 1)); + for (Map.Entry<String, Collection<Filter>> namespace : filters.entrySet()) { + Collection<Filter> namespaceFilters = new ArrayList<Filter>(namespace.getValue()); + this.filters.put(namespace.getKey(), namespaceFilters); + } + } + + /** + * Determines whether this filter allows the given bundle + * + * @param bundle the bundle + * @return <code>true</code> if the bundle is allowed and <code>false</code>otherwise + */ + public boolean isAllowed(Bundle bundle) { + HashMap<String, Object> attrs = new HashMap<String, Object>(3); + String bsn = bundle.getSymbolicName(); + if (bsn != null) + attrs.put(VISIBLE_BUNDLE_NAMESPACE, bsn); + attrs.put(org.osgi.framework.Constants.BUNDLE_VERSION_ATTRIBUTE, bundle.getVersion()); + attrs.put(BUNDLE_ID_ATTR, bundle.getBundleId()); + return isBundleAllowed(attrs); + } + + /** + * Determines whether this filter allows the given bundle + * + * @param bundle the bundle revision + * @return <code>true</code> if the bundle is allowed and <code>false</code>otherwise + */ + public boolean isAllowed(BundleRevision bundle) { + HashMap<String, Object> attrs = new HashMap<String, Object>(3); + String bsn = bundle.getSymbolicName(); + if (bsn != null) + attrs.put(VISIBLE_BUNDLE_NAMESPACE, bsn); + attrs.put(org.osgi.framework.Constants.BUNDLE_VERSION_ATTRIBUTE, bundle.getVersion()); + attrs.put(BUNDLE_ID_ATTR, getBundleId(bundle)); + return isBundleAllowed(attrs); + } + + /** + * Determines whether this filter allows the bundle with the given attributes + * + * @param bundleAttributes the bundle attributes + * @return <code>true</code> if the bundle is allowed and <code>false</code>otherwise + */ + private boolean isBundleAllowed(Map<String, ?> bundleAttributes) { + if (match(filters.get(VISIBLE_BUNDLE_NAMESPACE), bundleAttributes)) + return true; + return match(filters.get(VISIBLE_ALL_NAMESPACE), bundleAttributes); + } + + private boolean match(Collection<Filter> filters, Map<String, ?> attrs) { + if (filters == null) + return false; + for (Filter filter : filters) { + if (filter.matches(attrs)) + return true; + } + return false; + } + + private boolean match(Collection<Filter> filters, ServiceReference<?> service) { + if (filters == null) + return false; + for (Filter filter : filters) { + if (filter.match(service)) + return true; + } + return false; + } + + /** + * Determines whether this filter allows the given service reference. + * + * @param service the service reference of the service + * @return <code>true</code> if the service is allowed and <code>false</code>otherwise + */ + public boolean isAllowed(ServiceReference<?> service) { + if (match(filters.get(VISIBLE_SERVICE_NAMESPACE), service)) + return true; + return match(filters.get(VISIBLE_ALL_NAMESPACE), service); + } + + /** + * Determines whether this filter allows the given capability. + * + * @param capability the bundle capability + * @return <code>true</code> if the capability is allowed and <code>false</code>otherwise + */ + public boolean isAllowed(BundleCapability capability) { + String namespace = capability.getNamespace(); + Map<String, ?> attrs = capability.getAttributes(); + if (match(filters.get(namespace), attrs)) + return true; + return match(filters.get(VISIBLE_ALL_NAMESPACE), attrs); + } + + public Map<String, Collection<String>> getSharingPolicy() { + Map<String, Collection<String>> result = new HashMap<String, Collection<String>>((int) ((filters.size() / 0.75) + 1)); + for (Map.Entry<String, Collection<Filter>> namespace : filters.entrySet()) { + result.put(namespace.getKey(), getFilters(namespace.getValue())); + } + return result; + } + + private static Collection<String> getFilters(Collection<Filter> filters) { + Collection<String> result = new ArrayList<String>(filters.size()); + for (Filter filter : filters) { + result.add(filter.toString()); + } + return result; + } + + public String toString() { + return getSharingPolicy().toString(); + } + + private Long getBundleId(BundleRevision bundleRevision) { + // For testability, use the bundle revision's bundle before casting to ResolverBundle. + Bundle bundle = bundleRevision.getBundle(); + if (bundle != null) { + return bundle.getBundleId(); + } + if (bundleRevision instanceof BundleDescription) { + BundleDescription bundleDescription = (BundleDescription) bundleRevision; + return bundleDescription.getBundleId(); + } + throw new RuntimeException(String.format("Cannot determine bundle id of BundleRevision '%s'", bundleRevision)); + } +} diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionFilterBuilder.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionFilterBuilder.java new file mode 100644 index 000000000..2d4bd49b9 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionFilterBuilder.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2011 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.virgo.kernel.osgi.region.internal; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.virgo.kernel.osgi.region.RegionFilter; +import org.eclipse.virgo.kernel.osgi.region.RegionFilterBuilder; +import org.osgi.framework.Filter; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.InvalidSyntaxException; + +final class StandardRegionFilterBuilder implements RegionFilterBuilder { + + private final static String ALL_SPEC = "(|(!(all=*))(all=*))"; + + private final static Filter ALL; + static { + try { + ALL = FrameworkUtil.createFilter(ALL_SPEC); + } catch (InvalidSyntaxException e) { + // should never happen! + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + private final Object monitor = new Object(); + + private final Map<String, Collection<Filter>> policy = new HashMap<String, Collection<Filter>>(); + + public RegionFilterBuilder allow(String namespace, String filter) throws InvalidSyntaxException { + if (namespace == null) + throw new IllegalArgumentException("The namespace must not be null."); + if (filter == null) + throw new IllegalArgumentException("The filter must not be null."); + synchronized (this.monitor) { + Collection<Filter> namespaceFilters = policy.get(namespace); + if (namespaceFilters == null) { + namespaceFilters = new ArrayList<Filter>(); + policy.put(namespace, namespaceFilters); + } + // TODO need to use BundleContext.createFilter here + namespaceFilters.add(FrameworkUtil.createFilter(filter)); + } + return this; + } + + public RegionFilterBuilder allowAll(String namespace) { + if (namespace == null) + throw new IllegalArgumentException("The namespace must not be null."); + synchronized (this.monitor) { + Collection<Filter> namespaceFilters = policy.get(namespace); + if (namespaceFilters == null) { + namespaceFilters = new ArrayList<Filter>(); + policy.put(namespace, namespaceFilters); + } + // remove any other filters since this will override them all. + namespaceFilters.clear(); + namespaceFilters.add(ALL); + } + return this; + } + + public RegionFilter build() { + synchronized (this.monitor) { + return new StandardRegionFilter(policy); + } + } +} diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/SubgraphTraverser.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/SubgraphTraverser.java new file mode 100644 index 000000000..993abf33d --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/SubgraphTraverser.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2011 VMware Inc. + * 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: + * SpringSource, a division of VMware - initial API and implementation and/or initial documentation + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region.internal; + +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.virgo.kernel.osgi.region.Region; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraphVisitor; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraph.FilteredRegion; + +/** + * {@link SubgraphTraverser} is a utility for traversing a subgraph of a {@link RegionDigraph} calling a + * {@link RegionDigraphVisitor} on the way. + * <p /> + * + * <strong>Concurrent Semantics</strong><br /> + * Thread safe. + */ +final class SubgraphTraverser { + + void visitSubgraph(Region startingRegion, RegionDigraphVisitor visitor) { + visitRemainingSubgraph(startingRegion, visitor, new HashSet<Region>()); + } + + private void visitRemainingSubgraph(Region r, RegionDigraphVisitor visitor, Set<Region> path) { + if (!path.contains(r)) { + if (visitor.visit(r)) { + traverseEdges(r, visitor, path); + } + } + } + + private void traverseEdges(Region r, RegionDigraphVisitor visitor, Set<Region> path) { + for (FilteredRegion fr : r.getEdges()) { + if (visitor.preEdgeTraverse(fr.getFilter())) { + try { + visitRemainingSubgraph(fr.getRegion(), visitor, extendPath(r, path)); + } finally { + visitor.postEdgeTraverse(fr.getFilter()); + } + } + } + } + + private Set<Region> extendPath(Region r, Set<Region> path) { + Set<Region> newPath = new HashSet<Region>(path); + newPath.add(r); + return newPath; + } + +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/management/ManageableRegion.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/management/ManageableRegion.java new file mode 100644 index 000000000..1617a2200 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/management/ManageableRegion.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2011 VMware Inc. + * 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: + * VMware Inc. - initial contribution + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region.management; + +import javax.management.MXBean; + +import org.eclipse.virgo.kernel.osgi.region.Region; + +/** + * A {@link ManageableRegion} is a JMX representation of a {@link Region}. + * <p /> + * + * <strong>Concurrent Semantics</strong><br /> + * Thread safe. + */ +@MXBean +public interface ManageableRegion { + + /** + * Returns the region name. + * + * @return the region name + */ + String getName(); + + /** + * Returns the {@ManageableRegion}s that this region depends upon. + * + * @return an array of {@link ManageableRegion}s + */ + ManageableRegion[] getDependencies(); + + /** + * Returns the bundle ids belonging to this region. + * + * @return an array of bundle ids + */ + long[] getBundleIds(); + +} diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/management/ManageableRegionDigraph.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/management/ManageableRegionDigraph.java new file mode 100644 index 000000000..4dfc2b511 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/management/ManageableRegionDigraph.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2011 VMware Inc. + * 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: + * VMware Inc. - initial contribution + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region.management; + +import javax.management.MXBean; + +import org.eclipse.virgo.kernel.osgi.region.RegionDigraph; + +/** + * {@link ManageableRegionDigraph} is a JMX representation of the {@link RegionDigraph}. + * <p /> + * + * <strong>Concurrent Semantics</strong><br /> + * Thread safe. + */ +@MXBean +public interface ManageableRegionDigraph { + + /** + * Gets the {@link ManageableRegion}s in the digraph. + * + * @return an array of {@link ManageableRegion}s + */ + ManageableRegion[] getRegions(); + + /** + * Gets the {@link ManageableRegion} with the given name. + * + * @param regionName the region name + * @return a {@link ManageableRegion} or <code>null</code> if there is no region with the given name + */ + ManageableRegion getRegion(String regionName); + +} diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/management/internal/RegionObjectNameCreator.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/management/internal/RegionObjectNameCreator.java new file mode 100644 index 000000000..d57d87e9d --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/management/internal/RegionObjectNameCreator.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2011 VMware Inc. + * 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: + * VMware Inc. - initial contribution + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region.management.internal; + +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import org.eclipse.virgo.kernel.osgi.region.management.ManageableRegion; + +/** + * {@link RegionObjectNameCreator} is responsible for creating {@link ObjectName}s for {@link ManageableRegion}s. + * <p /> + * + * <strong>Concurrent Semantics</strong><br /> + * Thread safe. + */ +final class RegionObjectNameCreator { + + private final String domain; + + RegionObjectNameCreator(String domain) { + this.domain = domain; + } + + ObjectName getRegionObjectName(String regionName) { + try { + return new ObjectName(this.domain + ":type=Region,name=" + regionName); + } catch (MalformedObjectNameException e) { + e.printStackTrace(); + return null; + } + } + +} diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/management/internal/StandardManageableRegion.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/management/internal/StandardManageableRegion.java new file mode 100644 index 000000000..ced18a7aa --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/management/internal/StandardManageableRegion.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright (c) 2011 VMware Inc. + * 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: + * VMware Inc. - initial contribution + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region.management.internal; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.eclipse.virgo.kernel.osgi.region.Region; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraph; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraph.FilteredRegion; +import org.eclipse.virgo.kernel.osgi.region.management.ManageableRegion; +import org.eclipse.virgo.kernel.osgi.region.management.ManageableRegionDigraph; + +/** + * {@link StandardManageableRegion} is the default implementation of {@link ManageableRegion}. + * <p /> + * + * <strong>Concurrent Semantics</strong><br /> + * Thread safe. + */ +public class StandardManageableRegion implements ManageableRegion { + + private final Region region; + + private final ManageableRegionDigraph manageableRegionDigraph; + + private final RegionDigraph regionDigraph; + + public StandardManageableRegion(Region region, ManageableRegionDigraph manageableRegionDigraph, RegionDigraph regionDigraph) { + this.region = region; + this.manageableRegionDigraph = manageableRegionDigraph; + this.regionDigraph = regionDigraph; + } + + /** + * {@inheritDoc} + */ + public String getName() { + return region.getName(); + } + + /** + * {@inheritDoc} + */ + public ManageableRegion[] getDependencies() { + Set<FilteredRegion> edges = this.regionDigraph.getEdges(this.region); + List<ManageableRegion> dependencies = new ArrayList<ManageableRegion>(); + for (FilteredRegion edge : edges) { + ManageableRegion manageableRegion = this.manageableRegionDigraph.getRegion(edge.getRegion().getName()); + if (manageableRegion != null) { + dependencies.add(manageableRegion); + } + } + return dependencies.toArray(new ManageableRegion[dependencies.size()]); + } + + /** + * {@inheritDoc} + */ + public long[] getBundleIds() { + Set<Long> bundleIds = this.region.getBundleIds(); + long[] result = new long[bundleIds.size()]; + int i = 0; + for (Long bundleId : bundleIds) { + result[i++] = bundleId; + } + return result; + } + +} diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/management/internal/StandardManageableRegionDigraph.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/management/internal/StandardManageableRegionDigraph.java new file mode 100644 index 000000000..470413d30 --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/management/internal/StandardManageableRegionDigraph.java @@ -0,0 +1,160 @@ +/******************************************************************************* + * Copyright (c) 2011 VMware Inc. + * 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: + * VMware Inc. - initial contribution + *******************************************************************************/ + +package org.eclipse.virgo.kernel.osgi.region.management.internal; + +import java.lang.management.ManagementFactory; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import org.eclipse.virgo.kernel.osgi.region.Region; +import org.eclipse.virgo.kernel.osgi.region.RegionDigraph; +import org.eclipse.virgo.kernel.osgi.region.internal.RegionLifecycleListener; +import org.eclipse.virgo.kernel.osgi.region.management.ManageableRegion; +import org.eclipse.virgo.kernel.osgi.region.management.ManageableRegionDigraph; +import org.osgi.framework.BundleContext; + +/** + * {@link StandardManageableRegionDigraph} is a {@link ManageableRegionDigraph} that delegates to the + * {@link RegionDigraph}. + * <p /> + * + * <strong>Concurrent Semantics</strong><br /> + * Thread safe. + */ +public final class StandardManageableRegionDigraph implements ManageableRegionDigraph { + + private final RegionDigraph regionDigraph; + + private final String domain; + + private final RegionObjectNameCreator regionObjectNameCreator; + + private final Map<String, ManageableRegion> manageableRegions = new ConcurrentHashMap<String, ManageableRegion>(); + + private final BundleContext bundleContext; + + private final Object monitor = new Object(); + + private final MBeanServer mbeanServer; + + public StandardManageableRegionDigraph(RegionDigraph regionDigraph, String domain, BundleContext bundleContext) { + this.regionDigraph = regionDigraph; + this.domain = domain; + this.regionObjectNameCreator = new RegionObjectNameCreator(domain); + this.bundleContext = bundleContext; + this.mbeanServer = ManagementFactory.getPlatformMBeanServer(); + } + + private void registerRegionLifecycleListener() { + RegionLifecycleListener regionLifecycleListener = new RegionLifecycleListener() { + + public void regionAdded(Region region) { + addRegion(region); + } + + public void regionRemoving(Region region) { + removeRegion(region); + } + + }; + this.bundleContext.registerService(RegionLifecycleListener.class, regionLifecycleListener, null); + } + + public void registerMBean() { + registerRegionLifecycleListener(); + synchronized (this.monitor) { + // The following alien call is unavoidable to ensure consistency. + Set<Region> regions = this.regionDigraph.getRegions(); + for (Region region : regions) { + addRegion(region); + } + } + + ObjectName name; + try { + name = new ObjectName(this.domain + ":type=RegionDigraph"); + } catch (MalformedObjectNameException e) { + e.printStackTrace(); + throw new RuntimeException("Invalid domain name '" + this.domain + "'", e); + } + + safelyRegisterMBean(this, name); + } + + private void safelyRegisterMBean(Object mbean, ObjectName name) { + try { + try { + this.mbeanServer.registerMBean(mbean, name); + } catch (InstanceAlreadyExistsException e) { + // Recover as this happens when a JVM is reused. + this.mbeanServer.unregisterMBean(name); + this.mbeanServer.registerMBean(mbean, name); + } + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException("MBean registration failed", e); + } + } + + /** + * {@inheritDoc} + */ + public ManageableRegion[] getRegions() { + List<ManageableRegion> regions = new ArrayList<ManageableRegion>(); + synchronized (this.monitor) { + for (ManageableRegion manageableRegion : this.manageableRegions.values()) { + regions.add(manageableRegion); + } + } + return regions.toArray(new ManageableRegion[regions.size()]); + } + + /** + * {@inheritDoc} + */ + public ManageableRegion getRegion(String regionName) { + return this.manageableRegions.get(regionName); + } + + private void addRegion(Region region) { + StandardManageableRegion manageableRegion = new StandardManageableRegion(region, this, this.regionDigraph); + safelyRegisterMBean(manageableRegion, this.regionObjectNameCreator.getRegionObjectName(region.getName())); + synchronized (this.monitor) { + this.manageableRegions.put(region.getName(), manageableRegion); + } + } + + private void removeRegion(Region region) { + String regionName = region.getName(); + synchronized (this.monitor) { + this.manageableRegions.remove(regionName); + } + try { + this.mbeanServer.unregisterMBean(this.regionObjectNameCreator.getRegionObjectName(regionName)); + } catch (MBeanRegistrationException e) { + e.printStackTrace(); + throw new RuntimeException("Problem unregistering mbean", e); + } catch (InstanceNotFoundException e) { + } + } + +} diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/util/math/OrderedPair.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/util/math/OrderedPair.java new file mode 100644 index 000000000..e2b17e91e --- /dev/null +++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/util/math/OrderedPair.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * Copyright (c) 2008, 2011 VMware Inc. + * 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: + * VMware Inc. - initial contribution + *******************************************************************************/ + +package org.eclipse.virgo.util.math; + +/** + * Defines an ordered pair of elements of types <code>F</code> and <code>S</code> respectively. + * <p/> + * The elements may be null, in which case they are without type. + * <br/>For example: + * <pre> + * ( new OrderedPair<Long,Long >(42,null) ) + * .equals( new OrderedPair<Long,String>(42,null) )</pre> + * returns <code>true</code>. + * <p/> + * + * <strong>Concurrent Semantics</strong><br/> + * Implementation is immutable.<br/> + * <strong>Note:</strong> the elements are <code>final</code> but that doesn't stop + * them being modified after the pair is constructed. The <code>hashCode()</code> of the <code>OrderedPair</code> may then change. + * + * @param <F> type of first element + * @param <S> type of second element + * + */ +public final class OrderedPair<F, S> { + + private final F first; + + private final S second; + + /** + * Creates a new <code>OrderedPair</code>. + * + * @param first + * the first member of the <code>OrderedPair</code>. + * @param second + * the second member of the <code>OrderedPair</code>. + */ + public OrderedPair(F first, S second) { + this.first = first; + this.second = second; + } + + /** + * Gets the first member of the <code>OrderedPair</code>. + * + * @return the first member of the <code>OrderedPair</code>. + */ + public F getFirst() { + return this.first; + } + + /** + * Gets the second member of the <code>OrderedPair</code>. + * + * @return the second member of the <code>OrderedPair</code>. + */ + public S getSecond() { + return this.second; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + final int prime = 31; + int result = this.first == null ? 0 : this.first.hashCode(); + result = prime * result + (this.second == null ? 0 : this.second.hashCode()); + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + + @SuppressWarnings("unchecked") + final OrderedPair<F, S> other = (OrderedPair<F, S>) obj; + + return (this.first == null ? other.first == null : this.first.equals(other.first)) && (this.second == null ? other.second == null : this.second.equals(other.second)); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return "(" + String.valueOf(this.first) + ", " + String.valueOf(this.second) + ")"; + } + +} |