Graduation of the bundle from the equinox.incubator
diff --git a/bundles/org.eclipse.equinox.ds/.classpath b/bundles/org.eclipse.equinox.ds/.classpath
index acad1c2..755d49b 100644
--- a/bundles/org.eclipse.equinox.ds/.classpath
+++ b/bundles/org.eclipse.equinox.ds/.classpath
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/OSGi%Minimum-1.0"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/bundles/org.eclipse.equinox.ds/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.equinox.ds/.settings/org.eclipse.jdt.core.prefs
index 4a4dc43..d304116 100644
--- a/bundles/org.eclipse.equinox.ds/.settings/org.eclipse.jdt.core.prefs
+++ b/bundles/org.eclipse.equinox.ds/.settings/org.eclipse.jdt.core.prefs
@@ -1,23 +1,49 @@
-#Mon Feb 26 10:38:16 EST 2007
+#Thu Aug 16 11:00:59 EDT 2007
 eclipse.preferences.version=1
+org.eclipse.jdt.core.builder.cleanOutputFolder=clean
+org.eclipse.jdt.core.builder.duplicateResourceTask=warning
+org.eclipse.jdt.core.builder.invalidClasspath=abort
+org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch
+org.eclipse.jdt.core.circularClasspath=error
+org.eclipse.jdt.core.classpath.exclusionPatterns=enabled
+org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=disabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.4
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.doc.comment.support=enabled
+org.eclipse.jdt.core.compiler.maxProblemPerUnit=1000
 org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning
 org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
 org.eclipse.jdt.core.compiler.problem.deprecation=warning
 org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
-org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
-org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=error
 org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
 org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
-org.eclipse.jdt.core.compiler.problem.finalParameterBound=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=warning
+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
@@ -25,7 +51,6 @@
 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.rawTypeReference=ignore
 org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
 org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
 org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
@@ -37,16 +62,17 @@
 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=ignore
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unsafeTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled
 org.eclipse.jdt.core.compiler.problem.unusedImport=error
-org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
 org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
 org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
-org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
-org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
-org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.3
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
@@ -292,9 +318,14 @@
 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.ds/.settings/org.eclipse.jdt.ui.prefs b/bundles/org.eclipse.equinox.ds/.settings/org.eclipse.jdt.ui.prefs
index 9bf712c..023a27a 100644
--- a/bundles/org.eclipse.equinox.ds/.settings/org.eclipse.jdt.ui.prefs
+++ b/bundles/org.eclipse.equinox.ds/.settings/org.eclipse.jdt.ui.prefs
@@ -1,8 +1,57 @@
-#Mon Feb 26 10:45:44 EST 2007
+#Tue Aug 21 11:19:11 CDT 2007
 eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
 formatter_profile=_core
 formatter_settings_version=11
 org.eclipse.jdt.ui.ignorelowercasenames=true
 org.eclipse.jdt.ui.importorder=;
 org.eclipse.jdt.ui.ondemandthreshold=3
 org.eclipse.jdt.ui.staticondemandthreshold=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_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=true
+sp_cleanup.make_local_variable_final=false
+sp_cleanup.make_parameters_final=false
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_variable_declarations_final=true
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=false
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_blocks=false
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=false
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=false
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
diff --git a/bundles/org.eclipse.equinox.ds/.settings/org.eclipse.pde.core.prefs b/bundles/org.eclipse.equinox.ds/.settings/org.eclipse.pde.core.prefs
new file mode 100644
index 0000000..c5cfeff
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/.settings/org.eclipse.pde.core.prefs
@@ -0,0 +1,3 @@
+#Thu Mar 29 10:39:03 EEST 2007
+eclipse.preferences.version=1
+pluginProject.extensions=false
diff --git a/bundles/org.eclipse.equinox.ds/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.ds/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..9979b7a
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/META-INF/MANIFEST.MF
@@ -0,0 +1,43 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Declarative Services
+Bundle-SymbolicName: org.eclipse.equinox.ds
+Bundle-Version: 0.1.0.qualifier
+Bundle-Vendor: Eclipse
+Bundle-Activator: org.eclipse.equinox.internal.ds.Activator
+Bundle-Description: This bundle provides support for OSGi 
+ Declarative Services. This module implements a declarative service model,
+ which allows a bundle to delay instantiating the service object until
+ they are needed, and thus minimizing the resource consumption at
+ any point of time. That module is  also one of the core components for
+ the OSGi R4.
+Import-Package: 
+ org.eclipse.equinox.internal.util.event;version="1.0",
+ org.eclipse.equinox.internal.util.hash;version="1.0",
+ org.eclipse.equinox.internal.util.pool;version="1.0",
+ org.eclipse.equinox.internal.util.ref;version="1.0",
+ org.eclipse.equinox.internal.util.threadpool;version="1.0",
+ org.eclipse.equinox.internal.util.timer;version="1.0",
+ org.eclipse.osgi.util,
+ org.osgi.framework;version="1.3",
+ org.osgi.service.cm;version="1.2",
+ org.osgi.service.component;version="1.0",
+ org.osgi.service.metatype;version="1.1",
+ org.osgi.util.tracker;version="1.3"
+Export-Package: 
+ org.eclipse.equinox.internal.ds;x-internal:=true,
+ org.eclipse.equinox.internal.ds.impl;x-internal:=true,
+ org.eclipse.equinox.internal.ds.model;x-internal:=true,
+ org.eclipse.equinox.internal.ds.storage.file;x-internal:=true,
+ org.eclipse.equinox.internal.util.io;x-internal:=true,
+ org.eclipse.equinox.internal.util.xml;x-internal:=true,
+ org.eclipse.equinox.internal.util.xml.impl;x-internal:=true,
+ org.eclipse.equinox.internal.util.string;x-internal:=true
+Bundle-RequiredExecutionEnvironment: OSGi/Minimum-1.0,
+ CDC-1.0/Foundation-1.0,
+ J2SE-1.2,
+ J2SE-1.3,
+ J2SE-1.4,
+ J2SE-1.5,
+ JavaSE-1.6
+Lazy-ManifestFilter: (Service-Component=*)
diff --git a/bundles/org.eclipse.equinox.ds/OSGI-INF/permissions.perm b/bundles/org.eclipse.equinox.ds/OSGI-INF/permissions.perm
new file mode 100644
index 0000000..5a96587
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/OSGI-INF/permissions.perm
@@ -0,0 +1 @@
+(java.security.AllPermission "*" "*")
\ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.ds/about.html b/bundles/org.eclipse.equinox.ds/about.html
new file mode 100644
index 0000000..40e147d
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+ 
+<p>January 15, 2008</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>
diff --git a/bundles/org.eclipse.equinox.ds/build.properties b/bundles/org.eclipse.equinox.ds/build.properties
new file mode 100644
index 0000000..9cbab3c
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/build.properties
@@ -0,0 +1,6 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               about.html
+src.includes = about.html
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/Activator.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/Activator.java
new file mode 100644
index 0000000..46b2f0b
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/Activator.java
@@ -0,0 +1,237 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.ds;
+
+import java.util.Dictionary;
+import org.eclipse.equinox.internal.util.ref.Log;
+import org.osgi.framework.*;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ConfigurationListener;
+import org.osgi.service.component.ComponentConstants;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * This is the main starting class for the Service Component Runtime.
+ * 
+ * It also acts as a "Bundle Manager" - a listener for bundle events. Whenever a
+ * bundle is stopped or started it will invoke the resolver to respectively
+ * enable or disable neccessary service components.
+ * 
+ * Notice, the SynchronousBundleListener bundle listeners are called prior
+ * bundle event is completed. This will make the stuff a little bit faster ;)
+ * 
+ * @author Valentin Valchev
+ * @author Stoyan Boshev
+ * @author Pavlin Dobrev
+ * @version 1.1
+ */
+
+public class Activator implements BundleActivator, SynchronousBundleListener {
+
+	public static BundleContext bc = null;
+
+	private ServiceTracker cmTracker;
+	private ServiceRegistration cmTrackerReg;
+
+	private SCRManager scrManager = null;
+
+	private boolean inited = false;
+
+	public static Log log;
+	public static boolean DEBUG;
+	public static boolean PERF;
+	public static boolean DBSTORE;
+	public static boolean startup;
+
+	static long time[] = null;
+
+	public static void timeLog(int id) {
+		time[1] = time[0];
+		log.debug(0x0100, id, String.valueOf((time[0] = System.currentTimeMillis()) - time[1]), null, false, true);
+	}
+
+	private void initSCR() {
+		synchronized (this) {
+			if (inited)
+				return;
+			inited = true;
+		}
+
+		boolean lazyIniting = false;
+		if (startup && time == null) {
+			long tmp = System.currentTimeMillis();
+			time = new long[] {tmp, 0, tmp};
+			lazyIniting = true;
+			if (startup)
+				timeLog(114); /* 114 = "[BEGIN - lazy SCR init] " */
+		}
+
+		WorkThread.IDLE_TIMEOUT = getInteger("equinox.ds.idle_timeout", 1000);
+		WorkThread.BLOCK_TIMEOUT = getInteger("equinox.ds.block_timeout", 30000);
+
+		// start the config tracker
+		cmTracker = new ServiceTracker(bc, ConfigurationAdmin.class.getName(), null);
+
+		if (startup)
+			timeLog(102);
+		/*102 = "ConfigurationAdmin ServiceTracker instantiation took "*/
+
+		ConfigurationManager.cmTracker = cmTracker;
+		cmTracker.open();
+		if (startup)
+			timeLog(103); /* 103 = "ServiceTracker starting took " */
+
+		scrManager = new SCRManager(bc, log);
+		if (startup)
+			timeLog(104); /* 104 = "SCRManager instantiation took " */
+
+		// add the configuration listener - we to receive CM events to restart
+		// components
+		cmTrackerReg = bc.registerService(ConfigurationListener.class.getName(), scrManager, null);
+		if (startup)
+			timeLog(106); /*106 = "ConfigurationListener service registered for "*/
+		bc.addServiceListener(scrManager);
+		if (startup)
+			timeLog(107); /* 107 = "addServiceListener() method took " */
+
+		scrManager.startIt();
+		if (Activator.startup)
+			Activator.timeLog(113); /* 113 = "startIt() method took " */
+
+		if (startup && lazyIniting) {
+			/* 115 = "[END - lazy SCR init] Activator.initSCR() method executed for "*/
+			log.debug(0x0100, 115, String.valueOf(time[0] - time[2]), null, false);
+			time = null;
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+	 */
+	public void start(BundleContext bc) throws Exception {
+		Activator.bc = bc;
+		startup = getBoolean("equinox.measurements.full") || getBoolean("equinox.measurements.bundles");
+		if (startup) {
+			long tmp = System.currentTimeMillis();
+			time = new long[] {tmp, 0, tmp};
+		}
+		// initialize the logging routines
+		log = new Log(bc, false);
+		DEBUG = getBoolean("equinox.ds.debug");
+		PERF = getBoolean("equinox.ds.perf");
+		DBSTORE = getBoolean("equinox.ds.dbstore");
+		log.setDebug(DEBUG);
+		boolean print = getBoolean("equinox.ds.print");
+		log.setPrintOnConsole(print);
+		if (DEBUG) {
+			log.setMaps(TracerMap.getMap(), TracerMap.getStarts());
+		}
+
+		if (startup)
+			timeLog(100);
+		/*
+		 * 100 = "[BEGIN - start method] Creating Log
+		 * instance and initializing log system took "
+		 */
+
+		boolean hasHeaders = false;
+		Bundle[] allBundles = bc.getBundles();
+		for (int i = 0; i < allBundles.length; i++) {
+			Dictionary allHeaders = allBundles[i].getHeaders();
+			if (allHeaders.get(ComponentConstants.SERVICE_COMPONENT) != null) {
+				hasHeaders = true;
+				break;
+			}
+		}
+
+		if (hasHeaders) {
+			initSCR();
+		} else {
+			// there are no bundles holding components - SCR will not be
+			// initialized yet
+			bc.addBundleListener(this);
+		}
+		if (startup) {
+			log.debug(0x0100, 108, String.valueOf(time[0] - time[2]), null, false);
+			time = null;
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+	 */
+	public void stop(BundleContext bc) throws Exception {
+		log.info("Shutting down service component runtime!");
+		if (scrManager != null) {
+			bc.removeServiceListener(scrManager);
+		}
+		// dispose the CM Listener
+		if (cmTrackerReg != null) {
+			cmTrackerReg.unregister();
+		}
+		if (scrManager != null) {
+			bc.removeBundleListener(scrManager);
+		} else {
+			bc.removeBundleListener(this);
+		}
+
+		// untrack the cm!
+		if (cmTracker != null) {
+			ConfigurationManager.cmTracker = null;
+			cmTracker.close();
+			cmTracker = null;
+		}
+
+		if (scrManager != null) {
+			scrManager.stopIt();
+		}
+		log.close();
+		log = null;
+		bc = null;
+	}
+
+	public static Filter createFilter(String filter) throws InvalidSyntaxException {
+		return bc.createFilter(filter);
+	}
+
+	public void bundleChanged(BundleEvent event) {
+		if (event.getType() == BundleEvent.STARTING) {
+			Dictionary allHeaders = event.getBundle().getHeaders();
+			if ((allHeaders.get(ComponentConstants.SERVICE_COMPONENT)) != null) {
+				// The bundle is holding components - activate scr
+				bc.removeBundleListener(this);
+				initSCR();
+			}
+		}
+	}
+
+	public static boolean getBoolean(String property) {
+		String prop = (bc != null) ? bc.getProperty(property) : System.getProperty(property);
+		return ((prop != null) && prop.equalsIgnoreCase("true"));
+	}
+
+	public static int getInteger(String property, int defaultValue) {
+		String prop = (bc != null) ? bc.getProperty(property) : System.getProperty(property);
+		if (prop != null) {
+			try {
+				return Integer.decode(prop).intValue();
+			} catch (NumberFormatException e) {
+				//do nothing
+			}
+		}
+		return defaultValue;
+	}
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/CircularityException.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/CircularityException.java
new file mode 100644
index 0000000..9073f4b
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/CircularityException.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.ds;
+
+import org.eclipse.equinox.internal.ds.model.ServiceComponentProp;
+
+/**
+ * Used to find circular dependencies
+ *
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public class CircularityException extends Exception {
+	private static final long serialVersionUID = 1L;
+	private ServiceComponentProp causingComponent;
+
+	public CircularityException(ServiceComponentProp scp) {
+		this.causingComponent = scp;
+	}
+
+	public ServiceComponentProp getCausingComponent() {
+		return causingComponent;
+	}
+
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/ComponentStorage.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/ComponentStorage.java
new file mode 100644
index 0000000..6625008
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/ComponentStorage.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.ds;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.*;
+import org.eclipse.equinox.internal.ds.model.DeclarationParser;
+import org.osgi.framework.Bundle;
+import org.osgi.service.component.ComponentConstants;
+
+/**
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public abstract class ComponentStorage {
+
+	private final DeclarationParser parser = new DeclarationParser();
+
+	/**
+	 * This method will load the component definitions from a bundle. The
+	 * returned value should contain vector with 'ServiceComponent' elements.
+	 * 
+	 * @param bundleID
+	 *            id of the bundle, which is processed and if contains a
+	 *            component definitions - it's xml definition file got parsed.
+	 * @return <code>null</code> if there are no component definitions.
+	 */
+	public abstract Vector loadComponentDefinitions(long bundleID);
+
+	public abstract void deleteComponentDefinitions(long bundleID) throws Exception;
+
+	public abstract void stop();
+
+	protected Vector parseXMLDeclaration(Bundle bundle) throws Exception {
+		Vector components = new Vector();
+		Dictionary headers = bundle.getHeaders(null);
+		String header = (String) headers.get(ComponentConstants.SERVICE_COMPONENT);
+
+		if (header != null) {
+			StringTokenizer tok = new StringTokenizer(header, ",");
+			// the parser is not thread safe!!!
+			synchronized (parser) {
+				// process all definition file
+				while (tok.hasMoreElements()) {
+					String definitionFile = tok.nextToken().trim();
+					int ind = definitionFile.lastIndexOf('/');
+					String path = ind != -1 ? definitionFile.substring(0, ind) : "/";
+					InputStream is = null;
+
+					Enumeration urls = bundle.findEntries(path, ind != -1 ? definitionFile.substring(ind + 1) : definitionFile, false);
+					if (urls == null || !urls.hasMoreElements()) {
+						Activator.log.error("Component definition XMLs not found in bundle " + bundle.getSymbolicName() + ". The component header value is " + definitionFile, null);
+						continue;
+					}
+
+					// illegal components are ignored, but framework event is posted for
+					// them; however, it will continue and try to load any legal
+					// definitions
+					URL url;
+					while (urls.hasMoreElements()) {
+						url = (URL) urls.nextElement();
+						if (Activator.DEBUG) {
+							Activator.log.debug(0, 10017, url.toString(), null, false);
+							////Activator.log.debug("ComponentStorage.parseXMLDeclaration(): loading " + definitionFile, null);
+						}
+						try {
+							is = url.openStream();
+							if (is == null) {
+								Activator.log.error("ComponentStorage.parseXMLDeclaration(): missing file " + url, null);
+							} else {
+								parser.parse(is, bundle, components);
+							}
+						} catch (IOException ie) {
+							Activator.log.error("[SCR] Error occured while opening component definition file " + url, ie);
+						} catch (Throwable t) {
+							Activator.log.error("Illegal definition file: " + url, t);
+						}
+					}
+				} // end while
+
+				components = parser.components;
+				// make sure the clean-up the parser cache, for the next bundle to
+				// work properly!!!
+				parser.components = null;
+			}
+
+		}
+		return components;
+	}
+
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/ConfigurationManager.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/ConfigurationManager.java
new file mode 100644
index 0000000..1ebe428
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/ConfigurationManager.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.ds;
+
+import java.io.IOException;
+
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * ConfigurationManager.java
+ * 
+ * @author Valentin Valchev
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+class ConfigurationManager {
+
+	static ServiceTracker cmTracker;
+
+	static Configuration getConfiguration(String pid) throws IOException {
+		ConfigurationAdmin cmAdmin = (ConfigurationAdmin) cmTracker.getService();
+		if (cmAdmin != null) {
+			return cmAdmin.getConfiguration(pid);
+		}
+		return null;
+	}
+
+	static Configuration[] listConfigurations(String filter) throws IOException, InvalidSyntaxException {
+		ConfigurationAdmin cmAdmin = (ConfigurationAdmin) cmTracker.getService();
+		if (cmAdmin != null) {
+			return cmAdmin.listConfigurations(filter);
+		}
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/FactoryReg.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/FactoryReg.java
new file mode 100644
index 0000000..fd50fa6
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/FactoryReg.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.ds;
+
+import org.eclipse.equinox.internal.ds.model.ServiceComponentProp;
+import org.osgi.framework.*;
+import org.osgi.service.component.ComponentException;
+import org.osgi.service.component.ComponentInstance;
+
+/**
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+final class FactoryReg implements ServiceFactory {
+
+	/* the instance created */
+	private final ServiceComponentProp component;
+
+	FactoryReg(ServiceComponentProp component) {
+		this.component = component;
+	}
+
+	// ServiceFactory.getService method.
+	public Object getService(Bundle bundle, ServiceRegistration registration) {
+
+		try {
+			if (Activator.DEBUG) {
+				Activator.log.debug(0, 10001, component.name, null, false);
+				// //Activator.log.debug("FactoryReg.getService(): created new
+				// service for component '" + component.name, null);
+			}
+			ComponentInstance ci = InstanceProcess.staticRef.buildComponent(bundle, component, null, false);
+			// ci can be null if the component is already disposed while being built
+			if (ci != null) {
+				return ci.getInstance();
+			}
+		} catch (Throwable t) {
+			if (!(t instanceof ComponentException)) {
+				Activator.log.error("RegisterComponentService: Cannot create instance of " + component.name, t);
+			} else {
+				throw (ComponentException) t;
+			}
+		}
+		return null;
+	}
+
+	// ServiceFactory.ungetService method.
+	public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) {
+		if (Activator.DEBUG) {
+			Activator.log.debug(0, 10002, registration.toString(), null, false);
+		}
+
+		component.disposeObj(service);
+	}
+
+	public String toString() {
+		return component.name + " FactoryRegistration";
+	}
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/InstanceProcess.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/InstanceProcess.java
new file mode 100644
index 0000000..00ffede
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/InstanceProcess.java
@@ -0,0 +1,735 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.ds;
+
+import java.util.*;
+import org.eclipse.equinox.internal.ds.impl.ComponentFactoryImpl;
+import org.eclipse.equinox.internal.ds.impl.ComponentInstanceImpl;
+import org.eclipse.equinox.internal.ds.model.*;
+import org.osgi.framework.*;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.component.*;
+
+/**
+ * This class is responsible for creating, tracking and disposing of service
+ * instances and registrations.
+ * 
+ * @author Valentin Valchev
+ * @author Stoyan Boshev
+ * @author Pavlin Dobrev
+ * @version 1.2
+ */
+
+public class InstanceProcess {
+
+	public static Resolver resolver;
+	public static InstanceProcess staticRef;
+
+	/** map SCP:ServiceRegistration */
+	protected Hashtable factoryRegistrations;
+
+	/**
+	 * Used with stackCount to handle circular dependencies in the
+	 * {@link InstanceProcess#buildComponent(Bundle, ServiceComponentProp, Object)}
+	 * method.
+	 */
+	private Vector delayedBindList;
+
+	//key - the SPC being built;   value - the thread that builds the SCP
+	static Hashtable buildingThreads = new Hashtable(7);
+	//key - the building thread;   value - Counter - holds the count of entries in buildComponent method  
+	static Hashtable stackCounts = new Hashtable(7);
+	//specifies the maximum time that a thread must wait for the building thread to complete the building of the SCP
+	static int waitTime = Activator.getInteger("equinox.scr.waitTimeOnBlock", 10000);
+
+	//a flag used for synchronization of build/dispose operations
+	boolean busyBuilding = false;
+	//the working thread that performs the current build/dispose operation
+	Thread workingThread;
+	//an object used for synchronization when changing the status of busyBuilding flag
+	Object lock = new Object();
+	//used to count the number of times a lock is held when required recursively 
+	int lockCounter = 0;
+
+	/**
+	 * Handle Instance processing building and disposing.
+	 * 
+	 * @param resolver
+	 *            the resolver instance
+	 */
+	InstanceProcess(Resolver resolver) {
+		InstanceProcess.resolver = resolver;
+		factoryRegistrations = new Hashtable(19);
+		delayedBindList = new Vector(10);
+		staticRef = this;
+	}
+
+	/**
+	 * dispose cleanup the SCR is shutting down
+	 */
+	void dispose() {
+		factoryRegistrations = null;
+	}
+
+	// gets the synch lock to perform some build/release work
+	void getLock() {
+		synchronized (lock) {
+			Thread currentThread = Thread.currentThread();
+			if (!busyBuilding) {
+				busyBuilding = true;
+				lockCounter++;
+				workingThread = currentThread;
+			} else if (workingThread == currentThread) {
+				//increase the lock counter - the lock is required recursively
+				lockCounter++;
+			} else if (workingThread != currentThread) {
+				long start = System.currentTimeMillis();
+				long timeToWait = waitTime;
+				boolean lockSucceeded = false;
+				do {
+					try {
+						lock.wait(timeToWait);
+					} catch (InterruptedException e) {
+						// do nothing
+					}
+					if (!busyBuilding) {
+						busyBuilding = true;
+						lockCounter++;
+						workingThread = currentThread;
+						lockSucceeded = true;
+						break;
+					}
+					timeToWait = waitTime + start - System.currentTimeMillis();
+				} while (timeToWait > 0);
+				//check if the timeout has passed or the lock is actually successfully held
+				if (!lockSucceeded) {
+					// The lock is not yet released!
+					// Allow the operation but log a warning
+					Activator.log.warning("Getting a lock required more than " + InstanceProcess.waitTime + " ms. There might be a synchronization problem in this callstack " + "or just the build/dispose process of some components took too long!", new Exception("Debug stacktrace"));
+				}
+			}
+		}
+	}
+
+	// free the synch lock 
+	void freeLock() {
+		synchronized (lock) {
+			if (busyBuilding) {
+				if (workingThread == Thread.currentThread()) {
+					//only the thread holding the lock can release it
+					lockCounter--;
+				}
+				// release the lock in case the lock counter has decreased to 0
+				if (lockCounter == 0) {
+					busyBuilding = false;
+					workingThread = null;
+					lock.notify();
+				}
+			}
+		}
+	}
+
+	/**
+	 * Builds the Service Component descriptions (registration of needed
+	 * services, building of component instances if necessary (includes
+	 * activating and binding)
+	 * 
+	 * @param list -
+	 *            a Vector of all components to build.
+	 */
+	public void buildComponents(Vector list, boolean security) {
+		ServiceComponentProp scp = null;
+		ServiceComponent sc;
+		String factoryPid = null;
+
+		// loop through SCP list of enabled
+		if (list != null) {
+			for (int i = 0; i < list.size(); i++) {
+				scp = (ServiceComponentProp) list.elementAt(i);
+				if (scp.disposed)
+					continue;
+				getLock();
+				if (scp.disposed || !InstanceProcess.resolver.satisfiedSCPs.contains(scp)) {
+					//no need to build the component - it is disposed or about to be disposed
+					freeLock();
+					continue;
+				}
+				long start = 0l;
+				try {
+					if (Activator.PERF) {
+						start = System.currentTimeMillis();
+						Activator.log.info("[DS perf] Start building component " + scp);
+					}
+					sc = scp.serviceComponent;
+					if (sc.immediate) {
+						if (Activator.DEBUG) {
+							Activator.log.debug(0, 10003, scp.name, null, false);
+							// //Activator.log.debug("InstanceProcess.buildComponents():
+							// building immediate component " + scp.name, null);
+						}
+						if (sc.serviceInterfaces != null) {
+							// this component registers service
+
+							// this will create either plain service component
+							// registration
+							// or a service factory registration
+							registerService(scp, sc.serviceFactory, null);
+						}
+						if (scp.instances.isEmpty()) {
+							// nobody has required the service after registration
+							// (and no service instance could be created),
+							// so we need to force instance creation
+							try {
+								buildComponent(null, scp, null, security);
+							} catch (Exception e) {
+								if (!(e instanceof ComponentException)) {
+									Activator.log.error("[SCR] Cannot build component " + scp, e);
+								}
+							}
+						}
+					} else {
+
+						// ComponentFactory
+						if (sc.factory != null) {
+							// check if it is NOT a component config created by a
+							// component factory
+							if (scp.isComponentFactory()) {
+								if (Activator.DEBUG) {
+									Activator.log.debug(0, 10004, scp.name, null, false);
+									// //Activator.log.debug("InstanceProcess.buildComponents():
+									// building component factory " + scp.name,
+									// null);
+								}
+
+								// check if MSF
+								try {
+									Configuration config = ConfigurationManager.getConfiguration(sc.name);
+									if (config != null) {
+										factoryPid = config.getFactoryPid();
+									}
+								} catch (Exception e) {
+									Activator.log.error("[SCR] Cannot get configuration for component " + sc.name, e);
+								}
+
+								// if MSF throw exception - can't be
+								// ComponentFactory add MSF
+								if (factoryPid != null) {
+									throw new org.osgi.service.component.ComponentException("ManagedServiceFactory and ComponentFactory are incompatible");
+								}
+								registerComponentFactory(scp);
+								// when registering a ComponentFactory we must not
+								// reguister
+								// the component configuration as service
+								continue;
+							}
+						}
+
+						// check whether there is a service to register
+						if (sc.provides != null) {
+
+							// this will create either plain service component
+							// registration
+							// or a service factory registration
+							registerService(scp, sc.serviceFactory, null);
+						}
+					}
+				} catch (Throwable t) {
+					Activator.log.error("Exception occured while building component " + scp, t);
+				} finally {
+					freeLock();
+					if (Activator.PERF) {
+						start = System.currentTimeMillis() - start;
+						Activator.log.info("[DS perf] The component " + scp + " is built for " + start + " ms");
+					}
+				}
+			} // end for
+		} // end if (list != null)
+	}
+
+	/**
+	 * 
+	 * Dispose of Component Instances, includes unregistering services and
+	 * removing instances.
+	 * 
+	 * @param scpList -
+	 *            list of ComponentDescriptions plus Property objects to be
+	 *            disposed
+	 */
+	void disposeInstances(Vector scpList) {
+		// loop through SC+P list to be disposed
+		if (scpList != null) {
+			for (int i = 0; i < scpList.size(); i++) {
+				ServiceComponentProp scp = (ServiceComponentProp) scpList.elementAt(i);
+				if (scp.disposed)
+					continue;
+				getLock();
+				if (scp.disposed) {
+					freeLock();
+					continue;
+				}
+				long start = 0l;
+				try {
+					if (Activator.PERF) {
+						start = System.currentTimeMillis();
+						Activator.log.info("[DS perf] Start disposing component " + scp);
+					}
+					disposeInstances(scp);
+				} catch (Throwable t) {
+					Activator.log.error("Exception while disposing instances of component " + scp, t);
+				} finally {
+					freeLock();
+					if (Activator.PERF) {
+						start = System.currentTimeMillis() - start;
+						Activator.log.info("[DS perf] The component " + scp + " is disposed for " + start + " ms");
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * @param scp
+	 */
+	private void disposeInstances(ServiceComponentProp scp) {
+		ServiceComponent sc = scp.serviceComponent;
+		// if no Services provided - dispose of instance immediately
+		if (sc.provides == null) {
+			if (Activator.DEBUG) {
+				Activator.log.debug(0, 10006, scp.name, null, false);
+				// //Activator.log.debug("InstanceProcess.disposeInstances():
+				// disposing non-provider component " + scp.name, null);
+			}
+			scp.dispose();
+		} else {
+			// if ComponentFactory or if just Services
+			if (scp.isComponentFactory()) {
+				if (Activator.DEBUG) {
+					Activator.log.debug(0, 10007, scp.name, null, false);
+					// //Activator.log.debug("InstanceProcess.disposeInstances():
+					// disposing component factory " + scp.name, null);
+				}
+				ServiceRegistration reg = (ServiceRegistration) factoryRegistrations.remove(scp);
+				try {
+					if (reg != null)
+						reg.unregister();
+				} catch (IllegalStateException e) {
+					// Service is already unregistered do nothing
+					Activator.log.warning("InstanceProcess.disposeInstances(): registration for component factory " + scp.name + " is already diposed!", null);
+				}
+			}
+
+			if (Activator.DEBUG) {
+				Activator.log.debug(0, 10008, scp.name, null, false);
+				// //Activator.log.debug("InstanceProcess.disposeInstances():
+				// unregistering component " + scp.name, null);
+			}
+
+			// unregister services if any
+			if (scp.registration != null) {
+				try {
+					ServiceRegistration reg = scp.registration;
+					scp.setRegistration(null);
+					reg.unregister();
+				} catch (IllegalStateException e) {
+					// Service is already unregistered do nothing
+					Activator.log.warning("InstanceProcess.disposeInstances(): registration for component " + scp.name + " is already diposed!", null);
+				}
+			} else {
+				if (Activator.DEBUG) {
+					Activator.log.debug(0, 10009, scp.name, null, false);
+					// //Activator.log.debug("InstanceProcess.disposeInstances():
+					// cannot find registrations for " + scp.name, null);
+				}
+			}
+			scp.dispose();
+		}
+	}
+
+	/**
+	 * Register the Component Factory
+	 * 
+	 * @param scp
+	 */
+	private void registerComponentFactory(ServiceComponentProp scp) {
+		if (factoryRegistrations.get(scp) != null) {
+			//the service factory is already registered
+			return;
+		}
+		ComponentFactory factory = new ComponentFactoryImpl(scp);
+		ServiceComponent sc = scp.serviceComponent;
+		BundleContext bc = scp.bc;
+		// if the factory attribute is set on the component element then
+		// register a
+		// component factory service
+		// for the Service Component on behalf of the Service Component.
+		Hashtable properties = new Hashtable(2);
+		properties.put(ComponentConstants.COMPONENT_NAME, sc.name);
+		properties.put(ComponentConstants.COMPONENT_FACTORY, sc.factory);
+		ServiceRegistration reg = bc.registerService(ComponentFactory.class.getName(), factory, properties);
+		factoryRegistrations.put(scp, reg);
+	}
+
+	/**
+	 * Called by dispatcher ( Resolver) when work available on queue
+	 * 
+	 * @param refList
+	 *            Map of ReferenceDescription:subtable Subtable Maps scp:service
+	 *            object
+	 */
+	final void dynamicBind(Vector refList) {
+		if (refList == null || refList.isEmpty()) {
+			return;
+		}
+		for (int i = 0; i < refList.size(); i++) {
+			Reference ref = (Reference) refList.elementAt(i);
+			ServiceComponentProp scp = ref.scp;
+
+			Vector instances = scp.instances;
+			if (instances != null) {
+				for (int j = 0; j < instances.size(); j++) {
+					ComponentInstance compInstance = (ComponentInstance) instances.elementAt(j);
+					if (compInstance != null) {
+						try {
+							scp.bindReference(ref, compInstance);
+						} catch (Exception ex) {
+							// ex.printStackTrace();
+						}
+					}
+				}
+			} else {
+				// the component is not used and therefore it is not yet
+				// instantiated!
+				if (Activator.DEBUG) {
+					Activator.log.debug(0, 10012, scp.name, null, false);
+					// //Activator.log.debug("InstanceProcess.dynamicBind():
+					// null instances! for component " + scp.name, null);
+				}
+			}
+		}
+	}
+
+	/**
+	 * Called by dispatcher ( Resolver) when work available on queue
+	 * 
+	 * @param serviceTable
+	 *            Map of ReferenceDescription:subtable Subtable Maps scp:service
+	 *            object
+	 */
+	final void dynamicUnBind(Hashtable serviceTable) {
+		try {
+
+			if (serviceTable == null || serviceTable.isEmpty()) {
+				return;
+			}
+			// for each element in the table
+			Enumeration e = serviceTable.keys();
+			while (e.hasMoreElements()) {
+				Reference ref = (Reference) e.nextElement();
+				Hashtable serviceSubTable = (Hashtable) serviceTable.get(ref);
+				Enumeration sub = serviceSubTable.keys();
+				while (sub.hasMoreElements()) {
+					ServiceComponentProp scp = (ServiceComponentProp) sub.nextElement();
+					ServiceReference serviceReference = (ServiceReference) serviceSubTable.get(scp);
+					// get the list of instances created
+					Vector instances = scp.instances;
+					for (int i = 0; i < instances.size(); i++) {
+						ComponentInstance compInstance = (ComponentInstance) instances.elementAt(i);
+						if (compInstance != null) {
+							try {
+								scp.unbindDynamicReference(ref, compInstance, serviceReference);
+							} catch (Throwable t) {
+								t.printStackTrace();
+							}
+						}
+					}
+				}
+			}
+		} catch (Throwable e) {
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * registerService
+	 * 
+	 * @param scp
+	 *            ComponentDescription plus Properties
+	 * @param factory
+	 *            boolean
+	 * @param ci
+	 *            the component instance created by ComponentFactoryImpl!
+	 */
+	private void registerService(ServiceComponentProp scp, boolean factory, ComponentInstanceImpl ci) {
+
+		// register the service using a ServiceFactory
+		ServiceRegistration reg = null;
+		Object service;
+		if (scp.registration != null) {
+			//the service has already been registered
+			return;
+		}
+		if (factory) {
+			// register as service factory
+			service = new FactoryReg(scp);
+		} else {
+			service = new ServiceReg(scp, ci);
+		}
+		reg = scp.bc.registerService(scp.serviceComponent.provides, service, scp.getProperties());
+
+		if (Activator.DEBUG) {
+			Activator.log.debug("InstanceProcess.registerService(): " + scp.name + " registered as " + ((factory) ? "*factory*" : "*service*"), null);
+		}
+		if (scp.disposed) {
+			//must unregister the service because it was not able to unregister when the component was disposed
+			try {
+				reg.unregister();
+				if (Activator.DEBUG) {
+					Activator.log.debug("InstanceProcess.registerService(): " + scp.name + "'s service was unregistered because the component is already disposed!", null);
+				}
+			} catch (IllegalStateException e) {
+				// Service is already unregistered do nothing
+			}
+		} else {
+			scp.setRegistration(reg);
+		}
+	}
+
+	public ComponentInstanceImpl buildComponent(Bundle usingBundle, ServiceComponentProp scp, Object instance, boolean security) throws ComponentException {
+		if (Activator.DEBUG) {
+			Activator.log.debug(0, 10005, scp.name, null, false);
+			// //Activator.log.debug("buildInstances.buildComponent(): building
+			// component " + scp.name, null);
+		}
+		getLock();
+		Counter counter;
+		Thread curThread = Thread.currentThread();
+		synchronized (scp) {
+			Thread theSCPThread = (Thread) buildingThreads.get(scp);
+			if (theSCPThread != null && curThread != theSCPThread) { //manage cyclic calls 
+				if (scp.isKindOfFactory()) {
+					// The scp is a kind of factory - multiple instances are allowed. 
+					// The building of the scp is allowed
+				} else {
+					long start = System.currentTimeMillis();
+					long timeToWait = waitTime;
+					do {
+						try {
+							scp.wait(timeToWait);
+						} catch (InterruptedException ie) {
+							//do nothing
+						}
+						if (buildingThreads.get(scp) == null) {
+							//the lock is released
+							break;
+						}
+						timeToWait = waitTime + start - System.currentTimeMillis();
+					} while (timeToWait > 0);
+
+					//check if the timeout has passed or the scp is actually built	
+					if (buildingThreads.get(scp) != null) {
+						freeLock();
+						// The SCP is not yet built
+						// We have two options here:
+						// 1 - Return the instance (if already created) nevertheless it is not finished its binding and activation phase
+						// 2 - throw an exception because something may have gone wrong
+						if (!scp.instances.isEmpty()) {
+							Activator.log.warning("Returning SCP instance which is not fully activated!", new Exception("Debug callstack"));
+							return (ComponentInstanceImpl) scp.instances.firstElement();
+						}
+
+						throw new RuntimeException("The instance creation of component " + scp + " took longer than " + waitTime + " ms. There might be a synchronization problem in this callstack or just the instance creation took too long!");
+					}
+				}
+			}
+			buildingThreads.put(scp, curThread);
+
+			// keep track of how many times we have re-entered this method
+			counter = (Counter) stackCounts.get(curThread);
+			if (counter == null) {
+				counter = new Counter();
+				stackCounts.put(curThread, counter);
+			}
+			counter.count++;
+		}
+
+		long start = 0l;
+		try {
+			if (Activator.PERF) {
+				start = System.currentTimeMillis();
+				Activator.log.info("[DS perf] Start building instance of component " + scp);
+			}
+			ComponentInstanceImpl componentInstance = null;
+			try {
+				componentInstance = scp.build(usingBundle, instance, security);
+			} catch (ComponentException e) {
+				Activator.log.error(e.getMessage(), e.getCause());
+				throw e;
+			} catch (Throwable t) {
+				Activator.log.error("[SCR] Error while building component " + scp.name, t);
+				throw new ComponentException("Error while building component " + scp.name, t);
+			} finally {
+				// keep track of how many times we have re-entered this method
+				counter.count--;
+				if (Activator.PERF) {
+					start = System.currentTimeMillis() - start;
+					Activator.log.info("[DS perf] The instance of component " + scp + " is built for " + start + " ms");
+				}
+			}
+
+			// if this is the last time in this method and we have "delayed"
+			// bind actions to do (there was a circularity during bind)
+			if (counter.count == 0 && !delayedBindList.isEmpty()) {
+				// put delayed dynamic binds on the queue.
+				// (this is used to handle circularity)
+				resolver.mgr.enqueueWork(resolver, Resolver.DYNAMICBIND, delayedBindList.clone(), security);
+				delayedBindList.removeAllElements();
+			}
+
+			return componentInstance;
+		} finally {
+			synchronized (scp) {
+				if (counter.count == 0) {
+					stackCounts.remove(curThread);
+				}
+				buildingThreads.remove(scp);
+				scp.notify();
+			}
+			freeLock();
+		}
+	}
+
+	/**
+	 * Acquire a service object from a {@link ServiceReference}.
+	 * 
+	 * This method checks if "getting" the service could cause a cycle. If so,
+	 * it breaks the cycle and returns null.
+	 * 
+	 * @param reference
+	 * @param serviceReference
+	 * 
+	 * @return the service object or null if it would cause a circularity
+	 */
+	public Object getService(Reference reference, ServiceReference serviceReference) {
+		// check if getting this service would cause a circularity
+		if (checkCanCauseCycle(reference, serviceReference)) {
+			if (Activator.DEBUG) {
+				Activator.log.debug(0, 10010, reference.reference.name + " ; The service reference is " + serviceReference, null, false);
+				// //Activator.log.debug("InstanceProcess.getService(): cannot
+				// get service because of circularity! Reference is: " +
+				// reference.reference.name, null);
+			}
+			return null;
+		}
+
+		// getting this service will not cause a circularity
+		return reference.scp.bc.getService(serviceReference);
+
+	}
+
+	/**
+	 * Check the "cycle list" put in the scp by the resolver to see if getting
+	 * this reference would cause a circularity.
+	 * 
+	 * A circularity is only possible if the "producer" of the service is also a
+	 * service component.
+	 * 
+	 * If getting the service could cause a circularity and the reference's
+	 * policy is "dynamic", add an entry to the "delayed bind list" which is
+	 * processed when the component is built
+	 * 
+	 * @param reference
+	 * @param serviceReference
+	 * @return if getting the service could cause a circularity
+	 */
+	private boolean checkCanCauseCycle(Reference reference, ServiceReference serviceReference) {
+
+		ServiceComponentProp consumerSCP = reference.scp;
+		// if we are not building a component, no cycles possible
+		if (buildingThreads.isEmpty()) {
+			return false;
+		}
+
+		String producerComponentName = (String) serviceReference.getProperty(ComponentConstants.COMPONENT_NAME);
+
+		// if producer is not a service component, no cycles possible
+		if (producerComponentName == null) {
+			return false;
+		}
+
+		// check if producer is the "delayed activate" list
+		if (consumerSCP.getDelayActivateSCPNames() == null || !consumerSCP.getDelayActivateSCPNames().contains(producerComponentName)) {
+			return false;
+		}
+
+		// find producer scp
+		ServiceComponentProp producerSCP = null;
+		synchronized (resolver.satisfiedSCPs) {
+			for (int i = 0; i < resolver.satisfiedSCPs.size(); i++) {
+				ServiceComponentProp scp = (ServiceComponentProp) resolver.satisfiedSCPs.elementAt(i);
+				if (producerComponentName.equals(scp.serviceComponent.name)) {
+					// found the producer scp
+					producerSCP = scp;
+					break;
+				}
+			}
+		}
+
+		if (producerSCP != null) {
+			if (producerSCP.serviceComponent.serviceFactory) {
+				// producer is a service factory - there is a new instance for
+				// every
+				// bundle, so see if one of the instances is used by this bundle
+				if (!producerSCP.instances.isEmpty()) {
+					Bundle bundle = consumerSCP.bc.getBundle();
+					for (int i = 0; i < producerSCP.instances.size(); i++) {
+						ComponentInstanceImpl producerComponentInstance = (ComponentInstanceImpl) producerSCP.instances.elementAt(i);
+						if (producerComponentInstance.getComponentContext().getUsingBundle().equals(bundle)) {
+							// a producer already exists, so no cycle possible
+							return false;
+						}
+					}
+				}
+			} else {
+				// producer is not a service factory - there will only ever be
+				// one
+				// instance - if it exists then no cycle possible
+				if (!producerSCP.instances.isEmpty()) {
+					return false;
+				}
+			}
+		}
+
+		// producer scp is not active - do not activate it because that could
+		// cause circularity
+
+		// if reference has bind method and policy=dynamic, activate later and
+		// bind
+		if (reference.reference.bind != null && reference.policy == ComponentReference.POLICY_DYNAMIC) {
+			// delay bind by putting on the queue later
+			delayedBindList.addElement(reference);
+		}
+
+		// can't get service now because of circularity - we will bind later
+		// (dynamically) if the reference had a bind method and was dynamic
+		return true;
+	}
+
+	/**
+	 * Counts re-entry in to the
+	 * {@link InstanceProcess#buildComponent(Bundle, ServiceComponentProp, Object)} method. 
+	 * This is used to handle circular dependencies.
+	 */
+	class Counter {
+		int count = 0;
+	}
+
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/Reference.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/Reference.java
new file mode 100644
index 0000000..bfb5996
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/Reference.java
@@ -0,0 +1,213 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.ds;
+
+import java.util.Dictionary;
+import java.util.Vector;
+import org.eclipse.equinox.internal.ds.model.*;
+import org.osgi.framework.*;
+import org.osgi.service.component.ComponentConstants;
+
+/**
+ * The reference class is used only in the resolver. It is actually like
+ * "instance of a references". It is used to track available, eligible
+ * references. The reference objects relates to ServiceComponentProp as many to
+ * one.
+ * 
+ * @author Valentin Valchev
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public final class Reference {
+
+	public ComponentReference reference;
+	ServiceComponentProp scp;
+
+	// -- begin cache
+	String interfaceName;
+	String target;
+	int policy;
+	int cardinalityHigh;
+	int cardinalityLow;
+
+	// -- end cache
+
+	/**
+	 * Reference object
+	 * 
+	 * @param reference
+	 *            the component reference
+	 * @param properties
+	 *            the *actual* properties that the component has. These are the
+	 *            SCP properties, e.g the default one in the XML file + the one
+	 *            that are configured in the CM.
+	 */
+	Reference(ComponentReference reference, ServiceComponentProp scp, Dictionary properties) {
+		this.reference = reference;
+		this.scp = scp;
+		this.interfaceName = reference.interfaceName;
+		this.target = reference.target;
+
+		// RFC 80 section 5.3.1.3:
+		// If [target] is not specified and there is no <reference-name>.target
+		// component
+		// property, then the selection filter used to select the desired
+		// service is
+		// �(objectClass=�+<interface-name>+�)�.
+		if (properties != null) {
+			target = (String) properties.get(reference.name + ComponentConstants.REFERENCE_TARGET_SUFFIX);
+		}
+		if (target == null) {
+			target = "(objectClass=" + interfaceName + ")";
+		}
+
+		// If it is not specified, then a policy of �static� is used.
+		policy = reference.policy;
+
+		// Cardinality indicates the number of services, matching this
+		// reference,
+		// which will bind to this Service Component. Possible values are:
+		// 0..1, 0..n, 1..1 (i.e. exactly one), 1..n (i.e. at least one).
+		// This attribute is optional. If it is not specified, then a
+		// cardinality
+		// of �1..1� is used.
+		switch (reference.cardinality) {
+			case ComponentReference.CARDINALITY_0_1 :
+				cardinalityLow = 0;
+				cardinalityHigh = 1;
+				break;
+			case ComponentReference.CARDINALITY_0_N :
+				cardinalityLow = 0;
+				cardinalityHigh = 999999999;
+				break;
+			case ComponentReference.CARDINALITY_1_1 :
+				cardinalityLow = 1;
+				cardinalityHigh = 1;
+				break;
+			case ComponentReference.CARDINALITY_1_N :
+				cardinalityLow = 1;
+				cardinalityHigh = 999999999;
+		}
+
+	}
+
+	// used in Resolver.resolveEligible()
+	final boolean hasProviders() {
+		// check whether the component's bundle has service GET permission
+		if (System.getSecurityManager() != null && !scp.bc.getBundle().hasPermission(new ServicePermission(interfaceName, ServicePermission.GET))) {
+			return false;
+		}
+		// Get all service references for this target filter
+		try {
+			ServiceReference[] serviceReferences = null;
+			serviceReferences = scp.bc.getServiceReferences(interfaceName, target);
+			// if there is no service published that this Service
+			// ComponentReferences
+			if (serviceReferences != null) {
+				return true;
+			}
+		} catch (InvalidSyntaxException e) {
+			Activator.log.warning("Reference.hasLegacyProviders(): invalid target filter " + target, e);
+		}
+		return false;
+	}
+
+	// if the cardinality is "0..1" or "0..n" then this refernce is not required
+	final boolean isRequiredFor(ServiceComponent cd) {
+		// // we want to re-resolve if the component is static and already
+		// eligible
+		// if (policy == ComponentReference.POLICY_STATIC && cd.eligible) {
+		// return true;
+		// }
+		return cardinalityLow == 1;
+	}
+
+	final boolean isRequired() {
+		return cardinalityLow == 1;
+	}
+
+	// used in Resolver.selectDynamicBind()
+	final boolean bindNewReference(ServiceReference reference, boolean dynamicBind) {
+		if (dynamicBind) {
+			if (policy == ComponentReference.POLICY_STATIC) {
+				return false;
+			}
+		} else {
+			if (policy == ComponentReference.POLICY_DYNAMIC) {
+				return false;
+			}
+		}
+		String[] serviceNames = (String[]) reference.getProperty(Constants.OBJECTCLASS);
+		boolean hasName = false;
+		for (int i = 0; i < serviceNames.length; i++) {
+			if (serviceNames[i].equals(interfaceName)) {
+				hasName = true;
+				break;
+			}
+		}
+		if (!hasName) {
+			return false;
+		}
+		// check target filter
+		try {
+			Filter filter = FrameworkUtil.createFilter(target);
+			if (!filter.match(reference)) {
+				return false;
+			}
+		} catch (InvalidSyntaxException e) {
+			return false;
+		}
+		if (this.reference.serviceReferences.size() < cardinalityHigh) {
+			return true;
+		}
+		return false;
+	}
+
+	// used in Resolver.selectDynamicUnBind();
+	final boolean unBindReference(BundleContext bundleContext, ServiceReference reference) {
+		// nothing dynamic to do if static
+		if (policy == ComponentReference.POLICY_STATIC) {
+			return false;
+		}
+		// now check if the Service Reference is found in the list of saved
+		// ServiceReferences
+		if (!this.reference.serviceReferences.contains(reference)) {
+			return false;
+		}
+		return true;
+	}
+
+	public ServiceComponentProp findProviderSCP(Vector scps) {
+		Filter filter;
+		try {
+			filter = FrameworkUtil.createFilter(target);
+		} catch (InvalidSyntaxException e) {
+			Activator.log.warning("Reference.findProviderSCP(): invalid target filter " + target, e);
+			return null;
+		}
+		for (int i = 0; i < scps.size(); i++) {
+			ServiceComponentProp providerSCP = (ServiceComponentProp) scps.elementAt(i);
+			if (providerSCP.serviceComponent.serviceInterfaces != null && providerSCP.serviceComponent.serviceInterfaces.contains(interfaceName)) {
+				if (filter.match(providerSCP.getProperties())) {
+					return providerSCP;
+				}
+			}
+		}
+		return null;
+	}
+
+	public void setScp(ServiceComponentProp scp) {
+		this.scp = scp;
+	}
+
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/Resolver.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/Resolver.java
new file mode 100644
index 0000000..8b16060
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/Resolver.java
@@ -0,0 +1,1058 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.ds;
+
+import java.util.*;
+import org.eclipse.equinox.internal.ds.model.*;
+import org.osgi.framework.*;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.component.ComponentException;
+
+/**
+ * Resolver.java
+ * 
+ * @author Valentin Valchev
+ * @author Stoyan Boshev
+ * @author Pavlin Dobrev
+ * @version 1.1
+ */
+
+public final class Resolver implements WorkPerformer {
+
+	// these strings are used only for debugging purpose
+	static final String[] WORK_TITLES = {"BUILD ", "DYNAMICBIND "};
+
+	/**
+	 * Service Component instances need to be built.
+	 */
+	public static final int BUILD = 1;
+
+	/**
+	 * Service Component instances need to be rebound
+	 */
+	public static final int DYNAMICBIND = 2;
+
+	/* [SC+P] enabled */
+	private Vector scpEnabled;
+
+	/**
+	 * List of ComponentDescriptionProps, which are currently "satisfied"
+	 * Component Configurations. this list is a subset of
+	 * {@link Resolver#scpEnabled scpEnabled}.
+	 */
+	public Vector satisfiedSCPs;
+
+	private InstanceProcess instanceProcess;
+
+	private Object syncLock = new Object();
+
+	public SCRManager mgr;
+
+	// TODO: Add a hashtable connecting servicereference to a list of References
+	// which they are bound to
+	// This way the search of references to unbind becomes faster when there are
+	// plenty of components.
+	// Keep in mind that build process is asynchronous.
+
+	/**
+	 * Resolver constructor
+	 * 
+	 */
+	Resolver(SCRManager mgr) {
+		scpEnabled = new Vector();
+		satisfiedSCPs = new Vector();
+		instanceProcess = new InstanceProcess(this);
+		this.mgr = mgr;
+	}
+
+	public Object getSyncLock() {
+		return syncLock;
+	}
+
+	// This method should be called when the event processing thread is blocked
+	// in a user code
+	void queueBlocked() {
+		syncLock = new Object();
+		instanceProcess = new InstanceProcess(this);
+	}
+
+	/**
+	 * Clean up the SCR is shutting down
+	 */
+	void dispose() {
+		Activator.log.info("Resolver.dispose()");
+		if (instanceProcess != null) {
+			instanceProcess.dispose();
+			instanceProcess = null;
+		}
+
+		scpEnabled.removeAllElements();
+		satisfiedSCPs.removeAllElements();
+	}
+
+	// -- begin *enable* component routines
+	/**
+	 * enableComponents - called by the dispatchWorker
+	 * 
+	 * @param serviceComponents -
+	 *            a list of all component descriptions for a single bundle to be
+	 *            enabled Receive ArrayList of enabled CD's from ComponentCache
+	 *            For each CD add to list of enabled create list of CD:CD+P
+	 *            create list of CD+P:ref ( where ref is a Reference Object)
+	 *            resolve CD+P
+	 */
+	void enableComponents(Vector serviceComponents) {
+		long start = 0l;
+		if (Activator.DEBUG) {
+			Activator.log.debug(0, 10062, serviceComponents != null ? serviceComponents.toString() : "null", null, false);
+			// //Activator.log.debug("Resolver.enableComponents(): " +
+			// serviceComponents, null);
+		}
+		if (Activator.PERF) {
+			start = System.currentTimeMillis();
+		}
+
+		synchronized (syncLock) {
+			Configuration[] configs = null;
+
+			if (serviceComponents != null) {
+				for (int i = 0; i < serviceComponents.size(); i++) {
+					ServiceComponent current = (ServiceComponent) serviceComponents.elementAt(i);
+					// don't enable components which are not marked enabled
+					// this is done here, not in the activator just because it
+					// saves a little memory
+					if (!current.enabled) {
+						if (Activator.DEBUG) {
+							Activator.log.debug(0, 10019, current.name, null, false);
+							// //Activator.log.debug("Resolver.enableComponents():
+							// ignoring not enabled component " + current.name,
+							// null);
+						}
+						continue;
+					}
+
+					// check for a Configuration properties for this component
+					try {
+						String filter = "(|(" + Constants.SERVICE_PID + '=' + current.name + ")(" + ConfigurationAdmin.SERVICE_FACTORYPID + '=' + current.name + "))";
+						configs = ConfigurationManager.listConfigurations(filter);
+					} catch (Exception e) {
+						Activator.log.error("[SCR] Cannot list configurations for component " + current.name, e);
+					}
+					// if no Configuration
+					if (configs == null || configs.length == 0) {
+						// create ServiceComponent + Prop
+						map(current, (Dictionary) null);
+					} else {
+						// if ManagedServiceFactory
+						Configuration config = configs[0];
+						if (config.getFactoryPid() != null) {
+							// if ComponentFactory is specified
+							if (current.factory != null) {
+								Activator.log.error("[SCR - Resolver] Cannot specify both ComponentFactory and ManagedServiceFactory\n" + "The name of the ComponentFactory component is " + current.name, null);
+								continue; // skip current component
+							}
+							Activator.log.info("Resolver.enableComponents(): " + current.name + " as *managed service factory*");
+							try {
+								configs = ConfigurationManager.listConfigurations("(service.factoryPid=" + config.getFactoryPid() + ")");
+							} catch (Exception e) {
+								Activator.log.error("[SCR] Cannot list configurations for component " + current.name, e);
+							}
+							// for each MSF set of properties(P), map(CD, new
+							// CD+P(CD,P))
+							if (configs != null) {
+								for (int index = 0; index < configs.length; index++) {
+									map(current, configs[index]);
+								}
+							}
+						} else {
+							Activator.log.info("Resolver.enableComponents(): " + current.name + " as *service*");
+							// if Service, not ManagedServiceFactory
+							map(current, config);
+						}
+					} // end has configuration
+				} // end process all components!
+			}
+		}
+
+		buildNewlySatisfied();
+
+		if (Activator.PERF) {
+			start = System.currentTimeMillis() - start;
+			Activator.log.info((serviceComponents != null ? "[DS perf] " + serviceComponents.size() : "[DS perf]") + " Components enabled for " + start + " ms");
+		}
+	}
+
+	protected ServiceComponentProp map(ServiceComponent component, Configuration config) {
+		Dictionary configProps = null;
+		if (config != null) {
+			try {
+				configProps = config.getProperties();
+			} catch (IllegalStateException ise) {
+				// the configuration may have beed deleted already
+			}
+		}
+		ServiceComponentProp scp = map(component, configProps);
+		if (config != null) {
+			// set the service PID & Factory Pid
+			String pid = config.getPid();
+			String fpid = config.getFactoryPid();
+			if (pid != null)
+				scp.properties.put(Constants.SERVICE_PID, pid);
+			if (fpid != null)
+				scp.properties.put(ConfigurationAdmin.SERVICE_FACTORYPID, fpid);
+		}
+		return scp;
+	}
+
+	/**
+	 * Create the SCP and add to the maps
+	 * 
+	 * @param component
+	 * @param config
+	 *            CM configuration
+	 */
+	public ServiceComponentProp map(ServiceComponent component, Dictionary configProperties) {
+		ServiceComponentProp scp = null;
+		try {
+			if (Activator.DEBUG) {
+				Activator.log.debug(0, 10063, component.name, null, false);
+				// //Activator.log.debug("Resolver.map(): Creating SCP for
+				// component " + component.name, null);
+			}
+			scp = new ServiceComponentProp(component, configProperties, mgr);
+
+			// Get all the required service reference descriptions for this
+			Vector referenceDescriptions = component.references;
+
+			// for each Reference Description, create a reference object
+			if (referenceDescriptions != null && !referenceDescriptions.isEmpty()) {
+				Vector references = new Vector(referenceDescriptions.size());
+
+				for (int i = 0; i < referenceDescriptions.size(); i++) {
+					// create new Reference Object and add to CD+P:ref map
+					ComponentReference cRef = (ComponentReference) referenceDescriptions.elementAt(i);
+
+					Reference ref = new Reference(cRef, scp, scp.getProperties());
+					references.addElement(ref);
+				}
+				scp.references = references;
+			}
+			component.addServiceComponentProp(scp);
+			scpEnabled.addElement(scp);
+
+		} catch (Throwable t) {
+			t.printStackTrace();
+		}
+		return scp;
+	}
+
+	/**
+	 * Get the Eligible Components
+	 * 
+	 * loop through CD+P list of enabled get references check if eligible if
+	 * true add to eligible list send to Instance Process
+	 * 
+	 */
+	void getEligible(ServiceEvent event) {
+		if (scpEnabled.isEmpty())
+			return; // check for any enabled configurations
+
+		if (Activator.DEBUG) {
+			Activator.log.debug(0, 10020, event.toString(), null, false);
+			////Activator.log.debug("Resolver.getEligible(): processing service event " + event, null);
+			String eventType = "";
+			if (event.getType() == ServiceEvent.UNREGISTERING) {
+				eventType = "UNREGISTERING";
+			} else if (event.getType() == ServiceEvent.REGISTERED) {
+				eventType = "REGISTERED";
+			} else if (event.getType() == ServiceEvent.MODIFIED) {
+				eventType = "MODIFIED";
+			}
+			Activator.log.debug(0, 10050, eventType, null, false);
+		}
+
+		Object target = null;
+		Vector resolvedComponents = null;
+		switch (event.getType()) {
+			case ServiceEvent.REGISTERED :
+				Vector componentsWithStaticRefs;
+				synchronized (syncLock) {
+					componentsWithStaticRefs = selectStaticBind(satisfiedSCPs, event.getServiceReference());
+					if (componentsWithStaticRefs != null) {
+						removeAll(satisfiedSCPs, componentsWithStaticRefs);
+					}
+				}
+				if (componentsWithStaticRefs != null) {
+					instanceProcess.disposeInstances(componentsWithStaticRefs);
+				}
+
+				synchronized (syncLock) {
+					resolvedComponents = resolveEligible();
+					//no need to sync here
+					target = selectDynamicBind(resolvedComponents, event.getServiceReference());
+
+					// build the newly satisfied components
+					removeAll(resolvedComponents, satisfiedSCPs);
+					if (!resolvedComponents.isEmpty()) {
+						addAll(satisfiedSCPs, resolvedComponents);
+					}
+				}
+
+				//do synchronous bind
+				if (target != null) {
+					instanceProcess.dynamicBind((Vector) target);
+				}
+
+				if (!resolvedComponents.isEmpty()) {
+					instanceProcess.buildComponents(resolvedComponents, false);
+				}
+
+				break;
+			case ServiceEvent.UNREGISTERING :
+				Vector newlyUnsatisfiedSCPs;
+				synchronized (syncLock) {
+					newlyUnsatisfiedSCPs = (Vector) satisfiedSCPs.clone();
+					removeAll(newlyUnsatisfiedSCPs, resolveEligible());
+					if (!newlyUnsatisfiedSCPs.isEmpty()) {
+						removeAll(satisfiedSCPs, newlyUnsatisfiedSCPs);
+					}
+				}
+				if (!newlyUnsatisfiedSCPs.isEmpty()) {
+					// synchronously dispose newly unsatisfied components
+					instanceProcess.disposeInstances(newlyUnsatisfiedSCPs);
+				}
+
+				Vector componentsToDispose;
+				Vector newlySatisfiedSCPs = null;
+				synchronized (syncLock) {
+					//check for components with static reference to this service
+					componentsToDispose = selectStaticUnBind(satisfiedSCPs, event.getServiceReference());
+					if (componentsToDispose != null) {
+						removeAll(satisfiedSCPs, componentsToDispose);
+					}
+				}
+				//dispose instances from staticUnbind
+				if (componentsToDispose != null) {
+					instanceProcess.disposeInstances(componentsToDispose);
+				}
+
+				synchronized (syncLock) {
+					// Pass in the set of currently resolved components, check each one -
+					// do we need to unbind
+					target = selectDynamicUnBind(satisfiedSCPs, event.getServiceReference());
+
+					if (componentsToDispose != null) {
+						// some components with static references were disposed. Try to build them again
+						// get list of newly satisfied SCPs and build them
+						newlySatisfiedSCPs = resolveEligible();
+						removeAll(newlySatisfiedSCPs, satisfiedSCPs);
+						if (!newlySatisfiedSCPs.isEmpty()) {
+							addAll(satisfiedSCPs, newlySatisfiedSCPs);
+						}
+					}
+				}
+
+				instanceProcess.dynamicUnBind((Hashtable) target); // do synchronous unbind
+
+				if (newlySatisfiedSCPs != null && !newlySatisfiedSCPs.isEmpty()) {
+					instanceProcess.buildComponents(newlySatisfiedSCPs, false);
+				}
+
+				return;
+
+			case ServiceEvent.MODIFIED :
+				synchronized (syncLock) {
+					// check for newly unsatisfied components and synchronously
+					// dispose them
+					newlyUnsatisfiedSCPs = (Vector) satisfiedSCPs.clone();
+					removeAll(newlyUnsatisfiedSCPs, resolveEligible());
+					if (!newlyUnsatisfiedSCPs.isEmpty()) {
+						removeAll(satisfiedSCPs, newlyUnsatisfiedSCPs);
+					}
+				}
+
+				if (!newlyUnsatisfiedSCPs.isEmpty()) {
+					instanceProcess.disposeInstances(newlyUnsatisfiedSCPs);
+				}
+
+				synchronized (syncLock) {
+					//check for components with static reference to this service
+					componentsToDispose = selectStaticUnBind(satisfiedSCPs, event.getServiceReference());
+					if (componentsToDispose != null) {
+						removeAll(satisfiedSCPs, componentsToDispose);
+					}
+				}
+
+				if (componentsToDispose != null) {
+					instanceProcess.disposeInstances(componentsToDispose);
+				}
+
+				synchronized (syncLock) {
+					// dynamic unbind
+					// check each satisfied scp - do we need to unbind
+					target = selectDynamicUnBind(satisfiedSCPs, event.getServiceReference());
+				}
+
+				if (target != null) {
+					instanceProcess.dynamicUnBind((Hashtable) target);
+				}
+
+				synchronized (syncLock) {
+					// dynamic bind
+					target = selectDynamicBind(satisfiedSCPs, event.getServiceReference());
+
+					// get list of newly satisfied SCPs and build them
+					newlySatisfiedSCPs = resolveEligible();
+					removeAll(newlySatisfiedSCPs, satisfiedSCPs);
+					if (!newlySatisfiedSCPs.isEmpty()) {
+						addAll(satisfiedSCPs, newlySatisfiedSCPs);
+					}
+				}
+
+				if (target != null) {
+					instanceProcess.dynamicBind((Vector) target);
+				}
+				if (!newlySatisfiedSCPs.isEmpty()) {
+					instanceProcess.buildComponents(newlySatisfiedSCPs, false);
+				}
+		}
+	}
+
+	void buildNewlySatisfied() {
+		Vector resolvedComponents;
+		synchronized (syncLock) {
+			findDependencyCycles();
+			resolvedComponents = resolveEligible();
+			removeAll(resolvedComponents, satisfiedSCPs);
+			if (!resolvedComponents.isEmpty()) {
+				addAll(satisfiedSCPs, resolvedComponents);
+			}
+		}
+
+		if (!resolvedComponents.isEmpty()) {
+			instanceProcess.buildComponents(resolvedComponents, false);
+		}
+	}
+
+	private Vector resolveEligible() {
+		try {
+			Vector enabledSCPs = (Vector) scpEnabled.clone();
+			for (int k = enabledSCPs.size() - 1; k >= 0; k--) {
+				ServiceComponentProp scp = (ServiceComponentProp) enabledSCPs.elementAt(k);
+				Vector refs = scp.references;
+				for (int i = 0; refs != null && i < refs.size(); i++) {
+					// Loop though all the references (dependencies)for a given
+					// scp. If a dependency is not met, remove it's associated
+					// scp and
+					// re-run the algorithm
+					Reference reference = (Reference) refs.elementAt(i);
+					if (reference != null) {
+						boolean resolved = !reference.isRequiredFor(scp.serviceComponent) || reference.hasProviders();
+
+						if (!resolved) {
+							if (Activator.DEBUG) {
+								Activator.log.debug("Resolver.resolveEligible(): reference '" + reference.reference.name + "' of component '" + scp.name + "' is not resolved", null);
+							}
+							enabledSCPs.removeElementAt(k);
+							break;
+						} else if (scp.disposed) {
+							scp.disposed = false;
+						}
+					}
+				}
+				// check if the bundle providing the service has permission to
+				// register the provided interface(s)
+				if (scp.serviceComponent.provides != null && System.getSecurityManager() != null) {
+					String[] provides = scp.serviceComponent.provides;
+					boolean hasPermission = true;
+					int i = 0;
+					for (; i < provides.length; i++) {
+						// make sure bundle has permission to register the
+						// service
+						try {
+							if (!scp.bc.getBundle().hasPermission(new ServicePermission(provides[i], ServicePermission.REGISTER))) {
+								hasPermission = false;
+								break;
+							}
+						} catch (IllegalStateException ise) {
+							// the bundle of the service component is
+							// uninstalled
+							// System.out.println("IllegalStateException occured
+							// while processing component "+scp);
+							// ise.printStackTrace();
+							hasPermission = false;
+							break;
+						} catch (Throwable t) {
+							// System.out.println("Exception occured processing
+							// component "+scp);
+							// t.printStackTrace();
+							hasPermission = false;
+							break;
+						}
+					}
+					if (!hasPermission) {
+						if (Activator.DEBUG) {
+							Activator.log.debug("Resolver.resolveEligible(): Cannot satisfy component '" + scp.name + "' because its bundle does not have permissions to register service with interface " + provides[i], null);
+						}
+						scpEnabled.removeElementAt(k);
+						enabledSCPs.removeElementAt(k);
+						continue;
+					}
+				}
+			}
+
+			// if (Activator.DEBUG) {
+			// Activator.log.debug(0, 10021, enabledSCPs.toString(), null,
+			// false);
+			// ////Activator.log.debug("Resolver:resolveEligible(): resolved
+			// components = " + enabledSCPs, null);
+			// }
+			return enabledSCPs;
+		} catch (Throwable e) {
+			e.printStackTrace();
+			return null;
+		}
+	}
+
+	// -- begin *disable* component routines
+	/**
+	 * Disable list of ComponentDescriptions
+	 * 
+	 * get all CD+P's from CD:CD+P Map get instances from CD+P:list of instance
+	 * (1:n) map
+	 * 
+	 * Strip out of Map all CD+P's Continue to pull string check each Ref
+	 * dependency and continue to pull out CD+P's if they become not eligible
+	 * Then call Resolver to re-resolve
+	 * 
+	 * @param componentDescriptions
+	 */
+	void disableComponents(Vector componentDescriptions) {
+		long start = 0l;
+		if (Activator.PERF) {
+			start = System.currentTimeMillis();
+		}
+
+		ServiceComponentProp scp;
+		ServiceComponent component;
+
+		Vector removeList = null;
+
+		// Received list of CDs to disable
+		if (componentDescriptions != null) {
+			for (int i = 0; i < componentDescriptions.size(); i++) {
+				// get the first CD
+				component = (ServiceComponent) componentDescriptions.elementAt(i);
+				component.enabled = false;
+				if (Activator.DEBUG) {
+					Activator.log.debug(0, 10022, component.name, null, false);
+					////Activator.log.debug("Resolver.disableComponents()" + component.name, null);
+				}
+
+				// then get the list of SCPs for this CD
+				Vector scpList = component.componentProps;
+				if (scpList != null) {
+					for (int iter = 0; iter < scpList.size(); iter++) {
+						scp = (ServiceComponentProp) scpList.elementAt(iter);
+						if (removeList == null) {
+							removeList = new Vector();
+						}
+						removeList.addElement(scp);
+					}
+				}
+				if (removeList != null) {
+					disposeComponentConfigs(removeList);
+					removeList.removeAllElements();
+				}
+				if (component.componentProps != null) {
+					component.componentProps.removeAllElements();
+				}
+			}
+		}
+
+		Vector newlyUnsatisfiedSCPs;
+		synchronized (syncLock) {
+			// synchronously dispose newly unsatisfied components
+			newlyUnsatisfiedSCPs = (Vector) satisfiedSCPs.clone();
+			removeAll(newlyUnsatisfiedSCPs, resolveEligible());
+			if (!newlyUnsatisfiedSCPs.isEmpty()) {
+				removeAll(satisfiedSCPs, newlyUnsatisfiedSCPs);
+			}
+		}
+		if (!newlyUnsatisfiedSCPs.isEmpty()) {
+			instanceProcess.disposeInstances(newlyUnsatisfiedSCPs);
+		}
+		if (Activator.PERF) {
+			start = System.currentTimeMillis() - start;
+			Activator.log.info("[DS perf] " + componentDescriptions.size() + " Components disabled for " + start + " ms");
+		}
+	}
+
+	public void disposeComponentConfigs(Vector scps) {
+		// unregister, deactivate, and unbind
+		synchronized (syncLock) {
+			removeAll(satisfiedSCPs, scps);
+			removeAll(scpEnabled, scps);
+		}
+		instanceProcess.disposeInstances(scps);
+	}
+
+	// -- end *service listener*
+
+	public void performWork(int workAction, Object workObject) {
+		try {
+			if (Activator.DEBUG) {
+				String work = WORK_TITLES[workAction - 1];
+				Activator.log.debug(0, 10023, work + workObject, null, false);
+				////Activator.log.debug("Resolver.dispatchWork(): " + work + workObject, null);
+			}
+			switch (workAction) {
+				case BUILD :
+					if (workObject != null) {
+						Vector queue = (Vector) workObject;
+						synchronized (syncLock) {
+							// remove unsatisfied configs
+							for (int i = queue.size() - 1; i >= 0; i--) {
+								if (!satisfiedSCPs.contains(queue.elementAt(i))) {
+									//System.out.println("-----BUILD: removing "+queue.elementAt(i));
+									queue.removeElementAt(i);
+								}
+							}
+							if (queue.isEmpty())
+								return;
+						}
+						instanceProcess.buildComponents(queue, false);
+
+						// dispose configs that were already tried to dispose while building
+						Vector toDispose = null;
+						synchronized (syncLock) {
+							for (int i = queue.size() - 1; i >= 0; i--) {
+								if (!satisfiedSCPs.contains(queue.elementAt(i))) {
+									//System.out.println("-----DISPOSE after BUILD: removing "+queue.elementAt(i));
+									if (toDispose == null) {
+										toDispose = new Vector(2);
+									}
+									toDispose.addElement(queue.elementAt(i));
+								}
+							}
+							if (toDispose == null)
+								return; //nothing to dispose
+						}
+						instanceProcess.disposeInstances(toDispose);
+					}
+					break;
+				case DYNAMICBIND :
+					if (workObject != null) {
+						Vector toBind = (Vector) workObject;
+						synchronized (syncLock) {
+							// remove unsatisfied configs
+							for (int i = toBind.size() - 1; i >= 0; i--) {
+								Reference ref = (Reference) toBind.elementAt(i);
+								if (!satisfiedSCPs.contains(ref.scp)) {
+									//System.out.println("--BIND: removing "+ref.scp);
+									toBind.removeElementAt(i);
+								}
+							}
+							if (toBind.isEmpty())
+								return;
+						}
+						instanceProcess.dynamicBind(toBind);
+
+					}
+					break;
+			}
+		} catch (Throwable e) {
+			e.printStackTrace();
+		}
+	}
+
+	private Vector selectDynamicBind(Vector scps, ServiceReference serviceReference) {
+		try {
+			Vector toBind = null;
+			for (int i = 0, size = scps.size(); i < size; i++) {
+				ServiceComponentProp scp = (ServiceComponentProp) scps.elementAt(i);
+				// if it is not already eligible it will bind with the static
+				// scps
+				Vector references = scp.references;
+				// it is absolutely legal component if it doesn't contains
+				// references!
+				if (references != null) {
+					for (int j = 0; j < references.size(); j++) {
+						Reference reference = (Reference) references.elementAt(j);
+						if (reference.bindNewReference(serviceReference, true)) {
+							if (toBind == null) {
+								toBind = new Vector(2);
+							}
+							toBind.addElement(reference);
+						}
+					}
+				}
+			}
+			if (toBind != null && Activator.DEBUG) {
+				Activator.log.debug(0, 10025, toBind.toString(), null, false);
+				// //Activator.log.debug("Resolver.selectDynamicBind(): selected
+				// = " + bindTable, null);
+			}
+			return toBind;
+		} catch (Throwable t) {
+			t.printStackTrace();
+			return null;
+		}
+	}
+
+	private Vector selectStaticBind(Vector scps, ServiceReference serviceReference) {
+		try {
+			Vector toBind = null;
+			for (int i = 0, size = scps.size(); i < size; i++) {
+				ServiceComponentProp scp = (ServiceComponentProp) scps.elementAt(i);
+				// if it is not already eligible it will bind with the static
+				// scps
+				Vector references = scp.references;
+				if (references != null) {
+					for (int j = 0; j < references.size(); j++) {
+						Reference reference = (Reference) references.elementAt(j);
+						if (reference.bindNewReference(serviceReference, false)) {
+							if (toBind == null) {
+								toBind = new Vector(2);
+							}
+							toBind.addElement(scp);
+							break;
+						}
+					}
+				}
+			}
+			if (toBind != null && Activator.DEBUG) {
+				Activator.log.debug(0, 10061, toBind.toString(), null, false);
+				// //Activator.log.debug("Resolver.selectStaticBind(): selected
+				// = " + toBind, null);
+			}
+			return toBind;
+		} catch (Throwable t) {
+			t.printStackTrace();
+			return null;
+		}
+	}
+
+	private Vector selectStaticUnBind(Vector scpsToCheck, ServiceReference serviceReference) {
+		try {
+			Vector toUnbind = null;
+			for (int i = 0, size = scpsToCheck.size(); i < size; i++) {
+				ServiceComponentProp scp = (ServiceComponentProp) scpsToCheck.elementAt(i);
+				// if it is not already eligible it will bind with the static
+				// scps
+				Vector references = scp.references;
+				// it is absolutely legal component if it doesn't contains
+				// references!
+				if (references != null) {
+					for (int j = 0; j < references.size(); j++) {
+						Reference reference = (Reference) references.elementAt(j);
+						if (reference.policy == ComponentReference.POLICY_STATIC && reference.reference.serviceReferences.contains(serviceReference)) {
+
+							if (toUnbind == null) {
+								toUnbind = new Vector(2);
+							}
+							toUnbind.addElement(scp);
+						}
+					}
+				}
+			}
+			if (toUnbind != null)
+				if (Activator.DEBUG) {
+					Activator.log.debug(0, 10060, toUnbind.toString(), null, false);
+					// //Activator.log.debug("Resolver.selectStaticUnBind():
+					// selected = " + toUnbind, null);
+				}
+			return toUnbind;
+		} catch (Throwable t) {
+			t.printStackTrace();
+			return null;
+		}
+	}
+
+	/**
+	 * selectDynamicUnBind Determine which resolved component description with
+	 * properties need to unbind from this unregistering service Return map of
+	 * reference description and component description with properties, for
+	 * each.
+	 * 
+	 * @param scps
+	 * @param serviceReference
+	 * @return this is fairly complex to explain ;(
+	 */
+	private Hashtable selectDynamicUnBind(Vector scps, ServiceReference serviceReference) {
+		try {
+			if (Activator.DEBUG) {
+				Activator.log.debug(0, 10026, null, null, false);
+				// //Activator.log.debug("Resolver.selectDynamicUnBind():
+				// entered", null);
+			}
+			Hashtable unbindTable = null; // ReferenceDescription:subTable
+			Hashtable unbindSubTable = null; // scp:sr
+			for (int i = 0; i < scps.size(); i++) {
+				ServiceComponentProp scp = (ServiceComponentProp) scps.elementAt(i);
+
+				BundleContext bc = scp.bc;
+				Vector references = scp.references;
+				// some components may not contain references and it is
+				// absolutely valid
+				if (references != null) {
+					for (int j = 0; j < references.size(); j++) {
+						Reference reference = (Reference) references.elementAt(j);
+						// Does the scp require this service, use the Reference
+						// object to check
+						if (reference.unBindReference(bc, serviceReference)) {
+							if (Activator.DEBUG) {
+								Activator.log.debug(0, 10027, scp.toString(), null, false);
+								// //Activator.log.debug("Resolver.selectDynamicUnBind():
+								// unbinding " + scp, null);
+							}
+							if (unbindSubTable == null) {
+								unbindSubTable = new Hashtable(11);
+							}
+							unbindSubTable.put(scp, serviceReference);
+							if (unbindTable == null) {
+								unbindTable = new Hashtable(11);
+							}
+							unbindTable.put(reference, unbindSubTable);
+						} else {
+							if (Activator.DEBUG) {
+								Activator.log.debug("Resolver.selectDynamicUnBind(): not unbinding " + scp + " service ref=" + serviceReference, null);
+							}
+						}
+					}
+				}
+			}
+			if (unbindTable != null && Activator.DEBUG) {
+				Activator.log.debug(0, 10028, unbindTable.toString(), null, false);
+				// //Activator.log.debug("Resolver.selectDynamicUnBind():
+				// unbindTable is " + unbindTable, null);
+			}
+			return unbindTable;
+		} catch (Throwable t) {
+			t.printStackTrace();
+			return null;
+		}
+	}
+
+	// used by the ComponentFactoryImpl to build new Component configurations
+	public ServiceComponentProp mapNewFactoryComponent(ServiceComponent component, Dictionary configProperties) {
+		synchronized (syncLock) {
+			// create a new scp (adds to resolver enabledSCPs list)
+			ServiceComponentProp newSCP = map(component, configProperties);
+			newSCP.setComponentFactory(false); // avoid registration of new
+			// ComponentFactory
+
+			// we added a SCP, so check for circularity and mark cycles
+			findDependencyCycles();
+
+			// get list of newly satisfied SCPs and check whether the new SCP is
+			// satisfied
+			Vector newlySatisfiedSCPs = resolveEligible();
+			removeAll(newlySatisfiedSCPs, satisfiedSCPs);
+			if (!newlySatisfiedSCPs.contains(newSCP)) {
+				scpEnabled.removeElement(newSCP);
+				throw new ComponentException("Cannot resolve instance of " + newSCP + " with properties " + configProperties);
+			}
+			satisfiedSCPs.addElement(newSCP);
+
+			return newSCP;
+		}
+	}
+
+	/**
+	 * Check through the enabled list for cycles. Cycles can only exist if every
+	 * service is provided by a Service Component (not legacy OSGi). If the
+	 * cycle has no optional dependencies, log an error and disable a Component
+	 * Configuration in the cycle. If cycle can be "broken" by an optional
+	 * dependency, make a note (stored in the
+	 * {@link ServiceComponentProp#delayActivateSCPNames} Vector).
+	 * 
+	 * @throws CircularityException
+	 *             if cycle exists with no optional dependencies
+	 */
+	private void findDependencyCycles() {
+		Vector emptyVector = new Vector();
+		try {
+			// find the SCPs that resolve using other SCPs and record their
+			// dependencies
+			Hashtable dependencies = new Hashtable();
+
+			for (int i = scpEnabled.size() - 1; i >= 0; i--) {
+				ServiceComponentProp enabledSCP = (ServiceComponentProp) scpEnabled.elementAt(i);
+				if (enabledSCP.references != null) {
+					Vector dependencyVector = new Vector(1);
+					for (int j = 0; j < enabledSCP.references.size(); j++) {
+						Reference reference = (Reference) enabledSCP.references.elementAt(j);
+
+						// see if it resolves to one of the other enabled SCPs
+						ServiceComponentProp providerSCP = reference.findProviderSCP(scpEnabled);
+						if (providerSCP != null) {
+							dependencyVector.addElement(new ReferenceSCPWrapper(reference, providerSCP));
+						}
+					} // end for
+
+					if (!dependencyVector.isEmpty()) {
+						// SCP resolves using some other SCPs, could be a cycle
+						dependencies.put(enabledSCP, dependencyVector);
+					} else {
+						dependencies.put(enabledSCP, emptyVector);
+					}
+				}
+			} // end for
+
+			// traverse dependency tree and look for cycles
+			Hashtable visited = new Hashtable(11);
+			Enumeration keys = dependencies.keys();
+
+			while (keys.hasMoreElements()) {
+				ServiceComponentProp scp = (ServiceComponentProp) keys.nextElement();
+				if (!visited.containsKey(scp)) {
+					Vector currentStack = new Vector(2);
+					checkDependencies(scp, visited, dependencies, currentStack);
+				}
+			}
+		} catch (CircularityException e) {
+			Activator.log.error("[SCR] Circularity Exception found for component " + e.getCausingComponent(), e);
+			// disable offending SCP
+			scpEnabled.removeElement(e.getCausingComponent());
+			// try again
+			findDependencyCycles();
+		}
+	}
+
+	/**
+	 * Recursively do a depth-first traversal of a dependency tree, looking for
+	 * cycles.
+	 * <p>
+	 * If a cycle is found, calls
+	 * {@link Resolver#processDependencyCycle(ReferenceSCPWrapper, Vector)}.
+	 * </p>
+	 * 
+	 * @param scp
+	 *            current node in dependency tree
+	 * @param visited
+	 *            holdes the visited nodes
+	 * @param dependencies
+	 *            Dependency tree - a Hashtable of ({@link ServiceComponentProp}):(Vector
+	 *            of {@link ReferenceSCPWrapper}s)
+	 * @param currentStack
+	 *            Vector of {@link ReferenceSCPWrapper}s - the history of our
+	 *            traversal so far (the path back to the root of the tree)
+	 * @throws CircularityException
+	 *             if an cycle with no optional dependencies is found.
+	 */
+	private void checkDependencies(ServiceComponentProp scp, Hashtable visited, Hashtable dependencies, Vector currentStack) throws CircularityException {
+
+		// the component has already been visited and it's dependencies checked
+		// for cycles
+		if (visited.containsKey(scp)) {
+			return;
+		}
+
+		Vector refSCPs = (Vector) dependencies.get(scp);
+		if (refSCPs != null) {
+			for (int i = 0; i < refSCPs.size(); i++) {
+				ReferenceSCPWrapper refSCP = (ReferenceSCPWrapper) refSCPs.elementAt(i);
+				if (currentStack.contains(refSCP)) {
+					// may throw circularity exception
+					processDependencyCycle(refSCP, currentStack);
+					return;
+				}
+				currentStack.addElement(refSCP);
+
+				checkDependencies(refSCP.producer, visited, dependencies, currentStack);
+
+				currentStack.removeElement(refSCP);
+			}
+		}
+		visited.put(scp, "");
+	}
+
+	/**
+	 * A cycle was detected. SCP is referenced by the last element in
+	 * currentStack. Throws CircularityException if the cycle does not contain
+	 * an optional dependency, else choses a point at which to "break" the cycle
+	 * (the break point must be immediately after an optional dependency) and
+	 * adds a "cycle note".
+	 * 
+	 * @see ServiceComponentProp#delayActivateSCPNames
+	 */
+	private void processDependencyCycle(ReferenceSCPWrapper refSCP, Vector currentStack) throws CircularityException {
+		// find an optional dependency
+		ReferenceSCPWrapper optionalRefSCP = null;
+		for (int i = currentStack.indexOf(refSCP); i < currentStack.size(); i++) {
+			ReferenceSCPWrapper cycleRefSCP = (ReferenceSCPWrapper) currentStack.elementAt(i);
+			if (!cycleRefSCP.ref.isRequired()) {
+				optionalRefSCP = cycleRefSCP;
+				break;
+			}
+		}
+		if (optionalRefSCP == null) {
+			throw new CircularityException(refSCP.ref.scp);
+		}
+		// check whether the optional reference is static - this is not allowed
+		// because of the way components with static refereces are built
+		if (optionalRefSCP.ref.policy == ComponentReference.POLICY_STATIC) {
+			Activator.log.error("[SCR] Static optional reference detected in a component cycle " + "and it will be removed.The referece is " + optionalRefSCP.ref.reference, null);
+
+			optionalRefSCP.ref.scp.references.removeElement(optionalRefSCP.ref);
+		}
+
+		// the dependent component will be processed with delay whenever
+		// necessary
+		optionalRefSCP.ref.scp.setDelayActivateSCPName(optionalRefSCP.producer.serviceComponent.name);
+	}
+
+	// used to remove all elements of vector which occur in another vector
+	private void removeAll(Vector src, Vector elementsToRemove) {
+		for (int i = src.size() - 1; i >= 0; i--) {
+			if (elementsToRemove.contains(src.elementAt(i))) {
+				src.removeElementAt(i);
+			}
+		}
+	}
+
+	// used to add all elements of vector in another vector
+	private void addAll(Vector src, Vector elementsToAdd) {
+		for (int i = 0; i < elementsToAdd.size(); i++) {
+			if (!src.contains(elementsToAdd.elementAt(i))) {
+				src.addElement(elementsToAdd.elementAt(i));
+			}
+		}
+	}
+
+	public void removeFromSatisfiedList(ServiceComponentProp scp) {
+		synchronized (syncLock) {
+			satisfiedSCPs.remove(scp);
+		}
+	}
+
+	/**
+	 * Used to traverse the dependency tree in order to find cycles.
+	 * 
+	 */
+	private class ReferenceSCPWrapper {
+		public Reference ref;
+		public ServiceComponentProp producer;
+
+		protected ReferenceSCPWrapper(Reference ref, ServiceComponentProp producer) {
+			this.ref = ref;
+			this.producer = producer;
+		}
+
+		public String toString() {
+			return "Reference : " + ref + " ::: SCP : " + producer;
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/SCRManager.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/SCRManager.java
new file mode 100644
index 0000000..770a36e
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/SCRManager.java
@@ -0,0 +1,638 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.ds;
+
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.*;
+import org.eclipse.equinox.internal.ds.model.ServiceComponent;
+import org.eclipse.equinox.internal.ds.model.ServiceComponentProp;
+import org.eclipse.equinox.internal.util.event.Queue;
+import org.eclipse.equinox.internal.util.ref.Log;
+import org.eclipse.equinox.internal.util.threadpool.ThreadPoolManager;
+import org.osgi.framework.*;
+import org.osgi.service.cm.*;
+import org.osgi.service.component.ComponentConstants;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * Manager of update and delete events, forwarded by ConfigurationImpl to the
+ * corresponding ManagedService(Factories). As those events are asynchronuos, a
+ * separate thread is engaged for their execution.
+ * 
+ * @author Maria Ivanova
+ * @author Stoyan Boshev
+ * @author Pavlin Dobrev
+ * @version 1.2
+ */
+
+public class SCRManager implements ServiceListener, SynchronousBundleListener, ConfigurationListener, WorkPerformer, PrivilegedAction {
+
+	private Hashtable bundleToServiceComponents;
+	public BundleContext bc;
+	protected Queue queue;
+	public static Log log;
+	private Resolver resolver;
+
+	private WorkThread workThread;
+	protected boolean running = false;
+	protected boolean stopped = false;
+	private ServiceTracker threadPoolManagerTracker;
+	private boolean hasRegisteredServiceListener = false;
+
+	/** work action type */
+	public final int ENABLE_COMPONENTS = 1;
+	public final int DISABLE_COMPONENTS = 2;
+
+	private ComponentStorage storage;
+
+	/**
+	 * Constructs the SCRManager.
+	 */
+	public SCRManager(BundleContext bc, Log log) {
+		this.bc = bc;
+		SCRManager.log = log;
+
+		security = Log.security();
+
+		hasRegisteredServiceListener = true;
+		queue = new Queue(10);
+		if (Activator.startup)
+			Activator.timeLog(110); /* 110 = "Queue instantiated for " */
+
+		threadPoolManagerTracker = new ServiceTracker(bc, ThreadPoolManager.class.getName(), null);
+		threadPoolManagerTracker.open();
+		if (Activator.startup)
+			Activator.timeLog(111);
+		/*111 = "Threadpool service tracker opened for "*/
+
+		resolver = new Resolver(this);
+		if (Activator.startup)
+			Activator.timeLog(112); /* 112 = "Resolver instantiated for " */
+
+		bc.addBundleListener(this);
+		if (Activator.startup)
+			Activator.timeLog(105); /* 105 = "addBundleListener() method took " */
+
+		String storageClass = bc.getProperty("scr.storage.class");
+		if (storageClass == null) {
+			storageClass = "org.eclipse.equinox.internal.ds.storage.file.FileStorage";
+		}
+		try {
+			storage = (ComponentStorage) Class.forName(storageClass).getConstructor(new Class[] {BundleContext.class}).newInstance(new Object[] {bc});
+		} catch (Exception e) {
+			log.error("[SCR - SCRManager] could not create instance for " + storageClass, e);
+		}
+	}
+
+	public void startIt() {
+		// loop through the currently installed bundles
+		Bundle[] bundles = bc.getBundles();
+		if (bundles != null) {
+			for (int i = 0; i < bundles.length; i++) {
+				Bundle current = bundles[i];
+				// try to process the active ones.
+				if (current.getState() == Bundle.ACTIVE) {
+					startedBundle(current);
+				}
+			}
+		}
+	}
+
+	/**
+	 * Add an event to the queue. The event will be forwarded to target service
+	 * as soon as possible.
+	 * 
+	 * @param upEv
+	 *            event, holding info for update/deletion of a configuration.
+	 */
+	public void addEvent(Object upEv, boolean security) {
+		try {
+			synchronized (queue) {
+				queue.put(upEv);
+				if (!running) {
+					if (queue.size() > 0) {
+						running = true;
+						workThread = new WorkThread(this);
+						if (security) {
+							AccessController.doPrivileged(this);
+							return;
+						}
+						ThreadPoolManager threadPool = (ThreadPoolManager) threadPoolManagerTracker.getService();
+						if (threadPool != null) {
+							threadPool.execute(workThread, Thread.MAX_PRIORITY, "Component Resolve Thread");
+						} else {
+							new Thread(workThread, "Component Resolve Thread").start();
+						}
+					}
+				} else if (workThread.waiting > 0) {
+					queue.notifyAll();
+				}
+			}
+		} catch (Throwable e) {
+			e.printStackTrace();
+		}
+	}
+
+	static boolean security = false;
+
+	public Object run() {
+		ThreadPoolManager threadPool = (ThreadPoolManager) threadPoolManagerTracker.getService();
+		if (threadPool != null) {
+			threadPool.execute(workThread, Thread.MAX_PRIORITY, "Component Resolve Thread");
+		} else {
+			new Thread(workThread, "Component Resolve Thread").start();
+		}
+		return null;
+	}
+
+	public void queueBlocked() {
+		resolver.queueBlocked();
+		synchronized (queue) {
+			running = false;
+			addEvent(null, security); // will result in starting new
+			// WorkThread to process the queued work
+		}
+	}
+
+	/**
+	 * This methods takes the input parameters and creates a Queued object and
+	 * queues it. The thread is notified.
+	 * 
+	 * @param d
+	 *            Dispatcher for this item
+	 * @param a
+	 *            Action for this item
+	 * @param o
+	 *            Object for this item
+	 */
+	public void enqueueWork(WorkPerformer d, int a, Object o, boolean security) {
+		addEvent(new QueuedJob(d, a, o), security);
+	}
+
+	/**
+	 * Stops this thread, making it getting out of method run.
+	 */
+	public void stopIt() {
+		stopped = true;
+		disposeBundles();
+		if (queue != null) {
+			queue.clear();
+		}
+		if (running) {
+			synchronized (queue) {
+				queue.notify();
+			}
+			int counter = 0;
+
+			while (running && counter < 20) {
+				// wait maximum 2 seconds to complete current task in the queue
+				try {
+					Thread.sleep(100);
+				} catch (InterruptedException ie) {
+				}
+				counter++;
+			}
+		}
+		stopped = true;
+		threadPoolManagerTracker.close();
+		storage.stop();
+	}
+
+	public void serviceChanged(ServiceEvent sEv) {
+		resolver.getEligible(sEv);
+	}
+
+	public final void bundleChanged(BundleEvent event) {
+		long start = 0l;
+		if (Activator.PERF) {
+			start = System.currentTimeMillis();
+			log.info("[DS perf] Started processing bundle event " + event);
+		}
+		int type = event.getType();
+		if (type == BundleEvent.STOPPING) {
+			stoppingBundle(event.getBundle());
+		} else if (type == BundleEvent.STARTED) {
+			startedBundle(event.getBundle());
+		} else if (type == BundleEvent.UNINSTALLED && Activator.DBSTORE) {
+			try {
+				storage.deleteComponentDefinitions(event.getBundle().getBundleId());
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+		}
+		if (Activator.PERF) {
+			start = System.currentTimeMillis() - start;
+			log.info("[DS perf] Processed bundle event '" + event + "' for " + start + " ms");
+		}
+	}
+
+	// -- begin 'CM listener'
+	/**
+	 * Listen for configuration changes
+	 * 
+	 * Service Components can receive properties from the Configuration Admin
+	 * service. If a Service Component is activated and it�s properties are
+	 * updated in the Configuration Admin service, the SCR must deactivate the
+	 * component and activate the component again using the new properties.
+	 * 
+	 * @param event
+	 *            ConfigurationEvent
+	 */
+	public void configurationEvent(ConfigurationEvent event) {
+		if (bundleToServiceComponents != null && !bundleToServiceComponents.isEmpty()) {
+			addEvent(event, true);
+		}
+	}
+
+	protected void processConfigurationEvent(ConfigurationEvent event) {
+		if (bundleToServiceComponents == null || bundleToServiceComponents.isEmpty()) {
+			// no components found till now
+			return;
+		}
+		long start = 0l;
+		try {
+			if (Activator.DEBUG) {
+				Activator.log.debug(" Resolver.configurationEvent(): pid = " + event.getPid() + ", fpid = " + event.getFactoryPid(), null);
+			}
+			if (Activator.PERF) {
+				start = System.currentTimeMillis();
+				log.info("[DS perf] Started processing configuration event " + event);
+			}
+
+			String pid = event.getPid();
+			String fpid = event.getFactoryPid();
+			for (Enumeration keys = bundleToServiceComponents.keys(); keys.hasMoreElements();) {
+				if (Activator.DEBUG) {
+					Activator.log.debug(0, 10013, null, null, false);
+					// //Activator.log.debug(" hasNext", null);
+				}
+				Vector bundleComps = (Vector) bundleToServiceComponents.get(keys.nextElement());
+				// bundleComps may be null since bundleToServiceComponents
+				// may have been modified by another thread
+				if (bundleComps != null) {
+					for (int i = 0; i < bundleComps.size(); i++) {
+						ServiceComponent sc = (ServiceComponent) bundleComps.elementAt(i);
+						String name = sc.name;
+						if (Activator.DEBUG) {
+							Activator.log.debug(0, 10014, name, null, false);
+							// //Activator.log.debug(" component name " + name,
+							// null);
+						}
+						if (name.equals(pid) || name.equals(fpid)) {
+							if (name.equals(fpid) && sc.factory != null) {
+								Activator.log.error("[SCR - SCRManager] ComponentFactory " + name + " cannot be managed using factory configuration!", null);
+								return;
+							}
+							if (Activator.DEBUG) {
+								Activator.log.debug(0, 10015, pid, null, false);
+								// //Activator.log.debug("
+								// Resolver.configurationEvent(): found
+								// component - " + pid, null);
+							}
+							processConfigurationEvent(event, sc);
+							return;
+						}
+					}
+				}
+			}
+		} catch (Throwable e) {
+			Activator.log.error("[SCR] Error while processing configuration event for " + event.getReference().getBundle(), e);
+		} finally {
+			if (Activator.PERF) {
+				start = System.currentTimeMillis() - start;
+				log.info("[DS perf] Processed configuration event '" + event + "' for " + start + " ms");
+			}
+		}
+	}
+
+	private void processConfigurationEvent(ConfigurationEvent event, ServiceComponent sc) {
+		Configuration[] config = null;
+
+		String pid = event.getPid();
+		String fpid = event.getFactoryPid();
+
+		switch (event.getType()) {
+			case ConfigurationEvent.CM_UPDATED :
+
+				String filter = (fpid != null ? "(&" : "") + "(" + Constants.SERVICE_PID + "=" + pid + ")" + (fpid != null ? ("(" + ConfigurationAdmin.SERVICE_FACTORYPID + "=" + fpid + "))") : "");
+				try {
+					config = ConfigurationManager.listConfigurations(filter);
+				} catch (IOException e) {
+					log.error("Error while listing CM Configurations", e);
+				} catch (InvalidSyntaxException e) {
+					log.error("Error while listing CM Configurations", e);
+				}
+
+				if (config == null) {
+					// The configuration may have been deleted by the now
+					// If it does not exist we must do nothing
+					return;
+				}
+
+				// if NOT a factory
+				if (fpid == null) {
+					// there is only one SCP for this SC, so we can disable the SC
+					Vector components = new Vector();
+					components.addElement(sc);
+					resolver.disableComponents(components);
+
+					// now re-enable the SC - the resolver will pick up the new
+					// config
+					sc.enabled = true;
+					resolver.enableComponents(components);
+
+					// If a MSF
+					// create a new SCP or update an existing one
+				} else {
+
+					// get scp with this PID
+					ServiceComponentProp scp = sc.getComponentPropByPID(pid);
+
+					// if only the no-props scp exists, replace it
+					if (scp == null && sc.componentProps != null && sc.componentProps.size() == 1 && (((ServiceComponentProp) sc.componentProps.elementAt(0)).getProperties().get(Constants.SERVICE_PID) == null)) {
+						scp = (ServiceComponentProp) sc.componentProps.elementAt(0);
+					}
+					// if old scp exists, dispose of it
+					if (scp != null) {
+						// config already exists - dispose of it
+						sc.componentProps.removeElement(scp);
+						Vector components = new Vector();
+						components.addElement(scp);
+						resolver.disposeComponentConfigs(components);
+					}
+
+					// create a new scp (adds to resolver enabledSCPs list)
+					resolver.map(sc, config[0]);
+
+					// kick the resolver to figure out if SCP is satisfied, etc
+					resolver.enableComponents(null);
+				}
+
+				break;
+			case ConfigurationEvent.CM_DELETED :
+
+				// if not a factory
+				if (fpid == null) {
+
+					// there is only one SCP for this SC, so we can disable the SC
+					Vector components = new Vector();
+					components.addElement(sc);
+					resolver.disableComponents(components);
+
+					// now re-enable the SC - the resolver will create SCP with
+					// no configAdmin properties
+					sc.enabled = true;
+					resolver.enableComponents(components);
+				} else {
+					// config is a factory
+
+					// get SCP created for this config (with this PID)
+					ServiceComponentProp scp = sc.getComponentPropByPID(pid);
+
+					// if this was the last SCP created for this factory
+					if (sc.componentProps.size() == 1) {
+						// there is only one SCP for this SC, so we can disable the
+						// SC
+						Vector components = new Vector();
+						components.addElement(sc);
+						resolver.disableComponents(components);
+						// now re-enable the SC - the resolver will create SCP
+						// with no configAdmin properties
+						sc.enabled = true;
+						resolver.enableComponents(components);
+					} else {
+						// we can just dispose this SCP
+						sc.componentProps.removeElement(scp);
+						Vector components = new Vector();
+						components.addElement(scp);
+						resolver.disposeComponentConfigs(components);
+					}
+				}
+				break;
+		}
+	}
+
+	private void disposeBundles() {
+		log.info("disposeBundles()");
+		// dispose ALL bundles
+		if (bundleToServiceComponents != null) {
+			for (Enumeration e = bundleToServiceComponents.keys(); e.hasMoreElements();) {
+				Bundle bundle = (Bundle) e.nextElement();
+				stoppingBundle(bundle);
+			}
+			bundleToServiceComponents.clear();
+			bundleToServiceComponents = null;
+		}
+	}
+
+	void stoppingBundle(Bundle bundle) {
+		if (bundleToServiceComponents != null) {
+			Vector components = (Vector) bundleToServiceComponents.remove(bundle);
+			// disable the components which the bundle provides
+			if (components != null) {
+				if (Activator.DEBUG) {
+					String bundleName = bundle.getSymbolicName();
+					bundleName = (bundleName == null || "".equals(bundleName)) ? bundle.getLocation() : bundleName;
+					log.debug(0, 10016, bundleName, null, false);
+					// //log.debug("SCRManager.stoppingBundle(" + bundleName
+					// + ')', null);
+				}
+				resolver.disableComponents(components);
+				if (bundleToServiceComponents.size() == 0) {
+					hasRegisteredServiceListener = false;
+					bc.removeServiceListener(this);
+				}
+			}
+		}
+	}
+
+	synchronized void startedBundle(Bundle bundle) {
+		long start = 0l;
+		if (Activator.PERF) {
+			start = System.currentTimeMillis();
+		}
+		if (bundleToServiceComponents != null) {
+			if (bundleToServiceComponents.get(bundle) != null) {
+				// the bundle is already processed - skipping it
+				return;
+			}
+		}
+
+		Dictionary allHeaders = bundle.getHeaders();
+
+		if (!((allHeaders.get(ComponentConstants.SERVICE_COMPONENT)) != null)) {
+			// no component descriptions in this bundle
+			return;
+		}
+
+		Vector components = storage.loadComponentDefinitions(bundle.getBundleId());
+		if (components != null && !components.isEmpty()) {
+			if (!hasRegisteredServiceListener) {
+				hasRegisteredServiceListener = true;
+				bc.addServiceListener(this);
+			}
+			if (Activator.PERF) {
+				start = System.currentTimeMillis() - start;
+				log.info("[DS perf] The components for bundle " + bundle + " are parsed for " + start + " ms");
+			}
+			// store the components in the cache
+			if (bundleToServiceComponents == null) {
+				bundleToServiceComponents = new Hashtable(10);
+			}
+			bundleToServiceComponents.put(bundle, components);
+			for (int i = 0; i < components.size(); i++) {
+				ServiceComponent comp = (ServiceComponent) components.elementAt(i);
+				if (comp.autoenable) {
+					comp.enabled = true;
+				}
+			}
+			// this will also resolve the component dependencies!
+			enqueueWork(this, ENABLE_COMPONENTS, components, false);
+		}
+	}
+
+	public void enableComponent(String name, Bundle bundle) {
+		changeComponent(name, bundle, true);
+	}
+
+	private void changeComponent(String name, Bundle bundle, boolean enable) {
+		try {
+			Vector componentsToProcess = null;
+
+			if (Activator.DEBUG) {
+				String message = (enable ? "SCRManager.enableComponent(): " : "SCRManager.disableComponent(): ").concat(name != null ? name : "*all*") + " from bundle " + bundle.getSymbolicName();
+				Activator.log.debug(message, null);
+			}
+			if (bundleToServiceComponents == null) {
+				// already disposed!
+				return;
+			}
+			Vector bundleComponents = (Vector) bundleToServiceComponents.get(bundle);
+			if (bundleComponents != null) {
+				if (name != null) {
+					for (int i = 0; i < bundleComponents.size(); i++) {
+						ServiceComponent component = (ServiceComponent) bundleComponents.elementAt(i);
+						if (component.name.equals(name) && component.enabled != enable) {
+							component.enabled = enable;
+							componentsToProcess = new Vector(2);
+							componentsToProcess.addElement(component);
+							break;
+						}
+					}
+				} else {
+					if (enable) {
+						// processing null parameter should be done only when
+						// enabling components
+						ServiceComponent sc;
+						componentsToProcess = new Vector();
+						for (int i = 0; i < bundleComponents.size(); i++) {
+							sc = ((ServiceComponent) bundleComponents.elementAt(i));
+							if (!sc.enabled) {
+								componentsToProcess.addElement(sc);
+								sc.enabled = enable;
+							}
+						}
+					} else {
+						Activator.log.warning("[SCRManager] Cannot dispose all components of a bundle at once!", null);
+					}
+				}
+
+			}
+			// publish to resolver the list of SCs to enable
+			if (componentsToProcess != null && !componentsToProcess.isEmpty()) {
+				if (enable) {
+					enqueueWork(this, ENABLE_COMPONENTS, componentsToProcess, security);
+				} else {
+					enqueueWork(this, DISABLE_COMPONENTS, componentsToProcess, security);
+				}
+			}
+			if (Activator.DEBUG) {
+				Activator.log.debug(0, 10018, null, null, false);
+				// //Activator.log.debug("changeComponent method end", null);
+			}
+		} catch (Throwable e) {
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * QueuedJob represents the items placed on the asynch dispatch queue.
+	 */
+	public class QueuedJob {
+		final WorkPerformer performer;
+		/** the required type of action to do */
+		final int actionType;
+		/** work input data to be performed */
+		final Object workToDo;
+
+		/**
+		 * Constructor for work queue item
+		 * 
+		 * @param d
+		 *            Dispatcher for this item
+		 * @param a
+		 *            Action for this item
+		 * @param o
+		 *            Object for this item
+		 */
+		QueuedJob(WorkPerformer d, int a, Object o) {
+			performer = d;
+			actionType = a;
+			workToDo = o;
+		}
+
+		void dispatch() {
+			try {
+				/* Call the WorkPerformer to process the work. */
+				performer.performWork(actionType, workToDo);
+			} catch (Throwable t) {
+				t.printStackTrace();
+				log.error("[SCR] Error dispatching work ", t);
+			}
+		}
+
+		public String toString() {
+			return "[QueuedJob] WorkPerformer: " + performer + "; actionType " + actionType;
+		}
+	}
+
+	// -- begin enable/disable components
+	/**
+	 * disableComponent - The specified component name must be in the same
+	 * bundle as this component. Called by SC componentContext method
+	 * 
+	 * @param name
+	 *            The name of a component to disable
+	 * @param bundle
+	 *            The bundle which contains the Service Component to be disabled
+	 */
+	public void disableComponent(String name, Bundle bundle) {
+		changeComponent(name, bundle, false);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.equinox.internal.ds.util.WorkPerformer#performWork(int,
+	 *      java.lang.Object)
+	 */
+	public void performWork(int workAction, Object workObject) {
+		if (workAction == ENABLE_COMPONENTS) {
+			resolver.enableComponents((Vector) workObject);
+		} else if (workAction == DISABLE_COMPONENTS) {
+			resolver.disableComponents((Vector) workObject);
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/SCRUtil.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/SCRUtil.java
new file mode 100644
index 0000000..0bbbfa2
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/SCRUtil.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.ds;
+
+import java.lang.reflect.Method;
+import java.util.Dictionary;
+import java.util.Enumeration;
+
+import org.eclipse.equinox.internal.util.pool.ObjectCreator;
+import org.eclipse.equinox.internal.util.pool.ObjectPool;
+
+/**
+ * Util.java
+ * 
+ * @author Valentin Valchev
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public final class SCRUtil implements ObjectCreator {
+
+	private static ObjectPool objectArrayPool;
+
+	static {
+		SCRUtil u = new SCRUtil();
+		// FIXME: use some kind of logging for the object pool to determine
+		// the optimal solution!
+		objectArrayPool = new ObjectPool(u, 10, 2);
+	}
+
+	private SCRUtil() {
+	}
+
+	public static Object[] getObjectArray() {
+		return (Object[]) objectArrayPool.getObject();
+	}
+
+	public static void release(Object[] objectArray) {
+		for (int j = 0; j < objectArray.length; j++) {
+			objectArray[j] = null;
+		}
+		objectArrayPool.releaseObject(objectArray);
+	}
+
+	public Object getInstance() throws Exception {
+		return new Object[1];
+	}
+
+	public static void copyTo(Dictionary dst, Dictionary src) {
+		if (src == null || dst == null) {
+			return;
+		}
+		Object key;
+		for (Enumeration e = src.keys(); e.hasMoreElements();) {
+			key = e.nextElement();
+			dst.put(key, src.get(key));
+		}
+	}
+
+	private static Method setAccessibleMethod = null;
+	private static Object[] args = null;
+	private static boolean failed = false;
+
+	/**
+	 * This method is added only for JVM compatibility. Actually setAccessible()
+	 * is available since jdk1.2. The older java runtimes don't have this
+	 * method.
+	 * 
+	 * However, you can call this method. It is guaranteed that it will do the
+	 * right job.
+	 * 
+	 * @param method
+	 *            the method to set accessible.
+	 */
+	public static final void setAccessible(Method method) {
+		try {
+			if (setAccessibleMethod == null && !failed) {
+				setAccessibleMethod = Class.forName("java.lang.reflect.AccessibleObject").getMethod("setAccessible", new Class[] {boolean.class});
+				args = new Object[] {Boolean.TRUE};
+			}
+			if (setAccessibleMethod != null)
+				setAccessibleMethod.invoke(method, args);
+		} catch (Exception e) {
+			failed = true;
+		}
+	}
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/ServiceReg.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/ServiceReg.java
new file mode 100644
index 0000000..024418d
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/ServiceReg.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.ds;
+
+import org.eclipse.equinox.internal.ds.impl.ComponentInstanceImpl;
+import org.eclipse.equinox.internal.ds.model.ServiceComponentProp;
+import org.osgi.framework.*;
+import org.osgi.service.component.ComponentException;
+
+/**
+ * @author Stoyan Boshev
+ * @author Pavlin Dobrev
+ * @version 1.2
+ */
+
+final class ServiceReg implements ServiceFactory {
+
+	static boolean dontDisposeInstances = true;
+
+	// tracking the instance usage and re-instantiation
+	private int useCount = 0;
+	private ComponentInstanceImpl instance;
+
+	// model
+	private ServiceComponentProp scp;
+
+	static {
+		String tmp = Activator.bc.getProperty("equinox.scr.dontDisposeInstances");
+		dontDisposeInstances = (tmp != null) ? !tmp.equalsIgnoreCase("false") : true;
+	}
+
+	ServiceReg(ServiceComponentProp scp, ComponentInstanceImpl instance) {
+		this.scp = scp;
+		this.instance = instance;
+	}
+
+	// ServiceFactory.getService method.
+	public Object getService(Bundle bundle, ServiceRegistration registration) {
+		try {
+			if (instance == null) {
+				instance = InstanceProcess.staticRef.buildComponent(bundle, scp, null, false);
+				//instance could be null if the component is already disposed
+				if (instance == null) {
+					return null;
+				}
+			}
+			synchronized (this) {
+				useCount++;
+			}
+			if (Activator.DEBUG) {
+				Activator.log.debug("ServiceReg.getService(): service '" + scp.name + " is used " + useCount + " time(s), object = " + instance.getInstance(), null);
+			}
+			return instance.getInstance();
+		} catch (Exception e) {
+			if (!(e instanceof ComponentException)) {
+				Activator.log.error("ServiceReg.getService(): Could not create instance of " + scp.name, e);
+				return null;
+			}
+			throw (ComponentException) e;
+		}
+	}
+
+	// ServiceFactory.ungetService method.
+	public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) {
+		boolean shallDispose = false;
+		synchronized (this) {
+			useCount--;
+			if (useCount == 0) {
+				shallDispose = true;
+			}
+		}
+		if (shallDispose) {
+			if (!dontDisposeInstances && !scp.serviceComponent.immediate) {
+				//dispose instance only if disposing is allowed and the component is not immediate one.
+
+				//Immediate components are custom case - according to me, their instances should not be disposed
+				// because they are probably needed during the whole component's life  
+				if (Activator.DEBUG) {
+					Activator.log.debug("ServiceReg.ungetService(): service '" + scp.name + "' no longer used, disposing object = " + service, null);
+				}
+				// dispose only the instance - don't dispose the component
+				// itself!
+				scp.disposeObj(service);
+				// delete the instance so it can be garbage collected!
+				instance = null;
+			} else {
+				if (Activator.DEBUG) {
+					Activator.log.debug("ServiceReg.ungetService(): service '" + scp.name + " is used " + useCount + " times(s)", null);
+				}
+			}
+		} else {
+			if (useCount < 0) {
+				Activator.log.warning("ServiceReg.ungetService(): service '" + scp.name + " is used " + useCount + " times(s)", new Exception("Debug callstack"));
+			} else if (Activator.DEBUG) {
+				Activator.log.debug("ServiceReg.ungetService(): service '" + scp.name + " is used " + useCount + " times(s)", null);
+			}
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#toString()
+	 */
+	public String toString() {
+		return scp.name + " Service Registration";
+	}
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/TracerMap.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/TracerMap.java
new file mode 100644
index 0000000..129bf20
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/TracerMap.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.ds;
+
+import org.eclipse.equinox.internal.util.hash.HashIntObjNS;
+
+/**
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public class TracerMap {
+
+	public static HashIntObjNS getMap() {
+		HashIntObjNS map = new HashIntObjNS(61);
+
+		map.put(0, "SCR");
+		map.put(-0x0100, "SCR Activator");
+
+		/* time measurements */
+		map.put(100, "[BEGIN - start method] Creating Log instance and initializing log system took ");
+		map.put(101, "Getting FrameworkAccess service took ");
+		map.put(102, "ConfigurationAdmin ServiceTracker instantiation took ");
+		map.put(103, "ServiceTracker starting took ");
+		map.put(104, "SCRManager instantiation took ");
+		map.put(105, "addBundleListener() method took ");
+		map.put(106, "ConfigurationListener service registered for ");
+		map.put(107, "addServiceListener() method took ");
+		map.put(108, "[END - start method] Activator.start() method executed for ");
+		map.put(109, "SCR database got for ");
+		map.put(110, "Queue instantiated for ");
+		map.put(111, "Threadpool service tracker opened for ");
+		map.put(112, "Resolver instantiated for ");
+		map.put(113, "startIt() method took ");
+		map.put(114, "[BEGIN - lazy SCR init] ");
+		map.put(115, "[END - lazy SCR init] Activator.initSCR() method executed for ");
+		map.put(116, "DBManager service tracker opened for ");
+
+		// //old debug!
+		map.put(10001, "FactoryReg.getService(): created new service for component '");
+		map.put(10002, "FactoryReg.ungetService(): registration = ");
+		map.put(10003, "InstanceProcess.buildComponents(): building immediate component ");
+		map.put(10004, "InstanceProcess.buildComponents(): building component factory ");
+		map.put(10005, "InstanceProcess.buildComponent(): building component ");
+		map.put(10006, "InstanceProcess.disposeInstances(): disposing non-provider component ");
+		map.put(10007, "InstanceProcess.disposeInstances(): disposing component factory ");
+		map.put(10008, "InstanceProcess.disposeInstances(): unregistering component ");
+		map.put(10009, "InstanceProcess.disposeInstances(): cannot find registrations for ");
+		map.put(10010, "InstanceProcess.getService(): cannot get service because of circularity! Reference is: ");
+		map.put(10012, "InstanceProcess.dynamicBind(): null instances! for component ");
+		map.put(10013, "hasNext");
+		map.put(10014, "component name ");
+		map.put(10015, "SCRManager.configurationEvent(): found component - ");
+		map.put(10016, "SCRManager.stoppingBundle : ");
+		map.put(10017, "ComponentStorage.parseXMLDeclaration(): loading ");
+		map.put(10018, "changeComponent method end");
+		map.put(10019, "Resolver.enableComponents(): ignoring not enabled component ");
+		map.put(10020, "Resolver.getEligible(): processing service event ");
+		map.put(10021, "Resolver:resolveEligible(): resolved components = ");
+		map.put(10022, "Resolver.disableComponents()");
+		map.put(10023, "Resolver.performWork(): ");
+		map.put(10025, "Resolver.selectDynamicBind(): selected = ");
+		map.put(10026, "Resolver.selectDynamicUnBind(): entered");
+		map.put(10027, "Resolver.selectDynamicUnBind(): unbinding ");
+		map.put(10028, "Resolver.selectDynamicUnBind(): unbindTable is ");
+		map.put(10029, "WorkThread.Run()");
+		map.put(10030, "WorkThread.getObject ");
+		map.put(10032, "ComponentFactoryImpl.newInstance(): ");
+		map.put(10034, "getMethod() ");
+		map.put(10035, "ServiceComponentProp.dispose(): ");
+		map.put(10036, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ServiceComponentProp.activate(): name: ");
+		map.put(10037, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ServiceComponentProp.instance: ");
+		map.put(10038, "ServiceComponentProp.deactivate(): ");
+		map.put(10039, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ServiceComponentProp.using bundle: ");
+		map.put(10040, "ServiceComponentProp:bind(): the folowing reference doesn't specify bind method : ");
+		map.put(10041, "ServiceComponentProp.bindReferences(): component ");
+		map.put(10042, "ServiceComponentProp.unbindReference(): component ");
+		map.put(10050, "Service event type: ");
+		map.put(10060, "Resolver.selectStaticUnBind(): selected = ");
+		map.put(10061, "Resolver.selectStaticBind(): selected = ");
+		map.put(10062, "Resolver.enableComponents(): ");
+		map.put(10063, "Resolver.map(): Creating SCP for component");
+		map.put(10070, "ComponentContextImpl.locateService(): ");
+		map.put(10071, "ComponentContextImpl.locateServices():");
+		map.put(10072, "ComponentContextImpl.locateServices() the specified service reference is not bound to the specified reference");
+		map.put(10080, "ComponentInstanceImpl.dispose(): disposing instance of component ");
+
+		return map;
+	}
+
+	public static HashIntObjNS getStarts() {
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/WorkPerformer.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/WorkPerformer.java
new file mode 100644
index 0000000..c4197c1
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/WorkPerformer.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.ds;
+
+/**
+ * The WorkPerformer interface contains a method that is called by a queue to
+ * perform certain work.
+ * 
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public interface WorkPerformer {
+
+	/**
+	 * This method can then complete processing work on the work queue thread.
+	 * 
+	 * <p>
+	 * The job queue will ignore any Throwable thrown by this method in order to
+	 * continue proper dispatching the next work items.
+	 * 
+	 * @param actionId
+	 *            Action ID of the work type which has to be done.
+	 * @param dataToProcess
+	 *            The data which has to be processed
+	 */
+	public void performWork(int actionId, Object dataToProcess);
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/WorkThread.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/WorkThread.java
new file mode 100644
index 0000000..a449614
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/WorkThread.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.ds;
+
+import org.osgi.service.cm.ConfigurationEvent;
+
+import org.eclipse.equinox.internal.util.event.Queue;
+import org.eclipse.equinox.internal.util.ref.TimerRef;
+import org.eclipse.equinox.internal.util.timer.TimerListener;
+
+/**
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public class WorkThread implements Runnable, TimerListener {
+
+	boolean processBundle = false;
+
+	public static int IDLE_TIMEOUT = 1000;
+	public static int BLOCK_TIMEOUT = 30000;
+	private SCRManager mgr;
+	private Object objectToProcess;
+	boolean running = true;
+
+	int waiting = 0;
+
+	public WorkThread(SCRManager mgr) {
+		this.mgr = mgr;
+	}
+
+	/**
+	 * While the event queue has elements - they are processed, i.e.
+	 * ManagedService(Factories) are informed for the event.
+	 */
+	public void run() {
+		do {
+			try {
+				Queue queue = mgr.queue;
+				synchronized (queue) {
+					if (mgr.stopped) {
+						mgr.running = false;
+						break;
+					}
+					if (Activator.DEBUG) {
+						Activator.log.debug(0, 10029, null, null, false);
+						// //Activator.log.debug("WorkThread.Run()", null);
+					}
+					if (queue.size() == 0) { // wait for more events
+						try {
+							waiting++;
+							queue.wait(IDLE_TIMEOUT);
+						} catch (Exception ignore) {
+						}
+						waiting--;
+						if (mgr.stopped || queue.size() == 0) {
+							mgr.running = false;
+							break;
+						}
+					}
+					objectToProcess = queue.get();
+
+					if (objectToProcess != null) {
+						if (Activator.DEBUG) {
+							Activator.log.debug(0, 10030, objectToProcess.toString(), null, false);
+							// //Activator.log.debug("WorkThread.getObject " +
+							// object, null);
+						}
+					} else {
+						continue;
+					}
+				}
+				TimerRef.notifyAfter(this, BLOCK_TIMEOUT, 1);
+				if (objectToProcess instanceof SCRManager.QueuedJob) {
+					((SCRManager.QueuedJob) objectToProcess).dispatch();
+				} else if (objectToProcess instanceof ConfigurationEvent) {
+					mgr.processConfigurationEvent((ConfigurationEvent) objectToProcess);
+				}
+			} catch (Throwable t) {
+				// just for any case. Must not happen in order to keep thread
+				// alive
+				t.printStackTrace();
+			} finally {
+				TimerRef.removeListener(this, 1);
+			}
+		} while (running);
+		objectToProcess = null;
+	}
+
+	public void timer(int event) {
+		Activator.log.warning("[SCR - WorkThread] Timeout ocurred! Thread was blocked on processing " + objectToProcess, null);
+		running = false;
+		objectToProcess = null;
+		mgr.queueBlocked();
+	}
+
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/impl/ComponentContextImpl.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/impl/ComponentContextImpl.java
new file mode 100644
index 0000000..5eaab6e
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/impl/ComponentContextImpl.java
@@ -0,0 +1,330 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.ds.impl;
+
+import java.util.Dictionary;
+import java.util.Vector;
+
+import org.eclipse.equinox.internal.ds.*;
+import org.eclipse.equinox.internal.ds.model.*;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.ComponentException;
+import org.osgi.service.component.ComponentInstance;
+
+/**
+ * ComponentContextImpl.java
+ * 
+ * @author Valentin Valchev, Nina Ruseva
+ * @author Stoyan Boshev
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public class ComponentContextImpl implements ComponentContext {
+
+	/* ComponentInstance instance */
+	private ComponentInstanceImpl componentInstance;
+	/* ComponentDescription */
+	private ServiceComponentProp scp;
+
+	private Bundle usingBundle;
+
+	private SCRManager mgr;
+
+	public ComponentContextImpl(ServiceComponentProp scp, Bundle usingBundle, ComponentInstanceImpl ci, SCRManager mgr) {
+		this.scp = scp;
+		this.componentInstance = ci;
+		this.usingBundle = usingBundle;
+		this.mgr = mgr;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.osgi.service.component.ComponentContext#getProperties()
+	 */
+	public Dictionary getProperties() {
+		return (Dictionary) scp.getProperties().clone();
+	}
+
+	/*
+	 * (non-Javadoc) Returns the service object for the specified service
+	 * reference name.
+	 * 
+	 * @param name The name of a service reference as specified in a <code>reference</code>
+	 * element in this component's description. @return A service object for the
+	 * referenced service or <code>null</code> if the reference cardinality is
+	 * <code>0..1</code> or <code>0..n</code> and no matching service is
+	 * available. @throws ComponentException If the Service Component Runtime
+	 * catches an exception while activating the target service.
+	 * 
+	 * @see org.osgi.service.component.ComponentContext#locateService(java.lang.String)
+	 */
+	public Object locateService(String name) {
+		if (scp.references == null) {
+			return null;
+		}
+		if (Activator.DEBUG) {
+			Activator.log.debug(0, 10070, name, null, false);
+			// //Activator.log.debug("ComponentContextImpl.locateService(): " +
+			// name, null);
+		}
+		Vector references = scp.references;
+		for (int i = 0; i < references.size(); i++) {
+			Reference reference = (Reference) references.elementAt(i);
+			ComponentReference ref = reference.reference;
+
+			// find the Reference Description with the specified name
+			if (ref.name.equals(name)) {
+				ServiceReference serviceReference = null;
+				synchronized (ref.serviceReferences) {
+					if (!ref.serviceReferences.isEmpty()) {
+						serviceReference = (ServiceReference) ref.serviceReferences.firstElement();
+					}
+				}
+				try {
+					if (serviceReference == null) {
+						// try to find service in the FW
+						ServiceReference[] serviceReferences = scp.bc.getServiceReferences(ref.interfaceName, ref.target);
+						if (serviceReferences != null && serviceReferences.length > 0) {
+							// the servicese references are sorted by
+							// service.reference and service.id
+							// so get the first one in the list
+							serviceReference = serviceReferences[0];
+						}
+
+					}
+					if (serviceReference != null) {
+						Object cached = componentInstance.bindedServices.get(serviceReference);
+						if (cached != null) {
+							// will skip the circularity checking in
+							// InstanceProcess.getService
+							return cached;
+						}
+						Object theService = InstanceProcess.staticRef.getService(reference, serviceReference);
+						// the service object could be null because of
+						// circularity
+						if (theService != null) {
+							componentInstance.bindedServices.put(serviceReference, theService);
+							return theService;
+						}
+					}
+				} catch (Throwable t) {
+					if (t instanceof ComponentException) {
+						throw (ComponentException) t;
+					}
+					throw new ComponentException("Exception occured while locating service for interface " + name, t);
+				}
+				if (Activator.DEBUG) {
+					Activator.log.debug("ComponentContextImpl.locateService(): error, service not found - " + ref.interfaceName + "; the comp. context belongs to " + scp.name, null);
+				}
+			}
+		}
+		return null;
+	}
+
+	/*
+	 * Returns the service objects for the specified service reference name.
+	 * 
+	 * @param name The name of a service reference as specified in a <code>reference</code>
+	 * element in this component's description. @return An array of service
+	 * objects for the referenced service or <code>null</code> if the
+	 * reference cardinality is <code>0..1</code> or <code>0..n</code> and
+	 * no matching service is available.
+	 * 
+	 * @throws ComponentException If the Service Component Runtime catches an
+	 * exception while activating a target service.
+	 * 
+	 * @see org.osgi.service.component.ComponentContext#locateServices(java.lang.String)
+	 */
+	public Object[] locateServices(String name) {
+		if (scp.references == null) {
+			return null;
+		}
+
+		if (Activator.DEBUG) {
+			Activator.log.debug(0, 10071, name, null, false);
+			// //Activator.log.debug("ComponentContextImpl.locateServices(): " +
+			// name, null);
+		}
+		Vector references = scp.references;
+		for (int i = 0; i < references.size(); i++) {
+			Reference reference = (Reference) references.elementAt(i);
+			ComponentReference ref = reference.reference;
+
+			if (ref.name.equals(name)) {
+				ServiceReference[] serviceReferences = null;
+				try {
+					serviceReferences = scp.bc.getServiceReferences(ref.interfaceName, ref.target);
+					if (serviceReferences != null) {
+						Vector theServices = new Vector(5);
+						Object service;
+						for (int j = 0; j < serviceReferences.length; j++) {
+							// check whether the service is cached - this will
+							// skip
+							// the circularity checking in
+							// InstanceProcess.getService
+							service = componentInstance.bindedServices.get(serviceReferences[j]);
+							if (service == null) {
+								service = InstanceProcess.staticRef.getService(reference, serviceReferences[j]);
+							}
+							// the service object could be null because of
+							// circularity
+							if (service != null) {
+								theServices.addElement(service);
+								componentInstance.bindedServices.put(serviceReferences[j], service);
+							}
+						}
+						if (!theServices.isEmpty()) {
+							Object ret[] = new Object[theServices.size()];
+							for (int j = 0; j < ret.length; j++) {
+								ret[j] = theServices.elementAt(j);
+							}
+							return ret;
+						}
+					}
+				} catch (Throwable t) {
+					if (t instanceof ComponentException) {
+						throw (ComponentException) t;
+					}
+					throw new ComponentException("Exception occured while locating services for interface " + name, t);
+				}
+			}
+		}
+		return null;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.osgi.service.component.ComponentContext#locateService(String
+	 *      name, ServiceReference reference)
+	 */
+	public Object locateService(String name, ServiceReference serviceReference) {
+		if (scp.references == null) {
+			return null;
+		}
+		if (Activator.DEBUG) {
+			Activator.log.debug(0, 10070, name + " by service reference : " + serviceReference, null, false);
+			// //Activator.log.debug("ComponentContextImpl.locateService(): " +
+			// name, null);
+		}
+		Vector references = scp.references;
+		try {
+			for (int i = 0; i < references.size(); i++) {
+				Reference reference = (Reference) references.elementAt(i);
+				ComponentReference ref = reference.reference;
+
+				if (ref.name.equals(name)) {
+					if (serviceReference == null || !ref.serviceReferences.contains(serviceReference)) {
+						// the serviceReference is not bound to the specified
+						// reference
+						if (Activator.DEBUG) {
+							String referenceToString = (serviceReference == null) ? null : serviceReference.toString();
+							Activator.log.debug(0, 10072, referenceToString, null, false);
+						}
+						return null;
+					}
+
+					Object cached = componentInstance.bindedServices.get(serviceReference);
+					if (cached != null) {
+						// will skip the circularity checking in
+						// InstanceProcess.getService
+						return cached;
+					}
+					Object theService = InstanceProcess.staticRef.getService(reference, serviceReference);
+					// the service object could be null because of circularity
+					if (theService != null) {
+						componentInstance.bindedServices.put(serviceReference, theService);
+						return theService;
+					}
+				}
+			}
+		} catch (Throwable t) {
+			if (t instanceof ComponentException) {
+				throw (ComponentException) t;
+			}
+			throw new ComponentException("Exception occured while locating service for interface " + name, t);
+		}
+		return null;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.osgi.service.component.ComponentContext#getBundleContext()
+	 */
+	public BundleContext getBundleContext() {
+		return scp.bc;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.osgi.service.component.ComponentContext#getUsingBundle()
+	 */
+	public Bundle getUsingBundle() {
+		// this is only for service factories!
+		ServiceComponent componentDescription = scp.serviceComponent;
+		if ((componentDescription.provides == null) || (!componentDescription.serviceFactory)) {
+			return null;
+		}
+		return usingBundle;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.osgi.service.component.ComponentContext#getComponentInstance()
+	 */
+	public ComponentInstance getComponentInstance() {
+		return componentInstance;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.osgi.service.component.ComponentContext#enableComponent(java.lang.String)
+	 */
+	public void enableComponent(String name) {
+		mgr.enableComponent(name, scp.bc.getBundle());
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.osgi.service.component.ComponentContext#disableComponent(java.lang.String)
+	 */
+	public void disableComponent(String name) {
+		mgr.disableComponent(name, scp.bc.getBundle());
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.osgi.service.component.ComponentContext#getServiceReference()
+	 */
+	public ServiceReference getServiceReference() {
+		if (scp.serviceComponent.provides != null) {
+			ServiceRegistration reg = scp.registration;
+			if (reg != null) {
+				return reg.getReference();
+			}
+		}
+		return null;
+	}
+
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/impl/ComponentFactoryImpl.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/impl/ComponentFactoryImpl.java
new file mode 100644
index 0000000..c6bb9a9
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/impl/ComponentFactoryImpl.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.ds.impl;
+
+import java.util.*;
+import org.eclipse.equinox.internal.ds.*;
+import org.eclipse.equinox.internal.ds.model.ServiceComponentProp;
+import org.eclipse.equinox.internal.util.ref.Log;
+import org.osgi.service.component.*;
+
+/**
+ * ComponentFactoryImpl.java
+ * 
+ * @author Valentin Valchev
+ * @author Stoyan Boshev
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public class ComponentFactoryImpl implements ComponentFactory {
+
+	static boolean security = false;
+
+	private ServiceComponentProp sci;
+
+	/**
+	 * ComponentFactoryImpl
+	 * 
+	 * @param component
+	 *            the ComponentDescription Object with Properties
+	 */
+	public ComponentFactoryImpl(ServiceComponentProp component) {
+		security = Log.security();
+		this.sci = component;
+	}
+
+	/**
+	 * Create a new instance of the component. Additional properties may be
+	 * provided for the component instance.
+	 * 
+	 * @param properties
+	 *            Additional properties for the component instance.
+	 * @return A ComponentInstance object encapsulating the component instance.
+	 *         The returned component instance has been activated.
+	 */
+	public ComponentInstance newInstance(Dictionary additionalProps) {
+		ComponentInstanceImpl instance = null;
+		try {
+			if (Activator.DEBUG) {
+				Activator.log.debug(0, 10032, sci.name, null, false);
+				// //Activator.log.debug("ComponentFactoryImpl.newInstance(): "
+				// + sci.name, null);
+			}
+
+			// merge properties
+			Hashtable props = (Hashtable) sci.getProperties().clone();
+			SCRUtil.copyTo(props, additionalProps);
+
+			// create a new SCP (adds to resolver scpEnabled list)
+			ServiceComponentProp newSCP = InstanceProcess.resolver.mapNewFactoryComponent(sci.serviceComponent, props);
+
+			// register the component and make instance if immediate
+			Vector toBuild = new Vector(1);
+			toBuild.addElement(newSCP);
+			InstanceProcess.staticRef.buildComponents(toBuild, security);
+			if (!newSCP.instances.isEmpty()) {
+				// an instance was built because the component is either
+				// immediate
+				// or someone has got it as service (if provides one)
+				instance = (ComponentInstanceImpl) newSCP.instances.firstElement();
+			}
+			if (instance == null) {
+				// finally build an instance if not done yet
+				instance = InstanceProcess.staticRef.buildComponent(null, newSCP, null, security);
+			}
+			instance.factory = this;
+		} catch (Throwable e) {
+			if (e instanceof ComponentException) {
+				throw (ComponentException) e;
+			}
+			Activator.log.error("ComponentFactoryImpl.newInstance(): failed for " + sci.name + " with properties " + additionalProps, e);
+			throw new ComponentException("Failed to create new instance", e);
+		}
+		return instance;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#toString()
+	 */
+	public String toString() {
+		return "ComponentFactory for " + sci.name;
+	}
+
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/impl/ComponentInstanceImpl.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/impl/ComponentInstanceImpl.java
new file mode 100644
index 0000000..47386ec
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/impl/ComponentInstanceImpl.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.ds.impl;
+
+import java.util.*;
+import org.eclipse.equinox.internal.ds.Activator;
+import org.eclipse.equinox.internal.ds.InstanceProcess;
+import org.eclipse.equinox.internal.ds.model.ServiceComponentProp;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.ComponentInstance;
+
+/**
+ * ComponentInstanceImpl.java
+ * 
+ * @author Valentin Valchev
+ * @author Stoyan Boshev
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public class ComponentInstanceImpl implements ComponentInstance {
+
+	public Object instance;
+	ServiceComponentProp scp;
+	ComponentFactoryImpl factory;
+
+	private ComponentContext componentContext;
+
+	// ServiceReference to service objects which are binded to this instance
+	public Hashtable bindedServices = new Hashtable(11);
+
+	public ComponentInstanceImpl(Object instance, ServiceComponentProp scp) {
+		this.instance = instance;
+		this.scp = scp;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.osgi.service.component.ComponentInstance#dispose()
+	 */
+	public void dispose() {
+		if (scp == null) {
+			// already disposed!
+			return;
+		}
+		if (Activator.DEBUG) {
+			Activator.log.debug(0, 10080, scp.name, null, false);
+			// //Activator.log.debug("ComponentInstanceImpl.dispose(): disposing
+			// instance of component " + scp.name, null);
+		}
+		if (!scp.isComponentFactory() && scp.serviceComponent.factory != null) {
+			// this is a component factory instance, so dispose SCP
+			scp.serviceComponent.componentProps.removeElement(scp);
+			Vector toDispose = new Vector(1);
+			toDispose.addElement(scp);
+			InstanceProcess.resolver.disposeComponentConfigs(toDispose);
+			scp = null;
+		} else {
+			scp.dispose(this);
+		}
+
+		// free service references if some are left ungotten
+		freeServiceReferences();
+		componentContext = null;
+	}
+
+	// check whether some cached service references are not yet removed and
+	// ungotten
+	public void freeServiceReferences() {
+		if (!bindedServices.isEmpty()) {
+			Enumeration keys = bindedServices.keys();
+			while (keys.hasMoreElements()) {
+				ServiceReference reference = (ServiceReference) keys.nextElement();
+				bindedServices.remove(reference);
+				scp.bc.ungetService(reference);
+			}
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.osgi.service.component.ComponentInstance#getInstance()
+	 */
+	public Object getInstance() {
+		return instance;
+	}
+
+	public ComponentContext getComponentContext() {
+		return componentContext;
+	}
+
+	public void setComponentContext(ComponentContext componentContext) {
+		this.componentContext = componentContext;
+	}
+
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/ComponentReference.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/ComponentReference.java
new file mode 100644
index 0000000..ce754e7
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/ComponentReference.java
@@ -0,0 +1,442 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *    Jeremy Volkman 		- bug.id = 182560
+ *******************************************************************************/
+package org.eclipse.equinox.internal.ds.model;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.eclipse.equinox.internal.ds.*;
+import org.eclipse.equinox.internal.ds.impl.ComponentInstanceImpl;
+import org.eclipse.equinox.internal.ds.model.ServiceComponent;
+import org.eclipse.equinox.internal.util.io.Externalizable;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentInstance;
+
+
+/**
+ * @author Stoyan Boshev
+ * @author Pavlin Dobrev
+ * @version 1.1
+ */
+
+public class ComponentReference implements Externalizable {
+
+	public static final int CARDINALITY_0_1 = 0;
+	public static final int CARDINALITY_0_N = 1;
+	public static final int CARDINALITY_1_1 = 2;
+	public static final int CARDINALITY_1_N = 3;
+	public static final int POLICY_STATIC = 0;
+	public static final int POLICY_DYNAMIC = 1;
+
+	// --- begin: XML def
+	public String name; // required
+	public String interfaceName; // required
+	public int cardinality = CARDINALITY_1_1;
+	public int policy = POLICY_STATIC;
+	public String target;
+	public String bind;
+	public String unbind;
+	ServiceComponent component;
+	// --- end: XML def
+
+	// --- begin: cache
+	private boolean bindCached;
+	private boolean unbindCached;
+	private Method bindMethod;
+	private Method unbindMethod;
+	// --- end: cache
+
+	// --- begin: model
+
+	// ServiceReferences binded to this reference
+	public Vector serviceReferences = new Vector(2);
+
+	private Hashtable serviceReferencesToUnbind = new Hashtable(3);
+
+	static final Class[] SERVICE_REFERENCE = new Class[] {ServiceReference.class};
+
+	// --- end: model;
+
+	ComponentReference(ServiceComponent component) {
+		this.component = component;
+		if (this.component.references == null) {
+			this.component.references = new Vector(2);
+		}
+		this.component.references.addElement(this);
+	}
+
+	Method getMethod(ComponentInstanceImpl componentInstance, Reference reference, String methodName, ServiceReference serviceReference) {
+
+		Class consumerClass = componentInstance.getInstance().getClass();
+		Object serviceObject = null;
+		Class serviceObjectClass = null;
+		Class interfaceClass = null;
+		Class[] param_interfaceClass = null;
+		Method method = null;
+		while (consumerClass != null) {
+
+			// search this class' methods
+			// look for various forms of bind methods
+
+			// 1) check for bind(ServiceReference) method
+			try {
+				method = consumerClass.getDeclaredMethod(methodName, SERVICE_REFERENCE);
+			} catch (NoSuchMethodException e) {
+			} catch (NoClassDefFoundError err) {
+				// this may happen on skelmir VM
+			}
+
+			if (method != null)
+				break;
+
+			// we need a serviceObject to keep looking, create one if necessary
+			if (serviceObject == null) {
+				serviceObject = componentInstance.bindedServices.get(serviceReference);
+				if (serviceObject == null) {
+					serviceObject = InstanceProcess.staticRef.getService(reference, serviceReference);
+				}
+				if (serviceObject == null) {
+					// we could not create a serviceObject because of
+					// circularity
+					return null;
+				}
+				componentInstance.bindedServices.put(serviceReference, serviceObject);
+				serviceObjectClass = serviceObject.getClass();
+
+				// figure out the interface class - this is guaranteed to
+				// succeed or else
+				// the framework would not have let us have the service object
+				Class searchForInterfaceClass = serviceObjectClass;
+				while (searchForInterfaceClass != null) {
+					// first look through interfaces
+					Class[] interfaceClasses = searchForInterfaceClass.getInterfaces();
+					for (int i = 0; i < interfaceClasses.length; i++) {
+						if (interfaceClasses[i].getName().equals(interfaceName)) {
+							interfaceClass = interfaceClasses[i];
+							break;
+						}
+					}
+					if (interfaceClass != null) {
+						break;
+					}
+
+					// also check the class itself
+					if (searchForInterfaceClass.getName().equals(interfaceName)) {
+						interfaceClass = searchForInterfaceClass;
+						break;
+					}
+
+					// advance up the superclasses
+					searchForInterfaceClass = searchForInterfaceClass.getSuperclass();
+				}
+
+				param_interfaceClass = new Class[] {interfaceClass};
+
+			} // end if(serviceObject == null)
+
+			// 2) check for bind(Service interface) method
+			try {
+				method = consumerClass.getDeclaredMethod(methodName, param_interfaceClass);
+			} catch (NoSuchMethodException e) {
+			} catch (NoClassDefFoundError err) {
+				// this may happen on skelmir VM
+			}
+			if (method != null)
+				break;
+
+			// 3) check for bind(class.isAssignableFrom(serviceObjectClass))
+			// method
+			Method[] methods = consumerClass.getDeclaredMethods();
+			for (int i = 0; i < methods.length; i++) {
+				Class[] params = methods[i].getParameterTypes();
+				if (params.length == 1 && methods[i].getName().equals(methodName) && params[0].isAssignableFrom(serviceObjectClass)) {
+
+					method = methods[i];
+					break;
+				}
+			}
+			if (method != null)
+				break;
+			// we couldn't find the method - try the superclass
+			consumerClass = consumerClass.getSuperclass();
+		}
+
+		if (method == null) {
+			Activator.log.error("[SCR] Method was not found: " + methodName, null);
+			return null;
+		}
+
+		// if method is not protected or public, log error message
+		int modifier = method.getModifiers();
+		if (!(Modifier.isProtected(modifier) || Modifier.isPublic(modifier))) {
+			Activator.log.error("[SCR] Method " + methodName + " is not protected or public.", null);
+			return null;
+		}
+
+		if (Modifier.isProtected(modifier)) {
+			SCRUtil.setAccessible(method);
+		}
+
+		return method;
+	}
+
+	final void bind(Reference reference, ComponentInstance instance, ServiceReference serviceReference) throws Exception {
+		if (bind != null) {
+			// DON'T rebind the same object again
+			synchronized (serviceReferences) {
+				if (serviceReferences.contains(serviceReference)) {
+					Activator.log.warning("ComponentReference.bind(): service reference already bound: " + serviceReference, null);
+					return;
+				} else {
+					serviceReferences.addElement(serviceReference);
+				}
+			}
+			// retrieve the method from cache
+			if (!bindCached) {
+				bindMethod = getMethod((ComponentInstanceImpl) instance, reference, bind, serviceReference);
+				// bindMethod can be null in case of circularity
+				if (bindMethod != null) {
+					bindCached = true;
+				}
+			}
+			// invoke the method
+			if (bindMethod != null) {
+				Object methodParam = null;
+				if (bindMethod.getParameterTypes()[0].equals(ServiceReference.class)) {
+					methodParam = serviceReference;
+				} else {
+					// bindedServices is filled by the getMethod function
+					methodParam = ((ComponentInstanceImpl) instance).bindedServices.get(serviceReference);
+					if (methodParam == null) {
+						methodParam = InstanceProcess.staticRef.getService(reference, serviceReference);
+					}
+					if (methodParam == null) {
+						// cannot get serviceObject because of circularity
+
+						//remove the service reference marked as bind
+						serviceReferences.remove(serviceReference);
+						return;
+					}
+				}
+
+				Object[] params = SCRUtil.getObjectArray();
+				params[0] = methodParam;
+				try {
+					bindMethod.invoke(instance.getInstance(), params);
+				} catch (Throwable t) {
+					Activator.log.error("[SCR] Error while trying to bind reference " + this, t);
+					// rethrow exception so resolver is eventually notified that
+					// this component is bad
+					// throw t;
+				} finally {
+					SCRUtil.release(params);
+				}
+			} else {
+				//remove the service reference marked as bind
+				serviceReferences.remove(serviceReference);
+
+				// could be also circularity break
+				Activator.log.warning("ComponentReference.bind(): bind method " + bind + " is not accessible!", null);
+			}
+		}
+	}
+
+	public final void unbind(Reference reference, ComponentInstance instance, ServiceReference serviceReference) {
+		// don't unbind an object that wasn't bound
+		int index;
+		synchronized (serviceReferences) {
+			index = serviceReferences.indexOf(serviceReference);
+			if (index >= 0) {
+				if (serviceReferencesToUnbind.containsKey(serviceReference)) {
+					//the service reference is already in process of unbinding
+					return;
+				} else {
+					serviceReferencesToUnbind.put(serviceReference, "");
+				}
+			}
+		}
+		if (index == -1) {
+			Activator.log.warning("ComponentReference.unbind(): invalid service reference " + serviceReference, null);
+			return;
+		}
+		try {
+			if (unbind != null) {
+				// retrieve the unbind method from cache
+				if (!unbindCached) {
+					unbindCached = true;
+					unbindMethod = getMethod((ComponentInstanceImpl) instance, reference, unbind, serviceReference);
+				}
+				// invoke the method
+				if (unbindMethod != null) {
+					Object methodParam = null;
+					if (unbindMethod.getParameterTypes()[0].equals(ServiceReference.class)) {
+						methodParam = serviceReference;
+					} else {
+						// bindedServices is filled by the getMethod function
+						methodParam = ((ComponentInstanceImpl) instance).bindedServices.get(serviceReference);
+						if (methodParam == null) {
+							methodParam = InstanceProcess.staticRef.getService(reference, serviceReference);
+						}
+						if (methodParam == null) {
+							// probably cannot get serviceObject because of
+							// circularity
+							return;
+						}
+					}
+
+					Object[] params = SCRUtil.getObjectArray();
+					params[0] = methodParam;
+					try {
+						unbindMethod.invoke(instance.getInstance(), params);
+					} catch (Throwable t) {
+						Activator.log.error("Exception occured while unbining reference " + this, t);
+						// Activator.fwAccess.postFrameworkEvent(FrameworkEvent.ERROR,
+						// component.bundle, t);
+					} finally {
+						SCRUtil.release(params);
+					}
+				}
+			}
+		} finally {
+			synchronized (serviceReferences) {
+				serviceReferences.removeElementAt(index);
+				serviceReferencesToUnbind.remove(serviceReference);
+			}
+		}
+		if (((ComponentInstanceImpl) instance).bindedServices.remove(serviceReference) != null) {
+			component.bc.ungetService(serviceReference);
+		}
+	}
+
+	public final void dispose() {
+		bindCached = unbindCached = false;
+		bindMethod = unbindMethod = null;
+		serviceReferences = null;
+	}
+
+	public final String toString() {
+		StringBuffer buffer = new StringBuffer();
+		buffer.append("Reference[");
+		buffer.append("name = ").append(name);
+		buffer.append(", interface = ").append(interfaceName);
+		buffer.append(", policy = ");
+		switch (policy) {
+			case POLICY_DYNAMIC :
+				buffer.append("dynamic");
+				break;
+			case POLICY_STATIC :
+				buffer.append("static");
+		}
+
+		buffer.append(", cardinality = ");
+		switch (cardinality) {
+			case CARDINALITY_0_1 :
+				buffer.append("0..1");
+				break;
+			case CARDINALITY_0_N :
+				buffer.append("0..n");
+				break;
+			case CARDINALITY_1_1 :
+				buffer.append("1..1");
+				break;
+			case CARDINALITY_1_N :
+				buffer.append("1..n");
+		}
+		buffer.append(", target = ").append(target);
+		buffer.append(", bind = ").append(bind);
+		buffer.append(", unbind = ").append(unbind);
+		buffer.append("]");
+		return buffer.toString();
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.equinox.internal.util.io.Externalizable#writeObject(java.io.OutputStream)
+	 */
+	public synchronized void writeObject(OutputStream o) throws Exception {
+		try {
+
+			DataOutputStream out;
+			if (o instanceof DataOutputStream) {
+				out = (DataOutputStream) o;
+			} else {
+				out = new DataOutputStream(o);
+			}
+			boolean flag;
+			out.writeUTF(name);
+			out.writeUTF(interfaceName);
+			out.writeInt(cardinality);
+			out.writeInt(policy);
+
+			flag = target != null;
+			out.writeBoolean(flag);
+			if (flag)
+				out.writeUTF(target);
+
+			flag = bind != null;
+			out.writeBoolean(flag);
+			if (flag)
+				out.writeUTF(bind);
+
+			flag = unbind != null;
+			out.writeBoolean(flag);
+			if (flag)
+				out.writeUTF(unbind);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.equinox.internal.util.io.Externalizable#readObject(java.io.InputStream)
+	 */
+	public synchronized void readObject(InputStream s) throws Exception {
+		try {
+
+			DataInputStream in;
+			if (s instanceof DataInputStream) {
+				in = (DataInputStream) s;
+			} else {
+				in = new DataInputStream(s);
+			}
+			boolean flag;
+			name = in.readUTF();
+			interfaceName = in.readUTF();
+			cardinality = in.readInt();
+			policy = in.readInt();
+			flag = in.readBoolean();
+			if (flag)
+				target = in.readUTF();
+
+			flag = in.readBoolean();
+			if (flag)
+				bind = in.readUTF();
+
+			flag = in.readBoolean();
+			if (flag)
+				unbind = in.readUTF();
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/DeclarationParser.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/DeclarationParser.java
new file mode 100644
index 0000000..c67fbc5
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/DeclarationParser.java
@@ -0,0 +1,698 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.ds.model;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.*;
+import org.eclipse.equinox.internal.ds.Activator;
+import org.eclipse.equinox.internal.util.xml.*;
+import org.osgi.framework.*;
+import org.osgi.service.metatype.AttributeDefinition;
+
+/**
+ * ComponentParser.java
+ * 
+ * @author Valentin Valchev
+ * @author Stoyan Boshev
+ * @author Pavlin Dobrev
+ * @author Teodor Bakardzhiev
+ * @version 1.0
+ */
+
+public class DeclarationParser implements ExTagListener {
+
+	private static final String XMLNS = "http://www.osgi.org/xmlns/scr/v1.0.0";
+	private static final String ATTR_XMLNS = "xmlns";
+
+	private static final String ATTR_AUTOENABLE = "enabled";
+	private static final String ATTR_NAME = "name";
+	private static final String ATTR_FACTORY = "factory";
+	private static final String ATTR_IMMEDIATE = "immediate";
+
+	private static final String TAG_IMPLEMENTATION = "implementation";
+	private static final String ATTR_CLASS = "class";
+
+	private static final String TAG_PROPERTY = "property";
+	private static final String ATTR_VALUE = "value";
+	private static final String ATTR_TYPE = "type";
+
+	private static final String TAG_PROPERTIES = "properties";
+	private static final String ATTR_ENTRY = "entry";
+
+	private static final String TAG_SERVICE = "service";
+	private static final String ATTR_SERVICEFACTORY = "servicefactory";
+	private static final String TAG_PROVIDE = "provide";
+	private static final String ATTR_INTERFACE = "interface";
+
+	private static final String TAG_REFERENCE = "reference";
+	private static final String ATTR_CARDINALITY = "cardinality";
+	private static final String ATTR_POLICY = "policy";
+	private static final String ATTR_TARGET = "target";
+	private static final String ATTR_BIND = "bind";
+	private static final String ATTR_UNBIND = "unbind";
+
+	public Vector components;
+
+	private Bundle bundle;
+	private BundleContext bc;
+	private ServiceComponent currentComponent;
+	private String closeTag;
+	boolean immediateSet = false;
+	private Hashtable namespaces = null;
+	private boolean rootPassed = false;
+
+	/**
+	 * This method parses an XML file read from the given stream and converts
+	 * the components definitions into a java object.
+	 * <p>
+	 * 
+	 * It also performs a full XML verification of the definition.�
+	 * 
+	 * @param in
+	 *            the input stream to the XML declaration file
+	 * @param bundle
+	 *            this is used to load the 'properties' tag
+	 */
+	public void parse(InputStream in, Bundle bundle, Vector components) throws Exception {
+		this.components = components;
+		this.bundle = bundle;
+		this.bc = bundle.getBundleContext();
+		rootPassed = false;
+		XMLParser.parseXML(in, this, -1);
+
+		// release temporary objects
+		this.bundle = null;
+		this.bc = null;
+		this.currentComponent = null;
+		this.closeTag = null;
+		this.namespaces = null;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.equinox.internal.util.xml.ExTagListener#startTag(org.eclipse.equinox.internal.util.xml.Tag)
+	 */
+	public final void startTag(Tag tag) {
+		try {
+			processNamespacesEnter(tag);
+			String tagName = tag.getName();
+			if (isCorrectComponentTag(tagName)) {
+				doCorrectComponentTag(tag, tagName);
+			}
+		} catch (Throwable e) {
+			Activator.log.error("[SCR - DeclarationParser.startTag()] Error occured while processing start tag in bundle " + bundle, e);
+		} finally {
+			if (!rootPassed) {
+				rootPassed = true;
+			}
+		}
+	}
+
+	private void doEndTag(Tag tag) throws InvalidSyntaxException {
+		String tagName = tag.getName().intern();
+		if (currentComponent != null) {
+			if (tagName == TAG_IMPLEMENTATION) {
+				doImplementation(tag);
+			} else if (tagName == TAG_PROPERTY) {
+				doProperty(tag);
+			} else if (tagName == TAG_PROPERTIES) {
+				doProperties(tag);
+			} else if (tagName == TAG_SERVICE) {
+				doService(tag);
+			} else if (tagName == TAG_REFERENCE) {
+				doReference(tag);
+			} else if (tagName == TAG_PROVIDE) {
+				// empty - this tag is processed within the service tag
+			} else if (tagName == closeTag) {
+				// the component is completed - we can now fully validate it!
+
+				if (!immediateSet && (currentComponent.factory == null)) {
+					// if unset, immediate attribute is false if service element
+					// is
+					// specified or true otherwise
+					// if component factory then immediate by default is false
+					currentComponent.setImmediate(currentComponent.serviceInterfaces == null);
+				}
+				currentComponent.validate(tag.getLine());
+				if (components == null) {
+					components = new Vector(1, 1);
+				}
+				components.addElement(currentComponent);
+				currentComponent = null;
+				closeTag = null;
+			} else {
+				IllegalArgumentException e = new IllegalArgumentException("Found illegal tag named '" + tagName + "' in component XML, at line " + tag.getLine());
+				Activator.log.error("[SCR] " + e.toString(), e);
+				throw e;
+			}
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.equinox.internal.util.xml.ExTagListener#endTag(org.eclipse.equinox.internal.util.xml.Tag)
+	 */
+	public final void endTag(Tag tag) {
+		try {
+			doEndTag(tag);
+			processNamespacesLeave(tag);
+		} catch (Throwable e) {
+			currentComponent = null;
+			closeTag = null;
+			Activator.log.error("[SCR - DeclarationParser.endTag()] Error occured while processing end tag in bundle " + bundle, e);
+		}
+	}
+
+	/**
+	 * This method will return convert a string to a cardinality constant
+	 * 
+	 * @param value
+	 *            the input string
+	 * @return the cardinality or -1 to indicate error
+	 */
+	private int getCardinality(String value) {
+		if ("0..1".equals(value)) {
+			return ComponentReference.CARDINALITY_0_1;
+		} else if ("0..n".equals(value)) {
+			return ComponentReference.CARDINALITY_0_N;
+		} else if ("1..1".equals(value)) {
+			return ComponentReference.CARDINALITY_1_1;
+		} else if ("1..n".equals(value)) {
+			return ComponentReference.CARDINALITY_1_N;
+		} else {
+			return -1;
+		}
+	}
+
+	private void doReference(Tag tag) throws InvalidSyntaxException {
+		String name = tag.getAttribute(ATTR_NAME);
+		if (name == null) {
+			IllegalArgumentException e = new IllegalArgumentException("The 'reference' tag must have 'name' attribute, at line " + tag.getLine());
+			Activator.log.error("[SCR] " + e.getMessage(), e);
+			throw e;
+		}
+
+		String iface = tag.getAttribute(ATTR_INTERFACE);
+		if (iface == null) {
+			IllegalArgumentException e = new IllegalArgumentException("The 'reference' tag must have 'interface' attribute, at line " + tag.getLine());
+			Activator.log.error("[SCR] " + e.getMessage(), e);
+			throw e;
+		}
+
+		String cardinalityS = tag.getAttribute(ATTR_CARDINALITY);
+		int cardinality = ComponentReference.CARDINALITY_1_1; // default
+		if (cardinalityS != null) {
+			cardinality = getCardinality(cardinalityS);
+			if (cardinality < 0) {
+				IllegalArgumentException e = new IllegalArgumentException("The 'cardinality' attribute has invalid value '" + name + "' at line " + tag.getLine());
+				Activator.log.error("[SCR] " + e.getMessage(), e);
+				throw e;
+			}
+		} // if null - default cardinality is already initialized in
+		// constructor
+
+		String policyS = tag.getAttribute(ATTR_POLICY);
+		int policy = ComponentReference.POLICY_STATIC; // default
+		if (policyS != null) {
+			// verify the policy attribute values
+			if (policyS.equals("static")) {
+				policy = ComponentReference.POLICY_STATIC;
+			} else if (policyS.equals("dynamic")) {
+				policy = ComponentReference.POLICY_DYNAMIC;
+			} else {
+				IllegalArgumentException e = new IllegalArgumentException("The 'policy' attribute has invalid value '" + name + "' at line" + tag.getLine());
+				Activator.log.error("[SCR] " + e.getMessage(), e);
+				throw e;
+			}
+		} // if null - default policy is already initialized in constructor
+
+		String bind = tag.getAttribute(ATTR_BIND);
+		String unbind = tag.getAttribute(ATTR_UNBIND);
+		if ((bind != null && ((unbind == null) || bind.equals(unbind))) || (unbind != null && ((bind == null) || unbind.equals(bind)))) {
+			IllegalArgumentException e = new IllegalArgumentException("The 'reference' tag at line " + tag.getLine() + " is invalid: you must specify both but different 'bind' and 'unbind' attributes!");
+			Activator.log.error("[SCR] " + e.getMessage(), e);
+			throw e;
+		}
+
+		// the reference is autoadded in the ServiceComponent's list of
+		// references
+		// in its constructor
+		ComponentReference ref = new ComponentReference(currentComponent);
+		ref.name = name;
+		ref.interfaceName = iface;
+		ref.cardinality = cardinality;
+		ref.policy = policy;
+		ref.bind = bind;
+
+		ref.unbind = unbind;
+		ref.target = tag.getAttribute(ATTR_TARGET);
+		// validate the target filter
+		if (ref.target != null) {
+			Activator.createFilter(ref.target);
+		}
+	}
+
+	private void doImplementation(Tag tag) {
+		if (currentComponent.implementation != null) {
+			IllegalArgumentException e = new IllegalArgumentException("The 'component' tag must have exactly one 'implementation' attribute at line " + tag.getLine());
+			Activator.log.error("[SCR] " + e.getMessage(), e);
+			throw e;
+		}
+		String tmp = tag.getAttribute(ATTR_CLASS);
+		if (tmp == null) {
+			IllegalArgumentException e = new IllegalArgumentException("The 'implementation' element must have 'class' attribute set at line " + tag.getLine());
+			Activator.log.error("[SCR] " + e.getMessage(), e);
+			throw e;
+		}
+		currentComponent.implementation = tmp;
+	}
+
+	private void doService(Tag tag) {
+		String tmp = tag.getAttribute(ATTR_SERVICEFACTORY);
+		if (tmp != null) {
+			currentComponent.serviceFactory = Boolean.valueOf(tmp).booleanValue();
+		}
+		int size = tag.size();
+		if (size == 0) {
+			IllegalArgumentException e = new IllegalArgumentException("The 'service' tag must have one 'provide' tag set at line " + tag.getLine());
+			Activator.log.error("[SCR] " + e.getMessage(), e);
+			throw e;
+		}
+		for (int i = 0; i < size; i++) {
+			Tag p = tag.getTagAt(i);
+			String pName = p.getName().intern();
+			if (pName == TAG_PROVIDE) {
+				String iFace = p.getAttribute(ATTR_INTERFACE);
+				if (iFace == null) {
+					IllegalArgumentException e = new IllegalArgumentException("The 'provide' tag must have 'interface' attribute set at line " + tag.getLine());
+					Activator.log.error("[SCR] " + e.getMessage(), e);
+					throw e;
+				}
+				if (currentComponent.serviceInterfaces == null) {
+					currentComponent.serviceInterfaces = new Vector(size);
+				}
+				currentComponent.serviceInterfaces.addElement(iFace);
+			} else {
+				IllegalArgumentException e = new IllegalArgumentException("Found illegal element '" + pName + "' for tag 'service' at line " + tag.getLine());
+				Activator.log.error("[SCR] " + e.getMessage(), e);
+				throw e;
+			}
+		}
+	}
+
+	private void doProperty(Tag tag) {
+		String name = null;
+		try {
+			name = tag.getAttribute(ATTR_NAME);
+			if (name == null) {
+				IllegalArgumentException e = new IllegalArgumentException("The 'property' tag must have 'name' attribute set at line " + tag.getLine());
+				Activator.log.error("[SCR] " + e.getMessage(), e);
+				throw e;
+			}
+
+			String type = tag.getAttribute(ATTR_TYPE);
+			int mtType;
+			if (type == null || "String".equals(type)) {
+				mtType = AttributeDefinition.STRING;
+			} else if ("Boolean".equals(type)) {
+				mtType = AttributeDefinition.BOOLEAN;
+			} else if ("Integer".equals(type)) {
+				mtType = AttributeDefinition.INTEGER;
+			} else if ("Long".equals(type)) {
+				mtType = AttributeDefinition.LONG;
+			} else if ("Char".equals(type)) {
+				mtType = AttributeDefinition.CHARACTER;
+			} else if ("Double".equals(type)) {
+				mtType = AttributeDefinition.DOUBLE;
+			} else if ("Float".equals(type)) {
+				mtType = AttributeDefinition.FLOAT;
+			} else if ("Byte".equals(type)) {
+				mtType = AttributeDefinition.BYTE;
+			} else if ("Short".equals(type)) {
+				mtType = AttributeDefinition.SHORT;
+			} else {
+				IllegalArgumentException e = new IllegalArgumentException("Illegal property type '" + type + "' on line " + tag.getLine());
+				Activator.log.error("[SCR] " + e.getMessage(), e);
+				throw e;
+			}
+
+			String value = tag.getAttribute(ATTR_VALUE);
+			Object _value;
+			if (value != null) {
+				_value = makeObject(value, mtType);
+			} else {
+				// body must be specified
+				value = tag.getContent();
+				if (value == null) {
+					IllegalArgumentException e = new IllegalArgumentException("The 'property' tag must have body content if 'value' attribute is not specified!");
+					Activator.log.error("[SCR] " + e.getMessage(), e);
+					throw e;
+				}
+				StringTokenizer tok = new StringTokenizer(value, "\n\r");
+				Vector el = new Vector(10);
+				while (tok.hasMoreTokens()) {
+					String next = tok.nextToken().trim();
+					if (next.length() > 0) {
+						el.addElement(next);
+					}
+				}
+				if (el.size() == 0) {
+					IllegalArgumentException e = new IllegalArgumentException("The 'property' tag must have body content if 'value' attribute is not specified!");
+					Activator.log.error("[SCR] " + e.getMessage(), e);
+					throw e;
+				}
+				String[] values = new String[el.size()];
+				el.copyInto(values);
+				_value = makeArr(values, mtType);
+			}
+			if (currentComponent.properties == null) {
+				currentComponent.properties = new Properties();
+			}
+			currentComponent.properties.put(name, _value);
+		} catch (Throwable e) {
+			Activator.log.error("[SCR - DeclarationParser.doProperty()] Error while processing property " + name, e);
+		}
+	}
+
+	private void doProperties(Tag tag) {
+		String fileEntry = tag.getAttribute(ATTR_ENTRY);
+		if (fileEntry == null) {
+			IllegalArgumentException e = new IllegalArgumentException("The 'properties' tag must include 'entry' attribute, at line " + tag.getLine());
+			Activator.log.error("[SCR] " + e.getMessage(), e);
+			throw e;
+		}
+
+		InputStream is = null;
+		try {
+			URL resource = bundle.getResource(fileEntry);
+			is = resource != null ? resource.openStream() : null;
+		} catch (IOException ignore) {
+		}
+
+		boolean invalid = true;
+		// FIXME: this will not work on properties defined like
+		// com.prosyst.bla.component.properties
+		// in this case the path should be converted as
+		// com/prosyst/bla/component.properties
+		if (is != null) {
+			if (currentComponent.properties == null) {
+				currentComponent.properties = new Properties();
+			}
+			try {
+				currentComponent.properties.load(is);
+				invalid = false;
+			} catch (IOException e) {
+				Activator.log.error("[SCR - DeclarationParser.doProperties()] Error while loading properties file", e);
+			}
+		}
+
+		if (invalid) {
+			IllegalArgumentException e = new IllegalArgumentException("The specified 'entry' for the 'properties' tag at line " + tag.getLine() + " doesn't contain valid reference to a property file: " + fileEntry);
+			Activator.log.error("[SCR] " + e.getMessage(), e);
+			throw e;
+		}
+	}
+
+	private static String COMPONENT_TAG_NAME = "component";
+
+	private void doCorrectComponentTag(Tag tag, String tagName) {
+		closeTag = tagName.intern();
+		String tmp = tag.getAttribute(ATTR_NAME);
+		if (tmp == null) {
+			IllegalArgumentException e = new IllegalArgumentException("The 'component' tag MUST have 'name' tag set, at line " + tag.getLine());
+			Activator.log.error("[SCR] " + e.getMessage(), e);
+			return;
+		}
+		immediateSet = false;
+
+		currentComponent = new ServiceComponent();
+		// make sure that the bundle attribute is set - it is required further
+		currentComponent.bundle = bundle;
+		currentComponent.bc = bc;
+		currentComponent.name = tmp;
+		tmp = tag.getAttribute(ATTR_AUTOENABLE);
+		if (tmp != null) {
+			currentComponent.autoenable = Boolean.valueOf(tmp).booleanValue();
+		}
+		tmp = tag.getAttribute(ATTR_FACTORY);
+		if (tmp != null && tmp.length() == 0) {
+			tmp = null;
+		}
+		currentComponent.factory = tmp;
+		tmp = tag.getAttribute(ATTR_IMMEDIATE);
+		if (tmp != null && tmp.length() == 0) {
+			tmp = null;
+		}
+		if (tmp != null) {
+			currentComponent.immediate = Boolean.valueOf(tmp).booleanValue();
+			immediateSet = true;
+		}
+	}
+
+	private boolean isCorrectComponentTag(String tagName) {
+		String qualifier = getNamespaceQualifier(tagName);
+		String localTagName = (qualifier.length() == 0) ? tagName : tagName.substring(qualifier.length() + 1); // + one char for ':'
+		if (!localTagName.equals(COMPONENT_TAG_NAME)) {
+			return false;
+		}
+		String namespace = getCurrentNamespace(qualifier);
+		if (!rootPassed) { // this is the root element
+			return namespace.length() == 0 || namespace.equals(XMLNS);
+		} else { // not a root element
+			return namespace.equals(XMLNS);
+		}
+	}
+
+	/**
+	 * Creates an object from a <code>String</code> value and a type, as
+	 * returned by the corresponding {@link AttributeDefinition#getType()}
+	 * method.
+	 * 
+	 * @param string
+	 *            The <code>String</code> value representation of the object.
+	 * @param syntax
+	 *            The object's type as defined by
+	 *            <code>AttributeDefinition</code>.
+	 * 
+	 * @return an Object, which is of a type, corresponding to the given, and
+	 *         value - got from the string parameter. E.g. if syntax is equal to
+	 *         <code>AttributeDefinition.INTEGER</code> and string is "1",
+	 *         then the value returned should be Integer("1").
+	 * 
+	 * @exception IllegalArgumentException
+	 *                if a proper object can not be created due to
+	 *                incompatibility of syntax and value or if the parameters
+	 *                are not correct (e.g. syntax is not a valid
+	 *                <code>AttributeDefinition</code> constant).
+	 */
+	public static Object makeObject(String string, int syntax) throws IllegalArgumentException {
+		try {
+			switch (syntax) {
+				case AttributeDefinition.STRING : {
+					return string;
+				}
+				case AttributeDefinition.INTEGER : {
+					return new Integer(string);
+				}
+				case AttributeDefinition.LONG : {
+					return new Long(string);
+				}
+				case AttributeDefinition.FLOAT : {
+					return new Float(string);
+				}
+				case AttributeDefinition.DOUBLE : {
+					return new Double(string);
+				}
+				case AttributeDefinition.BYTE : {
+					return new Byte(string);
+				}
+				case AttributeDefinition.SHORT : {
+					return new Short(string);
+				}
+				case AttributeDefinition.CHARACTER : {
+					if (string.length() == 0) {
+						throw new IllegalArgumentException("Missing character ");
+					}
+					return new Character(string.charAt(0));
+				}
+				case AttributeDefinition.BOOLEAN : {
+					return Boolean.valueOf(string);
+				}
+				default : {
+					throw new IllegalArgumentException("Unsupported type: ".concat(String.valueOf(syntax)));
+				}
+			}
+		} catch (NumberFormatException ex) {
+			throw new IllegalArgumentException("Value: " + string + " does not fit its type!");
+		}
+	}
+
+	/**
+	 * Makes an array from the string array value and the syntax.
+	 * 
+	 * @param array
+	 *            <code>String</code> array representation of an array, which
+	 *            follows the rules defined by <code>AttributeDefinition</code>.
+	 * @param syntax
+	 *            The array's type as defined by
+	 *            <code>AttributeDefinition</code>.
+	 * 
+	 * @return an arary of primitives or objects, whose component type
+	 *         corresponds to <code>syntax</code>, and value build from the
+	 *         string array passed.
+	 * 
+	 * @exception IllegalArgumentException
+	 *                if any of the elements in the string array can not be
+	 *                converted to a proper object or primitive, or if the
+	 *                <code>syntax</code> is not a valid
+	 *                <code>AttributeDefinition</code> type constant.
+	 */
+	public static Object makeArr(String[] array, int syntax) throws IllegalArgumentException {
+		switch (syntax) {
+			case AttributeDefinition.STRING : {
+				return array;
+			}
+			case AttributeDefinition.INTEGER : {
+				int[] ints = new int[array.length];
+				for (int i = 0; i < array.length; i++) {
+					ints[i] = Integer.parseInt(array[i]);
+				}
+				return ints;
+			}
+			case AttributeDefinition.LONG : {
+				long[] longs = new long[array.length];
+				for (int i = 0; i < array.length; i++) {
+					longs[i] = Long.parseLong(array[i]);
+				}
+				return longs;
+			}
+			case AttributeDefinition.FLOAT : {
+				float[] floats = new float[array.length];
+				for (int i = 0; i < array.length; i++) {
+					floats[i] = Float.valueOf(array[i]).floatValue();
+				}
+				return floats;
+			}
+			case AttributeDefinition.DOUBLE : {
+				double[] doubles = new double[array.length];
+				for (int i = 0; i < array.length; i++) {
+					doubles[i] = Double.valueOf(array[i]).doubleValue();
+				}
+				return doubles;
+			}
+			case AttributeDefinition.BYTE : {
+				byte[] bytes = new byte[array.length];
+				for (int i = 0; i < array.length; i++) {
+					bytes[i] = Byte.parseByte(array[i]);
+				}
+				return bytes;
+			}
+			case AttributeDefinition.SHORT : {
+				short[] shorts = new short[array.length];
+				for (int i = 0; i < array.length; i++) {
+					shorts[i] = Short.parseShort(array[i]);
+				}
+				return shorts;
+			}
+			case AttributeDefinition.CHARACTER : {
+				char[] chars = new char[array.length];
+				for (int i = 0; i < array.length; i++) {
+					chars[i] = array[i].charAt(0);
+				}
+				return chars;
+			}
+			case AttributeDefinition.BOOLEAN : {
+				boolean[] booleans = new boolean[array.length];
+				for (int i = 0; i < array.length; i++) {
+					booleans[i] = Boolean.valueOf(array[i]).booleanValue();
+				}
+				return booleans;
+			}
+			default : {
+				throw new IllegalArgumentException("Unsupported type: ".concat(String.valueOf(syntax)));
+			}
+		}
+	}
+
+	private void processNamespacesEnter(Tag tag) {
+		Enumeration en = tag.getAttributeNames();
+		while (en.hasMoreElements()) {
+			String attrName = (String) en.nextElement();
+			if (attrName.startsWith(ATTR_XMLNS)) {
+				String qualifier = attrName.substring(ATTR_XMLNS.length());
+				if ((qualifier.length() == 0) || // <- default namespace
+						((qualifier.charAt(0) == ':') ? (qualifier = qualifier.substring(1)).length() > 0 : false)) {
+
+					if (namespaces == null) {
+						namespaces = new Hashtable();
+					}
+					Stack stack = null;
+					if ((stack = (Stack) namespaces.get(qualifier)) == null) {
+						stack = new Stack();
+						namespaces.put(qualifier, stack);
+					}
+					stack.push(tag.getAttribute(attrName));
+				}
+			}
+		}
+	}
+
+	private String getCurrentNamespace(String qualifier) {
+		if (namespaces == null || qualifier == null) {
+			return "";
+		}
+		Stack stack = (Stack) namespaces.get(qualifier);
+		if (stack == null || stack.empty()) {
+			return "";
+		}
+
+		return (String) stack.peek();
+	}
+
+	private void processNamespacesLeave(Tag tag) {
+		if (namespaces == null) {
+			return;
+		}
+		Enumeration en = tag.getAttributeNames();
+		while (en.hasMoreElements()) {
+			String attrName = (String) en.nextElement();
+			if (attrName.startsWith(ATTR_XMLNS)) {
+				String qualifier = attrName.substring(ATTR_XMLNS.length());
+				if ((qualifier.length() == 0) || // <- default namespace
+						((qualifier.charAt(0) == ':') ? (qualifier = qualifier.substring(1)).length() > 0 : false)) {
+
+					Stack stack = (Stack) namespaces.get(qualifier);
+					if (stack != null) {
+						if (!stack.empty()) {
+							stack.pop();
+						}
+						if (stack.empty()) {
+							namespaces.remove(qualifier);
+						}
+					}
+				}
+			}
+		}
+	}
+
+	private String getNamespaceQualifier(String name) {
+		int index = name.indexOf(':');
+		if (index < 0) {
+			return "";
+		}
+		return name.substring(0, index);
+	}
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/ServiceComponent.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/ServiceComponent.java
new file mode 100644
index 0000000..8f7f14c
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/ServiceComponent.java
@@ -0,0 +1,432 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.ds.model;
+
+import java.io.*;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.*;
+import org.eclipse.equinox.internal.ds.Activator;
+import org.eclipse.equinox.internal.ds.SCRUtil;
+import org.eclipse.equinox.internal.util.io.Externalizable;
+import org.eclipse.equinox.internal.util.io.ExternalizableDictionary;
+import org.osgi.framework.*;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.ComponentException;
+
+/**
+ * This is an OO wrapper for the XML representing the components. It also caches
+ * the (de)activate & (un)bind methods (reflection) of the component.
+ * 
+ * @author Valentin Valchev
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public class ServiceComponent implements Externalizable {
+
+	public Vector componentProps = null;
+
+	// --- begin: XML def
+	public String name;
+	public String factory;
+	String implementation; // the class name
+	Properties properties; // property or properties
+
+	// service
+	public Vector serviceInterfaces; // all strings
+	public String[] provides; // the same as above, but as String[]
+	public boolean serviceFactory = false;
+
+	public Vector references; // ComponentReference
+
+	public boolean autoenable = true;
+	public boolean immediate = false;
+	// --- end: XML def
+
+	// --- begin: cache
+	private boolean activateCached = false;
+	private boolean deactivateCached = false;
+	private Method activate; // this is optional!
+	private Method deactivate;
+	// --- end: cache
+
+	// --- begin: model
+	public boolean enabled;
+	public Bundle bundle;
+	public BundleContext bc;
+	// --- end: model
+
+	private static final Class ACTIVATE_METHODS_PARAMETERS[] = new Class[] {ComponentContext.class};
+
+	public ServiceComponent() {
+	}
+
+	private static final Method getMethod(Object instance, String name) {
+		if (Activator.DEBUG) {
+			Activator.log.debug(0, 10034, name, null, false);
+			// //Activator.log.debug("getMethod() " + name, null);
+		}
+		Method method = null;
+		Class clazz = instance != null ? instance.getClass() : null;
+
+		// search for the method in the parent classes!
+		while (method == null && clazz != null) {
+			try {
+				method = clazz.getDeclaredMethod(name, ACTIVATE_METHODS_PARAMETERS);
+			} catch (Throwable t) {
+			}
+			clazz = clazz.getSuperclass();
+		}
+		if (method != null) {
+			int modifiers = method.getModifiers();
+			if (Modifier.isProtected(modifiers)) {
+				SCRUtil.setAccessible(method);
+			} else if (!Modifier.isPublic(modifiers)) {
+				// not protected neither public
+				method = null;
+			}
+		}
+
+		return method;
+	}
+
+	void activate(Object instance, ComponentContext context) throws ComponentException {
+		// retrieve the activate method from cache
+		if (!activateCached) {
+			activateCached = true;
+			activate = getMethod(instance, "activate");
+		}
+		// invoke the method if any
+		if (activate != null) {
+			Object[] params = SCRUtil.getObjectArray();
+			params[0] = context;
+			try {
+				activate.invoke(instance, params);
+			} catch (Throwable t) {
+				Activator.log.error("[SCR] Cannot activate instance " + instance + " of component " + name, t);
+				throw new ComponentException("[SCR] Exception while activating instance " + instance + " of component " + name, t);
+				// rethrow exception so resolver is eventually notified that
+				// the processed SCP is bad
+			} finally {
+				SCRUtil.release(params);
+			}
+		}
+	}
+
+	void deactivate(Object instance, ComponentContext context) {
+		// retrieve the activate method from cache
+		if (!deactivateCached) {
+			deactivateCached = true;
+			deactivate = getMethod(instance, "deactivate");
+		}
+		// invoke the method
+		if (deactivate != null) {
+			Object[] params = SCRUtil.getObjectArray();
+			params[0] = context;
+			try {
+				deactivate.invoke(instance, params);
+			} catch (Throwable t) {
+				Activator.log.error("[SCR] Error while attempting to deactivate instance of component " + name, t);
+			} finally {
+				SCRUtil.release(params);
+			}
+		}
+	}
+
+	/**
+	 * this method is called from the xml parser to validate the component once
+	 * it is fully loaded!
+	 * 
+	 * @param line
+	 *            the line at which the the component definition ends
+	 */
+	void validate(int line) {
+		// name & implementations are required
+		if (name == null) {
+			throw new IllegalArgumentException("The component definition misses 'name' attribute, line " + line);
+		}
+		if (implementation == null) {
+			throw new IllegalArgumentException("The component '" + name + "' misses 'implementation' attribute, line " + line);
+		}
+
+		// component factory is incompatible with service factory
+		if (factory != null && serviceFactory) {
+			throw new IllegalArgumentException("The component '" + name + "' invalid specifies both ComponentFactory and ServiceFactory");
+		}
+
+		if (immediate) {
+			if (serviceFactory)
+				throw new IllegalArgumentException("The component '" + name + "' is invalid specified both as immediate and ServiceFactory");
+			if (factory != null)
+				throw new IllegalArgumentException("The component '" + name + "' is invalid specified both as immediate and ComponentFactory");
+		} else {
+			if ((serviceInterfaces == null) && (factory == null)) {
+				throw new IllegalArgumentException("The component '" + name + "' is invalid specifying immediate to false and providing no Services");
+			}
+		}
+
+		// make sure that references are also valid
+		if (references != null) {
+			for (int i = 0; i < references.size(); i++) {
+				ComponentReference r = (ComponentReference) references.elementAt(i);
+				if (r.name == null || r.interfaceName == null) {
+					throw new IllegalArgumentException("The component '" + name + "' defined at line " + line + " contains illegal reference " + r);
+				}
+			}
+		}
+
+		// cache the service interfaces as String[] too.
+		if (serviceInterfaces != null && !serviceInterfaces.isEmpty()) {
+			provides = new String[serviceInterfaces.size()];
+			serviceInterfaces.copyInto(provides);
+		}
+
+		// make sure that the component will get automaticaly enabled/disable!
+		enabled = autoenable;
+	}
+
+	/**
+	 * This method will instantiate the implementation class!
+	 * 
+	 * @return instance of the component implementation class. If the components
+	 *         exports some services, the implementation must implement all of
+	 *         them
+	 * @throws Exception
+	 *             is thrown if the implementation cannot be instantiated for
+	 *             some reasons.
+	 */
+	final Object createInstance() throws Exception {
+		try {
+			return bundle.loadClass(implementation).newInstance();
+		} catch (Throwable t) {
+			// Activator.log.error("[SCR] Unable to create an instance of
+			// component "+name, t);
+			throw new ComponentException("Exception occured while creating new instance of component " + name, t);
+		}
+	}
+
+	/**
+	 * This method will dispose everything
+	 */
+	// TODO : this method is not used - should be removed?
+	public final void dispose() {
+
+		activateCached = deactivateCached = false;
+		activate = deactivate = null;
+
+		enabled = false;
+		bundle = null;
+		// bc = null;
+
+		if (references != null) {
+			for (int i = 0; i < references.size(); i++) {
+				ComponentReference ref = (ComponentReference) references.elementAt(i);
+				ref.dispose();
+			}
+			references.removeAllElements();
+			references = null;
+		}
+
+		if (properties != null) {
+			properties.clear();
+			properties = null;
+		}
+
+		if (serviceInterfaces != null) {
+			serviceInterfaces.removeAllElements();
+			serviceInterfaces = null;
+		}
+	}
+
+	public boolean provides(String interfaceName) {
+		return serviceInterfaces != null && serviceInterfaces.contains(interfaceName);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#toString()
+	 */
+	public final String toString() {
+		StringBuffer buffer = new StringBuffer();
+		buffer.append("Component[");
+		buffer.append("\n\tname = ").append(name);
+		buffer.append("\n\tautoenable = ").append(autoenable);
+		buffer.append("\n\tfactory = ").append(factory);
+		buffer.append("\n\timmediate = ").append(immediate);
+
+		buffer.append("\n\timplementation = ").append(implementation);
+		buffer.append("\n\tproperties = ").append(properties);
+
+		buffer.append("\n\tserviceFactory = ").append(serviceFactory);
+		buffer.append("\n\tserviceInterface = ").append(serviceInterfaces);
+
+		if (references == null) {
+			buffer.append("\n\treferences = ").append("null");
+		} else {
+			buffer.append("\n\treferences = {");
+			for (int i = 0; i < references.size(); i++) {
+				buffer.append("\n\t\t").append(references.elementAt(i));
+			}
+			buffer.append("\n\t}");
+		}
+		buffer.append("\n]");
+		return buffer.toString();
+	}
+
+	public synchronized void writeObject(OutputStream s) throws Exception {
+
+		try {
+
+			DataOutputStream out;
+			if (s instanceof DataOutputStream) {
+				out = (DataOutputStream) s;
+			} else {
+				out = new DataOutputStream(s);
+			}
+
+			boolean flag;
+			int count;
+
+			out.writeUTF(name);
+			out.writeUTF(implementation);
+			out.writeBoolean(serviceFactory);
+			out.writeBoolean(autoenable);
+			out.writeBoolean(immediate);
+
+			flag = factory != null;
+			out.writeBoolean(flag);
+			if (flag)
+				out.writeUTF(factory);
+
+			count = serviceInterfaces == null ? 0 : serviceInterfaces.size();
+			out.writeInt(count);
+			for (int i = 0; i < count; i++) {
+				out.writeUTF(serviceInterfaces.elementAt(i).toString());
+			}
+
+			count = references == null ? 0 : references.size();
+			out.writeInt(count);
+			for (int i = 0; i < count; i++) {
+				ComponentReference ref = (ComponentReference) references.elementAt(i);
+				ref.writeObject(out);
+			}
+
+			flag = properties != null && !properties.isEmpty();
+			out.writeBoolean(flag);
+			if (flag) {
+				ExternalizableDictionary dictionary = new ExternalizableDictionary();
+				dictionary.copyFrom(properties);
+				dictionary.writeObject(out);
+			}
+
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * Don't forget to set the bundle & the bc attributes!!!!!!
+	 * 
+	 * @param s
+	 *            the input stream from which to read the object
+	 * @throws Exception
+	 * @see org.eclipse.equinox.internal.util.io.Externalizable#readObject(java.io.InputStream)
+	 */
+	public synchronized void readObject(InputStream s) throws Exception {
+		try {
+
+			DataInputStream in;
+			if (s instanceof DataInputStream) {
+				in = (DataInputStream) s;
+			} else {
+				in = new DataInputStream(s);
+			}
+			boolean flag;
+			int count;
+
+			name = in.readUTF();
+			implementation = in.readUTF();
+			serviceFactory = in.readBoolean();
+			autoenable = in.readBoolean();
+			immediate = in.readBoolean();
+
+			flag = in.readBoolean();
+			if (flag)
+				factory = in.readUTF();
+
+			count = in.readInt();
+			if (count > 0) {
+				serviceInterfaces = new Vector(count);
+				provides = new String[count];
+				for (int i = 0; i < count; i++) {
+					String entry = in.readUTF();
+					serviceInterfaces.addElement(entry);
+					provides[i] = entry;
+				}
+			}
+
+			count = in.readInt();
+			if (count > 0) {
+				references = new Vector(count);
+				for (int i = 0; i < count; i++) {
+					ComponentReference ref = new ComponentReference(this);
+					ref.readObject(in);
+				}
+			}
+
+			flag = in.readBoolean();
+			if (flag) {
+				ExternalizableDictionary dictionary = new ExternalizableDictionary();
+				dictionary.readObject(in);
+				Properties props = new Properties();
+				for (Enumeration keys = dictionary.keys(); keys.hasMoreElements();) {
+					String key = (String) keys.nextElement();
+					props.put(key, dictionary.get(key));
+				}
+				properties = props;
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	public ServiceComponentProp getComponentPropByPID(String pid) {
+		for (int i = 0; i < componentProps.size(); i++) {
+			ServiceComponentProp scp = (ServiceComponentProp) componentProps.elementAt(i);
+			if (scp.getProperties() != null) {
+				if (pid.equals(scp.getProperties().get(Constants.SERVICE_PID))) {
+					return scp;
+				}
+			}
+		}
+		return null;
+	}
+
+	public void addServiceComponentProp(ServiceComponentProp scp) {
+		if (componentProps == null) {
+			componentProps = new Vector(2);
+		}
+		if (!componentProps.contains(scp)) {
+			componentProps.addElement(scp);
+		}
+	}
+
+	public boolean isImmediate() {
+		return immediate;
+	}
+
+	public void setImmediate(boolean immediate) {
+		this.immediate = immediate;
+	}
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/ServiceComponentProp.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/ServiceComponentProp.java
new file mode 100644
index 0000000..a238fe9
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/model/ServiceComponentProp.java
@@ -0,0 +1,555 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.ds.model;
+
+import java.security.*;
+import java.util.*;
+import org.eclipse.equinox.internal.ds.*;
+import org.eclipse.equinox.internal.ds.impl.ComponentContextImpl;
+import org.eclipse.equinox.internal.ds.impl.ComponentInstanceImpl;
+import org.osgi.framework.*;
+import org.osgi.service.component.*;
+
+/**
+ * The ServiceComponentProp represents a ServiceComponent mapped to it's CM
+ * properties.
+ * 
+ * When the ServiceComponent contains plain CM properties, the mapping of
+ * ServiceComponentProp to ServiceComponent is 1:1.
+ * 
+ * However, when the ServiceComponent is a ManagedServiceFactory, there are so
+ * many ServiceComponentProp objects created as many are the configurations
+ * associated with the component.
+ * 
+ * @author Valentin Valchev
+ * @author Stoyan Boshev
+ * @author Pavlin Dobrev
+ * @version 1.2
+ */
+
+public class ServiceComponentProp implements PrivilegedExceptionAction {
+	public ServiceRegistration registration;
+	public String name;
+	public ServiceComponent serviceComponent;
+	public Hashtable properties;
+	public Vector instances = new Vector(2); // ComponentInstance objects
+	public BundleContext bc;
+	public Vector references;
+
+	private boolean kindOfFactory;
+
+	// This flag is used to check whether the component is a component factory.
+	// Since the component factory creates new ServiceComponentProp objects they
+	// have to
+	// be marked as non component factory components in order to prevent newly
+	// registered
+	// component factories as services.
+	protected boolean isComponentFactory = false;
+
+	//Used to mark the component as disposed
+	public boolean disposed = false;
+
+	/**
+	 * List of names (Strings) of Component Configurations we should not
+	 * activate during the activation of this Component Configuration. This is
+	 * populated by the {@link org.eclipse.equinox.internal.ds.Resolver Resolver}
+	 * and used by
+	 * {@link org.eclipse.equinox.internal.ds.InstanceProcess InstanceProcess}.
+	 */
+	protected Vector delayActivateSCPNames;
+
+	private SCRManager mgr;
+
+	// next free component id
+	private static long componentid = 0;
+
+	public ServiceComponentProp(ServiceComponent serviceComponent, Dictionary configProperties, SCRManager mgr) {
+
+		this.serviceComponent = serviceComponent;
+		this.name = serviceComponent.name;
+		this.bc = serviceComponent.bc;
+
+		initProperties(configProperties);
+
+		// cache locally if it is some kind of a factory
+		kindOfFactory = serviceComponent.factory != null || serviceComponent.serviceFactory;
+		isComponentFactory = serviceComponent.factory != null;
+
+		// used for component context
+		this.mgr = mgr;
+	}
+
+	/**
+	 * This method will dispose the service component instance. Along with the
+	 * service component itself and the properties files.
+	 */
+	public void dispose() {
+		if (Activator.DEBUG) {
+			Activator.log.debug(0, 10035, name, null, false);
+			// //Activator.log.debug("ServiceComponentProp.dispose(): ", null);
+		}
+		disposed = true;
+		while (!instances.isEmpty()) {
+			ComponentInstanceImpl current = (ComponentInstanceImpl) instances.firstElement();
+			dispose(current);
+			current.dispose();
+		}
+	}
+
+	/**
+	 * getProperties
+	 * 
+	 * @return Dictionary properties
+	 */
+	public Hashtable getProperties() {
+		return properties != null ? properties : serviceComponent.properties;
+	}
+
+	/**
+	 * This method will call the activate method on the specified object.
+	 * 
+	 * @param usingBundle
+	 *            the bundle that is using the component - this hase only means
+	 *            when the component is factory
+	 * @param componentInstance
+	 *            the component instance whcich will be activated.
+	 * @throws Exception
+	 *             could be thrown if the activate fails for some reason but NOT
+	 *             in case, if the instance doesn't define an activate method.
+	 */
+	public void activate(Bundle usingBundle, ComponentInstanceImpl componentInstance) throws Exception {
+		if (Activator.DEBUG) {
+			Activator.log.debug(0, 10036, name, null, false);
+			// //Activator.log.debug("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ServiceComponentProp.activate():
+			// name: " + name, null);
+			Activator.log.debug(0, 10039, (usingBundle != null ? usingBundle.getSymbolicName() : null), null, false);
+			// //Activator.log.debug(
+			// // "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ServiceComponentProp.using
+			// bundle: "
+			// // + (usingBundle != null ? usingBundle.getSymbolicName() :
+			// null),
+			// // null);
+			Activator.log.debug(0, 10037, componentInstance.toString(), null, false);
+			// //Activator.log.debug("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ServiceComponentProp.instance:
+			// " + componentInstance, null);
+		}
+
+		// call the activate method on the Service Component
+		serviceComponent.activate(componentInstance.getInstance(), componentInstance.getComponentContext());
+	}
+
+	/**
+	 * This method will call the deactivate method on the specified Object.
+	 * Notice, that this is not the ComponentInstance object, but the real
+	 * instance.
+	 * 
+	 * @param componentInstance
+	 *            component instance wrapper
+	 */
+	private void deactivate(ComponentInstanceImpl componentInstance) {
+		if (Activator.DEBUG) {
+			Activator.log.debug(0, 10038, name, null, false);
+			// //Activator.log.debug("ServiceComponentProp.deactivate(): " +
+			// name, null);
+		}
+		serviceComponent.deactivate(componentInstance.getInstance(), componentInstance.getComponentContext());
+	}
+
+	/**
+	 * Call the bind method for each of the Referenced Services in this Service
+	 * Component
+	 * 
+	 * @param componentInstance
+	 * @throws Exception
+	 */
+	public void bind(ComponentInstance componentInstance) throws Exception {
+		// Get all the required service Reference Descriptions for this Service
+		// Component
+		// call the Bind method if the Reference Description includes one
+		if (references != null) {
+			for (int i = 0; i < references.size(); i++) {
+				Reference ref = (Reference) references.elementAt(i);
+				if (ref.reference.bind != null) {
+					bindReference(ref, componentInstance);
+				} else if (Activator.DEBUG) {
+					Activator.log.debug(0, 10040, ref.reference.name, null, false);
+					// //Activator.log.debug(
+					// // "ServiceComponentProp:bind(): the reference '" +
+					// ref.name + "' doesn't specify bind method",
+					// // null);
+				}
+			}
+		}
+	}
+
+	/**
+	 * Call the unbind method for each of the Referenced Services in this
+	 * Serivce Component
+	 * 
+	 * @param componentInstance
+	 *            the object which unbind method(s) will be called, if ANY!
+	 */
+	public void unbind(ComponentInstance componentInstance) {
+		// call the unBind method if the Reference Description includes one
+		if (references != null) {
+			for (int i = references.size() - 1; i >= 0; i--) {
+				Reference ref = (Reference) references.elementAt(i);
+				if (ref.reference.unbind != null) {
+					unbindReference(ref, componentInstance);
+				}
+			}
+		}
+	}
+
+	public Object createInstance() throws Exception {
+		assertCreateSingleInstance();
+		return serviceComponent.createInstance();
+	}
+
+	boolean locked = false;
+	int waiting = 0;
+
+	Bundle bundle;
+	Object inst;
+
+	synchronized void lock(Bundle usingBundle, Object instance) {
+		while (locked) {
+			try {
+				waiting++;
+				wait();
+			} catch (Exception _) {
+			}
+			waiting--;
+		}
+		locked = true;
+		bundle = usingBundle;
+		inst = instance;
+	}
+
+	synchronized void unlock() {
+		locked = false;
+		bundle = null;
+		inst = null;
+		if (waiting > 0)
+			notifyAll();
+	}
+
+	public Object run() throws Exception {
+		Bundle bundle = this.bundle;
+		Object instance = inst;
+		unlock();
+		return build(bundle, instance, false);
+	}
+
+	public ComponentInstanceImpl build(Bundle usingBundle, Object instance, boolean security) throws Exception {
+		if (disposed) {
+			if (Activator.DEBUG) {
+				Activator.log.debug("Cannot build component, because it is already disposed: " + this, null);
+			}
+			return null;
+		}
+
+		if (security) {
+			this.lock(usingBundle, instance);
+			try {
+				return (ComponentInstanceImpl) AccessController.doPrivileged(this);
+			} catch (PrivilegedActionException pae) {
+
+			}
+		}
+		ComponentInstanceImpl componentInstance = null;
+		if (instance == null) {
+			if (!kindOfFactory) {
+				// it is a plain service, this is because this method
+				// is also called from ServiceReg
+				if (instances.isEmpty()) {
+					instance = createInstance();
+				} else {
+					componentInstance = (ComponentInstanceImpl) instances.firstElement();
+				}
+			} else {
+				instance = createInstance();
+			}
+		}
+		if (componentInstance == null) {
+			componentInstance = new ComponentInstanceImpl(instance, this);
+			componentInstance.setComponentContext(new ComponentContextImpl(this, usingBundle, componentInstance, mgr));
+			instances.addElement(componentInstance);
+			bind(componentInstance);
+			try {
+				activate(usingBundle, componentInstance);
+			} catch (Exception e) {
+				//must unbind and dispose this component instance 
+				InstanceProcess.resolver.removeFromSatisfiedList(this);
+				if (instances.removeElement(componentInstance)) {
+					unbind(componentInstance);
+				}
+				throw e;
+			}
+		}
+
+		return componentInstance;
+	}
+
+	public void disposeObj(Object obj) {
+		ComponentInstanceImpl ci = null;
+		synchronized (instances) {
+			for (int i = 0; i < instances.size(); i++) {
+				ci = (ComponentInstanceImpl) instances.elementAt(i);
+				if (ci.getInstance() == obj) {
+					break;
+				} else {
+					ci = null;
+				}
+			}
+		}
+		if (ci != null) {
+			dispose(ci);
+			return;
+		}
+		throw new RuntimeException("The Object '" + obj + "' is not created by the component named " + name);
+	}
+
+	public void dispose(ComponentInstanceImpl componentInstance) {
+		if (!instances.removeElement(componentInstance)) {
+			return; //the instance is already disposed  
+		}
+
+		deactivate(componentInstance);
+		unbind(componentInstance);
+	}
+
+	/**
+	 * Call the bind method for this referenceDescription
+	 * 
+	 * @param componentReference
+	 * @param componentInstance
+	 * @throws Exception
+	 * 
+	 */
+	public void bindReference(Reference reference, ComponentInstance componentInstance) throws Exception {
+
+		// bind the services ONLY if bind method is specified!
+		if (reference.reference.bind == null) {
+			return;
+		}
+
+		// ok, proceed!
+		if (Activator.DEBUG) {
+			Activator.log.debug(0, 10041, serviceComponent.name + " -> " + reference.reference, null, false);
+			// //Activator.log.debug(
+			// // "ServiceComponentProp.bindReferences(): component " +
+			// serviceComponent.name + " to " + componentReference,
+			// // null);
+		}
+
+		ServiceReference[] serviceReferences = null;
+
+		// if there is a published service, then get the ServiceObject and call
+		// bind
+		try {
+			// get all registered services using this target filter
+			serviceReferences = bc.getServiceReferences(reference.reference.interfaceName, reference.reference.target);
+		} catch (Exception e) {
+			Activator.log.error("[SCR] Cannot get references for " + reference.reference.interfaceName, e);
+			throw e;
+			// rethrow exception so resolver is eventually notified that this
+			// SCP is bad
+		}
+
+		// bind only if there is at least ONE service
+		if (serviceReferences != null && serviceReferences.length > 0) {
+			// the component binds to the first available service only!
+			switch (reference.reference.cardinality) {
+				case ComponentReference.CARDINALITY_1_1 :
+				case ComponentReference.CARDINALITY_0_1 :
+					reference.reference.bind(reference, componentInstance, serviceReferences[0]);
+					break;
+				case ComponentReference.CARDINALITY_1_N :
+				case ComponentReference.CARDINALITY_0_N :
+					// bind to all services
+					for (int i = 0; i < serviceReferences.length; i++) {
+						reference.reference.bind(reference, componentInstance, serviceReferences[i]);
+					}
+					break;
+			}
+		} else {
+			if (Activator.DEBUG) {
+				Activator.log.debug("ServiceComponentProp.bindReference(): The service is not yet registered, but it is already instantiated", null);
+			}
+		}
+	}
+
+	/**
+	 * Call the unbind method for this Reference Description
+	 * 
+	 * @param reference
+	 * @param componentInstance
+	 */
+	public void unbindReference(Reference reference, ComponentInstance componentInstance) {
+
+		// unbind the services ONLY if unbind method is specified!
+		if (reference.reference.unbind == null) {
+			return;
+		}
+
+		// ok, proceed!
+
+		if (Activator.DEBUG) {
+			Activator.log.debug(0, 10042, serviceComponent.name + " <- " + reference.reference, null, false);
+			// //Activator.log.debug(
+			// // "ServiceComponentProp.unbindReference(): component " + name +
+			// " from " + componentReference,
+			// // null);
+		}
+
+		Vector serviceReferences = reference.reference.serviceReferences;
+		for (int i = serviceReferences.size() - 1; i >= 0; i--) {
+			reference.reference.unbind(reference, componentInstance, (ServiceReference) serviceReferences.elementAt(i));
+		}
+	}
+
+	/**
+	 * Call the unbind method for this Reference Description
+	 * 
+	 * @param ref
+	 * @param instance
+	 * @param serviceObject
+	 * @throws Exception
+	 */
+	public void unbindDynamicReference(Reference ref, ComponentInstance instance, ServiceReference serviceReference) throws Exception {
+		try {
+			if (Activator.DEBUG) {
+				Activator.log.debug("ServiceComponentProp.unbindDynamicReference(): component = " + name + ", reference = " + ref.reference.name, null);
+			}
+			// check if we need to rebind
+			switch (ref.reference.cardinality) {
+				case ComponentReference.CARDINALITY_0_1 :
+				case ComponentReference.CARDINALITY_1_1 :
+					if (ref.reference.bind != null) {
+						bindReference(ref, instance);
+					}
+			}
+			ref.reference.unbind(ref, instance, serviceReference);
+		} catch (Throwable e) {
+			e.printStackTrace();
+		}
+	}
+
+	// -- begin helper methods
+	/**
+	 * Initialize Properties for this Component
+	 * 
+	 * The property elements provide default or supplemental property values if
+	 * not overridden by the properties retrieved from Configuration Admin
+	 * 
+	 * @param configProperties
+	 *            the configuration properties
+	 */
+	private void initProperties(Dictionary configProperties) {
+		// default component service properties
+		Properties propertyDescriptions = serviceComponent.properties;
+		if (propertyDescriptions != null && !propertyDescriptions.isEmpty()) {
+			properties = (Hashtable) propertyDescriptions.clone();
+		}
+
+		// set the component.name
+		if (properties == null) {
+			properties = new Hashtable(7);
+		}
+
+		// put the references in the properties
+		if (serviceComponent.references != null) {
+			ComponentReference ref;
+			for (int i = 0; i < serviceComponent.references.size(); i++) {
+				ref = (ComponentReference) serviceComponent.references.elementAt(i);
+				if (ref.target != null) {
+					properties.put(ref.name + ComponentConstants.REFERENCE_TARGET_SUFFIX, ref.target);
+				}
+			}
+		}
+
+		// properties from Configuration Admin
+		if (configProperties != null && !configProperties.isEmpty()) {
+			for (Enumeration keys = configProperties.keys(); keys.hasMoreElements();) {
+				Object key = keys.nextElement();
+				Object val = configProperties.get(key);
+				properties.put(key, val);
+			}
+		}
+
+		// always set the component name & the id
+		Long nextId = new Long(getNewComponentID());
+		properties.put(ComponentConstants.COMPONENT_ID, nextId);
+		properties.put(ComponentConstants.COMPONENT_NAME, serviceComponent.name);
+
+		if (serviceComponent.provides != null) {
+			String[] provides = new String[serviceComponent.provides.length];
+			System.arraycopy(serviceComponent.provides, 0, provides, 0, provides.length);
+			properties.put(Constants.OBJECTCLASS, provides);
+		}
+	}
+
+	private void assertCreateSingleInstance() {
+		if (!kindOfFactory && !instances.isEmpty()) {
+			throw new ComponentException("Instance of '" + name + "'is already created!");
+		}
+	}
+
+	public String toString() {
+		return name;
+	}
+
+	public void setRegistration(ServiceRegistration reg) {
+		registration = reg;
+	}
+
+	/**
+	 * Add a new Component Configuration name we should not activate in order to
+	 * prevent a cycle.
+	 * 
+	 * @see ServiceComponentProp#delayActivateSCPNames
+	 */
+	public void setDelayActivateSCPName(String scpName) {
+		if (delayActivateSCPNames == null) {
+			delayActivateSCPNames = new Vector(1);
+			delayActivateSCPNames.addElement(scpName);
+		} else if (!delayActivateSCPNames.contains(scpName)) {
+			delayActivateSCPNames.addElement(scpName);
+		}
+	}
+
+	public Vector getDelayActivateSCPNames() {
+		return delayActivateSCPNames;
+	}
+
+	public boolean isComponentFactory() {
+		return isComponentFactory;
+	}
+
+	// used by the ComponentFactoryImpl to mark component configs created by it
+	// that
+	// they are not component factories. This avoids subsecuent registrations of
+	// the same component factory.
+	public void setComponentFactory(boolean isComponentFactory) {
+		this.isComponentFactory = isComponentFactory;
+	}
+
+	static synchronized long getNewComponentID() {
+		return componentid++;
+	}
+
+	public boolean isKindOfFactory() {
+		return kindOfFactory;
+	}
+
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/storage/file/DBObject.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/storage/file/DBObject.java
new file mode 100644
index 0000000..aa8d932
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/storage/file/DBObject.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.ds.storage.file;
+
+import java.io.*;
+import java.util.Vector;
+import org.eclipse.equinox.internal.ds.model.ServiceComponent;
+
+/**
+ * @author Nina Ruseva
+ * 
+ * To change the template for this generated type comment go to
+ * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
+ * 
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public class DBObject implements Serializable {
+	private static final long serialVersionUID = 1L;
+
+	public DBObject() {
+	}
+
+	public Vector components;
+
+	public DBObject(Vector components) {
+		this.components = components;
+	}
+
+	public void writeObject(OutputStream out) throws Exception {
+		DataOutputStream dataOut;
+		if (out instanceof DataOutputStream) {
+			dataOut = (DataOutputStream) out;
+		} else {
+			dataOut = new DataOutputStream(out);
+		}
+		dataOut.writeInt(components == null ? 0 : components.size());
+		if (components != null && components.size() > 0) {
+			for (int k = 0; k < components.size(); k++) {
+				((ServiceComponent) components.elementAt(k)).writeObject(dataOut);
+			}
+		}
+	}
+
+	public void readObject(InputStream in) throws Exception {
+		DataInputStream dataIn;
+		if (in instanceof DataInputStream) {
+			dataIn = (DataInputStream) in;
+		} else {
+			dataIn = new DataInputStream(in);
+		}
+
+		int size = dataIn.readInt();
+		components = new Vector();
+		for (int k = 0; k < size; k++) {
+			ServiceComponent component = new ServiceComponent();
+			component.readObject(dataIn);
+			components.addElement(component);
+		}
+
+	}
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/storage/file/FileStorage.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/storage/file/FileStorage.java
new file mode 100644
index 0000000..1fc4d68
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/ds/storage/file/FileStorage.java
@@ -0,0 +1,233 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.ds.storage.file;
+
+import java.io.*;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Dictionary;
+import java.util.Vector;
+import org.eclipse.equinox.internal.ds.Activator;
+import org.eclipse.equinox.internal.ds.ComponentStorage;
+import org.eclipse.equinox.internal.ds.model.ServiceComponent;
+import org.eclipse.equinox.internal.util.io.ExternalizableDictionary;
+import org.eclipse.osgi.util.ManifestElement;
+import org.osgi.framework.*;
+import org.osgi.service.component.ComponentConstants;
+
+/**
+ * @author Pavlin Dobrev
+ * @version 1.1
+ */
+
+public class FileStorage extends ComponentStorage {
+
+	//TODO: this constant should be public and shared across other bundles that use the same property. 
+	//Probably it should be in the supplement bundle?
+	public static final String PROP_CHECK_CONFIG = "osgi.checkConfiguration";
+
+	private BundleContext bc;
+
+	private String[] dbBundlePath = new String[1];
+	private String[] dbCompPath = new String[] {null, "COMPONENTS"};
+	private static String CUSTOM_DB_NAME = "SCR";
+	private File file;
+	private ExternalizableDictionary data = new ExternalizableDictionary();
+	private StringBuffer pathBuffer = new StringBuffer();
+	private String separator;
+
+	public FileStorage(BundleContext bc) {
+		this.bc = bc;
+		separator = bc.getProperty("path.separator");
+		file = bc.getDataFile(CUSTOM_DB_NAME);
+		try {
+			if (file.exists()) {
+				data.readObject(new BufferedInputStream(new FileInputStream(file)));
+			}
+		} catch (FileNotFoundException e) {
+			// should be never thrown
+			e.printStackTrace();
+		} catch (IOException e) {
+			Activator.log.error("[SCR] Error while loading components from data file " + file.getAbsolutePath(), e);
+		} catch (Exception e) {
+			Activator.log.error("[SCR] Error while loading components from data file " + file.getAbsolutePath(), e);
+		}
+	}
+
+	public Vector loadComponentDefinitions(long bundleID) {
+		try {
+			Bundle bundle = bc.getBundle(bundleID);
+			Vector components = null;
+			if (!Activator.DBSTORE) {
+				return parseXMLDeclaration(bundle);
+			}
+
+			long lastModified;
+			// if not dev mode, we simply use the bundle's timestamp
+			if (!Activator.getBoolean(PROP_CHECK_CONFIG)) {
+				lastModified = bundle.getLastModified();
+			} else {
+				lastModified = getLastModifiedTimestamp(bundle);
+			}
+
+			dbBundlePath[0] = String.valueOf(bundleID);
+
+			String lastModifiedValue = (String) data.get(getPath(dbBundlePath));
+			if (lastModifiedValue == null) {
+				components = parseXMLDeclaration(bundle);
+				if (components != null && components.size() != 0) {
+					data.put(getPath(dbBundlePath), "" + lastModified);
+					saveComponentDefinitions(components, bundleID);
+				}
+
+			} else {
+				long dbLastModified = Long.parseLong(lastModifiedValue);
+				if (lastModified > dbLastModified) {
+					components = parseXMLDeclaration(bundle);
+					if (components != null && components.size() != 0) {
+						data.put(getPath(dbBundlePath), "" + lastModified);
+						saveComponentDefinitions(components, bundleID);
+					}
+
+				} else {
+					components = loadComponentsFromDB(bundle);
+				}
+			}
+			return components;
+		} catch (Throwable e) {
+			e.printStackTrace();
+			return null;
+		}
+	}
+
+	private Vector loadComponentsFromDB(Bundle bundle) throws Exception {
+		try {
+			ServiceComponent currentComponent = null;
+			long bundleId = bundle.getBundleId();
+			dbCompPath[0] = String.valueOf(bundleId);
+			DBObject value = new DBObject();
+			byte[] byteArr = (byte[]) data.get(getPath(dbCompPath));
+			ByteArrayInputStream tmpIn = new ByteArrayInputStream(byteArr);
+			value.readObject(tmpIn);
+			Vector components = value.components;
+			if (components == null) {
+				return null;
+			}
+			for (int i = 0; i < components.size(); i++) {
+				currentComponent = (ServiceComponent) components.elementAt(i);
+				currentComponent.bundle = bundle;
+				currentComponent.bc = bundle.getBundleContext();
+			}
+			return components;
+		} catch (Throwable t) {
+			Activator.log.error("[SCR] Error while loading components from DB", t);
+		}
+		return null;
+	}
+
+	public void deleteComponentDefinitions(long bundleID) throws Exception {
+		dbBundlePath[0] = String.valueOf(bundleID);
+		data.remove(getPath(dbBundlePath));
+	}
+
+	private void saveComponentDefinitions(Vector components, long bundleID) throws Exception {
+		try {
+			if (components == null || components.size() == 0) {
+				return;
+			}
+			dbCompPath[0] = String.valueOf(bundleID);
+
+			DBObject tmpObj = new DBObject(components);
+			ByteArrayOutputStream buf = new ByteArrayOutputStream();
+			tmpObj.writeObject(buf);
+			data.put(getPath(dbCompPath), buf.toByteArray());
+			saveFile();
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	public void stop() {
+		//no body
+	}
+
+	private void saveFile() {
+		FileOutputStream fos = null;
+		try {
+			fos = new FileOutputStream(file);
+			try {
+				data.writeObject(fos);
+				fos.flush();
+			} catch (IOException e) {
+				e.printStackTrace();
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+		} catch (FileNotFoundException e) {
+			e.printStackTrace();
+		} finally {
+			if (fos != null) {
+				try {
+					fos.close();
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+			}
+		}
+	}
+
+	private String getPath(String path[]) {
+		pathBuffer.setLength(0);
+		for (int i = 0; i < path.length; i++) {
+			pathBuffer.append(path[i]).append(separator);
+		}
+		return pathBuffer.toString();
+	}
+
+	/**
+	 * The last modified timestamp of the bundle. Should only be called in development mode
+	 * 
+	 * @param bundle
+	 * @return the last modified timestamp of the bundle
+	 */
+	protected long getLastModifiedTimestamp(Bundle bundle) {
+		if (bundle == null)
+			return 0;
+		long result = 0;
+		ManifestElement[] elements = parseManifestHeader(bundle);
+		for (int i = 0; i < elements.length; i++) {
+			URL componentURL = bundle.getEntry(elements[i].getValue());
+			try {
+				URLConnection connection = componentURL.openConnection();
+				long lastModified = connection.getLastModified();
+				if (lastModified > result)
+					result = lastModified;
+			} catch (IOException e) {
+				return 0;
+			}
+		}
+		return result;
+	}
+
+	private ManifestElement[] parseManifestHeader(Bundle bundle) {
+		Dictionary headers = bundle.getHeaders();
+		String files = (String) headers.get(ComponentConstants.SERVICE_COMPONENT);
+		if (files == null)
+			return new ManifestElement[0];
+		try {
+			return ManifestElement.parseHeader(ComponentConstants.SERVICE_COMPONENT, files);
+		} catch (BundleException e) {
+			Activator.log.error("Error attempting parse manifest element header", e); //$NON-NLS-1$
+			return new ManifestElement[0];
+		}
+	}
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/io/Externalizable.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/io/Externalizable.java
new file mode 100644
index 0000000..e2e8dc4
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/io/Externalizable.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.util.io;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Interface for custom serialization. Classes that implements this interface
+ * must have public empty constructor so deserialization can be done.
+ * 
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public interface Externalizable {
+
+	/**
+	 * Use this method for serialization of object state.
+	 */
+	public void writeObject(OutputStream oStream) throws Exception;
+
+	/**
+	 * Use this method to deserializion of object state.
+	 */
+	public void readObject(InputStream iStream) throws Exception;
+
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/io/ExternalizableDictionary.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/io/ExternalizableDictionary.java
new file mode 100644
index 0000000..b8c2cb1
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/io/ExternalizableDictionary.java
@@ -0,0 +1,759 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.util.io;
+
+import java.io.*;
+import java.lang.reflect.Array;
+import java.util.*;
+
+/**
+ * This class implements a hashtable, which serves the needs of
+ * ConfigurationManagement of capsulation of configuration properties with
+ * String keys, which are case insentive at lookup (at get, remove, put
+ * operations) but preserve the last case of keys.
+ * 
+ * The implementaion of the Externalizable interface allows remote transfer of
+ * those properties.
+ * 
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public class ExternalizableDictionary extends Dictionary implements Externalizable, Cloneable {
+
+	private static Class[] CLASSES = new Class[] {ExternalizableDictionary.class};
+	private HashtableEntry table[];
+	private int count;
+	private int threshold;
+	private float loadFactor;
+	private static int MIN_CAPACITY = 5;
+
+	ClassLoader loader;
+
+	/**
+	 * Constructs a new, empty dictionary with the specified initial capacity
+	 * and the specified load factor.
+	 * 
+	 * @param initialCapacity
+	 *            the initial capacity of the hashtable. when 0 is passed for
+	 *            capacity, minimum possible capacity is used; i.e. when the
+	 *            object is read as externalizable, then the table is created
+	 *            with the written size.
+	 * @param loadFactor
+	 *            a number between 0.0 and 1.0.
+	 * @exception IllegalArgumentException
+	 *                if the initial capacity is less than zero, or if the load
+	 *                factor is less than or equal to zero.
+	 */
+	public ExternalizableDictionary(int initialCapacity, float loadFactor) {
+		if ((initialCapacity < 0) || (loadFactor <= 0.0)) {
+			throw new IllegalArgumentException();
+		}
+		this.loadFactor = loadFactor;
+		if (initialCapacity > 0)
+			initTable(initialCapacity);
+	}
+
+	private void initTable(int initialCapacity) {
+		table = new HashtableEntry[initialCapacity];
+		threshold = (int) (initialCapacity * loadFactor);
+	}
+
+	/**
+	 * Constructs a new, empty dictionary with the wanted capacity and default
+	 * load factor.
+	 */
+	public ExternalizableDictionary(int initialCapacity) {
+		this(initialCapacity, 0.75f);
+	}
+
+	/**
+	 * Constructs a new, empty dictionary with a default capacity and load
+	 * factor.
+	 */
+	public ExternalizableDictionary() {
+		this(101, 0.75f);
+	}
+
+	public ClassLoader setClassLaoder(ClassLoader loader) {
+		ClassLoader tmp = this.loader;
+		this.loader = loader;
+		return tmp;
+	}
+
+	public ClassLoader setClassLoader(ClassLoader loader) {
+		ClassLoader tmp = this.loader;
+		this.loader = loader;
+		return tmp;
+	}
+
+	public Class[] remoteInterfaces() {
+		return CLASSES;
+	}
+
+	/**
+	 * Gets the size of the elements in the dictionary.
+	 * 
+	 * @return size of hashtable
+	 */
+	public int size() {
+		return count;
+	}
+
+	/**
+	 * Checks if there is any element in the dictionary.
+	 * 
+	 * @return true if empty.
+	 */
+	public boolean isEmpty() {
+		return count == 0;
+	}
+
+	/**
+	 * Gets an enumeration with dictionary's keys.
+	 * 
+	 * @return an enumeration with dictionary's keys.
+	 */
+	public synchronized Enumeration keys() {
+		return new HashtableEnumerator(table, true);
+	}
+
+	/**
+	 * Gets an enumeration with dictionary's values.
+	 * 
+	 * @return an enumeration with dictionary's values.
+	 */
+	public synchronized Enumeration elements() {
+		return new HashtableEnumerator(table, false);
+	}
+
+	private int hashCode(String key) {
+		return key.toLowerCase().hashCode();
+	}
+
+	/**
+	 * Gets the value corresponding to this key or any of its case
+	 * representations.
+	 * 
+	 * @param key
+	 *            String key
+	 * @return object value or null if none
+	 */
+	public synchronized Object get(Object key) {
+		if (table != null) {
+			HashtableEntry tab[] = table;
+			int hash = hashCode((String) key);
+			int index = (hash & 0x7FFFFFFF) % tab.length;
+			for (HashtableEntry e = tab[index]; e != null; e = e.next) {
+				if ((e.hash == hash) && e.key.equalsIgnoreCase((String) key)) {
+					return e.value;
+				}
+			}
+		}
+		return null;
+	}
+
+	protected void rehash() {
+		int oldCapacity = table.length;
+		HashtableEntry oldTable[] = table;
+
+		int newCapacity = oldCapacity * 2 + 1;
+		HashtableEntry newTable[] = new HashtableEntry[newCapacity];
+
+		threshold = (int) (newCapacity * loadFactor);
+		table = newTable;
+
+		for (int i = oldCapacity; i-- > 0;) {
+			for (HashtableEntry old = oldTable[i]; old != null;) {
+				HashtableEntry e = old;
+				old = old.next;
+				int index = (e.hash & 0x7FFFFFFF) % newCapacity;
+				e.next = newTable[index];
+				newTable[index] = e;
+			}
+		}
+	}
+
+	/**
+	 * Puts the key and the value in the table. If there already is a key equal
+	 * ignore case to the one passed the new value exchhanes the old one.
+	 * 
+	 * @param key
+	 *            String key
+	 * @param value
+	 *            object to put
+	 * @return old value if any, or null if none
+	 * @exception IllegalArgumentException
+	 *                if key is not a string
+	 */
+	public synchronized Object put(Object key, Object value) throws IllegalArgumentException {
+
+		if (value == null) {
+			throw new NullPointerException();
+		}
+		if (table == null)
+			initTable(MIN_CAPACITY);
+		try {
+			// Makes sure the key is not already in the hashtable.
+			int hash = hashCode((String) key);
+			int index;
+			HashtableEntry[] tab = null;
+			do {
+				tab = table;
+				index = (hash & 0x7FFFFFFF) % tab.length;
+				for (HashtableEntry e = tab[index]; e != null; e = e.next) {
+					if ((e.hash == hash) && e.key.equalsIgnoreCase((String) key)) {
+						Object old = e.value;
+						e.value = value;
+						return old;
+					}
+				}
+				if (count >= threshold) {
+					// Rehash the table if the threshold is exceeded
+					rehash();
+					continue;
+				}
+				break;
+			} while (true);
+
+			// Creates the new entry.
+			HashtableEntry e = new HashtableEntry();
+			e.hash = hash;
+			e.key = (String) key;
+			e.value = value;
+			e.next = tab[index];
+			tab[index] = e;
+			count++;
+			return null;
+		} catch (ClassCastException cce) {
+			throw new IllegalArgumentException("Non string keys are not accepted!");
+		}
+	}
+
+	/**
+	 * Removes the key and its corresponding value. Key is searched case
+	 * insensitively.
+	 * 
+	 * @param key
+	 *            string key
+	 * @return object removed or null if none
+	 * @exception IllegalArgumentException
+	 *                if key is not s string
+	 */
+	public synchronized Object remove(Object key) throws IllegalArgumentException {
+
+		if (table == null)
+			return null;
+		try {
+			HashtableEntry tab[] = table;
+			int hash = hashCode((String) key);
+			int index = (hash & 0x7FFFFFFF) % tab.length;
+			for (HashtableEntry e = tab[index], prev = null; e != null; prev = e, e = e.next) {
+				if ((e.hash == hash) && e.key.equalsIgnoreCase((String) key)) {
+					if (prev != null) {
+						prev.next = e.next;
+					} else {
+						tab[index] = e.next;
+					}
+					count--;
+					return e.value;
+				}
+			}
+			return null;
+		} catch (ClassCastException cce) {
+			throw new IllegalArgumentException("Non string keys are not accepted!");
+		}
+	}
+
+	/**
+	 * Clears all elements from the distionary.
+	 */
+	public synchronized void clear() {
+		if (table == null)
+			return;
+		for (int index = table.length; --index >= 0;) {
+			table[index] = null;
+		}
+		count = 0;
+	}
+
+	/**
+	 * Creates a shallow copy of this hashtable. The keys and values themselves
+	 * are not cloned.
+	 * 
+	 * @return a new CMDictioanry with the same fields
+	 */
+	public synchronized Object clone() {
+		try {
+			ExternalizableDictionary cmDict = (ExternalizableDictionary) super.clone();
+			if (table != null) {
+				cmDict.table = new HashtableEntry[table.length];
+				for (int i = table.length; i-- > 0;) {
+					cmDict.table[i] = (table[i] != null) ? (HashtableEntry) table[i].clone() : null;
+				}
+			}
+			return cmDict;
+		} catch (CloneNotSupportedException e) {
+			// this shouldn't happen, since we are Cloneable
+			throw new InternalError();
+		}
+	}
+
+	/**
+	 * Compares the specified Object with this Dictionary for equality,
+	 * 
+	 * @return true if the specified Object is equal to this Dictionary.
+	 */
+
+	public synchronized boolean equals(Object o) {
+		if (o == this)
+			return true;
+		if (!(o instanceof Dictionary))
+			return false;
+		Dictionary dict = (Dictionary) o;
+		int max = size();
+		if (dict.size() != max)
+			return false;
+		Enumeration k = keys();
+		Enumeration e = elements();
+		for (int i = 0; i < max; i++) {
+			Object key = k.nextElement();
+			Object value = e.nextElement();
+			if (!value.equals(dict.get(key))) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	/**
+	 * Makes a string represntation of this object.
+	 * 
+	 * @return string represntation of this object
+	 */
+	public synchronized String toString() {
+		int max = size() - 1;
+		StringBuffer buf = new StringBuffer();
+		Enumeration k = keys();
+		Enumeration e = elements();
+		buf.append('{');
+		for (int i = 0; i <= max; i++) {
+			String s1 = (String) k.nextElement();
+			String s2 = e.nextElement().toString();
+			buf.append(s1);
+			buf.append('=');
+			buf.append(s2);
+			if (i < max) {
+				buf.append(',');
+				buf.append(' ');
+			}
+		}
+		buf.append('}');
+		return buf.toString();
+	}
+
+	/**
+	 * Writes this object to the stream passed. The object can be loaded again
+	 * via its readObject method.
+	 * 
+	 * @param os
+	 *            strream to write data to.
+	 * @exception Exception
+	 *                if error of any kind occurs
+	 */
+	public synchronized void writeObject(OutputStream os) throws Exception {
+		Enumeration keys = keys();
+		Enumeration values = elements();
+		PDataStream.writeInt(size(), os);
+		// dictionary is never empty:
+		// it either has elements or is null
+		while (keys.hasMoreElements()) {
+			PDataStream.writeUTF((String) keys.nextElement(), os);
+			writeValue(values.nextElement(), os);
+		}
+	}
+
+	private static void writeValue(Object value, OutputStream os) throws IOException {
+
+		if (value == null) {
+			os.write(-1);
+		} else {
+			Class valueClass = value.getClass();
+			// write 0 for a single value, 1 for array, and 2 for Vector
+			if (valueClass.isArray()) {
+				os.write(1);
+				int length = Array.getLength(value);
+				PDataStream.writeInt(length, os);
+				Class componentType = valueClass.getComponentType();
+				if (componentType.isPrimitive()) {
+					// primitive
+					PDataStream.writeBoolean(true, os);
+					// 1: int;2: long; 3: byte; 4: boolean; 5: character; 6:
+					// short; 7: float; 8: double
+					writePrimitiveArray(componentType, value, length, os);
+				} else {
+					PDataStream.writeBoolean(false, os);
+					PDataStream.writeUTF(componentType.getName(), os);
+					Object[] oArr = (Object[]) value;
+					for (int i = 0; i < length; i++) {
+						writeValue(oArr[i], os);
+					}
+				}
+			} else if (valueClass.equals(Vector.class)) {
+				os.write(2);
+				int size = ((Vector) value).size();
+				PDataStream.writeInt(size, os);
+				for (int i = 0; i < size; i++) {
+					writeValue(((Vector) value).elementAt(i), os);
+				}
+			} else {
+				os.write(0);
+				writeRealObject(value, valueClass, os);
+			}
+		}
+	}
+
+	private static Object readValue(InputStream is, ClassLoader loader) throws Exception {
+		byte type = (byte) is.read();
+		if (type == -1) {
+			return null;
+		}
+		Class vClass = null;
+		if (type == 2) {
+			int length = PDataStream.readInt(is);
+			Vector v = new Vector(length);
+			for (int i = 0; i < length; i++) {
+				v.insertElementAt(readValue(is, loader), i);
+			}
+			return v;
+		} else if (type == 0) {
+			return readRealObject((byte) is.read(), is, loader);
+		} else {
+			int length = PDataStream.readInt(is);
+			boolean primitive = PDataStream.readBoolean(is);
+			if (primitive) {
+				return readPrimitiveArray(length, is);
+			}
+			vClass = loader == null ? Class.forName(PDataStream.readUTF(is)) : loader.loadClass(PDataStream.readUTF(is));
+			Object array = Array.newInstance(vClass, length);
+			for (int i = 0; i < length; i++) {
+				Array.set(array, i, readValue(is, loader));
+			}
+			return array;
+		}
+	}
+
+	/**
+	 * Reads the data from the InputStream and loads the data in the table.
+	 * 
+	 * @param is
+	 *            stream to read dictionary's data from
+	 * @exception Exception
+	 *                if an error of any kind occurs while reading
+	 */
+	public synchronized void readObject(InputStream is) throws Exception {
+		try {
+			int size = PDataStream.readInt(is);
+			if (table == null) {
+				if (size > 0) {
+					initTable(size);
+				} else
+					initTable(MIN_CAPACITY);
+			}
+			for (int i = 0; i < size; i++) {
+				put(PDataStream.readUTF(is), readValue(is, loader));
+			}
+		} catch (Exception e) {
+			throw e;
+		}
+	}
+
+	// 1: int;2: long; 3: byte; 4: boolean; 5: character;
+	// 6: short; 7: float; 8: double
+	private static void writePrimitiveArray(Class componentType, Object array, int length, OutputStream os) throws IOException {
+
+		if (componentType.equals(Integer.TYPE)) {
+			int[] ints = (int[]) array;
+			os.write(1);
+			for (int i = 0; i < length; i++) {
+				PDataStream.writeInt(ints[i], os);
+			}
+		} else if (componentType.equals(Long.TYPE)) {
+			os.write(2);
+			long[] longs = (long[]) array;
+			for (int i = 0; i < length; i++) {
+				PDataStream.writeLong(longs[i], os);
+			}
+		} else if (componentType.equals(Byte.TYPE)) {
+			os.write(3);
+			os.write((byte[]) array);
+		} else if (componentType.equals(Boolean.TYPE)) {
+			os.write(4);
+			boolean[] booleans = (boolean[]) array;
+			for (int i = 0; i < length; i++) {
+				PDataStream.writeBoolean(booleans[i], os);
+			}
+		} else if (componentType.equals(Character.TYPE)) {
+			os.write(5);
+			char[] chars = (char[]) array;
+			for (int i = 0; i < length; i++) {
+				PDataStream.writeChar(chars[i], os);
+			}
+		} else if (componentType.equals(Short.TYPE)) {
+			os.write(6);
+			short[] shorts = (short[]) array;
+			for (int i = 0; i < length; i++) {
+				PDataStream.writeShort(shorts[i], os);
+			}
+		} else if (componentType.equals(Float.TYPE)) {
+			os.write(7);
+			float[] floats = (float[]) array;
+			for (int i = 0; i < length; i++) {
+				PDataStream.writeFloat(floats[i], os);
+			}
+		} else if (componentType.equals(Double.TYPE)) {
+			os.write(8);
+			double[] doubles = (double[]) array;
+			for (int i = 0; i < length; i++) {
+				PDataStream.writeDouble(doubles[i], os);
+			}
+		} else {
+			throw new IllegalArgumentException("Unsupported Primitive Type: " + componentType);
+		}
+	}
+
+	private static Object readPrimitiveArray(int length, InputStream is) throws IOException {
+		byte type = (byte) is.read();
+		if (type == 1) {
+			int[] ints = new int[length];
+			for (int i = 0; i < length; i++) {
+				ints[i] = PDataStream.readInt(is);
+			}
+			return ints;
+		} else if (type == 2) {
+			long[] longs = new long[length];
+			for (int i = 0; i < length; i++) {
+				longs[i] = PDataStream.readLong(is);
+			}
+			return longs;
+		} else if (type == 3) {
+			byte[] bytes = new byte[length];
+			is.read(bytes);
+			return bytes;
+		} else if (type == 4) {
+			boolean[] booleans = new boolean[length];
+			for (int i = 0; i < length; i++) {
+				booleans[i] = PDataStream.readBoolean(is);
+			}
+			return booleans;
+		} else if (type == 5) {
+			char[] chars = new char[length];
+			for (int i = 0; i < length; i++) {
+				chars[i] = PDataStream.readChar(is);
+			}
+			return chars;
+		} else if (type == 6) {
+			short[] shorts = new short[length];
+			for (int i = 0; i < length; i++) {
+				shorts[i] = PDataStream.readShort(is);
+			}
+			return shorts;
+		} else if (type == 7) {
+			float[] floats = new float[length];
+			for (int i = 0; i < length; i++) {
+				floats[i] = PDataStream.readFloat(is);
+			}
+			return floats;
+		} else if (type == 8) {
+			double[] doubles = new double[length];
+			for (int i = 0; i < length; i++) {
+				doubles[i] = PDataStream.readDouble(is);
+			}
+			return doubles;
+		} else {
+			throw new IllegalArgumentException("Trying to read unsupported primitive type: " + type);
+		}
+	}
+
+	// only if this is an object (not primitive) and non null!
+	private static void writeRealObject(Object value, Class vClass, OutputStream os) throws IOException {
+		try {
+			if (vClass.equals(String.class)) {
+				os.write(0);
+				PDataStream.writeUTF((String) value, os);
+			} else if (vClass.equals(Integer.class)) {
+				os.write(1);
+				PDataStream.writeInt(((Integer) value).intValue(), os);
+			} else if (vClass.equals(Long.class)) {
+				os.write(2);
+				PDataStream.writeLong(((Long) value).longValue(), os);
+			} else if (vClass.equals(Byte.class)) {
+				os.write(3);
+				os.write(((Byte) value).byteValue());
+			} else if (vClass.equals(Boolean.class)) {
+				os.write(4);
+				PDataStream.writeBoolean(((Boolean) value).booleanValue(), os);
+			} else if (vClass.equals(Character.class)) {
+				os.write(5);
+				PDataStream.writeChar(((Character) value).charValue(), os);
+			} else if (vClass.equals(Short.class)) {
+				os.write(6);
+				PDataStream.writeShort(((Short) value).shortValue(), os);
+			} else if (vClass.equals(Float.class)) {
+				os.write(7);
+				PDataStream.writeFloat(((Float) value).floatValue(), os);
+			} else if (vClass.equals(Double.class)) {
+				os.write(8);
+				PDataStream.writeDouble(((Double) value).doubleValue(), os);
+			} else if (Externalizable.class.isAssignableFrom(vClass)) {
+				os.write(11);
+				String name = vClass.getName();
+				PDataStream.writeUTF(name, os);
+				Externalizable tmp = (Externalizable) value;
+				tmp.writeObject(os);
+			} else {
+				os.write(12);
+				ObjectOutputStream out = new ObjectOutputStream(os);
+				out.writeObject(value);
+			}
+		} catch (Exception exc) {
+			throw new IOException(exc.toString());
+		}
+	}
+
+	private static Object readRealObject(byte type, InputStream is, ClassLoader loader) throws IOException {
+		try {
+			if (type == 0) {
+				return PDataStream.readUTF(is);
+			} else if (type == 1) {
+				return new Integer(PDataStream.readInt(is));
+			} else if (type == 2) {
+				return new Long(PDataStream.readLong(is));
+			} else if (type == 3) {
+				return new Byte((byte) is.read());
+			} else if (type == 4) {
+				return PDataStream.readBoolean(is) ? Boolean.TRUE : Boolean.FALSE;
+			} else if (type == 5) {
+				return new Character(PDataStream.readChar(is));
+			} else if (type == 6) {
+				return new Short(PDataStream.readShort(is));
+			} else if (type == 7) {
+				return new Float(PDataStream.readFloat(is));
+			} else if (type == 8) {
+				return new Double(PDataStream.readDouble(is));
+			} else if (type == 11) {
+				String name = PDataStream.readUTF(is);
+				Class c = loader == null ? Class.forName(name) : loader.loadClass(name);
+				if (Externalizable.class.isAssignableFrom(c)) {
+					Externalizable obj = (Externalizable) c.newInstance();
+					obj.readObject(is);
+					return obj;
+				}
+				throw new IOException("Could not read object " + name);
+			} else if (type == 12) {
+				ObjectInputStream in = loader == null ? new ObjectInputStream(is) : (ObjectInputStream) new XObjectInputStream(loader, is);
+				return in.readObject();
+			}
+		} catch (ClassNotFoundException cnfe) {
+			throw new IOException("Could not find class " + cnfe.toString());
+		} catch (Exception exc) {
+			throw exc instanceof IOException ? (IOException) exc : new IOException("Could not read object " + exc.toString());
+		}
+		throw new IllegalArgumentException("Unsupported Typed Object: " + type);
+	}
+
+	/**
+	 * 
+	 * 
+	 * @param props
+	 * @exception IllegalArgumentException
+	 */
+	public synchronized void copyFrom(Dictionary props) throws IllegalArgumentException {
+		Enumeration keys = props.keys();
+		Enumeration values = props.elements();
+		while (keys.hasMoreElements()) {
+			put(keys.nextElement(), values.nextElement());
+		}
+	}
+
+}
+
+class HashtableEntry {
+	int hash;
+	String key;
+	Object value;
+	HashtableEntry next;
+
+	protected Object clone() {
+		HashtableEntry entry = new HashtableEntry();
+		entry.hash = hash;
+		entry.key = key;
+		entry.value = value;
+		entry.next = (next != null) ? (HashtableEntry) next.clone() : null;
+		return entry;
+	}
+}
+
+class HashtableEnumerator implements Enumeration {
+	boolean keys;
+	int index;
+	HashtableEntry table[];
+	HashtableEntry entry;
+
+	HashtableEnumerator(HashtableEntry table[], boolean keys) {
+		this.table = table;
+		this.keys = keys;
+		this.index = table.length;
+	}
+
+	public boolean hasMoreElements() {
+		if (table == null)
+			return false;
+		if (entry != null) {
+			return true;
+		}
+		while (index-- > 0) {
+			if ((entry = table[index]) != null) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	public Object nextElement() {
+		if (table != null) {
+			if (entry == null) {
+				while ((index-- > 0) && ((entry = table[index]) == null));
+			}
+			if (entry != null) {
+				HashtableEntry e = entry;
+				entry = e.next;
+				return keys ? e.key : e.value;
+			}
+		}
+		throw new NoSuchElementException("HashtableEnumerator");
+	}
+}
+
+class XObjectInputStream extends ObjectInputStream {
+
+	ClassLoader loader;
+
+	public XObjectInputStream(ClassLoader loader, InputStream is) throws IOException {
+		super(is);
+		this.loader = loader;
+	}
+
+	protected Class resolveClass(ObjectStreamClass v) throws ClassNotFoundException {
+		return loader.loadClass(v.getName());
+	}
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/io/PDataStream.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/io/PDataStream.java
new file mode 100644
index 0000000..bdcff9b
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/io/PDataStream.java
@@ -0,0 +1,236 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.util.io;
+
+import java.io.*;
+
+/**
+ * @author Pavlin Dobrev
+ * @author Georgi Andreev
+ * @version 1.0
+ */
+public final class PDataStream {
+
+	public static void writeInt(int i, OutputStream os) throws IOException {
+		os.write((i >>> 24) & 0xFF);
+		os.write((i >>> 16) & 0xFF);
+		os.write((i >>> 8) & 0xFF);
+		os.write(i & 0xFF);
+	}
+
+	public static void writeLong(long l, OutputStream os) throws IOException {
+		os.write((int) (l >>> 56) & 0xFF);
+		os.write((int) (l >>> 48) & 0xFF);
+		os.write((int) (l >>> 40) & 0xFF);
+		os.write((int) (l >>> 32) & 0xFF);
+		os.write((int) (l >>> 24) & 0xFF);
+		os.write((int) (l >>> 16) & 0xFF);
+		os.write((int) (l >>> 8) & 0xFF);
+		os.write((int) (l & 0xFF));
+	}
+
+	public static void writeShort(short s, OutputStream os) throws IOException {
+		os.write((s >>> 8) & 0xFF);
+		os.write(s & 0xFF);
+	}
+
+	public static void writeChar(char ch, OutputStream os) throws IOException {
+		os.write((ch >>> 8) & 0xFF);
+		os.write(ch & 0xFF);
+	}
+
+	public static void writeBoolean(boolean b, OutputStream os) throws IOException {
+		os.write(b ? 1 : 0);
+	}
+
+	public static void writeByte(byte b, OutputStream os) throws IOException {
+		os.write(b);
+	}
+
+	public static void writeBytes(String str, OutputStream os) throws IOException {
+		byte[] b = str.getBytes();
+		os.write(b);
+	}
+
+	public static void writeString(String str, OutputStream os) throws IOException {
+		if (str == null) {
+			writeBoolean(false, os);
+		} else {
+			writeBoolean(true, os);
+			writeUTF(str, os);
+		}
+	}
+
+	public static void writeUTF(String str, OutputStream os) throws IOException {
+		int strlen = str.length();
+		int utflen = 0;
+		for (int i = 0; i < strlen; i++) {
+			int ch = str.charAt(i);
+			if ((ch >= 0x0001) && (ch <= 0x007F)) {
+				utflen++;
+			} else if (ch > 0x07FF) {
+				utflen += 3;
+			} else {
+				utflen += 2;
+			}
+		}
+		if (utflen > 65535)
+			throw new UTFDataFormatException();
+		os.write((utflen >>> 8) & 0xFF);
+		os.write(utflen & 0xFF);
+		for (int i = 0; i < strlen; i++) {
+			int ch = str.charAt(i);
+			if ((ch >= 0x0001) && (ch <= 0x007F)) {
+				os.write(ch);
+			} else if (ch > 0x07FF) {
+				os.write(0xE0 | ((ch >> 12) & 0x0F));
+				os.write(0x80 | ((ch >> 6) & 0x3F));
+				os.write(0x80 | (ch & 0x3F));
+			} else {
+				os.write(0xC0 | ((ch >> 6) & 0x1F));
+				os.write(0x80 | (ch & 0x3F));
+			}
+		}
+	}
+
+	public static void writeChars(String str, OutputStream os) throws IOException {
+		int len = str.length();
+		for (int i = 0; i < len; i++) {
+			int ch = str.charAt(i);
+			os.write((ch >>> 8) & 0xFF);
+			os.write(ch & 0xFF);
+		}
+	}
+
+	public static void writeDouble(double d, OutputStream os) throws IOException {
+		writeLong(Double.doubleToLongBits(d), os);
+	}
+
+	public static void writeFloat(float f, OutputStream os) throws IOException {
+		writeInt(Float.floatToIntBits(f), os);
+	}
+
+	public static int readInt(InputStream is) throws IOException {
+		int ch1 = is.read();
+		int ch2 = is.read();
+		int ch3 = is.read();
+		int ch4 = is.read();
+		if ((ch1 | ch2 | ch3 | ch4) < 0) {
+			throw new IOException("Read Error");
+		}
+		return (ch1 << 24) | (ch2 << 16) | (ch3 << 8) | ch4;
+	}
+
+	public static char readChar(InputStream is) throws IOException {
+		int ch1 = is.read();
+		int ch2 = is.read();
+		if ((ch1 | ch2) < 0)
+			throw new IOException("Read Error");
+		return (char) ((ch1 << 8) | ch2);
+	}
+
+	public static short readShort(InputStream is) throws IOException {
+		int ch1 = is.read();
+		int ch2 = is.read();
+		if ((ch1 | ch2) < 0)
+			throw new IOException("Read Error");
+		return (short) ((ch1 << 8) | ch2);
+	}
+
+	public static long readLong(InputStream is) throws IOException {
+		return ((long) (readInt(is)) << 32) | (readInt(is) & 0xFFFFFFFFL);
+	}
+
+	public static boolean readBoolean(InputStream is) throws IOException {
+		int ch = is.read();
+		if (ch < 0) {
+			throw new EOFException();
+		}
+		return (ch != 0);
+	}
+
+	public static byte readByte(InputStream is) throws IOException {
+		int ch = is.read();
+		if (ch < 0)
+			throw new EOFException();
+		return (byte) (ch);
+	}
+
+	public static int readUnsignedByte(InputStream is) throws IOException {
+		int ch = is.read();
+		if (ch < 0)
+			throw new EOFException();
+		return ch;
+	}
+
+	public static double readDouble(InputStream is) throws IOException {
+		return Double.longBitsToDouble(readLong(is));
+	}
+
+	public static float readFloat(InputStream is) throws IOException {
+		return Float.intBitsToFloat(readInt(is));
+	}
+
+	public static String readString(InputStream is) throws IOException {
+		if (readBoolean(is))
+			return readUTF(is);
+		return null;
+	}
+
+	public static String readUTF(InputStream is) throws IOException {
+		int utflen = readShort(is);
+		char str[] = new char[utflen];
+		int cnt = 0;
+		int strlen = 0;
+		while (cnt < utflen) {
+			int c = readUnsignedByte(is);
+			int char2, char3;
+			switch (c >> 4) {
+				case 0 :
+				case 1 :
+				case 2 :
+				case 3 :
+				case 4 :
+				case 5 :
+				case 6 :
+				case 7 :
+					cnt++;
+					str[strlen++] = (char) c;
+					break;
+				case 12 :
+				case 13 :
+					cnt += 2;
+					if (cnt > utflen)
+						throw new UTFDataFormatException();
+					char2 = readUnsignedByte(is);
+					if ((char2 & 0xC0) != 0x80)
+						throw new UTFDataFormatException();
+					str[strlen++] = (char) (((c & 0x1F) << 6) | (char2 & 0x3F));
+					break;
+				case 14 :
+					cnt += 3;
+					if (cnt > utflen)
+						throw new UTFDataFormatException();
+					char2 = readUnsignedByte(is);
+					char3 = readUnsignedByte(is);
+					if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
+						throw new UTFDataFormatException();
+					str[strlen++] = (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | (char3 & 0x3F));
+					break;
+				default :
+					throw new UTFDataFormatException();
+			}
+		}
+		return new String(str, 0, strlen);
+	}
+
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/io/package.html b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/io/package.html
new file mode 100644
index 0000000..f03fa75
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/io/package.html
@@ -0,0 +1,8 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+</HEAD>
+<BODY LINK="#0000ff" VLINK="#800080">
+
+<P>The package contains utilities for easily transfer of objects</P></BODY>
+</HTML>
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/string/CharBuffer.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/string/CharBuffer.java
new file mode 100644
index 0000000..c0f7d6d
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/string/CharBuffer.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.util.string;
+
+/**
+ * Class which stores text in a <code>char</code> array buffer 
+ * and allows inserting, deleting, removing, appending etc. 
+ * actions with the stored text.
+ * 
+ * @author Pavlin Dobrev
+ * @author Georgi Andreev
+ * @version 1.0
+ */
+public class CharBuffer {
+
+	private char value[];
+	private int cnt;
+
+	public CharBuffer() {
+		this(16);
+	}
+
+	public CharBuffer(int len) {
+		value = new char[len];
+	}
+
+	public int length() {
+		return cnt;
+	}
+
+	public void ensureCapacity(int minCapacity) {
+		if (minCapacity > value.length)
+			expandCapacity(minCapacity);
+	}
+
+	private void expandCapacity(int minCapacity) {
+		int capacity = (value.length + 1) * 2;
+		if (minCapacity > capacity) {
+			capacity = minCapacity;
+		}
+		char newVal[] = new char[capacity];
+		System.arraycopy(value, 0, newVal, 0, cnt);
+		value = newVal;
+	}
+
+	public void setLength(int newLen) {
+		if (newLen > value.length)
+			expandCapacity(newLen);
+		if (cnt < newLen) {
+			for (; cnt < newLen; cnt++) {
+				value[cnt] = '\0';
+			}
+		} else {
+			cnt = newLen;
+		}
+	}
+
+	public char charAt(int index) {
+		if ((index < 0) || (index >= cnt))
+			throw new StringIndexOutOfBoundsException(index);
+		return value[index];
+	}
+
+	public void setCharAt(int index, char ch) {
+		if ((index < 0) || (index >= cnt))
+			throw new StringIndexOutOfBoundsException(index);
+		value[index] = ch;
+	}
+
+	public void append(String str) {
+		if (str == null)
+			str = String.valueOf(str);
+		int len = str.length();
+		int newcnt = cnt + len;
+		if (newcnt > value.length)
+			expandCapacity(newcnt);
+		str.getChars(0, len, value, cnt);
+		cnt = newcnt;
+	}
+
+	public void append(char str[], int offset, int len) {
+		int newcnt = cnt + len;
+		if (newcnt > value.length)
+			expandCapacity(newcnt);
+		System.arraycopy(str, offset, value, cnt, len);
+		cnt = newcnt;
+	}
+
+	public void append(char str[]) {
+		append(str, 0, str.length);
+	}
+
+	public void append(char c) {
+		int newcount = cnt + 1;
+		if (newcount > value.length)
+			expandCapacity(newcount);
+		value[cnt++] = c;
+	}
+
+	public String substring(int start, int end) {
+		return new String(value, start, end - start);
+	}
+
+	public String trim() {
+		int len = cnt;
+		int st = 0;
+		int off = 0;
+		char[] newVal = value;
+
+		while ((st < len) && (newVal[off + st] <= ' '))
+			st++;
+		while ((st < len) && (newVal[off + len - 1] <= ' '))
+			len--;
+
+		return ((st > 0) || (len < cnt)) ? substring(st, len) : toString();
+	}
+
+	public boolean equals(int offset, String with) {
+		int len = with.length();
+		if (offset >= cnt || offset + len != cnt)
+			return false;
+
+		for (int i = offset; i < cnt; i++) {
+			if (value[i] != with.charAt(i - offset))
+				return false;
+		}
+
+		return true;
+	}
+
+	public void getChars(int srcStart, int srcEnd, char dest[], int destStart) {
+		if ((srcStart < 0) || (srcStart >= cnt))
+			throw new StringIndexOutOfBoundsException(srcStart);
+		if ((srcEnd < 0) || (srcEnd > cnt))
+			throw new StringIndexOutOfBoundsException(srcEnd);
+
+		if (srcStart < srcEnd)
+			System.arraycopy(value, srcStart, dest, destStart, srcEnd - srcStart);
+		else if (srcStart > srcEnd)
+			throw new StringIndexOutOfBoundsException(srcEnd - srcStart);
+	}
+
+	public String toString() {
+		return new String(value, 0, cnt);
+	}
+
+	public char[] getValue() {
+		char[] retVal;
+		retVal = new char[cnt];
+		System.arraycopy(value, 0, retVal, 0, cnt);
+		return retVal;
+	}
+
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/string/package.html b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/string/package.html
new file mode 100644
index 0000000..6dbc55c
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/string/package.html
Binary files differ
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/ExTagListener.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/ExTagListener.java
new file mode 100644
index 0000000..c332b9a
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/ExTagListener.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.equinox.internal.util.xml;
+
+/**
+ * The XMLReader invokes methods of this listener either when the tag is just
+ * opened or when the tag is just closed.
+ * 
+ * @author Ivan Dimitrov
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public interface ExTagListener {
+
+	/**
+	 * Invoked when a tag is opened
+	 * 
+	 * @param aTag
+	 *            tag
+	 * @throws IllegalArgumentException
+	 */
+	public void startTag(Tag aTag) throws IllegalArgumentException;
+
+	/**
+	 * Invoked when a tag is closed
+	 * 
+	 * @param aTag
+	 *            tag
+	 * @throws IllegalArgumentException
+	 */
+	public void endTag(Tag aTag) throws IllegalArgumentException;
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/Tag.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/Tag.java
new file mode 100644
index 0000000..613fbe5
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/Tag.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.util.xml;
+
+import java.util.Enumeration;
+
+/**
+ * @author Ivan Dimitrov
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public interface Tag {
+	/**
+	 * Returns an attribute value for an attribute with a given name (aAttrName)
+	 * 
+	 * @param aAttrName
+	 *            the name of attribute
+	 * @return Attribute value for attribute with name given by attrName or null
+	 *         if there is no such an attribute
+	 */
+	public String getAttribute(String aAttrName);
+
+	/**
+	 * Returns an Enumeration of all the attributes' names for attributes belong
+	 * to the tag object
+	 * 
+	 * @return Enumeration that contains the attribute names of the attributes
+	 *         for this tag. If there is no attributes then the method returns
+	 *         Empty enumeration
+	 */
+	public Enumeration getAttributeNames();
+
+	/**
+	 * Returns an Enumeration that contains the attribute values for the
+	 * attributes that belong to the tag object
+	 * 
+	 * @return EEnumeration that contains the attribute values for the
+	 *         attributes that belong to the tag object. If there is no
+	 *         attributes then the method returns Empty enumeration
+	 */
+	public Enumeration getAttributeValues();
+
+	/**
+	 * Returns the name of the tag
+	 * 
+	 * @return the name of the tag
+	 */
+	public String getName();
+
+	/**
+	 * Returns a tag content
+	 * 
+	 * @return tag content. If the tag does not have a content, the method
+	 *         returns empty string
+	 */
+	public String getContent();
+
+	/**
+	 * Returns the line in the XML file where the tag definition starts
+	 * 
+	 * @return the line in the XML file where the tag definition starts
+	 */
+	public int getLine();
+
+	/**
+	 * Returns the number of the child tags of this tag
+	 * 
+	 * @return child tags number
+	 */
+	public int size();
+
+	/**
+	 * Returns the child tag at a given position in order that is equivalent to
+	 * the order of child tags defined in the XML file
+	 * 
+	 * @param aPosition
+	 *            child tag's position
+	 * @return the child tag at a given position
+	 */
+	public Tag getTagAt(int aPosition);
+
+	/**
+	 * Returns the content of a child tag with index position equals to aPos but
+	 * only if its name is equal to aName. Otherwise the method throws an
+	 * exception
+	 * 
+	 * @param aPos
+	 *            index of the tag in its parent list
+	 * @param aName
+	 *            the name of the tag
+	 * @return tag content
+	 * @throws NullPointerException
+	 *             if there is no tag on the given position
+	 * @throws IllegalArgumentException
+	 *             if the name of the tag on the given position does not match
+	 *             the requested name
+	 */
+	public String getContent(int aPos, String aName);
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/TagClass.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/TagClass.java
new file mode 100644
index 0000000..8634d65
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/TagClass.java
@@ -0,0 +1,296 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.util.xml;
+
+import java.util.Vector;
+import org.eclipse.equinox.internal.ds.Activator;
+import org.eclipse.equinox.internal.util.string.CharBuffer;
+
+/**
+ * Class corresponding to one XML tag, containing its tag name, attributes,
+ * content string and tree of the sub tags.
+ * 
+ * @author Ivan Dimitrov
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public class TagClass {
+
+	private static final String INTERN_TAGCONTENT = "xml.intern.tagcontent";
+	private static boolean fInternTagContent = Activator.getBoolean(INTERN_TAGCONTENT);
+
+	private CharBuffer fContent = null;
+	private String fName = null;
+	private Vector fTags = null;
+	String fAttributes = null;
+	private int fLine = -1;
+	protected boolean fInline = false;
+
+	/**
+	 * Creates an empty tag node
+	 */
+	public TagClass() {
+		// Do nothing here
+	}
+
+	/**
+	 * Creates tag node with specified name
+	 * 
+	 * @param name
+	 *            tag name
+	 */
+	public TagClass(String name) {
+		fName = name;
+	}
+
+	/**
+	 * Creates tag node with specified name
+	 * 
+	 * @param line
+	 *            the line in the XML file where the tags begin.
+	 * @param name
+	 *            tag name
+	 */
+	public TagClass(int line, String name) {
+		fLine = line;
+		fName = name;
+	}
+
+	/**
+	 * Creates tag node with specified name and content string
+	 * 
+	 * @param name
+	 *            tag name
+	 * @param contentStr
+	 *            content string of the tag
+	 */
+	public TagClass(String name, String contentStr) {
+		setup(-1, name, contentStr);
+	}
+
+	/**
+	 * Creates tag node with specified name and content string
+	 * 
+	 * @param line
+	 *            the line in the XML file where the tags begin.
+	 * @param name
+	 *            tag name
+	 * @param contentStr
+	 *            content string of the tag
+	 */
+	public TagClass(int line, String name, String contentStr) {
+		setup(line, name, contentStr);
+	}
+
+	private void setup(int line, String name, String contentStr) {
+		fLine = line;
+		fName = name;
+		if (contentStr != null && contentStr.length() > 0) {
+			fContent = new CharBuffer(contentStr.length());
+			fContent.append(contentStr);
+		}
+	}
+
+	/**
+	 * Appends the 'toAppend' CharBuffer content to the content buffer
+	 * 
+	 * @param toAppend
+	 *            CharBuffer content to append
+	 */
+	protected void appendContent(CharBuffer toAppend) {
+		if (fContent == null) {
+			fContent = new CharBuffer();
+		}
+		fContent.append(toAppend.getValue());
+	}
+
+	/**
+	 * Appends the 'toAppend' string to the content buffer
+	 * 
+	 * @param toAppend
+	 *            string to append
+	 */
+	protected void appendContent(String toAppend) {
+		if (fContent == null) {
+			fContent = new CharBuffer();
+		}
+		fContent.append(toAppend);
+	}
+
+	/**
+	 * Returns content string of the tag
+	 * 
+	 * @return tag content note: The content that is to be returned will be
+	 *         trimmed first
+	 */
+	/*
+	 * Implementation Note: The content string is not suitable to be interned
+	 * with String().intern() because it is more often to be unique and the
+	 * benefit will be much smaller than expected.
+	 */
+	public String getContent() {
+		String result = "";
+		if (fContent != null) {
+			result = fContent.trim();
+			if (fInternTagContent) {
+				result = result.intern();
+			}
+		}
+		return result;
+		// TODO -oIvan: Should not it be null instead of empty string?...
+		// Plamen: Yes it have to be null insted of "" because the old one used
+		// to return null.
+		// Ivan Dimitrov: The metatyping code relies on the fact that the
+		// content is never null
+	}
+
+	/**
+	 * Returns the content of a child tag with index position equals to aPos but
+	 * only if its name is equal to aName. Otherwise the method throws an
+	 * exception
+	 * 
+	 * @param aPos
+	 *            index of the tag in its parent list
+	 * @param aName
+	 *            the name of the tag
+	 * @return tag content
+	 * @throws NullPointerException
+	 *             if there is no tag on the given position
+	 * @throws IllegalArgumentException
+	 *             if the name of the tag on the given position does not match
+	 *             the requested name
+	 */
+	public String getContent(int aPos, String aName) {
+		TagClass child = getTagAt(aPos);
+		if (child == null)
+			throw new NullPointerException("There is no such a tag. [Parent tag name] = [" + aName + "], [child tag index] = " + aPos + ", [child tag name] = [" + aName + ']');
+
+		if (child.getName().equals(aName))
+			return child.getContent();
+
+		throw new IllegalArgumentException("There is no such a tag. [Parent tag name] = [" + aName + "], [child tag index] = " + aPos + ", [child tag name] = [" + aName + ']');
+	}
+
+	/**
+	 * Returns the internal content buffer
+	 * 
+	 * @return internal content buffer as CharBuffer
+	 */
+	protected CharBuffer getContentBuffer() {
+		if (fContent == null) {
+			fContent = new CharBuffer();
+		}
+		return fContent;
+	}
+
+	/**
+	 * Returns name of the tag
+	 * 
+	 * @return tag name
+	 */
+	public String getName() {
+		return fName;
+	}
+
+	/**
+	 * Sets the name of the tag
+	 * 
+	 * @param aName
+	 *            name of the tag
+	 */
+	protected void setName(String aName) {
+		fName = aName;
+	}
+
+	/**
+	 * Returns string with all attribute names and values of the tag, as is in
+	 * the XML content.
+	 * 
+	 * @return tag name and its attributes
+	 */
+	public String getAttributes() {
+		return (fAttributes != null) ? fAttributes : "";
+	}
+
+	/**
+	 * Returns an attribute value for an attribute with a given name (attrName)
+	 * 
+	 * @param attrName
+	 *            the name of attribute
+	 * @return Attribute value for attribute with name given by attrName or null
+	 *         if there is no such an attribute
+	 * @throws NullPointerException
+	 *             if attrName is null
+	 */
+	public String getAttribute(String attrName) {
+		return XMLUtil.getAttributeValue(fAttributes, attrName, 0);
+	}
+
+	/**
+	 * Adds a child tag to this one
+	 * 
+	 * @param aTag
+	 *            a tag to be added as a child tag
+	 */
+	public void addTag(TagClass aTag) {
+		if (fTags == null) {
+			fTags = new Vector(5, 5);
+		}
+		fTags.addElement(aTag);
+	}
+
+	/**
+	 * Returns sub tag of this one at a given position
+	 * 
+	 * @param aPos
+	 *            position of the searched tag
+	 * @return a child tag at a given position in the child-tags set or null if
+	 *         there is no such a tag
+	 */
+	public TagClass getTagAt(int aPos) {
+		return (fTags == null) ? null : (TagClass) fTags.elementAt(aPos);
+	}
+
+	/**
+	 * Returns children tags count
+	 * 
+	 * @return sub tags count
+	 */
+	public int size() {
+		return (fTags == null) ? 0 : fTags.size();
+	}
+
+	/**
+	 * Returns the line in the XML file where the tags begin.
+	 * 
+	 * @return Returns the line.
+	 */
+	public int getLine() {
+		return fLine;
+	}
+
+	/**
+	 * Sets the tag line number (the line in the XML file where the current tag
+	 * starts)
+	 * 
+	 * @param aLine
+	 *            current tag line number
+	 */
+	protected void setLine(int aLine) {
+		fLine = aLine;
+	}
+
+	protected void setInline() {
+		fInline = true;
+	}
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/TagListener.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/TagListener.java
new file mode 100644
index 0000000..df623e7
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/TagListener.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.util.xml;
+
+/**
+ * This interface is used while parsing xml files. It's method is invoked on
+ * every closing tag.
+ * 
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public interface TagListener {
+
+	/**
+	 * Invoked when a tag has been closed
+	 * 
+	 * @param tag
+	 *            tag with its content and its subtags
+	 * @throws IllegalArgumentException
+	 *             may be thrown while proccessing the tag structure
+	 */
+	public void useTag(TagClass tag) throws IllegalArgumentException;
+
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/XMLParser.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/XMLParser.java
new file mode 100644
index 0000000..86c7606
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/XMLParser.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.util.xml;
+
+import java.io.*;
+import org.eclipse.equinox.internal.util.xml.impl.XMLParserImpl;
+
+/**
+ * <p>
+ * Class used for reading of xml files, creating tree structure of 'TagClass'
+ * for each xml tag. When reader reaches a closed tag it notifies a given
+ * 'TagListener' and sends the last tag to it. If closing tag does not
+ * correspond with the last open IllegalArgumentException is thrown. There is a
+ * debug property 'xml.debug' used to dump an Exceptions occurred while
+ * operation is running.
+ * </p>
+ * 
+ * <p>
+ * The parser, in general, is a simple XML parser that implements
+ * &quot;Recursive descent&quot; parsing method.
+ * 
+ * Known limitations:<br>
+ * 
+ * <pre>
+ *  Currently this XMLParser does not support the following special tags:
+ *  1. &lt;?TAG_NAME ..... ?&gt;   or also &quot;Processing Instructions&quot;
+ *  2. &lt;!DOCTYPE .... &gt;
+ *  3. &lt;!ELEMENT .... &gt;
+ *  4. &lt;!ATTLIST .... &gt;
+ *  5. &lt;!ENTITY .... &gt;
+ * </pre>
+ * 
+ * <br>
+ * The parser skippes these tags (it searches for '>' symbol and closes the
+ * 'special' tag).<br>
+ * 
+ * @author Ivan Dimitrov
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public class XMLParser {
+
+	/**
+	 * Parses a XML file given through aInputStream and during the parsing
+	 * notifies aListener for close-tag and open-tag events <br>
+	 * <br>
+	 * <b>Note: The XMLReader does not close the passed Reader or InputStream
+	 * 
+	 * @param aInputStream
+	 *            an InputStream to read the XML file from
+	 * @param aListener
+	 *            ExTagListener that will be notified on close-tag and open-tag
+	 *            events
+	 * @param aLevel
+	 *            indicates the tag level that the listener will be invoked for.
+	 *            For example if the XML is:<br>
+	 * 
+	 * <pre>
+	 *  &lt;a&gt;
+	 *    &lt;b&gt;
+	 *      &lt;c /&gt;
+	 *    &lt;/b&gt;
+	 *  &lt;/a&gt;
+	 * </pre>
+	 * 
+	 * <br>
+	 *            and the passed aLevel is 2 then the listener will be invoked
+	 *            only for tags that have level 2, i.e. in our example the
+	 *            listener will be invoked only for tag &lt;b&gt;<br>
+	 *            <ul>
+	 *            <li>Value less than 0 indicates &quot;invoke listener for all
+	 *            tags no matter what are their levels&quot;</li>
+	 *            <li>Value of 0 indicates that the listener must not be
+	 *            invoked in general no matter what is the tag level</li>
+	 *            <li>Value greater than 0 indicates the tag level that the
+	 *            listener will be invoked for</li>
+	 *            description
+	 * @throws IOException
+	 *             if some IO error occurs when reading the XML file or if a
+	 *             parser error occurs.
+	 */
+	public static void parseXML(InputStream aInputStream, ExTagListener aListener, int aLevel) throws IOException {
+		XMLParserImpl xml = new XMLParserImpl(aInputStream, aListener);
+		xml.setLevel(aLevel);
+		xml.parseXML();
+	}
+
+	/**
+	 * Parses a XML file given through aReader and during the parsing notifies
+	 * aListener for close-tag and open-tag events <br>
+	 * <br>
+	 * <b>Note: The XMLReader does not close the passed Reader or InputStream
+	 * 
+	 * @param aReader
+	 *            aReader to read the XML file from
+	 * @param aListener
+	 *            ExTagListener that will be notified on close-tag and open-tag
+	 *            events
+	 * @param aLevel
+	 *            see parseXML(Reader aReader, TagListener aListener, int aLevel
+	 *            description
+	 * @throws IOException
+	 *             if some IO error occurs when reading the XML file or if a
+	 *             parser error occurs.
+	 */
+	public static void parseXML(Reader aReader, ExTagListener aListener, int aLevel) throws IOException {
+		XMLParserImpl xml = new XMLParserImpl(aReader, aListener);
+		xml.setLevel(aLevel);
+		xml.parseXML();
+	}
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/XMLReader.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/XMLReader.java
new file mode 100644
index 0000000..c0de29d
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/XMLReader.java
@@ -0,0 +1,1329 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.util.xml;
+
+import java.io.*;
+import org.eclipse.equinox.internal.ds.Activator;
+import org.eclipse.equinox.internal.util.string.CharBuffer;
+
+/**
+ * <p>
+ * Class used for reading of xml files, creating tree structure of 'TagClass'
+ * for each xml tag. When reader reaches a closed tag it notifies a given
+ * 'TagListener' and sends the last tag to it. If closing tag does not
+ * correspond with the last open IllegalArgumentException is thrown. There is a
+ * debug property 'xml.debug' used to dump an Exceptions occurred while
+ * operation is running.
+ * </p>
+ * 
+ * <p>
+ * The parser, in general, is a simple XML parser that implements
+ * &quot;Recursive descent&quot; parsing method.
+ * 
+ * Known limitations:<br>
+ * 
+ * <pre>
+ *  Currently this XMLParser does not support the following special tags:
+ *  1. &lt;?TAG_NAME ..... ?&gt;   or also &quot;Processing Instructions&quot;
+ *  2. &lt;!DOCTYPE .... &gt;
+ *  3. &lt;!ELEMENT .... &gt;
+ *  4. &lt;!ATTLIST .... &gt;
+ *  5. &lt;!ENTITY .... &gt;
+ * </pre>
+ * 
+ * <br>
+ * The parser skippes these tags (it searches for '>' symbol and closes the
+ * 'special' tag).<br>
+ * 
+ * @author Ivan Dimitrov
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public class XMLReader {
+
+	private static final String DEBUG = "equinox.ds.xml.debug";
+	private static final String SET_OLD_BEHAVIOUR = "equinox.ds.xml.oldbehaviour";
+	private static final String SET_OLD_LEVELS = "equinox.ds.xml.oldlevels";
+	private static final String INTERN_ATTRIBUTES = "equinox.ds.xml.intern.attributes";
+
+	private static final String CDATA = "CDATA";
+	private static final String XML = "xml";
+	private static final String VERSION = "version";
+	private static final String ENCODING = "encoding";
+	private static final String STANDALONE = "standalone";
+
+	private static final String ERR_EOS = "End-of-stream reached before the end of XML.";
+	private static final String ERR_ENTITY_EXPECTED = "Entity reference or Character reference expected.";
+	private static final String ERR_EQUAL_EXPECTED = "'=' expected.";
+	private static final String ERR_QUOT_EXPECTED = "''' or '\"' expected.";
+	private static final String ERR_GT_EXPECTED = "'>' expected.";
+	private static final String ERR_LT_EXPECTED = "'<' expected.";
+	private static final String ERR_CLOSE_TAG1_EXPECTED = "'/' or tag name expected.";
+	private static final String ERR_CLOSE_TAG2_EXPECTED = "'>', '/>' or more attributes expected.";
+	private static final String ERR_CLOSE_TAG3_EXPECTED = "'?>' expected.";
+	private static final String ERR_CONTENT_EXPECTED = "Content data, new tag or closing tag expected.";
+	private static final String ERR_QUESTIONMARK_EXPECTED = "'?' expected.";
+	private static final String ERR_ILLEGAL_CHARACTER = "Illegal character.";
+	private static final String ERR_TAGNAME_EXPECTED = "Tag name expected.";
+	private static final String ERR_TAGNAME2_EXPECTED = "Tag name, '?' or '!' expected.";
+	private static final String ERR_DASH_EXPECTED = "'-' expected.";
+	private static final String ERR_COMMENT_CLOSE_EXPECTED = "'-->' expected.";
+	private static final String ERR_CDATA_EXPECTED = "'CDATA' expected.";
+	private static final String ERR_OPENSQBRACKET_EXPECTED = "'[' expected.";
+	private static final String ERR_CLOSE_CDATA_EXPECTED = "']]>' expected.";
+	private static final String ERR_SEMICOLON_EXPECTED = "';' expected.";
+	private static final String ERR_XMLPROLOG_EXPECTED = "XML prolog '<?xml' is not expected at this position.";
+	private static final String ERR_VERSION_EXPECTED = "'version' attribute expected.";
+	private static final String ERR_ENCODING_STANDALONE_EXPECTED = "'encoding', 'standalone' or '?>' expected.";
+	private static final String ERR_STANDALONE_EXPECTED = "'standalone' attribute expected.";
+
+	private static final boolean fDebug = Activator.getBoolean(DEBUG);
+	private static final boolean fOldBehaviour = Activator.getBoolean(SET_OLD_BEHAVIOUR);
+	private static final boolean fOldLevels = Activator.getBoolean(SET_OLD_LEVELS);
+	private static final boolean fInternAttributes = Activator.getBoolean(INTERN_ATTRIBUTES);
+
+	private String fDefaultEncoding = "UTF-8";
+
+	// private CharBuffer c;
+	private CharBuffer temp = new CharBuffer();
+	private CharBuffer temp2 = null;
+
+	protected Reader fReader = null;
+	protected InputStream fStream = null;
+
+	protected char currentChar = 0;
+	protected TagListener fTagListener;
+
+	protected int fLine = 1;
+	protected int fPos = 0;
+
+	protected int fLevel = -1;
+	protected int fCurrentLevel = 1;
+
+	private String fVersion = "1.0";
+	private String fEncoding = "UTF-8";
+	private String fStandalone = "no";
+
+	protected static final String[] fNew_entities = {"amp", "apos", "lt", "gt", "quot"};
+	protected static final char[] fNew_ent_chars = {'&', '\'', '<', '>', '"'};
+
+	protected static final String[] fOld_entities = {"amp", "nbsp", "crlf", "tab", "lt", "gt", "quot", "apos"};
+	protected static final char[] fOld_ent_chars = {'&', ' ', '\n', '\t', '<', '>', '"', '\''};
+
+	/**
+	 * An empty default constructor
+	 */
+	public XMLReader() {
+		//
+	}
+
+	/**
+	 * Constructs a new XMLReader. <br>
+	 * <br>
+	 * <b>Note: The XMLReader does not close the passed Reader or InputStream
+	 * 
+	 * @param aInputStream
+	 *            an InputStream to read the XML file from
+	 * @param aListener
+	 *            TagListener that will be notified on tag close event
+	 * @throws IOException
+	 */
+	public XMLReader(InputStream aInputStream, TagListener aListener) {
+		fStream = aInputStream;
+		fTagListener = aListener;
+	}
+
+	/**
+	 * Constructs a new XMLReader. <br>
+	 * <br>
+	 * <b>Note: The XMLReader does not close the passed Reader or InputStream
+	 * 
+	 * @param aReader
+	 *            a reader that will be used to read the XML file from
+	 * @param aListener
+	 *            TagListener that will be notified on tag close event
+	 */
+	public XMLReader(Reader aReader, TagListener aListener) {
+		fReader = aReader;
+		fTagListener = aListener;
+	}
+
+	/**
+	 * Parses a XML file given through aInputStream and during the parsing
+	 * notifies aListener for close-tag events <br>
+	 * <br>
+	 * <b>Note: The XMLReader does not close the passed Reader or InputStream
+	 * 
+	 * @param aInputStream
+	 *            an InputStream to read the XML file from
+	 * @param aListener
+	 *            TagListener that will be notified on close-tag events
+	 * @throws IOException
+	 */
+	public static void read(InputStream aInputStream, TagListener aListener) throws IOException {
+		parseXML(aInputStream, aListener, -1);
+	}
+
+	/**
+	 * Parses a XML file given through aInputStream and during the parsing
+	 * notifies aListener for close-tag events <br>
+	 * <br>
+	 * <b>Note: The XMLReader does not close the passed Reader or InputStream
+	 * 
+	 * @param aInputStream
+	 *            an InputStream to read the XML file from
+	 * @param aListener
+	 *            TagListener that will be notified on close-tag events
+	 * @param aLevel
+	 *            see parseXML(Reader aReader, TagListener aListener, int aLevel
+	 *            description
+	 * @throws IOException
+	 */
+	public static void read(InputStream aInputStream, TagListener aListener, int aLevel) throws IOException {
+		parseXML(aInputStream, aListener, aLevel);
+	}
+
+	/**
+	 * Parses a XML file given through aReader and during the parsing notifies
+	 * aListener for close-tag events <br>
+	 * <br>
+	 * <b>Note: The XMLReader does not close the passed Reader or InputStream
+	 * 
+	 * @param aReader
+	 *            a Reader to read the XML file from
+	 * @param aListener
+	 *            TagListener that will be notified on close-tag events
+	 * @throws IOException
+	 */
+	public static void read(Reader aReader, TagListener aListener) throws IOException {
+		parseXML(aReader, aListener, -1);
+	}
+
+	/**
+	 * Parses a XML file given through aReader and during the parsing notifies
+	 * aListener for close-tag events <br>
+	 * <br>
+	 * <b>Note: The XMLReader does not close the passed Reader or InputStream
+	 * 
+	 * @param aReader
+	 *            a Reader to read the XML file from
+	 * @param aListener
+	 *            TagListener that will be notified on close-tag events
+	 * @param aLevel
+	 *            see parseXML(Reader aReader, TagListener aListener, int aLevel
+	 *            description
+	 * @throws IOException
+	 */
+	public static void read(Reader aReader, TagListener aListener, int aLevel) throws IOException {
+		parseXML(aReader, aListener, aLevel);
+	}
+
+	/**
+	 * Sets the parser's encoding. If there is a current encoding associated
+	 * with the parser the method returns immediately
+	 * 
+	 * @param aEncoding
+	 *            new encoding to be set
+	 * @throws UnsupportedEncodingException
+	 *             if the encoding is not supported.
+	 */
+	protected void setEncoding(String aEncoding) {
+		if (fReader == null) {
+			try {
+				fReader = new InputStreamReader(fStream, aEncoding);
+			} catch (Exception e) {
+				if (fDebug) {
+					System.err.println("[XMLReader] Failed setting the encoding \"" + aEncoding + "\", continue parsing with the default one.");
+				}
+				fReader = new InputStreamReader(fStream);
+			}
+		}
+	}
+
+	/**
+	 * Sets the level of tags bellow which the listener will be notified for.
+	 * For internal use only.
+	 * 
+	 * @param aLevel
+	 */
+	protected void setLevel(int aLevel) {
+		fLevel = aLevel;
+	}
+
+	/* A helper function to reuse a temp CharBuffers without recreating it */
+	protected CharBuffer getCharBuffer() {
+		if (temp.length() <= 0) {
+			return temp;
+		} else if (temp2 == null) {
+			temp2 = new CharBuffer(0);
+			return temp2;
+		} else if (temp2.length() <= 0) {
+			return temp2;
+		}
+		return new CharBuffer(0);
+	}
+
+	protected char prev_char = 0;
+	protected char[] fBuffer = new char[4096];
+	protected int fBufferLen = 0;
+	protected int fBufferPos = 0;
+
+	/**
+	 * Reads the next char from the input stream and sets it to private field
+	 * <code>currentChar</code>
+	 * 
+	 * @return true if the next char is successfully read of false if
+	 *         End-Of-Stream is reached
+	 * @throws IOException
+	 *             if some error occurs during reading the character or if the
+	 *             caller tries to read beyond the End-Of-Stream.
+	 */
+	protected boolean getNextChar() throws IOException {
+		// // Reading characters without buffering
+		// int ichar = 0;
+		// int count = 0;
+		// while (ichar == 0 && count < 100) {
+		// ichar = fReader.read();
+		// count++;
+		// }
+		//    
+		// if (ichar == 0)
+		// throw new IOException("Failed to read from the input file.");
+		//    
+		// if (ichar < 0 && prev_char == 0)
+		// throw new IOException(ERR_EOS);
+		//    
+		// char ch = (char) ichar;
+
+		char ch;
+
+		if (fReader == null) { // If there is no associated reader,
+			int ach = fStream.read(); // then reads from the InputStream until
+			if (ach < 0) { // the rigth encoding is recognized
+				ach = 0;
+			}
+
+			ch = (char) ach;
+			if (ch == 0 && prev_char == 0) {
+				throw new IOException(ERR_EOS);
+			}
+		} else {
+			if (fBufferLen < 0) {
+				throw new IOException(ERR_EOS);
+			}
+
+			if ((fBufferPos) >= fBufferLen) {
+				// Refetch the buffer
+				fBufferLen = 0;
+				fBufferPos = 0;
+				int count = 0;
+				while (fBufferLen == 0 && count < 100) {
+					fBufferLen = fReader.read(fBuffer);
+					count++;
+				}
+
+				ch = (fBufferLen > 0) ? fBuffer[fBufferPos++] : 0;
+
+				if (fBufferLen == 0) {
+					fBufferLen = -1;
+				}
+			} else {
+				ch = fBuffer[fBufferPos++];
+			}
+		}
+
+		prev_char = currentChar;
+		currentChar = ch;
+		fPos++;
+
+		switch (ch) {
+			case '\n' :
+				if (prev_char != '\r') {
+					fLine++;
+				}
+				fPos = 0;
+				break;
+			case '\r' :
+				fPos = 0;
+				fLine++;
+				break;
+		}
+		return (currentChar != 0);
+	}
+
+	/**
+	 * Parses the attribute value and if it's successful then adds it to the
+	 * CharBuffer. If there are EntityReferences of CharReferences in the
+	 * attribute value, they will be turned to their equivalent symbols.<br>
+	 * attr_value ::= (acceptable_char | EntityRef | CharRef)* - quot_symbol
+	 * 
+	 * @see parse_attr
+	 * @see parse_CharRef
+	 * @see parse_EntityRef
+	 */
+	protected void parse_attr_value(CharBuffer sb, char quot) throws IOException {
+		while (currentChar != quot && currentChar != '<') {
+			if (accept_char('&')) {
+				if (!parse_CharRef(sb)) {
+					if (!parse_EntityRef(sb, true)) {
+						err(fPos - 1, ERR_ENTITY_EXPECTED);
+					}
+				}
+			} else {
+				sb.append(currentChar);
+
+				if (!getNextChar()) {
+					break;
+				}
+			}
+		}
+	}
+
+	/**
+	 * Parses an attribute with the given simplified grammar:<br>
+	 * 
+	 * <pre>
+	 * attribute ::= S* + attr_name + S* + '=' + S* + ('\'' + (attr_value - '\'') + '\'')) | ('&quot;' + (attr_value - '&quot;') + '&quot;'))
+	 * attr_value ::= (acceptable_char | EntityRef | CharRef)*
+	 * attr_name ::= identifier
+	 * </pre>
+	 * 
+	 * @param aParent
+	 *            the parent tag where the correctly parsed attribute will be
+	 *            added
+	 * @throws IOException
+	 * @see parse_identifier
+	 * @see parse_attr_value
+	 */
+	protected boolean parse_attr(CharBuffer cb) throws IOException {
+		clearWhiteSpaces();
+
+		cb.append(' ');
+		int length = parse_identifier(cb);
+
+		if (length > 0) {
+			clearWhiteSpaces();
+
+			if (!accept_char('=')) {
+				err(ERR_EQUAL_EXPECTED);
+			}
+
+			cb.append('=');
+			clearWhiteSpaces();
+
+			char quot = 0;
+			if (accept_char('"')) {
+				quot = '"';
+			} else if (accept_char('\'')) {
+				quot = '\'';
+			} else {
+				err(ERR_QUOT_EXPECTED);
+			}
+
+			cb.append(quot);
+			parse_attr_value(cb, quot);
+
+			if (!accept_char(quot)) {
+				err("'" + quot + "' expected.");
+			}
+
+			cb.append(quot);
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Parses a tag attribute list with the following simplified grammar:
+	 * 
+	 * <pre>
+	 * attr_list ::= attribute*
+	 * @param aParent the parent tag that the parsed attributes will be added to
+	 * @return true if at least one attribute is parsed correctly and false otherwise
+	 * @throws IOException
+	 * @see parse_attr
+	 * 
+	 */
+	protected boolean parse_attr_list(TagClass aParent) throws IOException {
+		boolean result = false;
+
+		CharBuffer cb = getCharBuffer();
+		cb.append(aParent.getName());
+		while (parse_attr(cb)) {
+			result = true;
+		}
+
+		aParent.fAttributes = ((fInternAttributes) ? cb.toString().intern() : cb.toString());
+		cb.setLength(0);
+		return result;
+	}
+
+	private static final char bA = 'A' - 1;
+	private static final char aZ = 'Z' + 1;
+	private static final char ba = 'a' - 1;
+	private static final char az = 'z' + 1;
+	private static final char b0 = '0' - 1;
+	private static final char a9 = '9' + 1;
+
+	/**
+	 * This method returns true is the passed character may be used as starting
+	 * character for tag name and attribute name
+	 * 
+	 * @param ch
+	 *            the tested character
+	 * @return true if the character could be used as starting character for a
+	 *         tag name and an attribute name and false otherwise
+	 */
+	public final static boolean isNameStartChar(char ch) {
+		return (ch > bA && ch < aZ) || (ch > ba && ch < az) || (ch == ':') || (ch == '_') || (ch > 0xBF && ch < 0xD7) || (ch > 0xD7 && ch < 0xF7) || (ch > 0xF7 && ch < 0x300) || (ch > 0x36F && ch < 0x37E) || (ch > 0x37E && ch < 0x2000) || (ch > 0x200B && ch < 0x200E) || (ch > 0x206F && ch < 0x2190) || (ch > 0x2BFF && ch < 0x2FF0) || (ch > 0x3000 && ch < 0xD800) || (ch > 0xF900 && ch < 0xFDD0) || (ch > 0xFDEF && ch < 0xFFFE) || (ch > 0x0FFFF && ch < 0xF0000);
+	}
+
+	/**
+	 * This method returns true if the passed characted may be used as part of a
+	 * tag name or an attribute name
+	 * 
+	 * @param ch
+	 *            the tested character
+	 * @return true is the characted could be used as part of a tag name or an
+	 *         attribute name and false otherwise
+	 */
+	public final static boolean isNameChar(char ch) {
+		return (ch == '-') || (ch == '.') || (ch == 0xB7) || (ch > b0 && ch < a9) || isNameStartChar(ch) || (ch > 0x02FF && ch < 0x0370) || (ch > 0x203E && ch < 0x2041);
+	}
+
+	/**
+	 * Parses an identifier.
+	 * 
+	 * @return an identifier as a string if it is parsed successfully and null
+	 *         otherwise
+	 * @throws IOException
+	 *             if an exception occurs during read operations from the Reader
+	 *             or the InputStream
+	 */
+	protected String parse_identifier() throws IOException {
+		if (isNameStartChar(currentChar)) {
+			CharBuffer sb = getCharBuffer();
+
+			while (isNameChar(currentChar)) {
+				sb.append(currentChar);
+
+				if (!getNextChar()) {
+					break;
+				}
+			}
+			String result = sb.toString().intern();
+			sb.setLength(0);
+			return result;
+		}
+		return null;
+	}
+
+	/**
+	 * Parses an identifier and places it into the passed CharBuffer
+	 * 
+	 * @param cb
+	 *            CharBuffer where the parsed identifier will be placed into
+	 * @return the length of the parsed identifier
+	 * @throws IOException
+	 *             if an exception occurs during read operations from the Reader
+	 *             or the InputStream
+	 */
+	protected int parse_identifier(CharBuffer cb) throws IOException {
+		if (isNameStartChar(currentChar)) {
+			int length = 0;
+			while (isNameChar(currentChar)) {
+				cb.append(currentChar);
+				length++;
+
+				if (!getNextChar()) {
+					break;
+				}
+			}
+
+			return length;
+		}
+		return 0;
+	}
+
+	/**
+	 * Parses a tag name and if it is successfully parsed the method sets it as
+	 * a name of the parent tag
+	 * 
+	 * @param aParent
+	 *            parent tag
+	 * @return true if the name is parsed successfully and false otherwise
+	 * @throws IOException
+	 * @see parse_identifier
+	 */
+	protected boolean parse_tag_name(TagClass aParent) throws IOException {
+		String name = parse_identifier();
+		if (name != null) {
+			aParent.setName(name);
+		}
+		return name != null;
+	}
+
+	/**
+	 * Helper function that notify listeners depending on certain conditions
+	 * such as if the tag event is on-close or on-open
+	 * 
+	 * @param aTag
+	 *            The tag that the notification event is valid for.
+	 * @param isStart
+	 *            true if the event is on-open and false if it is on-close
+	 */
+	protected void notifyListeners(TagClass aTag) {
+		try {
+			if (fLevel <= 0 || fLevel == fCurrentLevel) {
+				fTagListener.useTag(aTag);
+			}
+		} catch (RuntimeException re) {
+			if (fDebug) {
+				System.err.println("An outside exception occured while processing a tag on line " + aTag.getLine() + ", the tag name is: " + aTag.getName() + ", the level is: " + fCurrentLevel);
+				re.printStackTrace(System.err);
+			}
+			throw re;
+		}
+	}
+
+	/**
+	 * Parses a normal tag. There are two cases - (1) the tag has separate open
+	 * and close tag elements and (2) the tag is simple suchas &lt;tag_name ...
+	 * /&gt;
+	 * 
+	 * @param aParent
+	 *            The parent tag that this tag will be added to if the parsing
+	 *            is successful
+	 * @return true on success and false otherwise
+	 * @throws IOException
+	 * @see clearWhiteSpaces
+	 * @see parse_tag_name
+	 * @see parse_attr_list
+	 * @see notifyListeners
+	 * @see accept_char
+	 * @see accept_seq
+	 * @see parse_PCDATA
+	 */
+	protected boolean parse_tag_normal(TagClass aParent) throws IOException {
+		// Looking for a tag_name (identifier)
+		if (isNameStartChar(currentChar)) {
+			TagClass tag = new TagClass();
+			tag.setLine(fLine);
+
+			parse_tag_name(tag);
+			parse_attr_list(tag);
+
+			clearWhiteSpaces();
+
+			if (accept_char('/')) {
+				if (!accept_char('>')) {
+					err(ERR_GT_EXPECTED);
+				}
+				tag.setInline();
+				aParent.addTag(tag);
+
+				if (!fOldBehaviour) {
+					notifyListeners(tag);
+				}
+
+				return true;
+			} else if (accept_char('>')) {
+
+				while (true) {
+					clearWhiteSpaces();
+					int pos = fPos;
+					if (currentChar == '<') { // Normal tag, Special tag or
+						// closing tag
+						if (!parse_tag(tag)) { // It may be a special tag.
+							if (!accept_char('/')) {
+								err(pos + 1, ERR_CLOSE_TAG1_EXPECTED);
+							}
+
+							// trying to accept: tag_name + S* + '>'
+							pos = fPos;
+							if (!accept_seq(tag.getName())) {
+								err(pos, '\'' + tag.getName() + "' string expected.");
+							}
+
+							clearWhiteSpaces();
+							if (!accept_char('>')) {
+								err(ERR_GT_EXPECTED);
+							}
+
+							aParent.addTag(tag);
+
+							notifyListeners(tag);
+
+							return true;
+						}
+					} else {
+						if (!parse_PCDATA(tag))
+							break;
+					}
+				}
+				err(ERR_CONTENT_EXPECTED);
+			} else {
+				err(ERR_CLOSE_TAG2_EXPECTED);
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Parses special tags, such that begins with:<br>
+	 * 
+	 * <pre><code>
+	 * &lt;!--         comments
+	 * &lt;!tag_name   Parsing instructions
+	 * &lt;![          CDATA element
+	 * &lt;?           DOCTYPE, etc.
+	 * </code></pre>
+	 * 
+	 * @param aParent
+	 *            The parent tag that this tag will be added to if the parsing
+	 *            is successful
+	 * @return true on success and false otherwise
+	 * @throws IOException
+	 * @see accept_char
+	 * @see clearWhiteSpaces
+	 * @see parse_tag_CDATA
+	 * @see parse_tag_name
+	 * @see parse_comment
+	 */
+	protected boolean parse_tag_special(TagClass aParent) throws IOException {
+		if (accept_char('!')) {
+
+			TagClass tag = new TagClass();
+
+			if (parse_tag_name(tag)) {
+				clearWhiteSpaces();
+
+				while (true) {
+					if (accept_char('>')) {
+						clearWhiteSpaces();
+						return true;
+					}
+					getNextChar();
+				}
+			} else if (parse_tag_CDATA(aParent)) { // parse CDATA tag
+				return true;
+			} else if (parse_comment(tag)) {
+				return true;
+			}
+		} else if (accept_char('?')) {
+			TagClass tag = new TagClass();
+
+			int pos = fPos;
+			if (parse_tag_name(tag)) {
+				if (tag.getName().equals(XML)) {
+					err(pos - 2, ERR_XMLPROLOG_EXPECTED);
+				}
+
+				char prevCh = 0;
+				while (true) {
+					if (currentChar == '>') {
+						if (prevCh == '?') {
+							accept_char('>');
+							clearWhiteSpaces();
+							return true;
+						}
+					}
+					prevCh = currentChar;
+					getNextChar();
+				}
+
+			}
+			err(pos, ERR_TAGNAME_EXPECTED);
+		}
+		return false;
+	}
+
+	/**
+	 * Parses an attribute value and returns it as a string
+	 * 
+	 * @return the parsed attribute value as a string.
+	 * @throws IOException
+	 *             if an exception occurs during read operations from the Reader
+	 *             or the InputStream
+	 */
+	protected String getAttrValue() throws IOException {
+		CharBuffer cb = getCharBuffer();
+
+		clearWhiteSpaces();
+		accept_char('=');
+		clearWhiteSpaces();
+
+		if (currentChar != '\'' && currentChar != '"') {
+			err(ERR_QUOT_EXPECTED);
+		}
+
+		char quot = currentChar;
+		accept_char(quot);
+		parse_attr_value(cb, quot);
+
+		if (!accept_char(quot)) {
+			err("'" + quot + "' expected.");
+		}
+
+		String result = cb.toString();
+		cb.setLength(0);
+		clearWhiteSpaces();
+		return result;
+	}
+
+	/**
+	 * Parses the XML prolog tag, i.e.<br>
+	 * <code> &lt;?xml version="..." encoding="..." standalone="..." ?&gt; </code><br>
+	 * 
+	 * @param parent
+	 *            the parent tag (in this case this is the root "fake" tag,
+	 *            which the listeners will never be informed for...)
+	 * @throws IOException
+	 *             if an exception occurs during read operations from the Reader
+	 *             or the InputStream
+	 */
+	protected boolean parse_xml_prolog(TagClass parent) throws IOException {
+		if (accept_char('?')) {
+			TagClass tag = new TagClass();
+
+			if (parse_tag_name(tag)) {
+				if (tag.getName().equalsIgnoreCase(XML)) {
+					if (fOldLevels)
+						fCurrentLevel++;
+
+					clearWhiteSpaces();
+
+					int pos = fPos;
+
+					String s = parse_identifier();
+
+					boolean bEncoding = false;
+					boolean bStandalone = false;
+
+					if (VERSION.equals(s)) {
+						fVersion = getAttrValue();
+						s = parse_identifier();
+					} else {
+						err(pos, ERR_VERSION_EXPECTED);
+					}
+
+					if (ENCODING.equals(s)) {
+						fEncoding = getAttrValue().toUpperCase();
+						s = parse_identifier();
+						bEncoding = true;
+					}
+
+					if (STANDALONE.equals(s)) {
+						fStandalone = getAttrValue();
+						s = parse_identifier();
+						bStandalone = true;
+					}
+
+					if (s != null) {
+						if (bEncoding && bStandalone)
+							err(ERR_CLOSE_TAG3_EXPECTED);
+
+						if (!bEncoding && !bStandalone)
+							err(ERR_ENCODING_STANDALONE_EXPECTED);
+
+						if (bEncoding)
+							err(ERR_STANDALONE_EXPECTED);
+						err(ERR_CLOSE_TAG3_EXPECTED);
+					}
+
+					clearWhiteSpaces();
+					pos = fPos;
+					if (!accept_seq("?>"))
+						err(pos, ERR_CLOSE_TAG3_EXPECTED);
+					return true;
+				}
+
+				char prevCh = 0;
+
+				while (true) {
+					if (currentChar == '>') {
+						if (prevCh == '?') {
+							accept_char('>');
+							clearWhiteSpaces();
+
+							return true;
+						}
+						err(ERR_QUESTIONMARK_EXPECTED);
+					} else if (currentChar == '<') {
+						err(ERR_ILLEGAL_CHARACTER + " ('<')");
+					}
+					prevCh = currentChar;
+					getNextChar();
+				}
+
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Parses a comment. The grammar is:<br>
+	 * Comment ::= '&lt;!--' ((Char - '-') | ('-' (Char - '-')))* '--&gt;'<br>
+	 * Note that the grammar does not allow a comment ending in ---&gt;. The
+	 * following example is not well-formed.<br>
+	 * <code>
+	 * &lt;!-- B+, B, or B---&gt;</code>
+	 * 
+	 * @param aParent
+	 *            The parent tag
+	 * @return true on success and false otherwise
+	 * @throws IOException
+	 * @see accept_char
+	 */
+	protected boolean parse_comment(TagClass aParent) throws IOException {
+		if (accept_char('-')) {
+			if (!accept_char('-')) {
+				err(ERR_DASH_EXPECTED);
+			}
+
+			while (true) {
+				if (accept_char('-')) {
+					if (accept_char('-')) {
+						if (accept_char('>')) {
+							break;
+						}
+
+						err(ERR_GT_EXPECTED);
+					}
+				}
+
+				if (!getNextChar()) {
+					err(ERR_COMMENT_CLOSE_EXPECTED);
+				}
+			}
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Parses either normal or special tag
+	 * 
+	 * @param aParent
+	 *            The parent tag that the successfully parsed tag will (if it is
+	 *            normal tag or CDATA element) be added
+	 * @return true on success and false otherwise
+	 * @throws IOException
+	 * @see accept_cahr
+	 * @see parse_tag_normal
+	 * @see parse_tag_special
+	 * @see clearWhiteSpaces
+	 */
+	protected boolean parse_tag(TagClass aParent) throws IOException {
+		clearWhiteSpaces();
+		try {
+			fCurrentLevel++;
+
+			if (accept_char('<')) {
+				if (parse_tag_normal(aParent) || parse_tag_special(aParent)) {
+					return true;
+				}
+			}
+			return false;
+		} finally {
+			fCurrentLevel--;
+		}
+	}
+
+	/**
+	 * Parses the content of the tag (including sub-tags and sub-elements)
+	 * 
+	 * @param aParent
+	 *            The parent tag that the content and tags will be added to
+	 * @return true on success and false otherwise
+	 * @throws IOException
+	 * @see parse_PCDATA
+	 * @see parse_tag
+	 */
+	protected boolean parse_content(TagClass aParent) throws IOException {
+		return (parse_PCDATA(aParent) || parse_tag(aParent));
+	}
+
+	/**
+	 * Parses a CDATA tag (or CDATA content element).
+	 * 
+	 * @param aParent
+	 *            The parent tag that the content will be added to
+	 * @return true on success and false otherwise
+	 * @throws IOException
+	 */
+	protected boolean parse_tag_CDATA(TagClass aParent) throws IOException {
+		if (accept_char('[')) {
+			int pos = fPos;
+			if (!accept_seq(CDATA))
+				err(pos, ERR_CDATA_EXPECTED);
+
+			if (!accept_char('['))
+				err(ERR_OPENSQBRACKET_EXPECTED);
+
+			do {
+				if (currentChar != '>') {
+					aParent.getContentBuffer().append(currentChar);
+				} else {
+					CharBuffer sb = aParent.getContentBuffer();
+					int l = sb.length();
+
+					if (l >= 2) {
+						if (sb.charAt(l - 1) == ']' && sb.charAt(l - 2) == ']') {
+							sb.setLength(l - 2); // Truncates the extra "]]"
+							// symbols appended at the
+							// end
+
+							getNextChar();
+							return true;
+						}
+					}
+					sb.append(currentChar);
+				}
+			} while (getNextChar());
+
+			err(fPos - 1, ERR_CLOSE_CDATA_EXPECTED);
+		}
+		return false;
+	}
+
+	/**
+	 * Parses PCDATA content (Parseable Content DATA). The EntityRefs and
+	 * CharRefs that are parsed will be turned to its symbol equivalent.
+	 * 
+	 * @param aParent
+	 *            The parent tag that the PCDATA will be added to
+	 * @return true on success and false otherwise
+	 * @throws IOException
+	 * @see accept_char
+	 * @see parse_CharRef
+	 * @see parse_EntityRef
+	 */
+	protected boolean parse_PCDATA(TagClass aParent) throws IOException {
+		boolean result = false;
+		while (currentChar != '<') {
+			result = true;
+
+			CharBuffer sbContent = aParent.getContentBuffer();
+
+			if (accept_char('&')) {
+				int pos = fPos;
+
+				if (!parse_CharRef(sbContent))
+					if (!parse_EntityRef(sbContent, false))
+						err(pos - 1, ERR_ENTITY_EXPECTED);
+
+			} else {
+				sbContent.append(currentChar);
+
+				if (!getNextChar())
+					break;
+			}
+		}
+		return result;
+	}
+
+	/**
+	 * Accepts one character from the input stream and if it's successful moves
+	 * one character forward.
+	 * 
+	 * @param ch
+	 *            The character that should be accepted
+	 * @return true on success and false otherwise
+	 * @throws IOException
+	 */
+	protected boolean accept_char(char ch) throws IOException {
+		if (currentChar == ch) {
+			getNextChar();
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Accepts a sequence of characters given by seq parameter. If the sequence
+	 * is accepted successfully then the currentChar field will contain the
+	 * character immediately after the accepted sequence.
+	 * 
+	 * @param seq
+	 *            The character sequence that should be accepted
+	 * @return true on success and false otherwise
+	 * @throws IOException
+	 */
+	protected boolean accept_seq(String seq) throws IOException {
+		for (int i = 0; i < seq.length(); i++) {
+			if (!accept_char(seq.charAt(i)))
+				return false;
+		}
+		return true;
+	}
+
+	private static final String[] fEntities = (fOldBehaviour) ? fOld_entities : fNew_entities;
+	private static final char[] fEnt_chars = (fOldBehaviour) ? fOld_ent_chars : fNew_ent_chars;
+
+	/**
+	 * <code>
+	 * EntityRef ::= '&' + EntityValue + ';'<br>
+	 * EntityValue ::= 'amp' | 'quot' | 'apos' | 'gt' | 'lt' | identifier
+	 * </code>
+	 * 
+	 * @param sb
+	 *            The string buffer that the recognized entity will be appended
+	 *            to
+	 * @throws IOException
+	 * @return true on success and false otherwise
+	 * @see parse_identifier
+	 * @see accept_char
+	 */
+	protected boolean parse_EntityRef(CharBuffer sb, boolean inAttribute) throws IOException {
+		String ent = parse_identifier();
+
+		if (!accept_char(';')) {
+			err(ERR_SEMICOLON_EXPECTED);
+		}
+
+		if (!inAttribute) {
+			int length = fEntities.length;
+			for (int i = 0; i < length; i++) {
+				if (fEntities[i] == ent) { // 'ent' is interned by
+					// parse_identifier() function
+					sb.append(fEnt_chars[i]);
+					return true;
+				}
+			}
+		}
+
+		sb.append('&');
+		if (ent != null) {
+			sb.append(ent);
+		}
+		sb.append(';');
+
+		return true;
+	}
+
+	/**
+	 * Parses a CharReference and if it is successful then appends it to the
+	 * passed CharBuffer
+	 * 
+	 * @param sb
+	 *            CharBuffer that the parsed CharReference will be added to
+	 * @return true on success and false otherwise
+	 * @throws IOException
+	 */
+	protected boolean parse_CharRef(CharBuffer sb) throws IOException {
+		if (accept_char('#')) {
+			// TODO - Postponed...
+			while (currentChar != ';') {
+				getNextChar();
+			}
+
+			if (!accept_char(';')) {
+				err(fPos - 1, ERR_SEMICOLON_EXPECTED);
+			}
+
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Clears the white spaces starting from the current position
+	 * 
+	 * @throws IOException
+	 */
+	protected void clearWhiteSpaces() throws IOException {
+		while (Character.isWhitespace(currentChar)) {
+			if (!getNextChar())
+				break;
+		}
+	}
+
+	/**
+	 * Throws an IOException with a given message. The current line number and
+	 * line position are appended to the error message
+	 * 
+	 * @param message
+	 *            The message of the exception
+	 * @throws IOException
+	 */
+	protected void err(String message) throws IOException {
+		err(fPos, message);
+	}
+
+	/**
+	 * Throws an IOException with the given message for the given line position.
+	 * The current line number and position (pos) are appended to the exception
+	 * message
+	 * 
+	 * @param pos
+	 *            The line position that the error will be reported for
+	 * @param message
+	 * @throws IOException
+	 */
+	protected void err(int pos, String message) throws IOException {
+		throw new IOException("[Line: " + fLine + ", Pos: " + pos + "]  " + message);
+	}
+
+	/**
+	 * Initiates parsing of the XML file given through aInputStream or aReader
+	 * in the given constructor when creating XMLReader object.
+	 * 
+	 * @throws IOException
+	 *             if an error occurs during reading the XML file or if a
+	 *             parsing error eccurs.
+	 */
+	protected void parseXML() throws IOException {
+		TagClass rootTag = new TagClass();
+
+		try {
+			getNextChar();
+			clearWhiteSpaces();
+
+			boolean start = false;
+
+			while (accept_char('<')) {
+				start = true;
+				int pos = fPos;
+
+				if (fPos == 2 && fLine == 1) {
+					if (parse_xml_prolog(rootTag)) {
+						// System.out.println("XML Prolog found.");
+						// System.out.println("XML Version: " + fVersion + ",
+						// encoding: " + fEncoding);
+						setEncoding(fEncoding);
+						clearWhiteSpaces();
+						continue;
+					}
+				} else {
+					setEncoding(fDefaultEncoding);
+				}
+
+				if (!parse_tag_special(rootTag)) {
+					if (parse_tag_normal(rootTag)) {
+						// TODO da se proveri dali e dostignat kraja na file-a,
+						// ako ne e -
+						// togava ot tuk natatuk moje da ima samo komentari.
+						return;
+					}
+					err(pos, ERR_TAGNAME2_EXPECTED);
+				}
+
+				clearWhiteSpaces();
+			}
+
+			if (!start) {
+				err(ERR_LT_EXPECTED);
+			}
+		} catch (IOException ioe) {
+			if (fDebug) {
+				ioe.printStackTrace(System.err);
+			}
+
+			throw ioe;
+		}
+	}
+
+	/**
+	 * Parses a XML file given through aInputStream and during the parsing
+	 * notifies aListener for close-tag events <br>
+	 * <br>
+	 * <b>Note: The XMLReader does not close the passed Reader or InputStream
+	 * 
+	 * @param aInputStream
+	 *            an InputStream to read the XML file from
+	 * @param aListener
+	 *            TagListener that will be notified on close-tag event
+	 * @param aLevel
+	 *            see parseXML(Reader aReader, TagListener aListener, int aLevel
+	 *            description
+	 * @throws IOException
+	 *             if some IO error occurs when reading the XML file or if a
+	 *             parser error occurs.
+	 */
+	public static void parseXML(InputStream aInputStream, TagListener aListener, int aLevel) throws IOException {
+		XMLReader xml = new XMLReader(aInputStream, aListener);
+		xml.setLevel(aLevel);
+		xml.parseXML();
+	}
+
+	/**
+	 * Parses a XML file given through aReader and during the parsing notifies
+	 * aListener for close-tag events <br>
+	 * <br>
+	 * <b>Note: The XMLReader does not close the passed Reader or InputStream
+	 * 
+	 * @param aReader
+	 *            a reader that will be used to read the XML file from
+	 * @param aListener
+	 *            TagListener that will be notified on close-tag event
+	 * @param aLevel
+	 *            indicates the tag level that the listener will be invoked for.
+	 *            For example if the XML is:<br>
+	 * 
+	 * <pre>
+	 *  &lt;a&gt;
+	 *    &lt;b&gt;
+	 *      &lt;c /&gt;
+	 *    &lt;/b&gt;
+	 *  &lt;/a&gt;
+	 * </pre>
+	 * 
+	 * <br>
+	 *            and the passed aLevel is 2 then the listener will be invoked
+	 *            only for tags that have level 2, i.e. in our example the
+	 *            listener will be invoked only for tag &lt;b&gt;<br>
+	 *            <ul>
+	 *            <li>Value less than 0 indicates &quot;invoke listener for all
+	 *            tags no matter what are their levels&quot;</li>
+	 *            <li>Value of 0 indicates that the listener must not be
+	 *            invoked in general no matter what is the tag level</li>
+	 *            <li>Value greater than 0 indicates the tag level that the
+	 *            listener will be invoked for</li>
+	 * @throws IOException
+	 *             if some IO error occurs when reading the XML file or if a
+	 *             parser error occurs.
+	 */
+	public static void parseXML(Reader aReader, TagListener aListener, int aLevel) throws IOException {
+		XMLReader xml = new XMLReader(aReader, aListener);
+		xml.setLevel(aLevel);
+		xml.parseXML();
+	}
+
+	/**
+	 * Returns the XML version attribute
+	 * 
+	 * @return the XML file version attribute
+	 */
+	public String getVersion() {
+		return fVersion;
+	}
+
+	/**
+	 * Returns the XML encoding attribute
+	 * 
+	 * @return the XML encoding attribute
+	 */
+	public String getEncoding() {
+		return fEncoding;
+	}
+
+	/**
+	 * Returns the value of XML standalone attribute
+	 * 
+	 * @return the value of XML standalone attribute
+	 */
+	public String getStandalone() {
+		return fStandalone;
+	}
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/XMLUtil.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/XMLUtil.java
new file mode 100644
index 0000000..96f188f
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/XMLUtil.java
@@ -0,0 +1,363 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.util.xml;
+
+import java.util.Vector;
+
+import org.eclipse.equinox.internal.util.string.CharBuffer;
+
+/**
+ *  Class with utility methods for extracting attributes from xml tags
+ *  
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public class XMLUtil {
+
+	/**
+	 * Coded chars placed in the xml content.
+	 */
+	public static String[] coded = {"&amp;", "&nbsp;", "&crlf;", "&tab;", "&lt;", "&gt;", "&quot;", "&apos;"};
+
+	/**
+	 * Corresponding decoded chars. First five of them cannot exist in plain
+	 * (decoded) form in the xml content, but the rest can be eighter coded or
+	 * decoded
+	 */
+	public static String[] decoded = {"&", " ", "\n", "\t", "<", ">", "\"", "'"};
+
+	/**
+	 * Replaces specified strings in a source string with corresponding strings
+	 * 
+	 * @param str
+	 *            source string
+	 * @param toBeReplaced
+	 *            array of strings which will be replaced with the next
+	 *            parameter
+	 * @param replaceWith
+	 *            array of the strings corresponding to "toBeReplaced"
+	 *            parameter. the length should be equal
+	 * @param length
+	 *            specify how many parameters of the string array will be
+	 *            replaced, the rest of "toBeReplaced" parameter will not.
+	 * @return replaced string
+	 */
+	public static String replaceChars(String str, String[] toBeReplaced, String[] replaceWith, int length) {
+
+		/*
+		 * first 5 characters are not allowed to exists in such form in xml, the
+		 * rest remains the same
+		 */
+		CharBuffer strBuf;
+		for (int i = 0; i < length; i++) {
+			strBuf = new CharBuffer();
+			replace(str, toBeReplaced[i], replaceWith[i], strBuf);
+			str = strBuf.toString();
+		}
+		return str;
+	}
+
+	/**
+	 * Replaces a specified string in a source string with a corresponding
+	 * string and adds the result in a buffer.
+	 * 
+	 * @param src
+	 *            source string
+	 * @param toBeReplaced
+	 *            string which will be replaced with the next parameter
+	 * @param toReplaceWith
+	 *            the string corresponding to "toBeReplaced" parameter.
+	 * @param strBuf
+	 *            here is added the replaced source string.
+	 */
+	public static void replace(String src, String toBeReplaced, String toReplaceWith, CharBuffer strBuf) {
+
+		int j;
+		int pos = 0;
+		int length = toBeReplaced.length();
+		while (((j = src.indexOf(toBeReplaced, pos)) > -1)) {
+			strBuf.append(src.substring(pos, j));
+			strBuf.append(toReplaceWith);
+			pos = j + length;
+		}
+		strBuf.append(src.substring(pos));
+	}
+
+	/**
+	 * Converts special xml chars to valid string e.g. "&amp;lt;" becomes "<"
+	 * and "&amp;gt;" becomes ">"
+	 * 
+	 * @param src
+	 *            source string which is coded
+	 * @return decoded string
+	 */
+	public static String getDecoded(String src) {
+		int begin = src.indexOf('&');
+		if (begin == -1) {
+			/*
+			 * improve speed when there is not any coded string (each coded
+			 * string begins with '&')
+			 */
+			return src;
+		}
+		int end = src.indexOf(';', begin);
+		if (end == -1) {
+			/*
+			 * improve speed when there is not any coded string (each coded
+			 * string ends with ';')
+			 */
+			return src;
+		}
+		int lastBegin = 0;
+		CharBuffer strBuf = new CharBuffer();
+		while (begin != -1) {
+			end = src.indexOf(';', begin); /*
+													 * this is used on the second turn
+													 * of the cycle
+													 */
+			if (end == -1) {
+				strBuf.append(src.substring(begin));
+				return strBuf.toString();
+			}
+			strBuf.append(src.substring(lastBegin, begin));
+			String part = src.substring(begin, end + 1);
+			boolean found = false;
+			for (int i = 0; i < decoded.length; i++) {
+				if (part.equals(coded[i])) {
+					strBuf.append(decoded[i]);
+					begin += part.length();
+					lastBegin = begin;
+					begin = src.indexOf('&', lastBegin);
+					found = true;
+					break; /*
+											 * one word replaced, go on searching with rest of
+											 * the src
+											 */
+				}
+			}
+			if (!found) {
+				strBuf.append(part);
+				begin += part.length();
+				lastBegin = begin;
+				begin = src.indexOf('&', begin);
+			}
+		}
+		strBuf.append(src.substring(lastBegin));
+		return strBuf.toString().intern();
+	}
+
+	/**
+	 * Extracts the name of the tag, from string containing the name and
+	 * attributes
+	 * 
+	 * @param tagAndAttributes
+	 *            string containing the name and attributes
+	 * @return tag name string separated by space from the tag attributes
+	 * @deprecated use TagClass.getName() instead
+	 */
+	public static String getTagName(String tagAndAttributes) {
+		int nameIndex = tagAndAttributes.indexOf(' ');
+		if (nameIndex != -1) {
+			int tabIndex = tagAndAttributes.indexOf('\t');
+			if (tabIndex > -1 && tabIndex < nameIndex) {
+				return tagAndAttributes.substring(0, tabIndex);
+			}
+			return tagAndAttributes.substring(0, nameIndex);
+		}
+
+		nameIndex = tagAndAttributes.indexOf('/');
+		if (nameIndex != -1) {
+			return tagAndAttributes.substring(0, nameIndex);
+		}
+		return tagAndAttributes;
+	}
+
+	public static boolean isEmptyTag(String tagName) {
+		return '/' == tagName.charAt(tagName.length() - 1);
+	}
+
+	/**
+	 * Checks whether the tag name string between &lt; and &gt;, ends with "/".
+	 * 
+	 * @param tagName
+	 *            string between &lt; and &gt; chars
+	 * @return true if and only if string ends with "/"
+	 */
+
+	protected static final String[] f_entities = {"amp", "nbsp", "crlf", "tab", "lt", "gt", "quot", "apos"};
+	protected static final char[] f_ent_chars = {'&', ' ', '\n', '\t', '<', '>', '"', '\''};
+
+	private static boolean substituteEntity(String ent, CharBuffer cb) {
+		for (int j = 0; j < f_entities.length; j++) {
+			if (f_entities[j].equals(ent)) {
+				cb.append(f_ent_chars[j]);
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Extracts an attribute value for a specified attribute name from tag
+	 * string.
+	 * 
+	 * @param tag
+	 *            whole tag name
+	 * @param att
+	 *            attribute name
+	 * @return value of the attribute if exists otherwise return null
+	 * @deprecated use TagClass.getAttrList() and TagClass.getAttribute(String
+	 *             attr) instead
+	 */
+	public static String getAttributeValue(String tag, String att, int begin) {
+		if (att.length() == 0)
+			return null;
+
+		int start = 0;
+		while (start >= 0) {
+			start = tag.indexOf(att, start);
+
+			if (start >= 0) {
+				// Checks if leading and trailing chars are valid attr_name
+				// chars
+				boolean b1 = (start > 0) ? XMLReader.isNameChar(tag.charAt(start - 1)) : true;
+				boolean b2 = ((start + att.length() + 1) < tag.length()) ? XMLReader.isNameChar(tag.charAt(start + att.length())) : true;
+
+				start += att.length();
+				if (!b1 && !b2) {
+					start = tag.indexOf('=', start) + 1;
+					if (start <= 0)
+						return null;
+
+					while (start < tag.length() && Character.isWhitespace(tag.charAt(start))) {
+						start++;
+					}
+
+					char quot = tag.charAt(start);
+					int end = tag.indexOf(quot, start + 1);
+					if ((start != -1) && (end > start)) {
+						int pos = tag.indexOf('&', start + 1);
+						if (pos < 0 || pos > end)
+							return tag.substring(start + 1, end).intern();
+
+						CharBuffer cb = new CharBuffer();
+
+						char ch;
+						for (int i = (start + 1); i < end; i++) {
+							ch = tag.charAt(i);
+							if (ch == '&') {
+								pos = tag.indexOf(';', i);
+								String ent = tag.substring(i + 1, pos);
+
+								if (substituteEntity(ent, cb)) {
+									i = pos;
+									continue;
+								}
+
+								cb.append('&');
+								cb.append(ent);
+								cb.append(';');
+								i = pos;
+								continue;
+							}
+							cb.append(ch);
+						}
+
+						return cb.toString().intern();
+					}
+					start = end;
+				}
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Extracts attribute names from tag string.
+	 * 
+	 * @param tag
+	 *            whole tag name
+	 * @return A vector with all attribute names
+	 * @deprecated use TagClass.getAttrList() instead
+	 */
+	public static Vector getAttributeNames(String tag) {
+		Vector names = new Vector();
+		int start = tag.indexOf(' '); /* avoid name of this tag */
+		int end;
+		while (start != -1) {
+			end = tag.indexOf('=', start + 1);
+			if (end == -1) {
+				break;
+			}
+			names.addElement(tag.substring(start + 1, end));
+			start = tag.indexOf('"', end + 1);
+			if (start == -1) {
+				break;
+			}
+			start = tag.indexOf('"', start + 1);
+			if (start == -1) {
+				break;
+			}
+			start = tag.indexOf(' ', start + 1);
+		}
+		return names;
+	}
+
+	/**
+	 * Extracts attribute values from tag string.
+	 * 
+	 * @param tag
+	 *            whole tag name
+	 * @return A vector with all attribute values
+	 * @deprecated use TagClass.getAttrList() instead
+	 */
+	public static Vector getAttributeValues(String tag) {
+		Vector values = new Vector();
+		int start = tag.indexOf('=');
+		int end;
+		while (start != -1) {
+			start = tag.indexOf('"', start + 1);
+			end = tag.indexOf('"', start + 1);
+			if ((start == -1) || (end == -1)) {
+				break;
+			}
+			values.addElement(tag.substring(start + 1, end).intern());
+			start = tag.indexOf('=', end + 1);
+		}
+		return values;
+	}
+
+	/**
+	 * Returns content of the specified subtag.
+	 * 
+	 * @param tag
+	 *            parent tag
+	 * @param pos
+	 *            position of the searched tag in child array of the parent tag
+	 * @param name
+	 *            name of the searched tag
+	 * @return content of the specified subtag
+	 * @exception IllegalArgumentException
+	 *                if the specified name does not match the name of the tag
+	 *                at specified position
+	 * @deprecated use TagClass.getContent(int pos, String name) instead
+	 */
+
+	public static String getContent(TagClass tag, int pos, String name) throws IllegalArgumentException {
+		TagClass subTag = tag.getTagAt(pos);
+		if (subTag.getName().equals(name)) {
+			return subTag.getContent();
+		}
+		throw new IllegalArgumentException("Missing subtag " + name + " in " + tag.getName());
+	}
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/XmlSerializer.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/XmlSerializer.java
new file mode 100644
index 0000000..80a9fff
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/XmlSerializer.java
@@ -0,0 +1,444 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.util.xml;
+
+import java.io.*;
+import java.util.Vector;
+
+/**
+ * XmlSerializer is an utility class, that simplifies creation of XML files. It
+ * is designed to be similar to the XML Pull API serializer.
+ * 
+ * @author Valentin Valchev
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public class XmlSerializer {
+
+	private Writer writer; // underlying writer
+	private Vector stack; // of XML entity names
+	private StringWriter attrsWriter; // current attribute writer
+	private StringBuffer attrs; // current attribute string
+	private boolean empty; // is the current node empty
+	private boolean closed; // is the current node closed...
+	private String indentString;
+	private boolean prologWritten;
+
+	/**
+	 * Opens and initializes XML output on top of existing Writer.
+	 * 
+	 * @param writer
+	 *            the output writer
+	 * @return self
+	 */
+	public XmlSerializer setOutput(Writer writer) {
+		this.writer = writer;
+		this.closed = true;
+		this.prologWritten = false;
+		if (stack == null) {
+			stack = new Vector(5);
+		} else {
+			stack.removeAllElements();
+		}
+		if (attrs != null) {
+			attrs.setLength(0);
+		}
+		return this;
+	}
+
+	/**
+	 * Set to use binary output stream with given encoding.
+	 * 
+	 * @param os
+	 *            the output stream
+	 * @param encoding
+	 *            the output encoding
+	 * @throws IOException
+	 * @see #setOutput(Writer)
+	 * @throws NullPointerException
+	 *             is output stream is null
+	 */
+	public void setOutput(OutputStream os, String encoding) throws IOException {
+		if (os == null)
+			throw new NullPointerException("output stream can not be null");
+		Writer writer = encoding != null ? //
+		new OutputStreamWriter(os, encoding)
+				: //
+				new OutputStreamWriter(os);
+		setOutput(writer);
+	}
+
+	/**
+	 * Writes XML prolog code:
+	 * 
+	 * <pre>
+	 *        &lt;?xml version=&quot;1.0&quot;?&gt;
+	 * </pre>
+	 * 
+	 * @param encoding
+	 *            the selected encoding. If <code>null</code> encoding
+	 *            attribute is not written.
+	 * @param standalone
+	 *            if the XML is stand-alone, no DTD or schema
+	 * @return self
+	 * @throws IOException
+	 *             on I/O error
+	 * @throws IllegalStateException
+	 *             if prolog code is already written
+	 */
+	public XmlSerializer startDocument(String encoding, Boolean standalone) throws IOException {
+		if (prologWritten) {
+			throw new IllegalStateException("Prolog already written");
+		}
+		writer.write("<?xml version=\"1.0\"");
+		if (encoding != null) {
+			writer.write(" encoding=\"");
+			writer.write(encoding);
+			writer.write("\"");
+		}
+		if (standalone != null) {
+			writer.write(" standalone=\"");
+			writer.write(standalone.booleanValue() ? "yes" : "no");
+			writer.write("\"");
+		}
+		writer.write("?>");
+		prologWritten = true;
+		return this;
+	}
+
+	/**
+	 * Close this writer. It does not close the underlying writer, but does
+	 * throw an exception if there are as yet unclosed tags.
+	 * 
+	 * @throws IllegalStateException
+	 *             if tags are not closed
+	 */
+	public void endDocument() {
+		if (!stack.isEmpty()) {
+			throw new IllegalStateException("Tags are not all closed. Possibly, '" + pop() + "' is unclosed. ");
+		}
+	}
+
+	/**
+	 * Returns the current depth of the element. Outside the root element, the
+	 * depth is 0. The depth is incremented by 1 when startTag() is called. The
+	 * depth is decremented after the call to endTag() event was observed.
+	 * 
+	 * <pre>
+	 *        &lt;!-- outside --&gt;     0
+	 *        &lt;root&gt;               1
+	 *          sometext                 1
+	 *            &lt;foobar&gt;         2
+	 *            &lt;/foobar&gt;        2
+	 *        &lt;/root&gt;              1
+	 *        &lt;!-- outside --&gt;     0
+	 * </pre>
+	 * 
+	 * @return the current level
+	 */
+	public int getDepth() {
+		return stack.size();
+	}
+
+	/**
+	 * Begin to output an entity.
+	 * 
+	 * @param name
+	 *            name of entity.
+	 * @return self
+	 * @throws IOException
+	 *             on I/O error
+	 */
+	public XmlSerializer startTag(String name) throws IOException {
+		if (!prologWritten) {
+			startDocument(null, null);
+		}
+		closeOpeningTag();
+		closed = false;
+		indent();
+		writer.write("<");
+		writer.write(name);
+		stack.addElement(name);
+		empty = true;
+		return this;
+	}
+
+	/**
+	 * End the current entity silently without validating if correct tag is
+	 * closed.
+	 * 
+	 * @return self
+	 * @throws IOException
+	 * @deprecated see {@link #endTag(String)}
+	 */
+	public XmlSerializer endTag() throws IOException {
+		return endTag(null);
+	}
+
+	/**
+	 * End the current entity. This will throw an exception if it is called when
+	 * there is not a currently open entity.
+	 * 
+	 * @param aName
+	 *            tag to close. This is used mostly for validation
+	 * @return self
+	 * @throws IOException
+	 *             on I/O error
+	 * @throws IllegalStateException
+	 *             if no entity waits to be closed
+	 * @throws IllegalArgumentException
+	 *             if expected element name is not the same
+	 */
+	public XmlSerializer endTag(String aName) throws IOException {
+
+		if (stack.isEmpty()) {
+			throw new IllegalStateException("Called endEntity too many times.");
+		}
+		String name = pop();
+		if (name != null) {
+			if (aName != null && !aName.equals(name)) {
+				throw new IllegalArgumentException("Expected element name '" + name + "', not '" + aName + "'");
+			}
+			if (empty) {
+				writeAttributes();
+				writer.write("/>");
+			} else {
+				indent();
+				writer.write("</");
+				writer.write(name);
+				writer.write(">");
+			}
+			empty = false;
+		}
+		return this;
+	}
+
+	/**
+	 * Write an attribute out for the current entity. Any XML characters in the
+	 * value are escaped. Calls to attribute() MUST follow a call to startTag()
+	 * immediately.
+	 * 
+	 * @param localName
+	 *            name of attribute.
+	 * @param value
+	 *            value of attribute.
+	 * @return self
+	 * @throws IOException
+	 *             on I/O error
+	 * @throws IllegalStateException
+	 *             if opening tag is closed
+	 */
+	public XmlSerializer attribute(String localName, String value) throws IOException {
+		if (closed) {
+			throw new IllegalStateException("Opening tag is already closed");
+		}
+		if (localName == null) {
+			throw new IllegalArgumentException("Attribute name is null");
+		}
+		if (value == null)
+			value = "";
+		if (attrsWriter == null) {
+			attrsWriter = new StringWriter();
+			attrs = attrsWriter.getBuffer();
+		}
+		attrs.append(" ");
+		attrs.append(localName);
+		attrs.append("=\"");
+		writeEscape(value, attrsWriter);
+		attrs.append("\"");
+		return this;
+	}
+
+	/**
+	 * Output body text. Any XML characters are escaped.
+	 * 
+	 * @param text
+	 *            the body text
+	 * @return self
+	 * @throws IOException
+	 *             on I/O error
+	 */
+	public XmlSerializer text(String text) throws IOException {
+		closeOpeningTag();
+		if (text != null && text.length() > 0) {
+			indent();
+			empty = false;
+			writeEscape(text, writer);
+		}
+		return this;
+	}
+
+	/**
+	 * Writes raw, CDATA section
+	 * 
+	 * @param text
+	 *            the data
+	 * @return self
+	 * @throws IOException
+	 *             on I/O error
+	 */
+	public XmlSerializer cdsect(String text) throws IOException {
+		closeOpeningTag();
+		writer.write("<![CDATA[");
+		writer.write(text);
+		writer.write("]]>");
+		return this;
+	}
+
+	/**
+	 * Writes XML comment code
+	 * 
+	 * @param text
+	 *            the comment
+	 * @return self
+	 * @throws IOException
+	 *             on I/O error
+	 */
+	public XmlSerializer comment(String text) throws IOException {
+		closeOpeningTag();
+		writer.write("<!--");
+		writer.write(text);
+		writer.write("-->");
+		return this;
+	}
+
+	/**
+	 * Writes DOCTYPE declaration. The document must be open prior calling that
+	 * method.
+	 * 
+	 * @param text
+	 *            declaration
+	 * @return self
+	 * @throws IOException
+	 *             on I/O error
+	 * @throws IllegalStateException
+	 *             if document is not open or start tag is already started
+	 */
+	public XmlSerializer docdecl(String text) throws IOException {
+		if (!prologWritten) {
+			throw new IllegalStateException("Document is not open");
+		}
+		if (getDepth() != 0) {
+			throw new IllegalStateException("Cannot add DOCTYPE after start tag has been opened!");
+		}
+		closeOpeningTag();
+		writer.write("<!DOCTYPE");
+		writer.write(text);
+		writer.write(">");
+		return this;
+	}
+
+	/**
+	 * Enables/disables indentation
+	 * 
+	 * @param indent
+	 *            an indentation string or <code>null</code> to disable
+	 *            indentation.
+	 */
+	public void setIndent(boolean indent) {
+		this.indentString = indent ? "\t" : null;
+	}
+
+	// close off the opening tag
+	private void closeOpeningTag() throws IOException {
+		if (!this.closed) {
+			writeAttributes();
+			closed = true;
+			writer.write(">");
+		}
+	}
+
+	// write out all current attributes
+	private void writeAttributes() throws IOException {
+		if (attrs != null) {
+			writer.write(attrs.toString());
+			attrs.setLength(0);
+			empty = false;
+		}
+	}
+
+	private final String pop() {
+		int location = stack.size() - 1;
+		String ret = (String) stack.elementAt(location);
+		stack.removeElementAt(location);
+		return ret;
+	}
+
+	private final void indent() throws IOException {
+		if (indentString != null) {
+			writer.write('\n');
+			for (int i = 0; i < stack.size(); i++) {
+				writer.write(indentString);
+			}
+		}
+	}
+
+	private final void writeEscape(String text, Writer out) throws IOException {
+		// escape '<', '&', '>', ', "
+		char[] buf = text.toCharArray();
+		int len = buf.length;
+		int pos = 0;
+		for (int i = 0; i < len; i++) {
+			final char ch = buf[i];
+
+			if (ch == '&') {
+				if (i > pos)
+					out.write(buf, pos, i - pos);
+				out.write("&amp;");
+				pos = i + 1;
+			} else if (ch == '<') {
+				if (i > pos)
+					out.write(buf, pos, i - pos);
+				out.write("&lt;");
+				pos = i + 1;
+			} else if (ch == '>') {
+				if (i > pos)
+					out.write(buf, pos, i - pos);
+				out.write("&gt;");
+				pos = i + 1;
+			} else if (ch == '"') {
+				if (i > pos)
+					out.write(buf, pos, i - pos);
+				out.write("&guot;");
+				pos = i + 1;
+			} else if (ch == '\'') {
+				if (i > pos)
+					out.write(buf, pos, i - pos);
+				out.write("&apos;");
+				pos = i + 1;
+			} else if (ch < 32) {
+				// in XML 1.0 only legal character are #x9 | #xA | #xD
+				if (ch == 9 || ch == 10 || ch == 13) {
+					// pass through
+				} else {
+					throw new IllegalStateException("character " + ch + " (" + Integer.toString(ch) + ") is not allowed in output");
+				}
+			}
+		}
+		if (len > pos) {
+			out.write(buf, pos, len - pos);
+		}
+	}
+
+	/*
+	 * public static void main(String[] args) throws IOException { XmlSerializer
+	 * o = new XmlSerializer(); Writer x = new java.io.StringWriter();
+	 * o.setIndent(true); o.setOutput(x); o.startDocument("UTF-8", null)//
+	 * .startTag("test")// .startTag("inner")// .attribute("attribute",
+	 * "value").text("text & ' < > \\\" ;[")// .comment("this is an embedded
+	 * comment inside the inner body")// .endTag("inner")//
+	 * .startTag("entry").cdsect("testing [] > < & ;").endTag("entry")//
+	 * .endTag("test")// .endDocument(); System.out.println(x); }
+	 */
+
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/impl/TagImpl.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/impl/TagImpl.java
new file mode 100644
index 0000000..2ecd239
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/impl/TagImpl.java
@@ -0,0 +1,381 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.util.xml.impl;
+
+import java.io.*;
+import java.util.*;
+import org.eclipse.equinox.internal.util.string.CharBuffer;
+import org.eclipse.equinox.internal.util.xml.Tag;
+
+/**
+ * @author Ivan Dimitrov
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public class TagImpl implements Tag {
+
+	private CharBuffer fContent = null;
+	private String fContentString = null;
+	private String fName = null;
+	private Hashtable fAttributes = null;
+	private Vector fTags = null;
+	private int fLine = -1;
+	protected boolean fInline = false;
+
+	/**
+	 * A hashtable enumerator class for empty hash tables, specializes the
+	 * general Enumerator
+	 */
+	private static Enumeration fEmptyEnumeration = new Enumeration() {
+		public boolean hasMoreElements() {
+			return false;
+		}
+
+		public Object nextElement() {
+			throw new NoSuchElementException("Hashtable Enumerator");
+		}
+	};
+
+	/**
+	 * 
+	 */
+	public TagImpl() {
+		super();
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.equinox.internal.util.xml.Tag#getAttribute(java.lang.String)
+	 */
+	public String getAttribute(String aAttrName) {
+		return (String) ((fAttributes != null) ? fAttributes.get(aAttrName) : null);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.equinox.internal.util.xml.Tag#getAttributes()
+	 */
+	public Enumeration getAttributeNames() {
+		return (fAttributes != null) ? fAttributes.keys() : fEmptyEnumeration;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.equinox.internal.util.xml.Tag#getAttributeValues()
+	 */
+	public Enumeration getAttributeValues() {
+		return (fAttributes != null) ? fAttributes.elements() : fEmptyEnumeration;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.equinox.internal.util.xml.Tag#getName()
+	 */
+	public String getName() {
+		return fName;
+	}
+
+	/**
+	 * @see org.eclipse.equinox.internal.util.xml.Tag#getContent() note: The content that
+	 *      is to be returned will be trimmed first
+	 */
+	public String getContent() {
+		if (fContentString != null) {
+			return fContentString;
+		} else if (fContent != null) {
+			fContentString = fContent.trim();
+			fContent = null;
+			return fContentString;
+		}
+		return "";
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.equinox.internal.util.xml.Tag#getLine()
+	 */
+	public int getLine() {
+		return fLine;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.equinox.internal.util.xml.Tag#size()
+	 */
+	public int size() {
+		return (fTags != null) ? fTags.size() : 0;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.equinox.internal.util.xml.Tag#getTagAt(int)
+	 */
+	public Tag getTagAt(int aPosition) {
+		return (Tag) fTags.elementAt(aPosition);
+	}
+
+	protected void setName(String aName) {
+		fName = aName;
+	}
+
+	protected void addAttribute(String aAttrName, String aAttrValue) {
+		if (fAttributes == null) {
+			fAttributes = new Hashtable(1);
+		}
+		fAttributes.put(aAttrName, aAttrValue);
+	}
+
+	protected void addTag(Tag aTag) {
+		if (fTags == null) {
+			fTags = new Vector(2, 3);
+		}
+		fTags.addElement(aTag);
+	}
+
+	protected void appendContent(CharBuffer toAppend) {
+		if (fContent == null) {
+			fContent = new CharBuffer(toAppend.length());
+		}
+		fContent.append(toAppend.getValue());
+	}
+
+	protected void appendContent(String toAppend) {
+		if (fContent == null) {
+			fContent = new CharBuffer(toAppend.length());
+		}
+		fContent.append(toAppend);
+	}
+
+	protected CharBuffer getContentBuffer() {
+		if (fContent == null) {
+			fContent = new CharBuffer(5);
+		}
+		return fContent;
+	}
+
+	protected void setLine(int aLine) {
+		fLine = aLine;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.equinox.internal.util.xml.Tag#getContent(int, java.lang.String)
+	 */
+	public String getContent(int aPos, String aName) {
+		Tag child = getTagAt(aPos);
+		if (child == null)
+			throw new NullPointerException("There is no such a tag. [Parent tag name] = [" + aName + "], [child tag index] = " + aPos + ", [child tag name] = [" + aName + ']');
+
+		if (child.getName().equals(aName))
+			return child.getContent();
+
+		throw new IllegalArgumentException("There is no such a tag. [Parent tag name] = [" + aName + "], [child tag index] = " + aPos + ", [child tag name] = [" + aName + ']');
+	}
+
+	/* begin serialization see FR [ 13325 ] XML: Make Tag externalizable */
+
+	/**
+	 * @see org.eclipse.equinox.internal.util.io.Externalizable#readObject(java.io.InputStream)
+	 */
+	public void readObject(InputStream is) throws Exception {
+		if (!(is instanceof ObjectInput)) {
+			is = new ObjectInputStream(is);
+		}
+		readExternal((ObjectInput) is);
+	}
+
+	/**
+	 * @see org.eclipse.equinox.internal.util.io.Externalizable#writeObject(java.io.OutputStream)
+	 */
+	public void writeObject(OutputStream os) throws Exception {
+		if (!(os instanceof ObjectOutput)) {
+			os = new ObjectOutputStream(os);
+		}
+		writeExternal((ObjectOutput) os);
+		os.flush();
+	}
+
+	/**
+	 * @param input
+	 * @throws IOException
+	 * @throws ClassNotFoundException
+	 */
+	public void readExternal(ObjectInput input) throws IOException, ClassNotFoundException {
+		fName = input.readUTF();
+		/* read content */
+		boolean hasContent = input.readBoolean();
+		if (hasContent) {
+			fContentString = input.readUTF();
+		}
+		int size;
+		/* read attributes */
+		size = input.readInt();
+		if (size > 0) {
+			fAttributes = new Hashtable(size, 1);
+			for (int i = 0; i < size; i++) {
+				String key = input.readUTF();
+				String val = input.readUTF();
+				fAttributes.put(key, val);
+			}
+		}
+		/* read elements */
+		size = input.readInt();
+		if (size > 0) {
+			fTags = new Vector(size);
+			for (int i = 0; i < size; i++) {
+				TagImpl tag = new TagImpl();
+				tag.readExternal(input);
+				fTags.addElement(tag);
+			}
+		}
+	}
+
+	/**
+	 * @param output
+	 * @throws IOException
+	 */
+	public void writeExternal(ObjectOutput output) throws IOException {
+		output.writeUTF(fName);
+		/* write content */
+		String content = null;
+		if (fContentString != null) {
+			content = fContentString;
+		} else if (fContent != null) {
+			content = fContent.trim();
+		}
+		if (content != null) {
+			output.writeBoolean(true);
+			output.writeUTF(content);
+		} else {
+			output.writeBoolean(false);
+		}
+		/* write attributes */
+		if (fAttributes != null) {
+			output.writeInt(fAttributes.size());
+			for (Enumeration e = fAttributes.keys(); e.hasMoreElements();) {
+				String key = (String) e.nextElement();
+				String val = (String) fAttributes.get(key);
+				output.writeUTF(key);
+				output.writeUTF(val);
+			}
+		} else {
+			output.writeInt(0);
+		}
+		/* write elements */
+		if (fTags != null) {
+			output.writeInt(fTags.size());
+			for (int i = 0, size = fTags.size(); i < size; i++) {
+				TagImpl current = (TagImpl) fTags.elementAt(i);
+				current.writeExternal(output);
+			}
+		} else {
+			output.writeInt(0);
+		}
+		output.flush();
+	}
+
+	/* begin simple, utility method for debugging */
+
+	/**
+	 * Writes the tag as formatted XML into the given writer.
+	 * 
+	 * @param out
+	 *            the output writer, where tag is serialized to XML
+	 * @param level
+	 *            the initial level. If set to negative value, the indent
+	 *            /formatting/ of the XML is disable, and it is written on a
+	 *            single line. Otherwise, the level is used to calculate the
+	 *            offset from the left margin.
+	 * @throws IOException
+	 *             on I/O error
+	 */
+	public void writeXml(Writer out, int level) throws IOException {
+		boolean indent = level >= 0;
+		for (int i = 0; indent && i < level; i++)
+			out.write(' '); /* indent */
+		out.write('<');
+		out.write(fName);
+		if (fAttributes != null) {
+			for (Enumeration e = fAttributes.keys(); e.hasMoreElements();) {
+				out.write(' ');
+				String key = (String) e.nextElement();
+				String val = (String) fAttributes.get(key);
+				out.write(key);
+				out.write("=\"");
+				out.write(val);
+				out.write('"');
+			}
+		}
+		/* don't use getContent() - this will demolish the buffer */
+		String content = null;
+		if (fContentString != null) {
+			content = fContentString;
+		} else if (fContent != null) {
+			content = fContent.trim();
+		}
+		boolean isShort = content == null && fTags == null;
+		if (isShort) {
+			/* close immediately */
+			out.write("/>");
+			if (indent)
+				out.write('\n');
+		} else {
+			out.write('>');
+			if (indent)
+				out.write('\n');
+			/* write elements */
+			for (int i = 0; fTags != null && i < fTags.size(); i++) {
+				TagImpl child = (TagImpl) fTags.elementAt(i);
+				child.writeXml(out, level < 0 ? -1 : (level + 1));
+			}
+			/* write contents */
+			if (content != null) {
+				for (int i = 0; indent && i < level + 1; i++)
+					out.write(' '); /* indent */
+				out.write(content);
+				if (indent)
+					out.write('\n');
+			}
+			/* write closing tag */
+			for (int i = 0; indent && i < level; i++)
+				out.write(' '); /* indent */
+			out.write("</");
+			out.write(fName);
+			out.write('>');
+			if (indent)
+				out.write('\n');
+		}
+	}
+
+	/**
+	 * @see java.lang.Object#toString()
+	 */
+	public String toString() {
+		StringWriter out = new StringWriter();
+		try {
+			writeXml(out, 0);
+		} catch (IOException e) {
+			/* this will never happen */
+		}
+		return out.toString();
+	}
+
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/impl/XMLParserImpl.java b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/impl/XMLParserImpl.java
new file mode 100644
index 0000000..a4947c3
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/impl/XMLParserImpl.java
@@ -0,0 +1,1219 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.util.xml.impl;
+
+import java.io.*;
+import org.eclipse.equinox.internal.ds.Activator;
+import org.eclipse.equinox.internal.util.string.CharBuffer;
+import org.eclipse.equinox.internal.util.xml.ExTagListener;
+
+/**
+ * <p>
+ * Class used for reading of xml files, creating tree structure of 'TagImpl' for
+ * each xml tag. When reader reaches a closed tag it notifies a given
+ * 'TagListener' and sends the last tag to it. If closing tag does not
+ * correspond with the last open IllegalArgumentException is thrown. There is a
+ * debug property 'xml.debug' used to dump an Exceptions occurred while
+ * operation is running.
+ * </p>
+ * 
+ * <p>
+ * The parser, in general, is a simple XML parser that implements
+ * &quot;Recursive descent&quot; parsing method.
+ * 
+ * Known limitations:<br>
+ * 
+ * <pre>
+ *  Currently this XMLParser does not support the following special tags:
+ *  1. &lt;?TAG_NAME ..... ?&gt;   or also &quot;Processing Instructions&quot;
+ *  2. &lt;!DOCTYPE .... &gt;
+ *  3. &lt;!ELEMENT .... &gt;
+ *  4. &lt;!ATTLIST .... &gt;
+ *  5. &lt;!ENTITY .... &gt;
+ * </pre>
+ * 
+ * <br>
+ * The parser skips these tags (it searches for '>' symbol and closes the
+ * 'special' tag).<br>
+ * 
+ * @author Ivan Dimitrov
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public class XMLParserImpl {
+
+	private static final String DEBUG = "xml.debug";
+	private static final String INTERN_ATTRIBUTES = "xml.intern.attributes";
+
+	private static final String CDATA = "CDATA";
+	private static final String XML = "xml";
+	private static final String VERSION = "version";
+	private static final String ENCODING = "encoding";
+	private static final String STANDALONE = "standalone";
+
+	private static final String ERR_EOS = "End-of-stream reached before the end of XML.";
+	private static final String ERR_ENTITY_EXPECTED = "Entity reference or Character reference expected.";
+	private static final String ERR_EQUAL_EXPECTED = "'=' expected.";
+	private static final String ERR_QUOT_EXPECTED = "''' or '\"' expected.";
+	private static final String ERR_GT_EXPECTED = "'>' expected.";
+	private static final String ERR_LT_EXPECTED = "'<' expected.";
+	private static final String ERR_CLOSE_TAG1_EXPECTED = "'/' or tag name expected.";
+	private static final String ERR_CLOSE_TAG2_EXPECTED = "'>', '/>' or more attributes expected.";
+	private static final String ERR_CLOSE_TAG3_EXPECTED = "'?>' expected.";
+	private static final String ERR_CONTENT_EXPECTED = "Content data, new tag or closing tag expected.";
+	private static final String ERR_QUESTIONMARK_EXPECTED = "'?' expected.";
+	private static final String ERR_ILLEGAL_CHARACTER = "Illegal character.";
+	private static final String ERR_TAGNAME_EXPECTED = "Tag name expected.";
+	private static final String ERR_TAGNAME2_EXPECTED = "Tag name, '?' or '!' expected.";
+	private static final String ERR_DASH_EXPECTED = "'-' expected.";
+	private static final String ERR_COMMENT_CLOSE_EXPECTED = "'-->' expected.";
+	private static final String ERR_CDATA_EXPECTED = "'CDATA' expected.";
+	private static final String ERR_OPENSQBRACKET_EXPECTED = "'[' expected.";
+	private static final String ERR_CLOSE_CDATA_EXPECTED = "']]>' expected.";
+	private static final String ERR_SEMICOLON_EXPECTED = "';' expected.";
+	private static final String ERR_XMLPROLOG_EXPECTED = "XML prolog '<?xml' is not expected at this position.";
+	private static final String ERR_VERSION_EXPECTED = "'version' attribute expected.";
+	private static final String ERR_ENCODING_STANDALONE_EXPECTED = "'encoding', 'standalone' or '?>' expected.";
+	private static final String ERR_STANDALONE_EXPECTED = "'standalone' attribute expected.";
+
+	protected static final boolean fDebug = Activator.getBoolean(DEBUG);
+	protected static final boolean fInternAttributes = Activator.getBoolean(INTERN_ATTRIBUTES);
+
+	private String fDefaultEncoding = "UTF-8";
+
+	// private CharBuffer c;
+	private CharBuffer temp = new CharBuffer();
+	private CharBuffer temp2 = null;
+
+	protected Reader fReader = null;
+	protected InputStream fStream = null;
+
+	protected char currentChar = 0;
+	protected ExTagListener fExTagListener;
+
+	protected int fLine = 1;
+	protected int fPos = 0;
+
+	protected int fLevel = -1;
+	protected int fCurrentLevel = 1;
+
+	private String fVersion = "1.0";
+	private String fEncoding = "UTF-8";
+	private String fStandalone = "yes";
+
+	/**
+	 * An empty default constructor
+	 * 
+	 */
+	public XMLParserImpl() {
+		//
+	}
+
+	/**
+	 * Constructs a new XMLReader. <br>
+	 * <br>
+	 * <b>Note: The XMLReader does not close the passed Reader or InputStream
+	 * 
+	 * @param aInputStream
+	 *            an InputStream to read the XML file from
+	 * @param aListener
+	 *            ExTagListener that will be notified on tag-open or tag-close
+	 *            events
+	 * @throws IOException
+	 */
+	public XMLParserImpl(InputStream aInputStream, ExTagListener aListener) {
+		fStream = aInputStream;
+		fExTagListener = aListener;
+	}
+
+	/**
+	 * Constructs a new XMLReader. <br>
+	 * <br>
+	 * <b>Note: The XMLReader does not close the passed Reader or InputStream
+	 * 
+	 * @param aReader
+	 *            a Reader to read the XML file from
+	 * @param aListener
+	 *            ExTagListener that will be notified on tag-open or tag-close
+	 *            events
+	 */
+	public XMLParserImpl(Reader aReader, ExTagListener aListener) {
+		fReader = aReader;
+		fExTagListener = aListener;
+	}
+
+	/**
+	 * Sets the level of tags bellow which the listener will be notified for.
+	 * For internal use only.
+	 * 
+	 * @param aLevel
+	 */
+	public void setLevel(int aLevel) {
+		fLevel = aLevel;
+	}
+
+	/**
+	 * Sets the parser's encoding. If there is a current encoding associated
+	 * with the parser the method returns immediately
+	 * 
+	 * @param aEncoding
+	 *            new encoding to be set
+	 * @throws UnsupportedEncodingException
+	 *             if the encoding is not supported.
+	 */
+	protected void setEncoding(String aEncoding) {
+		if (fReader == null) {
+			try {
+				fReader = new InputStreamReader(fStream, aEncoding);
+			} catch (Exception e) {
+				if (fDebug) {
+					System.err.println("[XMLParserImpl] Failed setting the encoding \"" + aEncoding + "\", continue parsing with the default one.");
+				}
+				fReader = new InputStreamReader(fStream);
+			}
+		}
+	}
+
+	/* A helper function to reuse a temp CharBuffers without recreating it */
+	protected CharBuffer getCharBuffer() {
+		if (temp.length() <= 0) {
+			return temp;
+		} else if (temp2 == null) {
+			temp2 = new CharBuffer(0);
+			return temp2;
+		} else if (temp2.length() <= 0) {
+			return temp2;
+		}
+		return new CharBuffer(0);
+	}
+
+	protected char prev_char = 0;
+	private char[] fBuffer = new char[4096];
+	private int fBufferLen = 0;
+	private int fBufferPos = 0;
+
+	/**
+	 * Reads the next char from the input stream and sets it to private field
+	 * <code>currentChar</code>
+	 * 
+	 * @return true if the next char is successfully read of false if
+	 *         End-Of-Stream is reached
+	 * @throws IOException
+	 *             if some error occurs during reading the character or if the
+	 *             caller tries to read beyond the End-Of-Stream.
+	 */
+	protected boolean getNextChar() throws IOException {
+		// // Reading characters without buffering
+		// int ichar = 0;
+		// int count = 0;
+		// while (ichar == 0 && count < 100) {
+		// ichar = fReader.read();
+		// count++;
+		// }
+		//    
+		// if (ichar == 0)
+		// throw new IOException("Failed to read from the input file.");
+		//    
+		// if (ichar < 0 && prev_char == 0)
+		// throw new IOException(ERR_EOS);
+		//    
+		// char ch = (char) ichar;
+
+		char ch;
+
+		if (fReader == null) { // If there is no associated reader,
+			int ach = fStream.read(); // then reads from the InputStream until
+			if (ach < 0) { // the rigth encoding is recognized
+				ach = 0;
+			}
+
+			ch = (char) ach;
+			if (ch == 0 && prev_char == 0) {
+				throw new IOException(ERR_EOS);
+			}
+		} else {
+			// Buffered reading
+			if (fBufferLen < 0) {
+				throw new IOException(ERR_EOS);
+			}
+
+			if ((fBufferPos) >= fBufferLen) {
+				// Refetch the buffer
+				fBufferLen = 0;
+				fBufferPos = 0;
+				int count = 0;
+				while (fBufferLen == 0 && count < 100) {
+					fBufferLen = fReader.read(fBuffer);
+					count++;
+				}
+
+				ch = (fBufferLen > 0) ? fBuffer[fBufferPos++] : 0;
+
+				if (fBufferLen == 0) {
+					fBufferLen = -1;
+				}
+			} else {
+				ch = fBuffer[fBufferPos++];
+			}
+		}
+
+		prev_char = currentChar;
+		currentChar = ch;
+		fPos++;
+
+		switch (ch) {
+			case '\n' :
+				if (prev_char != '\r') {
+					fLine++;
+				}
+				fPos = 0;
+				break;
+			case '\r' :
+				fPos = 0;
+				fLine++;
+				break;
+		}
+		return (currentChar != 0);
+	}
+
+	/**
+	 * Parses the attribute value and if it's successful then adds it to the
+	 * CharBuffer. If there are EntityReferences of CharReferences in the
+	 * attribute value, they will be turned to their equivalent symbols.<br>
+	 * attr_value ::= (acceptable_char | EntityRef | CharRef)* - quot_symbol
+	 * 
+	 * @see parse_attr
+	 * @see parse_CharRef
+	 * @see parse_EntityRef
+	 */
+	protected void parse_attr_value(CharBuffer sb, char quot) throws IOException {
+		while (currentChar != quot && currentChar != '<') {
+			if (accept_char('&')) {
+				if (!parse_CharRef(sb)) {
+					if (!parse_EntityRef(sb)) {
+						err(fPos - 1, ERR_ENTITY_EXPECTED);
+					}
+				}
+			} else {
+				sb.append(currentChar);
+
+				if (!getNextChar()) {
+					break;
+				}
+			}
+		}
+	}
+
+	/**
+	 * Parses an attribute with the given simplified grammar:<br>
+	 * 
+	 * <pre>
+	 * attribute ::= S* + attr_name + S* + '=' + S* + ('\'' + (attr_value - '\'') + '\'')) | ('&quot;' + (attr_value - '&quot;') + '&quot;'))
+	 * attr_value ::= (acceptable_char | EntityRef | CharRef)*
+	 * attr_name ::= identifier
+	 * </pre>
+	 * 
+	 * @param aParent
+	 *            the parent tag where the correctly parsed attribute will be
+	 *            added
+	 * @throws IOException
+	 * @see parse_identifier
+	 * @see parse_attr_value
+	 */
+	protected boolean parse_attr(TagImpl aParent) throws IOException {
+		clearWhiteSpaces();
+
+		String attrName = parse_identifier();
+
+		if (attrName != null) {
+			clearWhiteSpaces();
+
+			if (!accept_char('=')) {
+				err(ERR_EQUAL_EXPECTED);
+			}
+
+			clearWhiteSpaces();
+
+			char quot = 0;
+			if (accept_char('"')) {
+				quot = '"';
+			} else if (accept_char('\'')) {
+				quot = '\'';
+			} else {
+				err(ERR_QUOT_EXPECTED);
+			}
+
+			CharBuffer sb = getCharBuffer();
+			parse_attr_value(sb, quot);
+
+			if (!accept_char(quot)) {
+				err("'" + quot + "' expected.");
+			}
+
+			String attrValue = sb.toString();
+
+			if (fInternAttributes) {
+				attrValue.intern();
+			}
+
+			aParent.addAttribute(attrName, attrValue);
+			sb.setLength(0);
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Parses a tag attribute list with the following simplified grammar:
+	 * 
+	 * <pre>
+	 * attr_list ::= attribute*
+	 * @param aParent the parent tag that the parsed attributes will be added to
+	 * @return true if at least one attribute is parsed correctly and false otherwise
+	 * @throws IOException
+	 * @see parse_attr
+	 * 
+	 */
+	protected boolean parse_attr_list(TagImpl aParent) throws IOException {
+		boolean result = false;
+		while (parse_attr(aParent)) {
+			result = true;
+		}
+		return result;
+	}
+
+	private static final char bA = 'A' - 1;
+	private static final char aZ = 'Z' + 1;
+	private static final char ba = 'a' - 1;
+	private static final char az = 'z' + 1;
+	private static final char b0 = '0' - 1;
+	private static final char a9 = '9' + 1;
+
+	/**
+	 * This method returns true is the passed character may be used as starting
+	 * character for tag name and attribute name
+	 * 
+	 * @param ch
+	 *            the tested character
+	 * @return true if the character could be used as starting character for a
+	 *         tag name and an attribute name and false otherwise
+	 */
+	protected final boolean isNameStartChar(char ch) {
+		return (ch > bA && ch < aZ) || (ch > ba && ch < az) || (ch == ':') || (ch == '_') || (ch > 0xBF && ch < 0xD7) || (ch > 0xD7 && ch < 0xF7) || (ch > 0xF7 && ch < 0x300) || (ch > 0x36F && ch < 0x37E) || (ch > 0x37E && ch < 0x2000) || (ch > 0x200B && ch < 0x200E) || (ch > 0x206F && ch < 0x2190) || (ch > 0x2BFF && ch < 0x2FF0) || (ch > 0x3000 && ch < 0xD800) || (ch > 0xF900 && ch < 0xFDD0) || (ch > 0xFDEF && ch < 0xFFFE) || (ch > 0x0FFFF && ch < 0xF0000);
+	}
+
+	/**
+	 * This method returns true if the passed characted may be used as part of a
+	 * tag name or an attribute name
+	 * 
+	 * @param ch
+	 *            the tested character
+	 * @return true is the characted could be used as part of a tag name or an
+	 *         attribute name and false otherwise
+	 */
+	protected final boolean isNameChar(char ch) {
+		return (ch == '-') || (ch == '.') || (ch == 0xB7) || (ch > b0 && ch < a9) || isNameStartChar(ch) || (ch > 0x02FF && ch < 0x0370) || (ch > 0x203E && ch < 0x2041);
+	}
+
+	/**
+	 * Parses an identifier.
+	 * 
+	 * @return an identifier if it is parsed successfully and null otherwise
+	 * @throws IOException
+	 */
+	protected String parse_identifier() throws IOException {
+		if (isNameStartChar(currentChar)) {
+			CharBuffer sb = getCharBuffer();
+
+			while (isNameChar(currentChar)) {
+				sb.append(currentChar);
+
+				if (!getNextChar()) {
+					break;
+				}
+			}
+			String result = sb.toString().intern();
+			sb.setLength(0);
+			return result;
+		}
+		return null;
+	}
+
+	/**
+	 * Parses a tag name and if it is successfully parsed the method sets it as
+	 * a name of the parent tag
+	 * 
+	 * @param aParent
+	 *            parent tag
+	 * @return true if the name is parsed successfully and false otherwise
+	 * @throws IOException
+	 * @see parse_identifier
+	 */
+	protected boolean parse_tag_name(TagImpl aParent) throws IOException {
+		String name = parse_identifier();
+		if (name != null) {
+			aParent.setName(name);
+		}
+		return name != null;
+	}
+
+	/**
+	 * Helper function that notify listeners depending on certain conditions
+	 * such as if the tag event is on-close or on-open
+	 * 
+	 * @param aTag
+	 *            The tag that the notification event is valid for.
+	 * @param isStart
+	 *            true if the event is on-open and false if it is on-close
+	 */
+	protected void notifyListeners(TagImpl aTag, boolean isStart) {
+		try {
+			if (isStart) {
+				fExTagListener.startTag(aTag);
+			} else {
+				fExTagListener.endTag(aTag);
+			}
+		} catch (RuntimeException re) {
+			if (fDebug) {
+				System.err.println("An outside exception occured while processing a tag on line " + aTag.getLine() + ", the tag name is: " + aTag.getName());
+				re.printStackTrace(System.err);
+			}
+			throw re;
+		}
+	}
+
+	/**
+	 * Parses a normal tag. There are two cases - (1) the tag has separate open
+	 * and close tag elements and (2) the tag is simple suchas &lt;tag_name ...
+	 * /&gt;
+	 * 
+	 * @param aParent
+	 *            The parent tag that this tag will be added to if the parsing
+	 *            is successful
+	 * @return true on success and false otherwise
+	 * @throws IOException
+	 * @see clearWhiteSpaces
+	 * @see parse_tag_name
+	 * @see parse_attr_list
+	 * @see notifyListeners
+	 * @see accept_char
+	 * @see accept_seq
+	 * @see parse_PCDATA
+	 */
+	protected boolean parse_tag_normal(TagImpl aParent) throws IOException {
+		// Looking for a tag_name (identifier)
+		if (isNameStartChar(currentChar)) {
+			TagImpl tag = new TagImpl();
+			tag.setLine(fLine);
+
+			parse_tag_name(tag);
+			parse_attr_list(tag);
+
+			clearWhiteSpaces();
+
+			if (accept_char('/')) {
+				if (!accept_char('>')) {
+					err(ERR_GT_EXPECTED);
+				}
+				aParent.addTag(tag);
+
+				if ((fLevel <= 0 || fLevel == fCurrentLevel)) {
+					notifyListeners(tag, true);
+					notifyListeners(tag, false);
+				}
+
+				return true;
+			} else if (accept_char('>')) {
+
+				notifyListeners(tag, true);
+
+				while (true) {
+					clearWhiteSpaces();
+					int pos = fPos;
+					if (currentChar == '<') { // Normal tag, Special tag or
+						// closing tag
+						if (!parse_tag(tag)) { // It may be a special tag.
+							if (!accept_char('/')) {
+								err(pos + 1, ERR_CLOSE_TAG1_EXPECTED);
+							}
+
+							// trying to accept: tag_name + S* + '>'
+							pos = fPos;
+							if (!accept_seq(tag.getName())) {
+								err(pos, '\'' + tag.getName() + "' string expected.");
+							}
+
+							clearWhiteSpaces();
+							if (!accept_char('>')) {
+								err(ERR_GT_EXPECTED);
+							}
+
+							aParent.addTag(tag);
+
+							if (fLevel <= 0 || fLevel == fCurrentLevel) {
+								notifyListeners(tag, false);
+							}
+
+							return true;
+						}
+					} else {
+						if (!parse_PCDATA(tag)) {
+							break;
+						}
+					}
+				}
+				err(ERR_CONTENT_EXPECTED);
+			} else {
+				err(ERR_CLOSE_TAG2_EXPECTED);
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Returns true if the specified attribute is already parsed and false
+	 * otherwise
+	 * 
+	 * @param aTag
+	 *            the which attribute will be examined.
+	 * @param attrName
+	 *            an attribute name
+	 * @return true if the specified attribute is already parsed and false
+	 *         otherwise
+	 */
+	protected boolean accept_attr(TagImpl aTag, String attrName) {
+		return aTag.getAttribute(attrName) != null;
+	}
+
+	/**
+	 * Parses the XML prolog tag, i.e.<br>
+	 * <code> &lt;?xml version="..." encoding="..." standalone="..." ?&gt; </code><br>
+	 * 
+	 * @param parent
+	 *            the parent tag (in this case this is the root "fake" tag,
+	 *            which the listeners will never be informed for...)
+	 * @throws IOException
+	 *             if an exception occurs during read operations from the Reader
+	 *             or the InputStream
+	 */
+	protected boolean parse_xml_prolog(TagImpl parent) throws IOException {
+		if (accept_char('?')) {
+			TagImpl tag = new TagImpl();
+
+			if (parse_tag_name(tag)) {
+				if (tag.getName().equalsIgnoreCase(XML)) {
+					clearWhiteSpaces();
+
+					int pos = fPos;
+
+					if (parse_attr(tag)) {
+						String s = tag.getAttribute(VERSION);
+
+						if (s == null) {
+							err(pos, ERR_VERSION_EXPECTED);
+						}
+
+						fVersion = s;
+
+						clearWhiteSpaces();
+						pos = fPos;
+						if (parse_attr(tag)) {
+							clearWhiteSpaces();
+
+							if (accept_attr(tag, ENCODING)) {
+								fEncoding = tag.getAttribute(ENCODING);
+
+								pos = fPos;
+								if (parse_attr(tag)) {
+									clearWhiteSpaces();
+									if (accept_attr(tag, STANDALONE)) {
+										fStandalone = tag.getAttribute(STANDALONE);
+									} else {
+										err(pos, ERR_STANDALONE_EXPECTED);
+									}
+								}
+							} else if (accept_attr(tag, STANDALONE)) {
+								fStandalone = tag.getAttribute(STANDALONE);
+							} else {
+								err(pos, ERR_ENCODING_STANDALONE_EXPECTED);
+							}
+						}
+
+						clearWhiteSpaces();
+						pos = fPos;
+						if (!accept_seq("?>")) {
+							err(pos, ERR_CLOSE_TAG3_EXPECTED);
+						}
+					} else {
+						err(pos, ERR_VERSION_EXPECTED);
+					}
+					clearWhiteSpaces();
+					return true;
+				}
+
+				char prevCh = 0;
+
+				while (true) {
+					if (currentChar == '>') {
+						if (prevCh == '?') {
+							accept_char('>');
+							clearWhiteSpaces();
+
+							return true;
+						}
+						err(ERR_QUESTIONMARK_EXPECTED);
+					} else if (currentChar == '<') {
+						err(ERR_ILLEGAL_CHARACTER + " ('<')");
+					}
+					prevCh = currentChar;
+					getNextChar();
+				}
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Parses special tags, such that begins with:<br>
+	 * 
+	 * <pre><code>
+	 * &lt;!--         comments
+	 * &lt;!tag_name   Parsing instructions
+	 * &lt;![          CDATA element
+	 * &lt;?           DOCTYPE, etc.
+	 * </code></pre>
+	 * 
+	 * @param aParent
+	 *            The parent tag that this tag will be added to if the parsing
+	 *            is successful
+	 * @return true on success and false otherwise
+	 * @throws IOException
+	 * @see accept_char
+	 * @see clearWhiteSpaces
+	 * @see parse_tag_CDATA
+	 * @see parse_tag_name
+	 * @see parse_comment
+	 */
+	protected boolean parse_tag_special(TagImpl aParent) throws IOException {
+		if (accept_char('!')) {
+
+			TagImpl tag = new TagImpl();
+
+			if (parse_tag_name(tag)) {
+				clearWhiteSpaces();
+
+				while (true) {
+					if (accept_char('>')) {
+						clearWhiteSpaces();
+						return true;
+					}
+					getNextChar();
+				}
+			} else if (parse_tag_CDATA(aParent)) { // parse CDATA tag
+				return true;
+			} else if (parse_comment(tag)) {
+				return true;
+			}
+		} else if (accept_char('?')) {
+			TagImpl tag = new TagImpl();
+
+			int pos = fPos;
+			if (parse_tag_name(tag)) {
+				if (tag.getName().equals(XML)) {
+					err(pos - 2, ERR_XMLPROLOG_EXPECTED);
+				}
+
+				char prevCh = 0;
+				while (true) {
+					if (currentChar == '>') {
+						if (prevCh == '?') {
+							accept_char('>');
+							clearWhiteSpaces();
+							return true;
+						}
+					}
+					prevCh = currentChar;
+					getNextChar();
+				}
+
+			} else {
+				err(pos, ERR_TAGNAME_EXPECTED);
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Parses a comment. The grammar is:<br>
+	 * Comment ::= '&lt;!--' ((Char - '-') | ('-' (Char - '-')))* '--&gt;'<br>
+	 * Note that the grammar does not allow a comment ending in ---&gt;. The
+	 * following example is not well-formed.<br>
+	 * <code>
+	 * &lt;!-- B+, B, or B---&gt;</code>
+	 * 
+	 * @param aParent
+	 *            The parent tag
+	 * @return true on success and false otherwise
+	 * @throws IOException
+	 * @see accept_char
+	 */
+	protected boolean parse_comment(TagImpl aParent) throws IOException {
+		if (accept_char('-')) {
+			if (!accept_char('-')) {
+				err(ERR_DASH_EXPECTED);
+			}
+
+			while (true) {
+				if (accept_char('-')) {
+					if (accept_char('-')) {
+						if (accept_char('>')) {
+							break;
+						}
+						err(ERR_GT_EXPECTED);
+					}
+				}
+
+				if (!getNextChar()) {
+					err(ERR_COMMENT_CLOSE_EXPECTED);
+				}
+			}
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Parses either normal or special tag
+	 * 
+	 * @param aParent
+	 *            The parent tag that the successfully parsed tag will (if it is
+	 *            normal tag or CDATA element) be added
+	 * @return true on success and false otherwise
+	 * @throws IOException
+	 * @see accept_cahr
+	 * @see parse_tag_normal
+	 * @see parse_tag_special
+	 * @see clearWhiteSpaces
+	 */
+	protected boolean parse_tag(TagImpl aParent) throws IOException {
+		clearWhiteSpaces();
+		try {
+			fCurrentLevel++;
+
+			if (accept_char('<')) {
+				if (parse_tag_normal(aParent) || parse_tag_special(aParent)) {
+					return true;
+				}
+			}
+			return false;
+		} finally {
+			fCurrentLevel--;
+		}
+	}
+
+	/**
+	 * Parses the content of the tag (including sub-tags and sub-elements)
+	 * 
+	 * @param aParent
+	 *            The parent tag that the content and tags will be added to
+	 * @return true on success and false otherwise
+	 * @throws IOException
+	 * @see parse_PCDATA
+	 * @see parse_tag
+	 */
+	protected boolean parse_content(TagImpl aParent) throws IOException {
+		return (parse_PCDATA(aParent) || parse_tag(aParent));
+	}
+
+	/**
+	 * Parses a CDATA tag (or CDATA content element).
+	 * 
+	 * @param aParent
+	 *            The parent tag that the content will be added to
+	 * @return true on success and false otherwise
+	 * @throws IOException
+	 */
+	protected boolean parse_tag_CDATA(TagImpl aParent) throws IOException {
+		if (accept_char('[')) {
+			int pos = fPos;
+
+			if (!accept_seq(CDATA)) {
+				err(pos, ERR_CDATA_EXPECTED);
+			}
+
+			if (!accept_char('[')) {
+				err(ERR_OPENSQBRACKET_EXPECTED);
+			}
+
+			do {
+				if (currentChar != '>') {
+					aParent.getContentBuffer().append(currentChar);
+				} else {
+					CharBuffer sb = aParent.getContentBuffer();
+					int l = sb.length();
+
+					if (l >= 2) {
+						if (sb.charAt(l - 1) == ']' && sb.charAt(l - 2) == ']') {
+							sb.setLength(l - 2); // Truncates the extra "]]"
+							// symbols appended at the
+							// end
+
+							getNextChar();
+							return true;
+						}
+					}
+					sb.append(currentChar);
+				}
+			} while (getNextChar());
+
+			err(fPos - 1, ERR_CLOSE_CDATA_EXPECTED);
+		}
+		return false;
+	}
+
+	/**
+	 * Parses PCDATA content (Parseable Content DATA). The EntityRefs and
+	 * CharRefs that are parsed will be turned to its symbol equivalent.
+	 * 
+	 * @param aParent
+	 *            The parent tag that the PCDATA will be added to
+	 * @return true on success and false otherwise
+	 * @throws IOException
+	 * @see accept_char
+	 * @see parse_CharRef
+	 * @see parse_EntityRef
+	 */
+	protected boolean parse_PCDATA(TagImpl aParent) throws IOException {
+		boolean result = false;
+		while (currentChar != '<') {
+			result = true;
+
+			CharBuffer sbContent = aParent.getContentBuffer();
+
+			if (accept_char('&')) {
+				int pos = fPos;
+				if (!parse_CharRef(sbContent)) {
+					if (!parse_EntityRef(sbContent)) {
+						err(pos - 1, ERR_ENTITY_EXPECTED);
+					}
+				}
+			} else {
+				sbContent.append(currentChar);
+
+				if (!getNextChar()) {
+					break;
+				}
+			}
+		}
+		return result;
+	}
+
+	/**
+	 * Accepts one character from the input stream and if it's successful moves
+	 * one character forward.
+	 * 
+	 * @param ch
+	 *            The character that should be accepted
+	 * @return true on success and false otherwise
+	 * @throws IOException
+	 */
+	protected boolean accept_char(char ch) throws IOException {
+		if (currentChar == ch) {
+			getNextChar();
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Accepts a sequence of characters given by seq parameter. If the sequence
+	 * is accepted successfully then the currentChar field will contain the
+	 * character immediately after the accepted sequence.
+	 * 
+	 * @param seq
+	 *            The character sequence that should be accepted
+	 * @return true on success and false otherwise
+	 * @throws IOException
+	 */
+	protected boolean accept_seq(String seq) throws IOException {
+		for (int i = 0; i < seq.length(); i++) {
+			if (!accept_char(seq.charAt(i))) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	protected static final String[] entities = {"amp", "apos", "lt", "gt", "quot"};
+	protected static final char[] ent_chars = {'&', '\'', '<', '>', '"'};
+
+	/**
+	 * <code>
+	 * EntityRef ::= '&' + EntityValue + ';'<br>
+	 * EntityValue ::= 'amp' | 'quot' | 'apos' | 'gt' | 'lt' | identifier
+	 * </code>
+	 * 
+	 * @param sb
+	 *            The string buffer that the recognized entity will be appended
+	 *            to
+	 * @throws IOException
+	 * @return true on success and false otherwise
+	 * @see parse_identifier
+	 * @see accept_char
+	 */
+	protected boolean parse_EntityRef(CharBuffer sb) throws IOException {
+		String ent = parse_identifier();
+
+		if (!accept_char(';')) {
+			err(ERR_SEMICOLON_EXPECTED);
+		}
+
+		int length = entities.length;
+		for (int i = 0; i < length; i++) {
+			if (entities[i] == ent) { // 'ent' is interned by
+				// parse_identifier() function
+				sb.append(ent_chars[i]);
+				return true;
+			}
+		}
+
+		sb.append('&');
+
+		if (ent != null && ent.length() > 0) {
+			sb.append(ent);
+		}
+
+		sb.append(';');
+
+		return true;
+	}
+
+	/**
+	 * Parses a CharReference and if it is successful then appends it to the
+	 * passed CharBuffer
+	 * 
+	 * @param sb
+	 *            CharBuffer that the parsed CharReference will be added to
+	 * @return true on success and false otherwise
+	 * @throws IOException
+	 */
+	protected boolean parse_CharRef(CharBuffer sb) throws IOException {
+		if (accept_char('#')) {
+			// TODO - Postponed...
+			while (currentChar != ';') {
+				getNextChar();
+			}
+
+			if (!accept_char(';')) {
+				err(fPos - 1, ERR_SEMICOLON_EXPECTED);
+			}
+
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Clears the white spaces starting from the current position
+	 * 
+	 * @throws IOException
+	 */
+	protected void clearWhiteSpaces() throws IOException {
+		while (Character.isWhitespace(currentChar)) {
+			if (!getNextChar()) {
+				break;
+			}
+		}
+	}
+
+	/**
+	 * Throws an IOException with a given message. The current line number and
+	 * line position are appended to the error message
+	 * 
+	 * @param message
+	 *            The message of the exception
+	 * @throws IOException
+	 */
+	protected void err(String message) throws IOException {
+		err(fPos, message);
+	}
+
+	/**
+	 * Throws an IOException with the given message for the given line position.
+	 * The current line number and position (pos) are appended to the exception
+	 * message
+	 * 
+	 * @param pos
+	 *            The line position that the error will be reported for
+	 * @param message
+	 * @throws IOException
+	 */
+	protected void err(int pos, String message) throws IOException {
+		throw new IOException("[Line: " + fLine + ", Pos: " + pos + "]  " + message);
+	}
+
+	/**
+	 * Initiates parsing of the XML file given through aInputStream or aReader
+	 * in the given constructor when creating XMLReader object.
+	 * 
+	 * @throws IOException
+	 *             if an error occurs during reading the XML file or if a
+	 *             parsing error eccurs.
+	 */
+	public void parseXML() throws IOException {
+		TagImpl rootTag = new TagImpl();
+
+		try {
+			getNextChar();
+			clearWhiteSpaces();
+
+			boolean start = false;
+
+			while (accept_char('<')) {
+				start = true;
+				int pos = fPos;
+
+				if (fPos == 2 && fLine == 1) {
+					if (parse_xml_prolog(rootTag)) {
+						// System.out.println("XML Prolog found.");
+						// System.out.println("XML Version: " + fVersion + ",
+						// encoding: " + fEncoding);
+						setEncoding(fEncoding);
+						clearWhiteSpaces();
+						continue;
+					}
+				} else {
+					setEncoding(fDefaultEncoding);
+				}
+
+				if (!parse_tag_special(rootTag)) {
+					if (parse_tag_normal(rootTag)) {
+						// TODO da se proveri dali e dostignat kraja na file-a,
+						// ako ne e - togava ot tuk natatuk moje da ima samo
+						// komentari.
+						return;
+					}
+					err(pos, ERR_TAGNAME2_EXPECTED);
+				}
+
+				clearWhiteSpaces();
+			}
+
+			if (!start) {
+				err(ERR_LT_EXPECTED);
+			}
+		} catch (IOException ioe) {
+			if (fDebug) {
+				ioe.printStackTrace(System.err);
+			}
+
+			throw ioe;
+		}
+	}
+
+	/**
+	 * Parses a XML file given through aInputStream and during the parsing
+	 * notifies aListener for close-tag and open-tag events <br>
+	 * <br>
+	 * <b>Note: The XMLReader does not close the passed Reader or InputStream
+	 * 
+	 * @param aInputStream
+	 *            an InputStream to read the XML file from
+	 * @param aListener
+	 *            ExTagListener that will be notified on close-tag and open-tag
+	 *            events
+	 * @param aLevel
+	 *            indicates the tag level that the listener will be invoked for.
+	 *            For example if the XML is:<br>
+	 * 
+	 * <pre>
+	 *  &lt;a&gt;
+	 *    &lt;b&gt;
+	 *      &lt;c /&gt;
+	 *    &lt;/b&gt;
+	 *  &lt;/a&gt;
+	 * </pre>
+	 * 
+	 * <br>
+	 *            and the passed aLevel is 2 then the listener will be invoked
+	 *            only for tags that have level 2, i.e. in our example the
+	 *            listener will be invoked only for tag &lt;b&gt;<br>
+	 *            <ul>
+	 *            <li>Value less than 0 indicates &quot;invoke listener for all
+	 *            tags no matter what are their levels&quot;</li>
+	 *            <li>Value of 0 indicates that the listener must not be
+	 *            invoked in general no matter what is the tag level</li>
+	 *            <li>Value greater than 0 indicates the tag level that the
+	 *            listener will be invoked for</li>
+	 *            description
+	 * @throws IOException
+	 *             if some IO error occurs when reading the XML file or if a
+	 *             parser error occurs.
+	 */
+	public static void parseXML(InputStream aInputStream, ExTagListener aListener, int aLevel) throws IOException {
+		XMLParserImpl xml = new XMLParserImpl(aInputStream, aListener);
+		xml.setLevel(aLevel);
+		xml.parseXML();
+	}
+
+	/**
+	 * Parses a XML file given through aReader and during the parsing notifies
+	 * aListener for close-tag and open-tag events <br>
+	 * <br>
+	 * <b>Note: The XMLReader does not close the passed Reader or InputStream
+	 * 
+	 * @param aReader
+	 *            aReader to read the XML file from
+	 * @param aListener
+	 *            ExTagListener that will be notified on close-tag and open-tag
+	 *            events
+	 * @param aLevel
+	 *            see parseXML(Reader aReader, ExTagListener aListener, int
+	 *            aLevel description
+	 * @throws IOException
+	 *             if some IO error occurs when reading the XML file or if a
+	 *             parser error occurs.
+	 */
+	public static void parseXML(Reader aReader, ExTagListener aListener, int aLevel) throws IOException {
+		XMLParserImpl xml = new XMLParserImpl(aReader, aListener);
+		xml.setLevel(aLevel);
+		xml.parseXML();
+	}
+
+	/**
+	 * Returns the XML version attribute
+	 * 
+	 * @return the XML file version attribute
+	 */
+	public String getVersion() {
+		return fVersion;
+	}
+
+	/**
+	 * Returns the XML encoding attribute
+	 * 
+	 * @return the XML encoding attribute
+	 */
+	public String getEncoding() {
+		return fEncoding;
+	}
+
+	/**
+	 * Returns the value of XML standalone attribute
+	 * 
+	 * @return the value of XML standalone attribute
+	 */
+	public String getStandalone() {
+		return fStandalone;
+	}
+}
diff --git a/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/package.html b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/package.html
new file mode 100644
index 0000000..2f76572
--- /dev/null
+++ b/bundles/org.eclipse.equinox.ds/src/org/eclipse/equinox/internal/util/xml/package.html
@@ -0,0 +1,11 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="Generator" CONTENT="Microsoft Word 97">
+<META NAME="Template" CONTENT="F:\Program Files\Microsoft Office\Office\html.dot">
+</HEAD>
+<BODY LINK="#0000ff" VLINK="#800080">
+
+<P>The <CODE>org.eclipse.equinox.util.xml</CODE> package contains classes that can read and parse a XML document. Through the <CODE>XMLReader</CODE> class you can read a XML from an input stream or through a reader. To get aware of every read tag, you should pass a <CODE>TagListener</CODE> implementation as an argument in the chosen <CODE>read</CODE> method of <CODE>XMLReader</CODE>. When the end of a tag is reached, the <CODE>TagListener</CODE> will received an instance of <CODE>TagClass</CODE> that represents this tag. To read the name, content, attributes and a child tag at a specific index, you can use <CODE>TagClass</CODE> and <CODE>XMLUtil</CODE>. With <CODE>XMLUtil</CODE> you can also replace a tag. You cannot create new XMLs with the XML utilities.</P>
+</BODY>
+</HTML>
diff --git a/bundles/org.eclipse.equinox.io/.classpath b/bundles/org.eclipse.equinox.io/.classpath
new file mode 100644
index 0000000..755d49b
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/OSGi%Minimum-1.0"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/bundles/org.eclipse.equinox.io/.cvsignore b/bundles/org.eclipse.equinox.io/.cvsignore
new file mode 100644
index 0000000..ba077a4
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/.cvsignore
@@ -0,0 +1 @@
+bin
diff --git a/bundles/org.eclipse.equinox.io/.project b/bundles/org.eclipse.equinox.io/.project
new file mode 100644
index 0000000..8c9bd86
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.equinox.io</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.io/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.equinox.io/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..d304116
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,331 @@
+#Thu Aug 16 11:00:59 EDT 2007
+eclipse.preferences.version=1
+org.eclipse.jdt.core.builder.cleanOutputFolder=clean
+org.eclipse.jdt.core.builder.duplicateResourceTask=warning
+org.eclipse.jdt.core.builder.invalidClasspath=abort
+org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch
+org.eclipse.jdt.core.circularClasspath=error
+org.eclipse.jdt.core.classpath.exclusionPatterns=enabled
+org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=disabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.4
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.doc.comment.support=enabled
+org.eclipse.jdt.core.compiler.maxProblemPerUnit=1000
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=error
+org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
+org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=ignore
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning
+org.eclipse.jdt.core.compiler.problem.invalidJavadoc=warning
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=private
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=enabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public
+org.eclipse.jdt.core.compiler.problem.missingJavadocTags=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=enabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=public
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unsafeTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=error
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.3
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=false
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=false
+org.eclipse.jdt.core.formatter.comment.format_line_comments=false
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=false
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=800
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=false
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.incompatibleJDKLevel=ignore
+org.eclipse.jdt.core.incompleteClasspath=error
diff --git a/bundles/org.eclipse.equinox.io/.settings/org.eclipse.jdt.ui.prefs b/bundles/org.eclipse.equinox.io/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..023a27a
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,57 @@
+#Tue Aug 21 11:19:11 CDT 2007
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_core
+formatter_settings_version=11
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=;
+org.eclipse.jdt.ui.ondemandthreshold=3
+org.eclipse.jdt.ui.staticondemandthreshold=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_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=true
+sp_cleanup.make_local_variable_final=false
+sp_cleanup.make_parameters_final=false
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_variable_declarations_final=true
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=false
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_blocks=false
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=false
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=false
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
diff --git a/bundles/org.eclipse.equinox.io/.settings/org.eclipse.pde.core.prefs b/bundles/org.eclipse.equinox.io/.settings/org.eclipse.pde.core.prefs
new file mode 100644
index 0000000..c37bbc4
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/.settings/org.eclipse.pde.core.prefs
@@ -0,0 +1,3 @@
+#Thu Mar 29 10:30:40 EEST 2007
+eclipse.preferences.version=1
+pluginProject.extensions=false
diff --git a/bundles/org.eclipse.equinox.io/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.io/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..4a908f8
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/META-INF/MANIFEST.MF
@@ -0,0 +1,31 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: IO Connector Service
+Bundle-SymbolicName: org.eclipse.equinox.io
+Bundle-Version: 0.1.0.qualifier
+Bundle-Vendor: Eclipse
+Bundle-Activator: org.eclipse.equinox.internal.io.impl.Activator
+Bundle-Description: This bundle contains service for creating connections. 
+Import-Package: 
+ javax.microedition.io,
+ org.eclipse.equinox.internal.util.hash;version="1.0.0",
+ org.eclipse.equinox.internal.util.pool;version="1.0.0",
+ org.eclipse.equinox.internal.util.ref;version="1.0.0",
+ org.osgi.framework;version="1.0",
+ org.osgi.service.io;version="1.0",
+ org.osgi.service.log;version="1.0.0",
+ org.osgi.util.tracker;version="1.2"
+Export-Package: 
+ javax.microedition.io,
+ org.eclipse.equinox.internal.io; x-internal:=true,
+ org.eclipse.equinox.internal.io.impl; x-internal:=true,
+ org.eclipse.equinox.internal.io.util; x-internal:=true
+Bundle-RequiredExecutionEnvironment: OSGi/Minimum-1.0,
+ CDC-1.0/Foundation-1.0,
+ J2SE-1.2,
+ J2SE-1.3,
+ J2SE-1.4,
+ J2SE-1.5,
+ JavaSE-1.6,
+ CDC-1.1/Foundation-1.1
+Provided-Services: class=org.osgi.service.io.ConnectorService
diff --git a/bundles/org.eclipse.equinox.io/OSGI-INF/permissions.perm b/bundles/org.eclipse.equinox.io/OSGI-INF/permissions.perm
new file mode 100644
index 0000000..6cedcdd
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/OSGI-INF/permissions.perm
@@ -0,0 +1,18 @@
+(org.osgi.framework.PackagePermission "javax.microedition.io" "import")
+(org.osgi.framework.PackagePermission "org.osgi.service.io" "import")
+(org.osgi.framework.PackagePermission "org.osgi.service.log" "import")
+(org.osgi.framework.PackagePermission "org.osgi.util.tracker" "import")
+(org.osgi.framework.PackagePermission "org.osgi.framework" "import")
+(org.osgi.framework.PackagePermission "org.eclipse.equinox.internal.util.hash" "import")
+(org.osgi.framework.PackagePermission "org.eclipse.equinox.internal.util.pool" "import")
+(org.osgi.framework.PackagePermission "org.eclipse.equinox.internal.util.ref" "import")
+(org.osgi.framework.PackagePermission "org.eclipse.equinox.internal.io" "export")
+(org.osgi.framework.PackagePermission "org.eclipse.equinox.internal.io.impl" "export")
+(org.osgi.framework.PackagePermission "org.eclipse.equinox.internal.io.util" "export")
+(org.osgi.framework.PackagePermission "javax.microedition.io" "export")
+(org.osgi.framework.BundlePermission "*" "provide")
+(org.osgi.framework.BundlePermission "*" "host")
+(org.osgi.framework.ServicePermission "org.osgi.service.io.ConnectionFactory" "get")
+(org.osgi.framework.ServicePermission "org.osgi.service.io.ConnectorService" "register")
+(java.util.PropertyPermission "*" "read")
+(java.net.SocketPermission "*" "listen")
diff --git a/bundles/org.eclipse.equinox.io/about.html b/bundles/org.eclipse.equinox.io/about.html
new file mode 100644
index 0000000..40e147d
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+ 
+<p>January 15, 2008</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>
diff --git a/bundles/org.eclipse.equinox.io/build.properties b/bundles/org.eclipse.equinox.io/build.properties
new file mode 100644
index 0000000..9cbab3c
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/build.properties
@@ -0,0 +1,6 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               about.html
+src.includes = about.html
diff --git a/bundles/org.eclipse.equinox.io/src/javax/microedition/io/Connection.java b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/Connection.java
new file mode 100644
index 0000000..1d5fffd
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/Connection.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package javax.microedition.io;
+
+public abstract interface Connection {
+
+	public abstract void close() throws java.io.IOException;
+
+}
diff --git a/bundles/org.eclipse.equinox.io/src/javax/microedition/io/ConnectionNotFoundException.java b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/ConnectionNotFoundException.java
new file mode 100644
index 0000000..68a9016
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/ConnectionNotFoundException.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package javax.microedition.io;
+
+public class ConnectionNotFoundException extends java.io.IOException {
+
+	private static final long serialVersionUID = 1L;
+
+	public ConnectionNotFoundException() {
+	}
+
+	public ConnectionNotFoundException(java.lang.String var0) {
+	}
+
+}
diff --git a/bundles/org.eclipse.equinox.io/src/javax/microedition/io/Connector.java b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/Connector.java
new file mode 100644
index 0000000..dceb48e
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/Connector.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package javax.microedition.io;
+
+public class Connector {
+
+	private Connector() {
+	}
+
+	public static javax.microedition.io.Connection open(java.lang.String var0) throws java.io.IOException {
+		return null;
+	}
+
+	public static javax.microedition.io.Connection open(java.lang.String var0, int var1) throws java.io.IOException {
+		return null;
+	}
+
+	public static javax.microedition.io.Connection open(java.lang.String var0, int var1, boolean var2) throws java.io.IOException {
+		return null;
+	}
+
+	public static java.io.DataInputStream openDataInputStream(java.lang.String var0) throws java.io.IOException {
+		return null;
+	}
+
+	public static java.io.DataOutputStream openDataOutputStream(java.lang.String var0) throws java.io.IOException {
+		return null;
+	}
+
+	public static java.io.InputStream openInputStream(java.lang.String var0) throws java.io.IOException {
+		return null;
+	}
+
+	public static java.io.OutputStream openOutputStream(java.lang.String var0) throws java.io.IOException {
+		return null;
+	}
+
+	public final static int READ = 1;
+
+	public final static int WRITE = 2;
+
+	public final static int READ_WRITE = 3;
+
+}
diff --git a/bundles/org.eclipse.equinox.io/src/javax/microedition/io/ContentConnection.java b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/ContentConnection.java
new file mode 100644
index 0000000..8064b2f
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/ContentConnection.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package javax.microedition.io;
+
+public abstract interface ContentConnection extends javax.microedition.io.StreamConnection {
+
+	public abstract java.lang.String getEncoding();
+
+	public abstract long getLength();
+
+	public abstract java.lang.String getType();
+
+}
diff --git a/bundles/org.eclipse.equinox.io/src/javax/microedition/io/Datagram.java b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/Datagram.java
new file mode 100644
index 0000000..b59b5bf
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/Datagram.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package javax.microedition.io;
+
+public abstract interface Datagram extends java.io.DataInput, java.io.DataOutput {
+
+	public abstract java.lang.String getAddress();
+
+	public abstract byte[] getData();
+
+	public abstract int getLength();
+
+	public abstract int getOffset();
+
+	public abstract void reset();
+
+	public abstract void setAddress(javax.microedition.io.Datagram var0);
+
+	public abstract void setAddress(java.lang.String var0) throws java.io.IOException;
+
+	public abstract void setData(byte[] var0, int var1, int var2);
+
+	public abstract void setLength(int var0);
+
+}
diff --git a/bundles/org.eclipse.equinox.io/src/javax/microedition/io/DatagramConnection.java b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/DatagramConnection.java
new file mode 100644
index 0000000..b97d452
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/DatagramConnection.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package javax.microedition.io;
+
+public abstract interface DatagramConnection extends javax.microedition.io.Connection {
+
+	public abstract int getMaximumLength() throws java.io.IOException;
+
+	public abstract int getNominalLength() throws java.io.IOException;
+
+	public abstract javax.microedition.io.Datagram newDatagram(byte[] var0, int var1) throws java.io.IOException;
+
+	public abstract javax.microedition.io.Datagram newDatagram(byte[] var0, int var1, java.lang.String var2) throws java.io.IOException;
+
+	public abstract javax.microedition.io.Datagram newDatagram(int var0) throws java.io.IOException;
+
+	public abstract javax.microedition.io.Datagram newDatagram(int var0, java.lang.String var1) throws java.io.IOException;
+
+	public abstract void receive(javax.microedition.io.Datagram var0) throws java.io.IOException;
+
+	public abstract void send(javax.microedition.io.Datagram var0) throws java.io.IOException;
+
+}
diff --git a/bundles/org.eclipse.equinox.io/src/javax/microedition/io/HttpConnection.java b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/HttpConnection.java
new file mode 100644
index 0000000..6a3bb45
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/HttpConnection.java
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package javax.microedition.io;
+
+public abstract interface HttpConnection extends javax.microedition.io.ContentConnection {
+
+	public abstract long getDate() throws java.io.IOException;
+
+	public abstract long getExpiration() throws java.io.IOException;
+
+	public abstract java.lang.String getFile();
+
+	public abstract java.lang.String getHeaderField(int var0) throws java.io.IOException;
+
+	public abstract java.lang.String getHeaderField(java.lang.String var0) throws java.io.IOException;
+
+	public abstract long getHeaderFieldDate(java.lang.String var0, long var1) throws java.io.IOException;
+
+	public abstract int getHeaderFieldInt(java.lang.String var0, int var1) throws java.io.IOException;
+
+	public abstract java.lang.String getHeaderFieldKey(int var0) throws java.io.IOException;
+
+	public abstract java.lang.String getHost();
+
+	public abstract long getLastModified() throws java.io.IOException;
+
+	public abstract int getPort();
+
+	public abstract java.lang.String getProtocol();
+
+	public abstract java.lang.String getQuery();
+
+	public abstract java.lang.String getRef();
+
+	public abstract java.lang.String getRequestMethod();
+
+	public abstract java.lang.String getRequestProperty(java.lang.String var0);
+
+	public abstract int getResponseCode() throws java.io.IOException;
+
+	public abstract java.lang.String getResponseMessage() throws java.io.IOException;
+
+	public abstract java.lang.String getURL();
+
+	public abstract void setRequestMethod(java.lang.String var0) throws java.io.IOException;
+
+	public abstract void setRequestProperty(java.lang.String var0, java.lang.String var1) throws java.io.IOException;
+
+	public final static java.lang.String GET = "GET";
+
+	public final static java.lang.String HEAD = "HEAD";
+
+	public final static java.lang.String POST = "POST";
+
+	public final static int HTTP_ACCEPTED = 202;
+
+	public final static int HTTP_BAD_GATEWAY = 502;
+
+	public final static int HTTP_BAD_METHOD = 405;
+
+	public final static int HTTP_BAD_REQUEST = 400;
+
+	public final static int HTTP_CLIENT_TIMEOUT = 408;
+
+	public final static int HTTP_CONFLICT = 409;
+
+	public final static int HTTP_CREATED = 201;
+
+	public final static int HTTP_ENTITY_TOO_LARGE = 413;
+
+	public final static int HTTP_EXPECT_FAILED = 417;
+
+	public final static int HTTP_FORBIDDEN = 403;
+
+	public final static int HTTP_GATEWAY_TIMEOUT = 504;
+
+	public final static int HTTP_GONE = 410;
+
+	public final static int HTTP_INTERNAL_ERROR = 500;
+
+	public final static int HTTP_LENGTH_REQUIRED = 411;
+
+	public final static int HTTP_MOVED_PERM = 301;
+
+	public final static int HTTP_MOVED_TEMP = 302;
+
+	public final static int HTTP_MULT_CHOICE = 300;
+
+	public final static int HTTP_NO_CONTENT = 204;
+
+	public final static int HTTP_NOT_ACCEPTABLE = 406;
+
+	public final static int HTTP_NOT_AUTHORITATIVE = 203;
+
+	public final static int HTTP_NOT_FOUND = 404;
+
+	public final static int HTTP_NOT_IMPLEMENTED = 501;
+
+	public final static int HTTP_NOT_MODIFIED = 304;
+
+	public final static int HTTP_OK = 200;
+
+	public final static int HTTP_PARTIAL = 206;
+
+	public final static int HTTP_PAYMENT_REQUIRED = 402;
+
+	public final static int HTTP_PRECON_FAILED = 412;
+
+	public final static int HTTP_PROXY_AUTH = 407;
+
+	public final static int HTTP_REQ_TOO_LONG = 414;
+
+	public final static int HTTP_RESET = 205;
+
+	public final static int HTTP_SEE_OTHER = 303;
+
+	public final static int HTTP_TEMP_REDIRECT = 307;
+
+	public final static int HTTP_UNAUTHORIZED = 401;
+
+	public final static int HTTP_UNAVAILABLE = 503;
+
+	public final static int HTTP_UNSUPPORTED_RANGE = 416;
+
+	public final static int HTTP_UNSUPPORTED_TYPE = 415;
+
+	public final static int HTTP_USE_PROXY = 305;
+
+	public final static int HTTP_VERSION = 505;
+
+}
diff --git a/bundles/org.eclipse.equinox.io/src/javax/microedition/io/InputConnection.java b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/InputConnection.java
new file mode 100644
index 0000000..c738f18
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/InputConnection.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package javax.microedition.io;
+
+public abstract interface InputConnection extends javax.microedition.io.Connection {
+
+	public abstract java.io.DataInputStream openDataInputStream() throws java.io.IOException;
+
+	public abstract java.io.InputStream openInputStream() throws java.io.IOException;
+
+}
diff --git a/bundles/org.eclipse.equinox.io/src/javax/microedition/io/OutputConnection.java b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/OutputConnection.java
new file mode 100644
index 0000000..e03cbea
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/OutputConnection.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package javax.microedition.io;
+
+public abstract interface OutputConnection extends javax.microedition.io.Connection {
+
+	public abstract java.io.DataOutputStream openDataOutputStream() throws java.io.IOException;
+
+	public abstract java.io.OutputStream openOutputStream() throws java.io.IOException;
+
+}
diff --git a/bundles/org.eclipse.equinox.io/src/javax/microedition/io/StreamConnection.java b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/StreamConnection.java
new file mode 100644
index 0000000..aecb893
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/StreamConnection.java
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package javax.microedition.io;
+
+public abstract interface StreamConnection extends javax.microedition.io.InputConnection, javax.microedition.io.OutputConnection {
+
+}
diff --git a/bundles/org.eclipse.equinox.io/src/javax/microedition/io/StreamConnectionNotifier.java b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/StreamConnectionNotifier.java
new file mode 100644
index 0000000..9b718bf
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/StreamConnectionNotifier.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package javax.microedition.io;
+
+public abstract interface StreamConnectionNotifier extends javax.microedition.io.Connection {
+
+	public abstract javax.microedition.io.StreamConnection acceptAndOpen() throws java.io.IOException;
+
+}
diff --git a/bundles/org.eclipse.equinox.io/src/javax/microedition/io/package.html b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/package.html
new file mode 100644
index 0000000..84f3c6f
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/javax/microedition/io/package.html
@@ -0,0 +1,9 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html">
+</head>
+<body bgcolor="#FFFFFF">
+The classes for the generic connections.
+</body>
+</html>
diff --git a/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/ConnectionListener.java b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/ConnectionListener.java
new file mode 100644
index 0000000..c698fe2
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/ConnectionListener.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.io;
+
+import java.util.EventListener;
+import javax.microedition.io.Connection;
+
+/**
+ * Interface for a listener that will receive notification when the connection
+ * is created and when is closed.
+ * <p>
+ * Listener is notified for creation of the connection only when the connector
+ * service creates connection that implements only this and the Connection
+ * interface, when the needed IOProvider is not available at the moment of
+ * creation. When the provider becomes available then all registered listeners
+ * will receive event
+ * <p>
+ * <code>CONNECTION_CREATED</code> and the created connection. Event
+ * <code>CONNECTION_CLOSED</code> must be send from every connection that
+ * implements this interface when it is closing.
+ * 
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public interface ConnectionListener extends EventListener {
+	/**
+	 * Constant for event type created
+	 */
+	public static final int CONNECTION_CREATED = 0;
+	/**
+	 * Constant for event type closed
+	 */
+	public static final int CONNECTION_CLOSED = 1;
+
+	/**
+	 * Receives notification that a connection has been created or closed.
+	 */
+	public void notify(String uri, int eventType, Connection conn);
+
+}
diff --git a/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/ConnectionNotifier.java b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/ConnectionNotifier.java
new file mode 100644
index 0000000..86029c6
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/ConnectionNotifier.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.io;
+
+/**
+ * Provides methods for registering listeners for receiving events from a
+ * connection (that implements this interface).
+ * 
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public interface ConnectionNotifier {
+	/**
+	 * Adds the given listener to the set of listeners that will be notified
+	 * when the connection is created or closed.
+	 */
+	public void addConnectionListener(ConnectionListener l);
+
+	/**
+	 * Removes the given listener from the set of listeners that will be
+	 * notified when the connection is created or closed.
+	 */
+	public void removeConnectionListener(ConnectionListener l);
+}
diff --git a/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/RandomAccessConnection.java b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/RandomAccessConnection.java
new file mode 100644
index 0000000..c550e5e
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/RandomAccessConnection.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.io;
+
+import java.io.*;
+import javax.microedition.io.InputConnection;
+import javax.microedition.io.OutputConnection;
+
+/**
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public interface RandomAccessConnection extends InputConnection, OutputConnection, DataInput, DataOutput {
+
+	public long length() throws IOException;
+
+	public long getFilePointer() throws IOException;
+
+	public boolean isSelected();
+
+	public int read() throws IOException;
+
+	public int read(byte[] buff, int off, int len) throws IOException;
+
+	public void seek(long len) throws IOException;
+
+	public void write(int b) throws IOException;
+
+	public void write(byte[] buff, int off, int len) throws IOException;
+
+	public void flush() throws IOException;
+}
diff --git a/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/impl/Activator.java b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/impl/Activator.java
new file mode 100644
index 0000000..f159f87
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/impl/Activator.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.io.impl;
+
+import org.eclipse.equinox.internal.util.ref.Log;
+import org.osgi.framework.*;
+
+/**
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public class Activator implements BundleActivator {
+
+	public static BundleContext bc = null;
+	private ConnectorServiceImpl connector;
+	private Log log;
+
+	public void start(BundleContext bc) throws BundleException {
+		Activator.bc = bc;
+		log = new Log(bc, false);
+		log.setDebug(getBoolean("equinox.connector.debug"));
+		log.setPrintOnConsole(getBoolean("equinox.connector.console"));
+		if (log.getDebug()) {
+			log.setMaps(TracerConfigConnector.getMap(), null);
+		}
+		connector = new ConnectorServiceImpl(bc, log);
+	}
+
+	public void stop(BundleContext bc) {
+		if (connector != null) {
+			connector.close();
+			connector = null;
+			log.close();
+		}
+		bc = null;
+	}
+
+	public static boolean getBoolean(String property) {
+		String prop = (bc != null) ? bc.getProperty(property) : System.getProperty(property);
+		return ((prop != null) && prop.equalsIgnoreCase("true"));
+	}
+
+	public static int getInteger(String property, int defaultValue) {
+		String prop = (bc != null) ? bc.getProperty(property) : System.getProperty(property);
+		if (prop != null) {
+			try {
+				return Integer.decode(prop).intValue();
+			} catch (NumberFormatException e) {
+				//do nothing
+			}
+		}
+		return defaultValue;
+	}
+}
diff --git a/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/impl/ConnectionFactoryListener.java b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/impl/ConnectionFactoryListener.java
new file mode 100644
index 0000000..bdce47f
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/impl/ConnectionFactoryListener.java
@@ -0,0 +1,152 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.io.impl;
+
+import java.io.IOException;
+import java.util.*;
+import javax.microedition.io.Connection;
+import org.eclipse.equinox.internal.io.impl.PrivilegedRunner.PrivilegedDispatcher;
+import org.osgi.framework.*;
+import org.osgi.service.io.ConnectionFactory;
+
+/**
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public class ConnectionFactoryListener implements ServiceListener, PrivilegedDispatcher {
+	private static Hashtable urlToConN = new Hashtable(5);
+	private BundleContext bc;
+
+	public ConnectionFactoryListener(BundleContext bc) {
+		this.bc = bc;
+
+		try {
+			bc.addServiceListener(this, '(' + Constants.OBJECTCLASS + '=' + ConnectionFactory.class.getName() + ')');
+		} catch (InvalidSyntaxException ex) {
+			// Ignored - syntax is right!
+		}
+	}
+
+	public void close() {
+		bc.removeServiceListener(this);
+
+		if (!urlToConN.isEmpty()) {
+			Vector copyV = new Vector(urlToConN.size());
+
+			for (Enumeration en = urlToConN.elements(); en.hasMoreElements();) {
+				copyV.addElement(en.nextElement());
+			}
+
+			for (Enumeration en = copyV.elements(); en.hasMoreElements();) {
+				ConnectionNotifierImpl cn = (ConnectionNotifierImpl) en.nextElement();
+				try {
+					cn.close();
+				} catch (IOException ex) {
+				}
+			}
+		}
+	}
+
+	static void removeConnectionNotifier(String url) {
+		urlToConN.remove(url);
+	}
+
+	static int count = 0;
+
+	static Connection getConnectionNotifier(String scheme, String url, int mode, boolean timeouts, String filter, int count) throws IOException {
+		ConnectionNotifierImpl ret = null;
+		synchronized (urlToConN) {
+			if (urlToConN.containsKey(url)) {
+				return (Connection) urlToConN.get(url);
+			}
+
+			ret = new ConnectionNotifierImpl(scheme, url, mode, timeouts, filter);
+			urlToConN.put(url, ret);
+			if (count == ConnectionFactoryListener.count)
+				return ret;
+		}
+
+		Connection c = ConnectorServiceImpl.getConnection(filter, url, mode, timeouts, false);
+		if (c != null) {
+			if (ret.hasListeners())
+				ret.notifyCreated(c);
+			else
+				ret.close();
+		}
+		return c;
+	}
+
+	public void serviceChanged(ServiceEvent event) {
+		if (event.getType() == ServiceEvent.REGISTERED && !urlToConN.isEmpty()) {
+			ServiceReference ref = event.getServiceReference();
+			ConnectionFactory factory = (ConnectionFactory) bc.getService(ref);
+			String[] schemes = (String[]) ref.getProperty(ConnectionFactory.IO_SCHEME);
+
+			Vector toNotify = new Vector(urlToConN.size());
+			synchronized (urlToConN) {
+				for (Enumeration en = urlToConN.elements(); en.hasMoreElements();) {
+					ConnectionNotifierImpl cn = (ConnectionNotifierImpl) en.nextElement();
+					if (match(schemes, cn.scheme))
+						toNotify.addElement(cn);
+				}
+			}
+			for (int i = 0; i < toNotify.size(); i++) {
+				ConnectionNotifierImpl cn = (ConnectionNotifierImpl) toNotify.elementAt(i);
+				try {
+					if (cn.context != null) {
+						PrivilegedRunner.doPrivileged(cn.context, this, 0, cn, factory, null, null);
+						return;
+					}
+					Connection connection = factory.createConnection(cn.url, cn.mode, cn.timeouts);
+					if (cn.hasListeners())
+						cn.notifyCreated(connection);
+					else
+						cn.close();
+				} catch (Throwable ex) {
+					ex.printStackTrace();
+				}
+			}
+
+			bc.ungetService(ref);
+		}
+	}
+
+	static boolean match(String[] schemes, String scheme) {
+		if (schemes != null && scheme != null) {
+			for (int i = 0; i < schemes.length; i++) {
+				if (scheme.equals(schemes[i])) {
+					return true;
+				}
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.equinox.internal.io.impl.PrivilegedRunner.PrivilegedDispatcher#dispatchPrivileged(int,
+	 *      java.lang.Object, java.lang.Object, java.lang.Object,
+	 *      java.lang.Object)
+	 */
+	public Object dispatchPrivileged(int type, Object arg1, Object arg2, Object arg3, Object arg4) throws Exception {
+		ConnectionNotifierImpl cn = (ConnectionNotifierImpl) arg1;
+		ConnectionFactory factory = (ConnectionFactory) arg2;
+		Connection connection = factory.createConnection(cn.url, cn.mode, cn.timeouts);
+		if (cn.hasListeners()) {
+			cn.notifyCreated(connection);
+		} else {
+			cn.close();
+		}
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/impl/ConnectionNotifierImpl.java b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/impl/ConnectionNotifierImpl.java
new file mode 100644
index 0000000..c5fbf4a
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/impl/ConnectionNotifierImpl.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.io.impl;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+import javax.microedition.io.Connection;
+import org.eclipse.equinox.internal.io.ConnectionListener;
+import org.eclipse.equinox.internal.io.ConnectionNotifier;
+
+/**
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+class ConnectionNotifierImpl implements ConnectionNotifier, Connection {
+	private Vector list;
+	String scheme;
+	int mode;
+	boolean timeouts;
+	String url;
+	String filter;
+
+	boolean notified = false;
+	Object context;
+
+	ConnectionNotifierImpl(String scheme, String url, int mode, boolean timeouts, String filter) {
+		list = new Vector(3, 5);
+		this.scheme = scheme;
+		this.url = url;
+		this.mode = mode;
+		this.timeouts = timeouts;
+		this.filter = filter;
+		SecurityManager sm = System.getSecurityManager();
+		if (sm != null)
+			context = System.getSecurityManager().getSecurityContext();
+	}
+
+	public void addConnectionListener(ConnectionListener l) {
+		long timeStart = 0;
+		if (ConnectorServiceImpl.hasDebug) {
+			ConnectorServiceImpl.debug(16050, l.getClass().getName(), null);
+			timeStart = System.currentTimeMillis();
+		}
+		try {
+			synchronized (list) {
+				if (!notified) {
+					if (!list.contains(l))
+						list.addElement(l);
+					return;
+				}
+			}
+			Connection c = ConnectorServiceImpl.getConnection(filter, url, mode, timeouts, false);
+			if (c != null)
+				l.notify(url, ConnectionListener.CONNECTION_CREATED, c);
+		} catch (Exception exc) {
+		} finally {
+			if (ConnectorServiceImpl.hasDebug) {
+				ConnectorServiceImpl.debug(16051, String.valueOf(System.currentTimeMillis() - timeStart), null);
+			}
+		}
+	}
+
+	public void removeConnectionListener(ConnectionListener l) {
+		if (ConnectorServiceImpl.hasDebug) {
+			ConnectorServiceImpl.debug(16052, l.getClass().getName(), null);
+		}
+		list.removeElement(l);
+	}
+
+	boolean hasListeners() {
+		return !list.isEmpty();
+	}
+
+	void notifyCreated(Connection conn) {
+		notify(ConnectionListener.CONNECTION_CREATED, conn);
+	}
+
+	private void notify(int eventType, Connection conn) {
+		if (eventType != ConnectionListener.CONNECTION_CREATED && eventType != ConnectionListener.CONNECTION_CLOSED) {
+			return;
+		}
+
+		synchronized (list) {
+			if (notified)
+				return;
+			notified = true;
+		}
+		ConnectionFactoryListener.removeConnectionNotifier(url);
+		for (Enumeration en = list.elements(); en.hasMoreElements();) {
+			ConnectionListener l = (ConnectionListener) en.nextElement();
+			l.notify(url, eventType, conn);
+		}
+	}
+
+	public void close() throws IOException {
+		if (ConnectorServiceImpl.hasDebug) {
+			ConnectorServiceImpl.debug(16053, url, null);
+		}
+		synchronized (list) {
+			if (notified)
+				return;
+			notified = true;
+		}
+		ConnectionFactoryListener.removeConnectionNotifier(url);
+	}
+}
diff --git a/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/impl/ConnectorServiceImpl.java b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/impl/ConnectorServiceImpl.java
new file mode 100644
index 0000000..e9217f9
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/impl/ConnectorServiceImpl.java
@@ -0,0 +1,401 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.io.impl;
+
+import java.io.*;
+import javax.microedition.io.*;
+import org.eclipse.equinox.internal.util.ref.Log;
+import org.osgi.framework.*;
+import org.osgi.service.io.ConnectionFactory;
+import org.osgi.service.io.ConnectorService;
+
+/**
+ * ConnectorService implementation.
+ * 
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public class ConnectorServiceImpl implements ConnectorService {
+	static BundleContext bc;
+	ServiceRegistration reg;
+	ConnectionFactoryListener listener;
+
+	static boolean enableNotification = Activator.getBoolean("eclipse.io.enable.notification");
+	public static boolean hasDebug;
+	private static Log log;
+
+	public ConnectorServiceImpl(BundleContext bc, Log log) {
+		ConnectorServiceImpl.log = log;
+		ConnectorServiceImpl.hasDebug = log.getDebug();
+		init(bc);
+	}
+
+	public static void debug(int id, String message, Throwable t) {
+		log.debug(0x1200, id, message, t, false);
+	}
+
+	public ConnectorServiceImpl(BundleContext bc) {
+		init(bc);
+	}
+
+	private void init(BundleContext bc) {
+		ConnectorServiceImpl.bc = bc;
+
+		if (enableNotification) {
+			listener = new ConnectionFactoryListener(bc);
+		}
+
+		reg = bc.registerService(ConnectorService.class.getName(), this, null);
+	}
+
+	public void close() {
+		reg.unregister();
+
+		if (listener != null) {
+			listener.close();
+		}
+	}
+
+	public Connection open(String uri) throws IOException {
+		return open(uri, READ_WRITE);
+	}
+
+	public Connection open(String uri, int mode) throws IOException {
+		return open(uri, mode, false);
+	}
+
+	static char[] chars = {'~', '='};
+
+	public Connection open(String uri, int mode, boolean timeouts) throws IOException {
+		long timeStart = 0;
+		if (hasDebug) {
+			debug(16001, uri + ", " + (mode == READ_WRITE ? "READ_WRITE" : (mode == READ) ? "READ" : "WRITE"), null);
+			timeStart = System.currentTimeMillis();
+		}
+		try {
+			if (uri == null) {
+				throw new IllegalArgumentException("URL cannot be NULL!");
+			}
+
+			int sPos = uri.indexOf(":");
+
+			if (sPos < 1) { // scheme must be at least with 1 symbol
+				throw new IllegalArgumentException("Does not have scheme");
+			}
+
+			String scheme = uri.substring(0, sPos);
+			StringBuffer filter = new StringBuffer(scheme.length() + 13);
+			filter.append('(');
+			filter.append(ConnectionFactory.IO_SCHEME);
+			filter.append(chars);
+			filter.append(scheme);
+			filter.append(')');
+
+			int count = 0;
+			if (listener != null)
+				count = ConnectionFactoryListener.count;
+			Connection c = getConnection(filter.toString(), uri, mode, timeouts, true);
+
+			if (c == null && listener != null)
+				c = ConnectionFactoryListener.getConnectionNotifier(scheme, uri, mode, timeouts, filter.toString(), count);
+			if (c == null)
+				throw new ConnectionNotFoundException("Failed to create connection " + uri);
+			return c;
+		} finally {
+			if (hasDebug) {
+				debug(16002, String.valueOf(System.currentTimeMillis() - timeStart), null);
+			}
+		}
+	}
+
+	static protected Connection getConnection(String filter, String uri, int mode, boolean timeouts, boolean connector) throws IOException {
+		ServiceReference[] cfRefs = null;
+		Connection ret = null;
+		try {
+			cfRefs = bc.getServiceReferences(ConnectionFactory.class.getName(), filter);
+		} catch (InvalidSyntaxException ex) {
+		}
+
+		if (cfRefs != null) {
+			sort(cfRefs, 0, cfRefs.length);
+		}
+
+		IOException ioExc = null;
+		boolean not_found = false;
+		if (cfRefs != null)
+			for (int i = 0; i < cfRefs.length; i++) {
+				ConnectionFactory prov = (ConnectionFactory) bc.getService(cfRefs[i]);
+				if (prov != null)
+					try {
+						not_found = true;
+						ret = prov.createConnection(uri, mode, timeouts);
+					} catch (IOException e) {
+						if (hasDebug) {
+							debug(16003, prov.getClass().getName(), e);
+						}
+						if (ioExc == null)
+							ioExc = e;
+					} finally {
+						if (ret == null)
+							bc.ungetService(cfRefs[i]);
+						else {
+							if (hasDebug) {
+								debug(16004, prov.getClass().getName(), null);
+							}
+							return ret;
+						}
+					}
+			}
+
+		if (connector)
+			try {
+				ret = Connector.open(uri, mode, timeouts);
+			} catch (ConnectionNotFoundException ignore) { // returns null ->
+				// ConnectionNotifier
+				// is created
+				debug(16014, null, ignore);
+			} finally {
+				if (ret == null) {
+					if (ioExc != null)
+						throw ioExc;
+					if (not_found)
+						throw new ConnectionNotFoundException("Failed to create connection " + uri);
+
+				} else {
+					if (hasDebug) {
+						debug(16005, null, null);
+					}
+				}
+			}
+		return ret;
+	}
+
+	private static void sort(ServiceReference[] array, int start, int end) {
+		int middle = (start + end) / 2;
+		if (start + 1 < middle)
+			sort(array, start, middle);
+		if (middle + 1 < end)
+			sort(array, middle, end);
+		if (start + 1 >= end)
+			return; // this case can only happen when this method is called by
+		// the user
+
+		if (getRanking(array[middle - 1]) == getRanking(array[middle])) {
+			if (getServiceID(array[middle - 1]) < getServiceID(array[middle])) {
+				return;
+			}
+		} else if (getRanking(array[middle - 1]) >= getRanking(array[middle])) {
+			return;
+		}
+
+		if (start + 2 == end) {
+			ServiceReference temp = array[start];
+			array[start] = array[middle];
+			array[middle] = temp;
+			return;
+		}
+		int i1 = start, i2 = middle, i3 = 0;
+		Object[] merge = new Object[end - start];
+		while (i1 < middle && i2 < end) {
+			if (getRanking(array[i1]) == getRanking(array[i2])) {
+				merge[i3++] = getServiceID(array[i1]) < getServiceID(array[i2]) ? array[i1++] : array[i2++];
+			} else {
+				merge[i3++] = getRanking(array[i1]) >= getRanking(array[i2]) ? array[i1++] : array[i2++];
+			}
+		}
+		if (i1 < middle)
+			System.arraycopy(array, i1, merge, i3, middle - i1);
+		System.arraycopy(merge, 0, array, start, i2 - start);
+	}
+
+	private static int getRanking(ServiceReference ref) {
+		Object rank = ref.getProperty(Constants.SERVICE_RANKING);
+
+		if (rank == null || !(rank instanceof Integer)) {
+			return 0;
+		}
+
+		return ((Integer) rank).intValue();
+	}
+
+	private static long getServiceID(ServiceReference ref) {
+		Object sid = ref.getProperty(Constants.SERVICE_ID);
+
+		if (sid == null || !(sid instanceof Long)) {
+			return 0;
+		}
+
+		return ((Long) sid).intValue();
+	}
+
+	/**
+	 * Create and open an <tt>DataInputStream</tt> object for the specified
+	 * name.
+	 * 
+	 * @param name
+	 *            the URI for the connection.
+	 * @throws IOException
+	 *             if and I/O error occurs
+	 * @throws ConnectionNotFoundException
+	 *             if the <tt>Connection</tt> object can not be made or if no
+	 *             handler for the requested scheme can be found.
+	 * @throws IllegalArgumentException
+	 *             if the given uri is invalid
+	 * @return A <tt>DataInputStream</tt> to the given URI
+	 */
+	public DataInputStream openDataInputStream(String name) throws IOException {
+		long timeBegin = 0;
+		if (hasDebug) {
+			debug(16006, name, null);
+			timeBegin = System.currentTimeMillis();
+		}
+		try {
+			Connection conn = open(name, READ);
+
+			if (!(conn instanceof InputConnection)) {
+				try {
+					conn.close();
+				} catch (IOException e) {
+				}
+				throw new IOException("Connection does not implement InputConnection:" + conn.getClass());
+			}
+
+			return ((InputConnection) conn).openDataInputStream();
+		} finally {
+			if (hasDebug) {
+				debug(16007, String.valueOf(System.currentTimeMillis() - timeBegin), null);
+			}
+		}
+	}
+
+	/**
+	 * Create and open an <tt>DataOutputStream</tt> object for the specified
+	 * name.
+	 * 
+	 * @param name
+	 *            the URI for the connection.
+	 * @throws IOException
+	 *             if and I/O error occurs
+	 * @throws ConnectionNotFoundException
+	 *             if the <tt>Connection</tt> object can not be made or if no
+	 *             handler for the requested scheme can be found.
+	 * @throws IllegalArgumentException
+	 *             if the given uri is invalid
+	 * @return A <tt>DataOutputStream</tt> to the given URI
+	 */
+	public DataOutputStream openDataOutputStream(String name) throws IOException {
+		long timeBegin = 0;
+		if (hasDebug) {
+			debug(16008, name, null);
+		}
+		try {
+			Connection conn = open(name, WRITE);
+
+			if (!(conn instanceof OutputConnection)) {
+				try {
+					conn.close();
+				} catch (IOException e) {
+				}
+
+				throw new IOException("Connection does not implement OutputConnection:" + conn.getClass());
+			}
+
+			return ((OutputConnection) conn).openDataOutputStream();
+		} finally {
+			if (hasDebug) {
+				debug(16009, String.valueOf(System.currentTimeMillis() - timeBegin), null);
+			}
+		}
+	}
+
+	/**
+	 * Create and open an <tt>InputStream</tt> object for the specified name.
+	 * 
+	 * 
+	 * @param name
+	 *            the URI for the connection.
+	 * @throws IOException
+	 *             if and I/O error occurs
+	 * @throws ConnectionNotFoundException
+	 *             if the <tt>Connection</tt> object can not be made or if no
+	 *             handler for the requested scheme can be found.
+	 * @throws IllegalArgumentException
+	 *             if the given uri is invalid
+	 * @return A <tt>InputStream</tt> to the given URI
+	 */
+	public InputStream openInputStream(String name) throws IOException {
+		long timeBegin = 0;
+		if (hasDebug) {
+			debug(16010, name, null);
+			timeBegin = System.currentTimeMillis();
+		}
+		try {
+			Connection conn = open(name, READ);
+
+			if (!(conn instanceof InputConnection)) {
+				try {
+					conn.close();
+				} catch (IOException e) {
+				}
+
+				throw new IOException("Connection does not implement InputConnection:" + conn.getClass());
+			}
+
+			return ((InputConnection) conn).openInputStream();
+		} finally {
+			if (hasDebug) {
+				debug(16011, String.valueOf(System.currentTimeMillis() - timeBegin), null);
+			}
+		}
+	}
+
+	/**
+	 * Create and open an <tt>OutputStream</tt> object for the specified name.
+	 * 
+	 * @param name
+	 *            the URI for the connection.
+	 * @throws IOException
+	 *             if and I/O error occurs
+	 * @throws ConnectionNotFoundException
+	 *             if the <tt>Connection</tt> object can not be made or if no
+	 *             handler for the requested scheme can be found.
+	 * @throws IllegalArgumentException
+	 *             if the given uri is invalid
+	 * @return A <tt>OutputStream</tt> to the given URI
+	 */
+	public OutputStream openOutputStream(String name) throws IOException {
+		long timeBegin = 0;
+		if (hasDebug) {
+			debug(16012, name, null);
+			timeBegin = System.currentTimeMillis();
+		}
+		try {
+			Connection conn = open(name, WRITE);
+
+			if (!(conn instanceof OutputConnection)) {
+				try {
+					conn.close();
+				} catch (IOException e) {
+				}
+
+				throw new IOException("Connection does not implement OutputConnection:" + conn.getClass());
+			}
+
+			return ((OutputConnection) conn).openOutputStream();
+		} finally {
+			if (hasDebug) {
+				debug(16013, String.valueOf(System.currentTimeMillis() - timeBegin), null);
+			}
+		}
+	}
+}
diff --git a/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/impl/PrivilegedRunner.java b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/impl/PrivilegedRunner.java
new file mode 100644
index 0000000..485724e
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/impl/PrivilegedRunner.java
@@ -0,0 +1,194 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.io.impl;
+
+import java.security.*;
+import org.eclipse.equinox.internal.util.pool.ObjectCreator;
+import org.eclipse.equinox.internal.util.pool.ObjectPool;
+
+/**
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public final class PrivilegedRunner implements ObjectCreator {
+
+	private static ObjectPool POOL;
+
+	static {
+		try {
+			POOL = new ObjectPool(new PrivilegedRunner(), 5, 10);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	/* prevent instantiations */
+	private PrivilegedRunner() {
+	}
+
+	/**
+	 * Same as the longer doPrivileged method, but fills in the first parameter
+	 * only. All other parameters are set to <code>null</code>.
+	 * 
+	 * @param dispatcher
+	 *            the dispatcher which should be called
+	 * @param type
+	 *            the type of the action - used in the dispatcher
+	 * @param arg1
+	 *            a parameter received by the dispatcher
+	 * @see #doPrivileged(PrivilegedDispatcher, int, Object, Object, Object,
+	 *      Object)
+	 * @return the object returned from the execution
+	 * @throws Exception
+	 *             if the dispatcher fails
+	 */
+	public static final Object doPrivileged(PrivilegedDispatcher dispatcher, int type, Object arg1) throws Exception {
+		return doPrivileged(null, dispatcher, type, arg1, null, null, null);
+	}
+
+	/**
+	 * Performs a privileged action. The method calls the dispatcher inside the
+	 * privileged call passing it the same parameters that were passed to this
+	 * method.
+	 * 
+	 * @param dispatcher
+	 *            the dispatcher which should be called
+	 * @param type
+	 *            the type of the action - used in the dispatcher
+	 * @param arg1
+	 *            a parameter received by the dispatcher
+	 * @param arg2
+	 *            a parameter received by the dispatcher
+	 * @param arg3
+	 *            a parameter received by the dispatcher
+	 * @param arg4
+	 *            a parameter received by the dispatcher
+	 * @return the object returned from the execution
+	 * @throws Exception
+	 *             if the dispatcher fails
+	 */
+	public static final Object doPrivileged(PrivilegedDispatcher dispatcher, int type, Object arg1, Object arg2, Object arg3, Object arg4) throws Exception {
+		return doPrivileged(null, dispatcher, type, arg1, arg2, arg3, arg4);
+	}
+
+	/**
+	 * Performs a privileged action. The method calls the dispatcher inside the
+	 * privileged call passing it the same parameters that were passed to this
+	 * method.
+	 * 
+	 * @param context
+	 *            the access context
+	 * @param dispatcher
+	 *            the dispatcher which should be called
+	 * @param type
+	 *            the type of the action - used in the dispatcher
+	 * @param arg1
+	 *            a parameter received by the dispatcher
+	 * @param arg2
+	 *            a parameter received by the dispatcher
+	 * @param arg3
+	 *            a parameter received by the dispatcher
+	 * @param arg4
+	 *            a parameter received by the dispatcher
+	 * @return the object returned from the execution
+	 * @throws Exception
+	 *             if the dispatcher fails
+	 */
+	public static final Object doPrivileged(Object context, PrivilegedDispatcher dispatcher, int type, Object arg1, Object arg2, Object arg3, Object arg4) throws Exception {
+		/* init runner */
+		PA runner = (PA) POOL.getObject();
+		runner.dispatcher = dispatcher;
+		runner.type = type;
+		runner.arg1 = arg1;
+		runner.arg2 = arg2;
+		runner.arg3 = arg3;
+		runner.arg4 = arg4;
+
+		try {
+			if (System.getSecurityManager() != null) {
+				/*
+				 * if security manager is set - then privileged execution is
+				 * started
+				 */
+				return (context != null)
+				// 
+				? AccessController.doPrivileged(runner, (AccessControlContext) context)
+						: AccessController.doPrivileged(runner);
+			}
+			/* if no security manager is set - simply run the action */
+			return runner.run();
+		} catch (PrivilegedActionException e) {
+			throw e.getException();
+		} finally {
+			runner.recycle();
+			POOL.releaseObject(runner);
+		}
+	}
+
+	/**
+	 * @see org.eclipse.equinox.internal.util.pool.ObjectCreator#getInstance()
+	 */
+	public Object getInstance() throws Exception {
+		return new PA();
+	}
+
+	/**
+	 * This dispatcher is the handler that is called within the privileged call.
+	 * It should dispatch and perform the requested actions depending on the
+	 * action type and using the given job parameters.
+	 * 
+	 * @author Valentin Valchev
+	 * @version $Revision: 1.3 $
+	 */
+	public static interface PrivilegedDispatcher {
+
+		/**
+		 * @param type
+		 *            the type of the action
+		 * @param arg1
+		 *            parameter 1 - depends on the action type
+		 * @param arg2
+		 *            parameter 2 - depends on the action type
+		 * @param arg3
+		 *            parameter 3 - depends on the action type
+		 * @param arg4
+		 *            parameter 4 - depends on the action type
+		 * @return an object which should be returned from the
+		 *         PrivilegedAction.run() method
+		 * @throws Exception
+		 *             on error
+		 */
+		Object dispatchPrivileged(int type, Object arg1, Object arg2, Object arg3, Object arg4) throws Exception;
+	}
+
+	static class PA implements PrivilegedExceptionAction {
+
+		int type;
+		Object arg1, arg2, arg3, arg4;
+		PrivilegedDispatcher dispatcher;
+
+		void recycle() {
+			dispatcher = null;
+			type = -1;
+			arg1 = arg2 = arg3 = arg4 = null;
+		}
+
+		/**
+		 * @see java.security.PrivilegedExceptionAction#run()
+		 */
+		public Object run() throws Exception {
+			return dispatcher.dispatchPrivileged(type, arg1, arg2, arg3, arg4);
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/impl/TracerConfigConnector.java b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/impl/TracerConfigConnector.java
new file mode 100644
index 0000000..caa5445
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/impl/TracerConfigConnector.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.io.impl;
+
+import org.eclipse.equinox.internal.util.hash.HashIntObjNS;
+
+/**
+ * @author Lubomir Mitev
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+public class TracerConfigConnector {
+
+	public static HashIntObjNS getMap() {
+		/*
+		 * increase size if you add more dumps in the table - at this moment the
+		 * entries in table are 159
+		 */
+		HashIntObjNS map = new HashIntObjNS(28);// (int)(28 * 0.7) = 19, 18
+		constructMap(map);
+		return map;
+	}
+
+	public static void constructMap(HashIntObjNS map) {
+		map.put(-0x1200, "Connector Service");
+		map.put(16001, "[BEGIN - open connection] The values of the URI and the access mode are");
+		map.put(16002, "[END - open connection] took");
+		map.put(16003, "IOException when connection is created from ConnectionFactory");
+		map.put(16004, "Connection is created from ConnectionFactory");
+		map.put(16005, "Connection is created from javax.microedition.io.Connector");
+		map.put(16006, "[BEGIN - open DataInputStream] The URI is");
+		map.put(16007, "[END - open DataInputStream] took");
+		map.put(16008, "[BEGIN - open DataOutputStream] The URI is");
+		map.put(16009, "[END - open DataOutputStream] took");
+		map.put(16010, "[BEGIN - open InputStream] The URI is");
+		map.put(16011, "[END - open InputStream] took");
+		map.put(16012, "[BEGIN - open OutputStream] The URI is");
+		map.put(16013, "[END - open OutputStream] took");
+		map.put(16014, "ConnectionNotFoundException thrown from system javax.microedition.io.Connector");
+		map.put(16050, "[BEGIN - add ConnectionListener] The ConnectionListener is");
+		map.put(16051, "[END - add ConnectionListener] took");
+		map.put(16052, "Remove ConnectionListener");
+		map.put(16053, "Close connection. The URI is");
+	}
+}
diff --git a/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/package.html b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/package.html
new file mode 100644
index 0000000..32d3d84
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/package.html
@@ -0,0 +1,10 @@
+<!-- $Header: /cvsroot/eclipse/equinox-incubator/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/package.html,v 1.1 2007/11/30 13:45:13 pdobrev Exp $ -->
+<BODY>
+<P>The OSGi IO Provider Specification Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the <TT>Import-Package</TT> header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.service.io; specification-version=1.0
+</pre>
+</BODY>
diff --git a/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/util/AbstractConnectionNotifier.java b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/util/AbstractConnectionNotifier.java
new file mode 100644
index 0000000..5cf2968
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/util/AbstractConnectionNotifier.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.io.util;
+
+import java.util.*;
+import javax.microedition.io.Connection;
+import org.eclipse.equinox.internal.io.ConnectionListener;
+import org.eclipse.equinox.internal.io.ConnectionNotifier;
+
+/**
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public abstract class AbstractConnectionNotifier extends Dictionary implements ConnectionNotifier {
+	private Vector list;
+	private Hashtable info;
+
+	// the local address to which the connection is bound
+
+	public final static String LOCAL_ADDRESS = "local_address";
+
+	// the local port to which the connection is bound.
+
+	public final static String LOCAL_PORT = "local_port";
+
+	// the remote address to which the connection is connected.
+
+	public final static String ADDRESS = "address";
+
+	// the remote port to which the connection is connected.
+
+	public final static String PORT = "port";
+
+	// the encoder used
+
+	public final static String ENCODER = "enc";
+
+	public static final String SO_TIMEOUT = "timeout";
+
+	protected AbstractConnectionNotifier() {
+		list = new Vector(2, 3);
+		info = new Hashtable(30);
+	}
+
+	// ConnectionNotifier methods
+	public void addConnectionListener(ConnectionListener l) {
+		if (!list.contains(l)) {
+			list.addElement(l);
+		}
+	}
+
+	public void removeConnectionListener(ConnectionListener l) {
+		list.removeElement(l);
+	}
+
+	// returns the url of connection
+	protected abstract String getURL();
+
+	// the connection to which this ConnectionLife is bound to
+	protected abstract Connection getConnection();
+
+	protected void notifyClosed() {
+		for (Enumeration en = list.elements(); en.hasMoreElements();) {
+			ConnectionListener l = (ConnectionListener) en.nextElement();
+			l.notify(getURL(), ConnectionListener.CONNECTION_CLOSED, getConnection());
+		}
+	}
+
+	protected void setInfo(String key, Object value) {
+		if (key != null && value != null) {
+			info.put(key, value);
+		}
+	}
+
+	public int size() {
+		return info.size();
+	}
+
+	public boolean isEmpty() {
+		return info.isEmpty();
+	}
+
+	public Enumeration keys() {
+		return info.keys();
+	}
+
+	public Enumeration elements() {
+		return info.elements();
+	}
+
+	public Object get(Object key) {
+		return info.get(key);
+	}
+
+	public Object remove(Object key) {
+		return info.remove(key);
+	}
+
+}
diff --git a/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/util/AbstractDatagram.java b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/util/AbstractDatagram.java
new file mode 100644
index 0000000..4f81da4
--- /dev/null
+++ b/bundles/org.eclipse.equinox.io/src/org/eclipse/equinox/internal/io/util/AbstractDatagram.java
@@ -0,0 +1,434 @@
+/*******************************************************************************
+ * Copyright (c) 1997-2007 by ProSyst Software GmbH
+ * http://www.prosyst.com
+ * 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:
+ *    ProSyst Software GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.io.util;
+
+import java.io.*;
+import javax.microedition.io.Datagram;
+
+/**
+ * @author Pavlin Dobrev
+ * @version 1.0
+ */
+
+public abstract class AbstractDatagram implements Datagram {
+	protected byte[] data;
+	private int pos;
+	private int count;
+
+	public AbstractDatagram(int size) {
+		this(new byte[size]);
+	}
+
+	public AbstractDatagram(byte[] data) {
+		this.data = data;
+		pos = 0;
+		count = data.length;
+	}
+
+	public AbstractDatagram(byte[] data, int start, int length) {
+		if (start > data.length || (start + length) > data.length) {
+			throw new IllegalArgumentException("Start possition or length is greater than data length");
+		}
+
+		this.data = data;
+		pos = start;
+		count = length;
+	}
+
+	public synchronized byte[] getData() {
+		return data;
+	}
+
+	public int getLength() {
+		return count;
+	}
+
+	public int getOffset() {
+		return pos;
+	}
+
+	public void setLength(int len) {
+		if (len < 0 || len > data.length) {
+			throw new IllegalArgumentException("Given length is negative or greater than buffer size");
+		}
+
+		count = len;
+	}
+
+	public synchronized void setData(byte[] buffer, int offset, int len) {
+		if (offset > buffer.length || (offset + len) > buffer.length) {
+			throw new IllegalArgumentException();
+		}
+
+		data = buffer;
+		pos = offset;
+		count = len;
+	}
+
+	public void reset() {
+		pos = 0;
+		count = 0;
+	}
+
+	public int read() {
+		return (pos < count) ? (data[pos++] & 0xff) : -1;
+	}
+
+	public void readFully(byte b[]) throws IOException {
+		readFully(b, 0, b.length);
+	}
+
+	public void readFully(byte b[], int off, int len) throws IOException {
+		if (len < 0) {
+			throw new IndexOutOfBoundsException();
+		}
+
+		int n = 0;
+
+		while (n < len) {
+			int ch = read();
+
+			if (ch < 0) {
+				throw new EOFException();
+			}
+
+			b[off + (n++)] = (byte) ch;
+		}
+	}
+
+	public int skipBytes(int n) throws IOException {
+		if (pos + n > count) {
+			n = count - pos;
+		}
+
+		if (n < 0) {
+			return 0;
+		}
+
+		pos += n;
+		return n;
+	}
+
+	public boolean readBoolean() throws IOException {
+		int ch = read();
+
+		if (ch < 0) {
+			throw new EOFException();
+		}
+
+		return (ch != 0);
+	}
+
+	public byte readByte() throws IOException {
+		int ch = read();
+
+		if (ch < 0) {
+			throw new EOFException();
+		}
+
+		return (byte) (ch);
+	}
+
+	public int readUnsignedByte() throws IOException {
+		int ch = read();
+
+		if (ch < 0) {
+			throw new EOFException();
+		}
+
+		return ch;
+	}
+
+	public short readShort() throws IOException {
+		int ch1 = read();
+		int ch2 = read();
+
+		if ((ch1 | ch2) < 0) {
+			throw new EOFException();
+		}
+
+		return (short) ((ch1 << 8) + (ch2 << 0));
+	}
+
+	public int readUnsignedShort() throws IOException {
+		int ch1 = read();
+		int ch2 = read();
+
+		if ((ch1 | ch2) < 0) {
+			throw new EOFException();
+		}
+
+		return (ch1 << 8) + (ch2 << 0);
+	}
+
+	public char readChar() throws IOException {
+		int ch1 = read();
+		int ch2 = read();
+
+		if ((ch1 | ch2) < 0) {
+			throw new EOFException();
+		}
+
+		return (char) ((ch1 << 8) + (ch2 << 0));
+	}
+
+	public int readInt() throws IOException {
+		int ch1 = read();
+		int ch2 = read();
+		int ch3 = read();
+		int ch4 = read();
+
+		if ((ch1 | ch2 | ch3 | ch4) < 0) {
+			throw new EOFException();
+		}
+
+		return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
+	}
+
+	public long readLong() throws IOException {
+		return ((long) (readInt()) << 32) + (readInt() & 0xFFFFFFFFL);
+	}
+
+	public float readFloat() throws IOException {
+		return Float.intBitsToFloat(readInt());
+	}
+
+	public double readDouble() throws IOException {
+		return Double.longBitsToDouble(readLong());
+	}
+
+	public String readLine() throws IOException {
+		throw new RuntimeException("Function not supported");
+	}
+
+	public String readUTF() throws IOException {
+		return readUTF(this);
+	}
+
+	public final static String readUTF(DataInput in) throws IOException {
+		int utflen = in.readUnsignedShort();
+		StringBuffer str = new StringBuffer(utflen);
+		byte bytearr[] = new byte[utflen];
+		int c, char2, char3;
+		int count = 0;
+
+		in.readFully(bytearr, 0, utflen);
+
+		while (count < utflen) {
+			c = bytearr[count] & 0xff;
+
+			switch (c >> 4) {
+				case 0 :
+				case 1 :
+				case 2 :
+				case 3 :
+				case 4 :
+				case 5 :
+				case 6 :
+				case 7 :
+					/* 0xxxxxxx */
+					count++;
+					str.append((char) c);
+					break;
+
+				case 12 :
+				case 13 :
+					/* 110x xxxx 10xx xxxx */
+					count += 2;
+
+					if (count > utflen) {
+						throw new UTFDataFormatException();
+					}
+
+					char2 = bytearr[count - 1];
+
+					if ((char2 & 0xC0) != 0x80) {
+						throw new UTFDataFormatException();
+					}
+
+					str.append((char) (((c & 0x1F) << 6) | (char2 & 0x3F)));
+					break;
+
+				case 14 :
+					/* 1110 xxxx 10xx xxxx 10xx xxxx */
+					count += 3;
+
+					if (count > utflen) {
+						throw new UTFDataFormatException();
+					}
+
+					char2 = bytearr[count - 2];
+					char3 = bytearr[count - 1];
+
+					if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) {
+						throw new UTFDataFormatException();
+					}
+
+					str.append((char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0)));
+					break;
+
+				default :
+					/* 10xx xxxx, 1111 xxxx */
+					throw new UTFDataFormatException();
+			}
+		}
+
+		// The number of chars produced may be less than utflen
+		return str.toString();