Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Watson2011-04-13 15:48:34 +0000
committerThomas Watson2011-04-13 15:48:34 +0000
commitd86e4f0fff4e8209754c4ac651ce3ac1880bd679 (patch)
tree3c12c6071785d68bd9c86cf840dd03fabc960691
parent9f5fad996ed2f5d3fb2e0ef84bcd25c7ebed750e (diff)
downloadrt.equinox.bundles-d86e4f0fff4e8209754c4ac651ce3ac1880bd679.tar.gz
rt.equinox.bundles-d86e4f0fff4e8209754c4ac651ce3ac1880bd679.tar.xz
rt.equinox.bundles-d86e4f0fff4e8209754c4ac651ce3ac1880bd679.zip
Initial check in of region digraph to equinox.
-rw-r--r--bundles/org.eclipse.equinox.region.tests/.classpath18
-rw-r--r--bundles/org.eclipse.equinox.region.tests/.project28
-rw-r--r--bundles/org.eclipse.equinox.region.tests/.settings/org.eclipse.core.resources.prefs3
-rw-r--r--bundles/org.eclipse.equinox.region.tests/.settings/org.eclipse.jdt.core.prefs353
-rw-r--r--bundles/org.eclipse.equinox.region.tests/.settings/org.eclipse.jdt.ui.prefs61
-rw-r--r--bundles/org.eclipse.equinox.region.tests/.settings/org.eclipse.pde.core.prefs4
-rw-r--r--bundles/org.eclipse.equinox.region.tests/META-INF/MANIFEST.MF20
-rw-r--r--bundles/org.eclipse.equinox.region.tests/about.html28
-rw-r--r--bundles/org.eclipse.equinox.region.tests/build.properties42
-rw-r--r--bundles/org.eclipse.equinox.region.tests/bundles_src/BundleClient1/META-INF/MANIFEST.MF6
-rw-r--r--bundles/org.eclipse.equinox.region.tests/bundles_src/CapabilityClient1/META-INF/MANIFEST.MF8
-rw-r--r--bundles/org.eclipse.equinox.region.tests/bundles_src/CapabilityProvider1/META-INF/MANIFEST.MF6
-rw-r--r--bundles/org.eclipse.equinox.region.tests/bundles_src/CapabilityProvider2/META-INF/MANIFEST.MF11
-rw-r--r--bundles/org.eclipse.equinox.region.tests/bundles_src/CapabilityProvider2/capabilityprovider2/Activator.java53
-rw-r--r--bundles/org.eclipse.equinox.region.tests/bundles_src/PackageClient1/META-INF/MANIFEST.MF7
-rw-r--r--bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider1/META-INF/MANIFEST.MF7
-rw-r--r--bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider1/pkg1/a/A.java15
-rw-r--r--bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider1/pkg1/b/B.java15
-rw-r--r--bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider2/META-INF/MANIFEST.MF8
-rw-r--r--bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider2/pkg2/a/A.java15
-rw-r--r--bundles/org.eclipse.equinox.region.tests/bundles_src/PackageProvider2/pkg2/b/B.java15
-rw-r--r--bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceClient1/META-INF/MANIFEST.MF10
-rw-r--r--bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceClient1/serviceclient1/Activator.java52
-rw-r--r--bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceProvider1/META-INF/MANIFEST.MF7
-rw-r--r--bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceProvider1/serviceprovider1/Activator.java31
-rw-r--r--bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceProvider2/META-INF/MANIFEST.MF7
-rw-r--r--bundles/org.eclipse.equinox.region.tests/bundles_src/ServiceProvider2/serviceprovider2/Activator.java31
-rw-r--r--bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/tests/AllTests.java36
-rw-r--r--bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/tests/BundleInstaller.java198
-rw-r--r--bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/tests/system/AbstractRegionSystemTest.java101
-rw-r--r--bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/tests/system/RegionSystemTests.java266
-rw-r--r--bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionBundleEventHookTests.java93
-rw-r--r--bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionBundleFindHookTests.java263
-rw-r--r--bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionResolverHookTests.java580
-rw-r--r--bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionServiceEventHookTests.java91
-rw-r--r--bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionServiceFindHookTests.java305
-rw-r--r--bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/internal/BundleIdBasedRegionTests.java307
-rw-r--r--bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraphPeristenceTests.java283
-rw-r--r--bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraphTests.java190
-rw-r--r--bundles/org.eclipse.equinox.region.tests/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionFilterTests.java191
-rw-r--r--bundles/org.eclipse.equinox.region.tests/stubs/README3
-rw-r--r--bundles/org.eclipse.equinox.region.tests/stubs/org.eclipse.virgo.teststubs.osgi-sources.jarbin0 -> 39330 bytes
-rw-r--r--bundles/org.eclipse.equinox.region.tests/stubs/org.eclipse.virgo.teststubs.osgi.jarbin0 -> 66255 bytes
-rw-r--r--bundles/org.eclipse.equinox.region.tests/test.xml63
-rw-r--r--bundles/org.eclipse.equinox.region/.classpath7
-rw-r--r--bundles/org.eclipse.equinox.region/.project28
-rw-r--r--bundles/org.eclipse.equinox.region/.settings/org.eclipse.core.resources.prefs3
-rw-r--r--bundles/org.eclipse.equinox.region/.settings/org.eclipse.jdt.core.prefs329
-rw-r--r--bundles/org.eclipse.equinox.region/.settings/org.eclipse.jdt.ui.prefs61
-rw-r--r--bundles/org.eclipse.equinox.region/.settings/org.eclipse.pde.core.prefs4
-rw-r--r--bundles/org.eclipse.equinox.region/META-INF/MANIFEST.MF17
-rw-r--r--bundles/org.eclipse.equinox.region/OSGI-INF/l10n/bundle.properties12
-rw-r--r--bundles/org.eclipse.equinox.region/about.html28
-rw-r--r--bundles/org.eclipse.equinox.region/build.properties7
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/Region.java192
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/RegionDigraph.java156
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/RegionDigraphPersistence.java55
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/RegionDigraphVisitor.java48
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/RegionFilter.java118
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/RegionFilterBuilder.java49
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionBundleEventHook.java112
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionBundleFindHook.java90
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionDigraphVisitorBase.java165
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionResolverHook.java174
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionResolverHookFactory.java42
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionServiceEventHook.java62
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/hook/RegionServiceFindHook.java85
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/BundleIdBasedRegion.java280
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/RegionLifecycleListener.java42
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/RegionManager.java155
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraph.java330
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraphPersistence.java210
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionFilter.java159
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionFilterBuilder.java82
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/internal/SubgraphTraverser.java61
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/management/ManageableRegion.java49
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/management/ManageableRegionDigraph.java43
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/management/internal/RegionObjectNameCreator.java43
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/management/internal/StandardManageableRegion.java80
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/kernel/osgi/region/management/internal/StandardManageableRegionDigraph.java160
-rw-r--r--bundles/org.eclipse.equinox.region/src/org/eclipse/virgo/util/math/OrderedPair.java111
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 (&quot;Content&quot;). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). 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, &quot;Program&quot; 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 (&quot;Redistributor&quot;) 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
new file mode 100644
index 000000000..baf9e683a
--- /dev/null
+++ b/bundles/org.eclipse.equinox.region.tests/stubs/org.eclipse.virgo.teststubs.osgi-sources.jar
Binary files differ
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
new file mode 100644
index 000000000..a2730a2a7
--- /dev/null
+++ b/bundles/org.eclipse.equinox.region.tests/stubs/org.eclipse.virgo.teststubs.osgi.jar
Binary files differ
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 (&quot;Content&quot;). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). 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, &quot;Program&quot; 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 (&quot;Redistributor&quot;) 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) + ")";
+ }
+
+}

Back to the top