You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2014/04/18 23:35:51 UTC

[1/6] [KARAF-2923] Region support in features service

Repository: karaf
Updated Branches:
  refs/heads/master 53ad48f2a -> 2705ad889


http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/src/main/java/org/apache/karaf/region/persist/internal/model/FilterAttributeType.java
----------------------------------------------------------------------
diff --git a/region/src/main/java/org/apache/karaf/region/persist/internal/model/FilterAttributeType.java b/region/src/main/java/org/apache/karaf/region/persist/internal/model/FilterAttributeType.java
deleted file mode 100644
index 857c2b3..0000000
--- a/region/src/main/java/org/apache/karaf/region/persist/internal/model/FilterAttributeType.java
+++ /dev/null
@@ -1,94 +0,0 @@
-//
-// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.1-833 
-// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
-// Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2011.10.28 at 03:20:55 PM PDT 
-//
-
-
-package org.apache.karaf.region.persist.internal.model;
-
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlType;
-
-
-/**
- * <p>Java class for filterAttributeType complex type.
- * 
- * <p>The following schema fragment specifies the expected content contained within this class.
- * 
- * <pre>
- * &lt;complexType name="filterAttributeType">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *       &lt;/sequence>
- *       &lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *       &lt;attribute name="value" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
- * 
- * 
- */
-@XmlAccessorType(XmlAccessType.FIELD)
-@XmlType(name = "filterAttributeType")
-public class FilterAttributeType {
-
-    @XmlAttribute(required = true)
-    protected String name;
-    @XmlAttribute(required = true)
-    protected String value;
-
-    /**
-     * Gets the value of the name property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
-     */
-    public String getName() {
-        return name;
-    }
-
-    /**
-     * Sets the value of the name property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
-     */
-    public void setName(String value) {
-        this.name = value;
-    }
-
-    /**
-     * Gets the value of the value property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
-     */
-    public String getValue() {
-        return value;
-    }
-
-    /**
-     * Sets the value of the value property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
-     */
-    public void setValue(String value) {
-        this.value = value;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/src/main/java/org/apache/karaf/region/persist/internal/model/FilterBundleType.java
----------------------------------------------------------------------
diff --git a/region/src/main/java/org/apache/karaf/region/persist/internal/model/FilterBundleType.java b/region/src/main/java/org/apache/karaf/region/persist/internal/model/FilterBundleType.java
deleted file mode 100644
index a9a9fbb..0000000
--- a/region/src/main/java/org/apache/karaf/region/persist/internal/model/FilterBundleType.java
+++ /dev/null
@@ -1,156 +0,0 @@
-//
-// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.1-833 
-// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
-// Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2011.10.28 at 03:20:55 PM PDT 
-//
-
-
-package org.apache.karaf.region.persist.internal.model;
-
-import java.util.ArrayList;
-import java.util.List;
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlType;
-
-
-/**
- * <p>Java class for filterBundleType complex type.
- * 
- * <p>The following schema fragment specifies the expected content contained within this class.
- * 
- * <pre>
- * &lt;complexType name="filterBundleType">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *         &lt;element name="attribute" type="{http://karaf.apache.org/xmlns/region/v1.0.0}filterAttributeType" maxOccurs="unbounded" minOccurs="0"/>
- *       &lt;/sequence>
- *       &lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}long" />
- *       &lt;attribute name="symbolic-name" type="{http://www.w3.org/2001/XMLSchema}string" />
- *       &lt;attribute name="version" type="{http://www.w3.org/2001/XMLSchema}string" />
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
- * 
- * 
- */
-@XmlAccessorType(XmlAccessType.FIELD)
-@XmlType(name = "filterBundleType", propOrder = {
-    "attribute"
-})
-public class FilterBundleType {
-
-    protected List<FilterAttributeType> attribute;
-    @XmlAttribute
-    protected Long id;
-    @XmlAttribute(name = "symbolic-name")
-    protected String symbolicName;
-    @XmlAttribute
-    protected String version;
-
-    /**
-     * Gets the value of the attribute property.
-     * 
-     * <p>
-     * This accessor method returns a reference to the live list,
-     * not a snapshot. Therefore any modification you make to the
-     * returned list will be present inside the JAXB object.
-     * This is why there is not a <CODE>set</CODE> method for the attribute property.
-     * 
-     * <p>
-     * For example, to add a new item, do as follows:
-     * <pre>
-     *    getAttribute().add(newItem);
-     * </pre>
-     * 
-     * 
-     * <p>
-     * Objects of the following type(s) are allowed in the list
-     * {@link FilterAttributeType }
-     * 
-     * 
-     */
-    public List<FilterAttributeType> getAttribute() {
-        if (attribute == null) {
-            attribute = new ArrayList<FilterAttributeType>();
-        }
-        return this.attribute;
-    }
-
-    /**
-     * Gets the value of the id property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link Long }
-     *     
-     */
-    public Long getId() {
-        return id;
-    }
-
-    /**
-     * Sets the value of the id property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link Long }
-     *     
-     */
-    public void setId(Long value) {
-        this.id = value;
-    }
-
-    /**
-     * Gets the value of the symbolicName property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
-     */
-    public String getSymbolicName() {
-        return symbolicName;
-    }
-
-    /**
-     * Sets the value of the symbolicName property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
-     */
-    public void setSymbolicName(String value) {
-        this.symbolicName = value;
-    }
-
-    /**
-     * Gets the value of the version property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
-     */
-    public String getVersion() {
-        return version;
-    }
-
-    /**
-     * Sets the value of the version property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
-     */
-    public void setVersion(String value) {
-        this.version = value;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/src/main/java/org/apache/karaf/region/persist/internal/model/FilterNamespaceType.java
----------------------------------------------------------------------
diff --git a/region/src/main/java/org/apache/karaf/region/persist/internal/model/FilterNamespaceType.java b/region/src/main/java/org/apache/karaf/region/persist/internal/model/FilterNamespaceType.java
deleted file mode 100644
index 52b937a..0000000
--- a/region/src/main/java/org/apache/karaf/region/persist/internal/model/FilterNamespaceType.java
+++ /dev/null
@@ -1,102 +0,0 @@
-//
-// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.1-833 
-// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
-// Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2011.10.28 at 03:20:55 PM PDT 
-//
-
-
-package org.apache.karaf.region.persist.internal.model;
-
-import java.util.ArrayList;
-import java.util.List;
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlType;
-
-
-/**
- * <p>Java class for filterNamespaceType complex type.
- * 
- * <p>The following schema fragment specifies the expected content contained within this class.
- * 
- * <pre>
- * &lt;complexType name="filterNamespaceType">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *         &lt;element name="attribute" type="{http://karaf.apache.org/xmlns/region/v1.0.0}filterAttributeType" maxOccurs="unbounded" minOccurs="0"/>
- *       &lt;/sequence>
- *       &lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
- * 
- * 
- */
-@XmlAccessorType(XmlAccessType.FIELD)
-@XmlType(name = "filterNamespaceType", propOrder = {
-    "attribute"
-})
-public class FilterNamespaceType {
-
-    protected List<FilterAttributeType> attribute;
-    @XmlAttribute(required = true)
-    protected String name;
-
-    /**
-     * Gets the value of the attribute property.
-     * 
-     * <p>
-     * This accessor method returns a reference to the live list,
-     * not a snapshot. Therefore any modification you make to the
-     * returned list will be present inside the JAXB object.
-     * This is why there is not a <CODE>set</CODE> method for the attribute property.
-     * 
-     * <p>
-     * For example, to add a new item, do as follows:
-     * <pre>
-     *    getAttribute().add(newItem);
-     * </pre>
-     * 
-     * 
-     * <p>
-     * Objects of the following type(s) are allowed in the list
-     * {@link FilterAttributeType }
-     * 
-     * 
-     */
-    public List<FilterAttributeType> getAttribute() {
-        if (attribute == null) {
-            attribute = new ArrayList<FilterAttributeType>();
-        }
-        return this.attribute;
-    }
-
-    /**
-     * Gets the value of the name property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
-     */
-    public String getName() {
-        return name;
-    }
-
-    /**
-     * Sets the value of the name property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
-     */
-    public void setName(String value) {
-        this.name = value;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/src/main/java/org/apache/karaf/region/persist/internal/model/FilterPackageType.java
----------------------------------------------------------------------
diff --git a/region/src/main/java/org/apache/karaf/region/persist/internal/model/FilterPackageType.java b/region/src/main/java/org/apache/karaf/region/persist/internal/model/FilterPackageType.java
deleted file mode 100644
index b4216ee..0000000
--- a/region/src/main/java/org/apache/karaf/region/persist/internal/model/FilterPackageType.java
+++ /dev/null
@@ -1,129 +0,0 @@
-//
-// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.1-833 
-// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
-// Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2011.10.28 at 03:20:55 PM PDT 
-//
-
-
-package org.apache.karaf.region.persist.internal.model;
-
-import java.util.ArrayList;
-import java.util.List;
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlType;
-
-
-/**
- * <p>Java class for filterPackageType complex type.
- * 
- * <p>The following schema fragment specifies the expected content contained within this class.
- * 
- * <pre>
- * &lt;complexType name="filterPackageType">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *         &lt;element name="attribute" type="{http://karaf.apache.org/xmlns/region/v1.0.0}filterAttributeType" maxOccurs="unbounded" minOccurs="0"/>
- *       &lt;/sequence>
- *       &lt;attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
- *       &lt;attribute name="version" type="{http://www.w3.org/2001/XMLSchema}string" />
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
- * 
- * 
- */
-@XmlAccessorType(XmlAccessType.FIELD)
-@XmlType(name = "filterPackageType", propOrder = {
-    "attribute"
-})
-public class FilterPackageType {
-
-    protected List<FilterAttributeType> attribute;
-    @XmlAttribute
-    protected String name;
-    @XmlAttribute
-    protected String version;
-
-    /**
-     * Gets the value of the attribute property.
-     * 
-     * <p>
-     * This accessor method returns a reference to the live list,
-     * not a snapshot. Therefore any modification you make to the
-     * returned list will be present inside the JAXB object.
-     * This is why there is not a <CODE>set</CODE> method for the attribute property.
-     * 
-     * <p>
-     * For example, to add a new item, do as follows:
-     * <pre>
-     *    getAttribute().add(newItem);
-     * </pre>
-     * 
-     * 
-     * <p>
-     * Objects of the following type(s) are allowed in the list
-     * {@link FilterAttributeType }
-     * 
-     * 
-     */
-    public List<FilterAttributeType> getAttribute() {
-        if (attribute == null) {
-            attribute = new ArrayList<FilterAttributeType>();
-        }
-        return this.attribute;
-    }
-
-    /**
-     * Gets the value of the name property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
-     */
-    public String getName() {
-        return name;
-    }
-
-    /**
-     * Sets the value of the name property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
-     */
-    public void setName(String value) {
-        this.name = value;
-    }
-
-    /**
-     * Gets the value of the version property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
-     */
-    public String getVersion() {
-        return version;
-    }
-
-    /**
-     * Sets the value of the version property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
-     */
-    public void setVersion(String value) {
-        this.version = value;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/src/main/java/org/apache/karaf/region/persist/internal/model/FilterType.java
----------------------------------------------------------------------
diff --git a/region/src/main/java/org/apache/karaf/region/persist/internal/model/FilterType.java b/region/src/main/java/org/apache/karaf/region/persist/internal/model/FilterType.java
deleted file mode 100644
index f4d1352..0000000
--- a/region/src/main/java/org/apache/karaf/region/persist/internal/model/FilterType.java
+++ /dev/null
@@ -1,195 +0,0 @@
-//
-// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.1-833 
-// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
-// Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2011.10.28 at 03:20:55 PM PDT 
-//
-
-
-package org.apache.karaf.region.persist.internal.model;
-
-import java.util.ArrayList;
-import java.util.List;
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlType;
-
-
-/**
- * <p>Java class for filterType complex type.
- * 
- * <p>The following schema fragment specifies the expected content contained within this class.
- * 
- * <pre>
- * &lt;complexType name="filterType">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *         &lt;element name="bundle" type="{http://karaf.apache.org/xmlns/region/v1.0.0}filterBundleType" maxOccurs="unbounded" minOccurs="0"/>
- *         &lt;element name="package" type="{http://karaf.apache.org/xmlns/region/v1.0.0}filterPackageType" maxOccurs="unbounded" minOccurs="0"/>
- *         &lt;element name="namespace" type="{http://karaf.apache.org/xmlns/region/v1.0.0}filterNamespaceType" maxOccurs="unbounded" minOccurs="0"/>
- *       &lt;/sequence>
- *       &lt;attribute name="from" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *       &lt;attribute name="to" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
- * 
- * 
- */
-@XmlAccessorType(XmlAccessType.FIELD)
-@XmlType(name = "filterType", propOrder = {
-    "bundle",
-    "_package",
-    "namespace"
-})
-public class FilterType {
-
-    protected List<FilterBundleType> bundle;
-    @XmlElement(name = "package")
-    protected List<FilterPackageType> _package;
-    protected List<FilterNamespaceType> namespace;
-    @XmlAttribute(required = true)
-    protected String from;
-    @XmlAttribute(required = true)
-    protected String to;
-
-    /**
-     * Gets the value of the bundle property.
-     * 
-     * <p>
-     * This accessor method returns a reference to the live list,
-     * not a snapshot. Therefore any modification you make to the
-     * returned list will be present inside the JAXB object.
-     * This is why there is not a <CODE>set</CODE> method for the bundle property.
-     * 
-     * <p>
-     * For example, to add a new item, do as follows:
-     * <pre>
-     *    getBundle().add(newItem);
-     * </pre>
-     * 
-     * 
-     * <p>
-     * Objects of the following type(s) are allowed in the list
-     * {@link FilterBundleType }
-     * 
-     * 
-     */
-    public List<FilterBundleType> getBundle() {
-        if (bundle == null) {
-            bundle = new ArrayList<FilterBundleType>();
-        }
-        return this.bundle;
-    }
-
-    /**
-     * Gets the value of the package property.
-     * 
-     * <p>
-     * This accessor method returns a reference to the live list,
-     * not a snapshot. Therefore any modification you make to the
-     * returned list will be present inside the JAXB object.
-     * This is why there is not a <CODE>set</CODE> method for the package property.
-     * 
-     * <p>
-     * For example, to add a new item, do as follows:
-     * <pre>
-     *    getPackage().add(newItem);
-     * </pre>
-     * 
-     * 
-     * <p>
-     * Objects of the following type(s) are allowed in the list
-     * {@link FilterPackageType }
-     * 
-     * 
-     */
-    public List<FilterPackageType> getPackage() {
-        if (_package == null) {
-            _package = new ArrayList<FilterPackageType>();
-        }
-        return this._package;
-    }
-
-    /**
-     * Gets the value of the namespace property.
-     * 
-     * <p>
-     * This accessor method returns a reference to the live list,
-     * not a snapshot. Therefore any modification you make to the
-     * returned list will be present inside the JAXB object.
-     * This is why there is not a <CODE>set</CODE> method for the namespace property.
-     * 
-     * <p>
-     * For example, to add a new item, do as follows:
-     * <pre>
-     *    getNamespace().add(newItem);
-     * </pre>
-     * 
-     * 
-     * <p>
-     * Objects of the following type(s) are allowed in the list
-     * {@link FilterNamespaceType }
-     * 
-     * 
-     */
-    public List<FilterNamespaceType> getNamespace() {
-        if (namespace == null) {
-            namespace = new ArrayList<FilterNamespaceType>();
-        }
-        return this.namespace;
-    }
-
-    /**
-     * Gets the value of the from property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
-     */
-    public String getFrom() {
-        return from;
-    }
-
-    /**
-     * Sets the value of the from property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
-     */
-    public void setFrom(String value) {
-        this.from = value;
-    }
-
-    /**
-     * Gets the value of the to property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
-     */
-    public String getTo() {
-        return to;
-    }
-
-    /**
-     * Sets the value of the to property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
-     */
-    public void setTo(String value) {
-        this.to = value;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/src/main/java/org/apache/karaf/region/persist/internal/model/ObjectFactory.java
----------------------------------------------------------------------
diff --git a/region/src/main/java/org/apache/karaf/region/persist/internal/model/ObjectFactory.java b/region/src/main/java/org/apache/karaf/region/persist/internal/model/ObjectFactory.java
deleted file mode 100644
index 54f5f3c..0000000
--- a/region/src/main/java/org/apache/karaf/region/persist/internal/model/ObjectFactory.java
+++ /dev/null
@@ -1,116 +0,0 @@
-//
-// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.1-833 
-// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
-// Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2011.10.28 at 03:20:55 PM PDT 
-//
-
-
-package org.apache.karaf.region.persist.internal.model;
-
-import javax.xml.bind.JAXBElement;
-import javax.xml.bind.annotation.XmlElementDecl;
-import javax.xml.bind.annotation.XmlRegistry;
-import javax.xml.namespace.QName;
-
-
-/**
- * This object contains factory methods for each 
- * Java content interface and Java element interface 
- * generated in the org.apache.karaf.region.persist.internal.model package. 
- * <p>An ObjectFactory allows you to programatically 
- * construct new instances of the Java representation 
- * for XML content. The Java representation of XML 
- * content can consist of schema derived interfaces 
- * and classes representing the binding of schema 
- * type definitions, element declarations and model 
- * groups.  Factory methods for each of these are 
- * provided in this class.
- * 
- */
-@XmlRegistry
-public class ObjectFactory {
-
-    private final static QName _Regions_QNAME = new QName("http://karaf.apache.org/xmlns/region/v1.0.0", "regions");
-
-    /**
-     * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.apache.karaf.region.persist.internal.model
-     * 
-     */
-    public ObjectFactory() {
-    }
-
-    /**
-     * Create an instance of {@link FilterNamespaceType }
-     * 
-     */
-    public FilterNamespaceType createFilterNamespaceType() {
-        return new FilterNamespaceType();
-    }
-
-    /**
-     * Create an instance of {@link FilterType }
-     * 
-     */
-    public FilterType createFilterType() {
-        return new FilterType();
-    }
-
-    /**
-     * Create an instance of {@link RegionBundleType }
-     * 
-     */
-    public RegionBundleType createRegionBundleType() {
-        return new RegionBundleType();
-    }
-
-    /**
-     * Create an instance of {@link FilterBundleType }
-     * 
-     */
-    public FilterBundleType createFilterBundleType() {
-        return new FilterBundleType();
-    }
-
-    /**
-     * Create an instance of {@link FilterPackageType }
-     * 
-     */
-    public FilterPackageType createFilterPackageType() {
-        return new FilterPackageType();
-    }
-
-    /**
-     * Create an instance of {@link FilterAttributeType }
-     * 
-     */
-    public FilterAttributeType createFilterAttributeType() {
-        return new FilterAttributeType();
-    }
-
-    /**
-     * Create an instance of {@link RegionType }
-     * 
-     */
-    public RegionType createRegionType() {
-        return new RegionType();
-    }
-
-    /**
-     * Create an instance of {@link RegionsType }
-     * 
-     */
-    public RegionsType createRegionsType() {
-        return new RegionsType();
-    }
-
-    /**
-     * Create an instance of {@link JAXBElement }{@code <}{@link RegionsType }{@code >}}
-     * 
-     */
-    @XmlElementDecl(namespace = "http://karaf.apache.org/xmlns/region/v1.0.0", name = "regions")
-    public JAXBElement<RegionsType> createRegions(RegionsType value) {
-        return new JAXBElement<RegionsType>(_Regions_QNAME, RegionsType.class, null, value);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/src/main/java/org/apache/karaf/region/persist/internal/model/RegionBundleType.java
----------------------------------------------------------------------
diff --git a/region/src/main/java/org/apache/karaf/region/persist/internal/model/RegionBundleType.java b/region/src/main/java/org/apache/karaf/region/persist/internal/model/RegionBundleType.java
deleted file mode 100644
index 7ba3585..0000000
--- a/region/src/main/java/org/apache/karaf/region/persist/internal/model/RegionBundleType.java
+++ /dev/null
@@ -1,94 +0,0 @@
-//
-// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.1-833 
-// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
-// Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2011.10.28 at 03:20:55 PM PDT 
-//
-
-
-package org.apache.karaf.region.persist.internal.model;
-
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlType;
-
-
-/**
- * <p>Java class for regionBundleType complex type.
- * 
- * <p>The following schema fragment specifies the expected content contained within this class.
- * 
- * <pre>
- * &lt;complexType name="regionBundleType">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *       &lt;/sequence>
- *       &lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}long" />
- *       &lt;attribute name="location" type="{http://www.w3.org/2001/XMLSchema}string" />
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
- * 
- * 
- */
-@XmlAccessorType(XmlAccessType.FIELD)
-@XmlType(name = "regionBundleType")
-public class RegionBundleType {
-
-    @XmlAttribute
-    protected Long id;
-    @XmlAttribute
-    protected String location;
-
-    /**
-     * Gets the value of the id property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link Long }
-     *     
-     */
-    public Long getId() {
-        return id;
-    }
-
-    /**
-     * Sets the value of the id property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link Long }
-     *     
-     */
-    public void setId(Long value) {
-        this.id = value;
-    }
-
-    /**
-     * Gets the value of the location property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
-     */
-    public String getLocation() {
-        return location;
-    }
-
-    /**
-     * Sets the value of the location property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
-     */
-    public void setLocation(String value) {
-        this.location = value;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/src/main/java/org/apache/karaf/region/persist/internal/model/RegionType.java
----------------------------------------------------------------------
diff --git a/region/src/main/java/org/apache/karaf/region/persist/internal/model/RegionType.java b/region/src/main/java/org/apache/karaf/region/persist/internal/model/RegionType.java
deleted file mode 100644
index f7a810d..0000000
--- a/region/src/main/java/org/apache/karaf/region/persist/internal/model/RegionType.java
+++ /dev/null
@@ -1,106 +0,0 @@
-//
-// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.1-833 
-// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
-// Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2011.10.28 at 03:20:55 PM PDT 
-//
-
-
-package org.apache.karaf.region.persist.internal.model;
-
-import java.util.ArrayList;
-import java.util.List;
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlType;
-
-
-/**
- * 
- *                 Regions element
- *             
- * 
- * <p>Java class for regionType complex type.
- * 
- * <p>The following schema fragment specifies the expected content contained within this class.
- * 
- * <pre>
- * &lt;complexType name="regionType">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *         &lt;element name="bundle" type="{http://karaf.apache.org/xmlns/region/v1.0.0}regionBundleType" maxOccurs="unbounded" minOccurs="0"/>
- *       &lt;/sequence>
- *       &lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
- * 
- * 
- */
-@XmlAccessorType(XmlAccessType.FIELD)
-@XmlType(name = "regionType", propOrder = {
-    "bundle"
-})
-public class RegionType {
-
-    protected List<RegionBundleType> bundle;
-    @XmlAttribute(required = true)
-    protected String name;
-
-    /**
-     * Gets the value of the bundle property.
-     * 
-     * <p>
-     * This accessor method returns a reference to the live list,
-     * not a snapshot. Therefore any modification you make to the
-     * returned list will be present inside the JAXB object.
-     * This is why there is not a <CODE>set</CODE> method for the bundle property.
-     * 
-     * <p>
-     * For example, to add a new item, do as follows:
-     * <pre>
-     *    getBundle().add(newItem);
-     * </pre>
-     * 
-     * 
-     * <p>
-     * Objects of the following type(s) are allowed in the list
-     * {@link RegionBundleType }
-     * 
-     * 
-     */
-    public List<RegionBundleType> getBundle() {
-        if (bundle == null) {
-            bundle = new ArrayList<RegionBundleType>();
-        }
-        return this.bundle;
-    }
-
-    /**
-     * Gets the value of the name property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
-     */
-    public String getName() {
-        return name;
-    }
-
-    /**
-     * Sets the value of the name property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
-     */
-    public void setName(String value) {
-        this.name = value;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/src/main/java/org/apache/karaf/region/persist/internal/model/RegionsType.java
----------------------------------------------------------------------
diff --git a/region/src/main/java/org/apache/karaf/region/persist/internal/model/RegionsType.java b/region/src/main/java/org/apache/karaf/region/persist/internal/model/RegionsType.java
deleted file mode 100644
index be172e4..0000000
--- a/region/src/main/java/org/apache/karaf/region/persist/internal/model/RegionsType.java
+++ /dev/null
@@ -1,112 +0,0 @@
-//
-// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.1-833 
-// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
-// Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2011.10.28 at 03:20:55 PM PDT 
-//
-
-
-package org.apache.karaf.region.persist.internal.model;
-
-import java.util.ArrayList;
-import java.util.List;
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
-
-
-/**
- * 
- *                 Regions element
- *             
- * 
- * <p>Java class for regionsType complex type.
- * 
- * <p>The following schema fragment specifies the expected content contained within this class.
- * 
- * <pre>
- * &lt;complexType name="regionsType">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *         &lt;element name="region" type="{http://karaf.apache.org/xmlns/region/v1.0.0}regionType" maxOccurs="unbounded" minOccurs="0"/>
- *         &lt;element name="filter" type="{http://karaf.apache.org/xmlns/region/v1.0.0}filterType" maxOccurs="unbounded" minOccurs="0"/>
- *       &lt;/sequence>
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
- * 
- * 
- */
-@XmlRootElement(name = "regions")
-@XmlAccessorType(XmlAccessType.FIELD)
-@XmlType(name = "regionsType", propOrder = {
-    "region",
-    "filter"
-})
-public class RegionsType {
-
-    protected List<RegionType> region;
-    protected List<FilterType> filter;
-
-    /**
-     * Gets the value of the region property.
-     * 
-     * <p>
-     * This accessor method returns a reference to the live list,
-     * not a snapshot. Therefore any modification you make to the
-     * returned list will be present inside the JAXB object.
-     * This is why there is not a <CODE>set</CODE> method for the region property.
-     * 
-     * <p>
-     * For example, to add a new item, do as follows:
-     * <pre>
-     *    getRegion().add(newItem);
-     * </pre>
-     * 
-     * 
-     * <p>
-     * Objects of the following type(s) are allowed in the list
-     * {@link RegionType }
-     * 
-     * 
-     */
-    public List<RegionType> getRegion() {
-        if (region == null) {
-            region = new ArrayList<RegionType>();
-        }
-        return this.region;
-    }
-
-    /**
-     * Gets the value of the filter property.
-     * 
-     * <p>
-     * This accessor method returns a reference to the live list,
-     * not a snapshot. Therefore any modification you make to the
-     * returned list will be present inside the JAXB object.
-     * This is why there is not a <CODE>set</CODE> method for the filter property.
-     * 
-     * <p>
-     * For example, to add a new item, do as follows:
-     * <pre>
-     *    getFilter().add(newItem);
-     * </pre>
-     * 
-     * 
-     * <p>
-     * Objects of the following type(s) are allowed in the list
-     * {@link FilterType }
-     * 
-     * 
-     */
-    public List<FilterType> getFilter() {
-        if (filter == null) {
-            filter = new ArrayList<FilterType>();
-        }
-        return this.filter;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/src/main/java/org/apache/karaf/region/persist/internal/model/package-info.java
----------------------------------------------------------------------
diff --git a/region/src/main/java/org/apache/karaf/region/persist/internal/model/package-info.java b/region/src/main/java/org/apache/karaf/region/persist/internal/model/package-info.java
deleted file mode 100644
index cae062c..0000000
--- a/region/src/main/java/org/apache/karaf/region/persist/internal/model/package-info.java
+++ /dev/null
@@ -1,9 +0,0 @@
-//
-// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.1-833 
-// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
-// Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2011.10.28 at 03:20:55 PM PDT 
-//
-
-@javax.xml.bind.annotation.XmlSchema(namespace = "http://karaf.apache.org/xmlns/region/v1.0.0", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
-package org.apache.karaf.region.persist.internal.model;

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/src/main/java/org/apache/karaf/region/persist/internal/util/ManifestHeaderProcessor.java
----------------------------------------------------------------------
diff --git a/region/src/main/java/org/apache/karaf/region/persist/internal/util/ManifestHeaderProcessor.java b/region/src/main/java/org/apache/karaf/region/persist/internal/util/ManifestHeaderProcessor.java
deleted file mode 100644
index 410121c..0000000
--- a/region/src/main/java/org/apache/karaf/region/persist/internal/util/ManifestHeaderProcessor.java
+++ /dev/null
@@ -1,661 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-
-package org.apache.karaf.region.persist.internal.util;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.osgi.framework.Constants;
-
-public class ManifestHeaderProcessor
-{
-  public static final String NESTED_FILTER_ATTRIBUTE = "org.apache.aries.application.filter.attribute";
-  private static final Pattern FILTER_ATTR = Pattern.compile("(\\(!)?\\((.*?)([<>]?=)(.*?)\\)\\)?");
-  private static final String LESS_EQ_OP = "<=";
-  private static final String GREATER_EQ_OP = ">=";
-
-  /**
-   * A simple class to associate two types.
-   *
-   */
-  public static class NameValuePair {
-    private String name;
-    private Map<String,String> attributes;
-
-    public NameValuePair(String name, Map<String,String> value)
-    {
-      this.name = name;
-      this.attributes = value;
-    }
-    public String getName()
-    {
-      return name;
-    }
-    public void setName(String name)
-    {
-      this.name = name;
-    }
-
-    public Map<String,String> getAttributes()
-    {
-      return attributes;
-    }
-    public void setAttributes(Map<String,String> value)
-    {
-      this.attributes = value;
-    }
-
-    @Override
-    public String toString(){
-      return "{"+name.toString()+"::"+attributes.toString()+"}";
-    }
-    @Override
-    public int hashCode()
-    {
-      final int prime = 31;
-      int result = 1;
-      result = prime * result + ((name == null) ? 0 : name.hashCode());
-      result = prime * result + ((attributes == null) ? 0 : attributes.hashCode());
-      return result;
-    }
-    @Override
-    public boolean equals(Object obj)
-    {
-      if (this == obj) return true;
-      if (obj == null) return false;
-      if (getClass() != obj.getClass()) return false;
-      final NameValuePair other = (NameValuePair) obj;
-      if (name == null) {
-        if (other.name != null) return false;
-      } else if (!name.equals(other.name)) return false;
-      if (attributes == null) {
-    	  if (other.attributes != null) return false;
-      } else if (!attributes.equals(other.attributes)) return false;
-      return true;
-    }
-  }
-
-  /**
-   * Intended to provide a standard way to add Name/Value's to
-   * aggregations of Name/Value's.
-   *
-   */
-  public static interface NameValueCollection {
-    /**
-     * Add this Name & Value to the collection.
-     * @param n
-     * @param v
-     */
-    public void addToCollection(String n, Map<String,String> v);
-  }
-
-  /**
-   * Map of Name -> Value.
-   *
-   */
-  public static class NameValueMap extends HashMap<String, Map<String,String>> implements NameValueCollection, Map<String, Map<String,String>>{
-	private static final long serialVersionUID = -6446338858542599141L;
-
-	public void addToCollection(String n, Map<String,String> v){
-      this.put(n,v);
-    }
-
-	@Override
-	public String toString(){
-      StringBuilder sb = new StringBuilder();
-      sb.append("{");
-      boolean first=true;
-      for(Map.Entry<String, Map<String,String>> entry : this.entrySet()){
-        if(!first)sb.append(",");
-        first=false;
-        sb.append(entry.getKey()+"->"+entry.getValue());
-      }
-      sb.append("}");
-      return sb.toString();
-    }
-  }
-
-  /**
-   * List of Name/Value
-   *
-   */
-  public static class NameValueList extends ArrayList<NameValuePair> implements NameValueCollection, List<NameValuePair> {
-	private static final long serialVersionUID = 1808636823825029983L;
-
-	public void addToCollection(String n, Map<String,String> v){
-      this.add(new NameValuePair(n,v));
-    }
-	@Override
-    public String toString(){
-      StringBuffer sb = new StringBuffer();
-      sb.append("{");
-      boolean first = true;
-      for(NameValuePair nvp : this){
-        if(!first)sb.append(",");
-        first=false;
-        sb.append(nvp.toString());
-      }
-      sb.append("}");
-      return sb.toString();
-    }
-  }
-
-  /**
-   *
-   * Splits a delimiter separated string, tolerating presence of non separator commas
-   * within double quoted segments.
-   *
-   * Eg.
-   * com.ibm.ws.eba.helloWorldService;version="[1.0.0, 1.0.0]" &
-   * com.ibm.ws.eba.helloWorldService;version="1.0.0"
-   * com.ibm.ws.eba.helloWorld;version="2";bundle-version="[2,30)"
-   * com.acme.foo;weirdAttr="one;two;three";weirdDir:="1;2;3"
-   *  @param value          the value to be split
-   *  @param delimiter      the delimiter string such as ',' etc.
-   *  @return List<String>  the components of the split String in a list
-   */
-  public static List<String> split(String value, String delimiter)
-  {
-    return ManifestHeaderUtils.split(value, delimiter);
-  }
-
-
-  /**
-   * Internal method to parse headers with the format<p>
-   *   [Name](;[Name])*(;[attribute-name]=[attribute-value])*<br>
-   * Eg.<br>
-   *   rumplestiltskin;thing=value;other=something<br>
-   *   littleredridinghood
-   *   bundle1;bundle2;other=things
-   *   bundle1;bundle2
-   *
-   * @param s data to parse
-   * @return a list of NameValuePair, with the Name being the name component,
-   *         and the Value being a NameValueMap of key->value mappings.
-   */
-  private static List<NameValuePair> genericNameWithNameValuePairProcess(String s){
-    String name;
-    Map<String,String> params = null;
-    List<NameValuePair> nameValues = new ArrayList<NameValuePair>();
-    List<String> pkgs = new ArrayList<String>();
-    int index = s.indexOf(";");
-    if(index==-1){
-      name = s;
-      params = new HashMap<String, String>();
-      pkgs.add(name);
-    }else{
-      name = s.substring(0,index).trim();
-      String tail = s.substring(index+1).trim();
-
-      pkgs.add(name); // add the first package
-      StringBuilder parameters = new StringBuilder();
-
-
-      // take into consideration of multiple packages separated by ';'
-      // while they share the same attributes or directives
-      List<String> tailParts = split(tail, ";");
-      boolean firstParameter =false;
-
-      for (String part : tailParts) {
-        // if it is not a parameter and no parameter appears in front of it, it must a package
-        if (!!!(part.contains("=")))  {
-          // Need to make sure no parameter appears before the package, otherwise ignore this string
-          // as this syntax is invalid
-          if (!!!(firstParameter))
-            pkgs.add(part);
-        } else {
-          if (!!!(firstParameter))
-            firstParameter = true;
-
-          parameters.append(part + ";");
-        }
-      }
-
-      if (parameters.length() != 0) {
-        //remove the final ';' if there is one
-        if (parameters.toString().endsWith(";")) {
-
-          parameters = parameters.deleteCharAt(parameters.length() -1);
-        }
-
-        params = genericNameValueProcess(parameters.toString());
-      }
-
-    }
-    for (String pkg : pkgs) {
-      nameValues.add(new NameValuePair(pkg,params));
-    }
-
-    return nameValues;
-
-  }
-
-  /**
-   * Internal method to parse headers with the format<p>
-   *   [attribute-name]=[attribute-value](;[attribute-name]=[attribute-value])*<br>
-   * Eg.<br>
-   *   thing=value;other=something<br>
-   * <p>
-   * Note. Directives (name:=value) are represented in the map with name suffixed by ':'
-   *
-   * @param s data to parse
-   * @return a NameValueMap, with attribute-name -> attribute-value.
-   */
-  private static Map<String,String> genericNameValueProcess(String s){
-    Map<String,String> params = new HashMap<String,String>();
-    List<String> parameters = split(s, ";");
-    for(String parameter : parameters) {
-      List<String> parts = split(parameter,"=");
-      // do a check, otherwise we might get NPE
-      if (parts.size() ==2) {
-        String second = parts.get(1).trim();
-        if (second.startsWith("\"") && second.endsWith("\""))
-          second = second.substring(1,second.length()-1);
-
-        String first = parts.get(0).trim();
-
-        // make sure for directives we clear out any space as in "directive  :=value"
-        if (first.endsWith(":")) {
-            first = first.substring(0, first.length()-1).trim()+":";
-        }
-
-        params.put(first, second);
-      }
-    }
-
-    return params;
-  }
-
-  /**
-   * Processes an import/export style header.. <p>
-   *  pkg1;attrib=value;attrib=value,pkg2;attrib=value,pkg3;attrib=value
-   *
-   * @param out The collection to add each package name + attrib map to.
-   * @param s The data to parse
-   */
-  private static void genericImportExportProcess(NameValueCollection out, String s){
-    List<String> packages = split(s, ",");
-    for(String pkg : packages){
-      List<NameValuePair> ps = genericNameWithNameValuePairProcess(pkg);
-      for (NameValuePair p : ps) {
-        out.addToCollection(p.getName(), p.getAttributes());
-      }
-    }
-  }
-
-  /**
-   * Parse an export style header.<p>
-   *   pkg1;attrib=value;attrib=value,pkg2;attrib=value,pkg3;attrib=value2
-   * <p>
-   * Result is returned as a list, as export does allow duplicate package exports.
-   *
-   * @param s The data to parse.
-   * @return List of NameValuePairs, where each Name in the list is an exported package,
-   *         with its associated Value being a NameValueMap of any attributes declared.
-   */
-  public static List<NameValuePair> parseExportString(String s){
-    NameValueList retval = new NameValueList();
-    genericImportExportProcess(retval, s);
-    return retval;
-  }
-
-  /**
-   * Parse an export style header in a list.<p>
-   *   pkg1;attrib=value;attrib=value
-   *   pkg2;attrib=value
-   *   pkg3;attrib=value2
-   * <p>
-   * Result is returned as a list, as export does allow duplicate package exports.
-   *
-   * @param list The data to parse.
-   * @return List of NameValuePairs, where each Name in the list is an exported package,
-   *         with its associated Value being a NameValueMap of any attributes declared.
-   */
-  public static List<NameValuePair> parseExportList(List<String> list){
-    NameValueList retval = new NameValueList();
-    for(String pkg : list){
-      List<NameValuePair> ps = genericNameWithNameValuePairProcess(pkg);
-      for (NameValuePair p : ps) {
-        retval.addToCollection(p.getName(), p.getAttributes());
-      }
-    }
-    return retval;
-  }
-
-  /**
-   * Parse an import style header.<p>
-   *   pkg1;attrib=value;attrib=value,pkg2;attrib=value,pkg3;attrib=value
-   * <p>
-   * Result is returned as a set, as import does not allow duplicate package imports.
-   *
-   * @param s The data to parse.
-   * @return Map of NameValuePairs, where each Key in the Map is an imported package,
-   *         with its associated Value being a NameValueMap of any attributes declared.
-   */
-  public static Map<String, Map<String, String>> parseImportString(String s){
-    NameValueMap retval = new NameValueMap();
-    genericImportExportProcess(retval, s);
-    return retval;
-  }
-
-  /**
-   * Parse a bundle symbolic name.<p>
-   *   bundlesymbolicname;attrib=value;attrib=value
-   * <p>
-   *
-   * @param s The data to parse.
-   * @return NameValuePair with Name being the BundleSymbolicName,
-   *         and Value being any attribs declared for the name.
-   */
-  public static NameValuePair parseBundleSymbolicName(String s){
-    return genericNameWithNameValuePairProcess(s).get(0); // should just return the first one
-  }
-
-  /**
-   * Parse a version range..
-   *
-   * @param s
-   * @return VersionRange object.
-   * @throws IllegalArgumentException if the String could not be parsed as a VersionRange
-   */
-  public static VersionRange parseVersionRange(String s) throws IllegalArgumentException{
-    return new VersionRange(s);
-  }
-
-  /**
-   * Parse a version range and indicate if the version is an exact version
-   *
-   * @param s
-   * @param exactVersion
-   * @return VersionRange object.
-   * @throws IllegalArgumentException if the String could not be parsed as a VersionRange
-   */
-  public static VersionRange parseVersionRange(String s, boolean exactVersion) throws IllegalArgumentException{
-    return new VersionRange(s, exactVersion);
-  }
-
-  /**
-	 * Generate a filter from a set of attributes. This filter will be suitable
-	 * for presentation to OBR This means that, due to the way OBR works, it
-	 * will include a stanza of the form, (mandatory:<*mandatoryAttribute)
-	 * Filter strings generated by this method will therefore tend to break the
-	 * standard OSGi Filter class. The OBR stanza can be stripped out later if
-	 * required.
-	 *
-	 * @param attribs
-	 * @return filter string
-	 */
-	public static String generateFilter(Map<String, Object> attribs) {
-		StringBuilder filter = new StringBuilder("(&");
-		boolean realAttrib = false;
-		StringBuffer realAttribs = new StringBuffer();
-
-		if (attribs == null) {
-			attribs = new HashMap<String, Object>();
-		}
-
-		for (Map.Entry<String, Object> attrib : attribs.entrySet()) {
-			String attribName = attrib.getKey();
-
-			if (attribName.endsWith(":")) {
-				// skip all directives. It is used to affect the attribs on the
-				// filter xml.
-			} else if ((Constants.VERSION_ATTRIBUTE.equals(attribName))
-					|| (Constants.BUNDLE_VERSION_ATTRIBUTE.equals(attribName))) {
-				// version and bundle-version attrib requires special
-				// conversion.
-				realAttrib = true;
-
-				VersionRange vr = ManifestHeaderProcessor
-						.parseVersionRange(attrib.getValue().toString());
-
-				filter.append("(" + attribName + ">=" + vr.getMinimumVersion());
-
-				if (vr.getMaximumVersion() != null) {
-					filter.append(")(" + attribName + "<=");
-					filter.append(vr.getMaximumVersion());
-				}
-
-				if (vr.getMaximumVersion() != null && vr.isMinimumExclusive()) {
-					filter.append(")(!(" + attribName + "=");
-					filter.append(vr.getMinimumVersion());
-					filter.append(")");
-				}
-
-				if (vr.getMaximumVersion() != null && vr.isMaximumExclusive()) {
-					filter.append(")(!(" + attribName + "=");
-					filter.append(vr.getMaximumVersion());
-					filter.append(")");
-				}
-				filter.append(")");
-
-			} else if (NESTED_FILTER_ATTRIBUTE.equals(attribName)) {
-				// Filters go in whole, no formatting needed
-				realAttrib = true;
-				filter.append(attrib.getValue());
-
-			} else if (Constants.OBJECTCLASS.equals(attribName)) {
-				realAttrib = true;
-				// objectClass has a "," separated list of interfaces
-				String[] values = attrib.getValue().toString().split(",");
-				for (String s : values)
-					filter.append("(" + Constants.OBJECTCLASS + "=" + s + ")");
-
-			} else {
-				// attribName was not version..
-				realAttrib = true;
-
-				filter.append("(" + attribName + "=" + attrib.getValue() + ")");
-				// store all attributes in order to build up the mandatory
-				// filter and separate them with ", "
-				// skip bundle-symbolic-name in the mandatory directive query
-				if (!!!Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE
-						.equals(attribName)) {
-					realAttribs.append(attribName);
-					realAttribs.append(", ");
-				}
-			}
-		}
-//		/*
-//		 * The following is how OBR makes mandatory attributes work, we require
-//		 * that the set of mandatory attributes on the export is a subset of (or
-//		 * equal to) the set of the attributes we supply.
-//		 */
-//
-//		if (realAttribs.length() > 0) {
-//			String attribStr = (realAttribs.toString()).trim();
-//			// remove the final ,
-//			if ((attribStr.length() > 0) && (attribStr.endsWith(","))) {
-//				attribStr = attribStr.substring(0, attribStr.length() - 1);
-//			}
-//			// build the mandatory filter, e.g.(mandatory:&lt;*company, local)
-//			filter.append("(" + Constants.MANDATORY_DIRECTIVE + ":" + "<*"
-//					+ attribStr + ")");
-//		}
-
-		// Prune (& off the front and ) off end
-		String filterString = filter.toString();
-		int openBraces = 0;
-		for (int i = 0; openBraces < 3; i++) {
-			i = filterString.indexOf('(', i);
-			if (i == -1) {
-				break;
-			} else {
-				openBraces++;
-			}
-		}
-		if (openBraces < 3 && filterString.length() > 2) {
-			filter.delete(0, 2);
-		} else {
-			filter.append(")");
-		}
-
-		String result = "";
-		if (realAttrib != false) {
-			result = filter.toString();
-		}
-		return result;
-	}
-
-	/**
-   * Generate a filter from a set of attributes. This filter will be suitable
-   * for presentation to OBR. This means that, due to the way OBR works, it will
-   * include a stanza of the form, (mandatory:<*mandatoryAttribute) Filter
-   * strings generated by this method will therefore tend to break the standard
-   * OSGi Filter class. The OBR stanza can be stripped out later if required.
-   *
-   * We may wish to consider relocating this method since VersionRange has its
-   * own top level class.
-   *
-   * @param type
-   * @param name
-   * @param attribs
-   * @return filter string
-   */
-  public static String generateFilter(String type, String name,
-      Map<String, Object> attribs) {
-    StringBuffer filter = new StringBuffer();
-    String result;
-    // shortcut for the simple case with no attribs.
-
-    if (attribs == null || attribs.isEmpty())
-      filter.append("(" + type + "=" + name + ")");
-    else {
-      // process all the attribs passed.
-      // find out whether there are attributes on the filter
-
-      filter.append("(&(" + type + "=" + name + ")");
-
-      String filterString = generateFilter(attribs);
-
-      int start = 0;
-      int end = filterString.length();
-      if (filterString.startsWith("(&")) {
-        start = 2;
-        end--;
-      }
-
-      if ("".equals(filterString)) {
-        filter.delete(0, 2);
-      } else {
-        filter.append(filterString, start, end);
-        filter.append(")");
-      }
-    }
-
-    result = filter.toString();
-
-    return result;
-  }
-
-  private static Map<String, String> parseFilterList(String filter) {
-
-    Map<String, String> result = new HashMap<String, String>();
-    Set<String> negatedVersions = new HashSet<String>();
-    Set<String> negatedBundleVersions = new HashSet<String>();
-
-    String lowerVersion = null;
-    String upperVersion = null;
-    String lowerBundleVersion = null;
-    String upperBundleVersion = null;
-
-    Matcher m = FILTER_ATTR.matcher(filter);
-    while (m.find()) {
-      boolean negation = m.group(1) != null;
-      String attr = m.group(2);
-      String op = m.group(3);
-      String value = m.group(4);
-
-      if (Constants.VERSION_ATTRIBUTE.equals(attr)) {
-        if (negation) {
-          negatedVersions.add(value);
-        } else {
-          if (GREATER_EQ_OP.equals(op))
-            lowerVersion = value;
-          else if (LESS_EQ_OP.equals(op))
-            upperVersion = value;
-          else
-            throw new IllegalArgumentException();
-        }
-      } else if (Constants.BUNDLE_VERSION_ATTRIBUTE.equals(attr)) {
-        // bundle-version is like version, but may be specified at the
-        // same time
-        // therefore we have similar code with separate variables
-        if (negation) {
-          negatedBundleVersions.add(value);
-        } else {
-          if (GREATER_EQ_OP.equals(op))
-            lowerBundleVersion = value;
-          else if (LESS_EQ_OP.equals(op))
-            upperBundleVersion = value;
-          else
-            throw new IllegalArgumentException();
-        }
-      } else {
-        result.put(attr, value);
-      }
-    }
-
-    if (lowerVersion != null) {
-      StringBuilder versionAttr = new StringBuilder(lowerVersion);
-      if (upperVersion != null) {
-        versionAttr.append(",").append(upperVersion).insert(0,
-            negatedVersions.contains(lowerVersion) ? '(' : '[').append(
-            negatedVersions.contains(upperVersion) ? ')' : ']');
-      }
-
-      result.put(Constants.VERSION_ATTRIBUTE, versionAttr.toString());
-    }
-    // Do it again for bundle-version
-    if (lowerBundleVersion != null) {
-      StringBuilder versionAttr = new StringBuilder(lowerBundleVersion);
-      if (upperBundleVersion != null) {
-        versionAttr.append(",").append(upperBundleVersion).insert(0,
-            negatedBundleVersions.contains(lowerBundleVersion) ? '(' : '[')
-            .append(
-                negatedBundleVersions.contains(upperBundleVersion) ? ')' : ']');
-      }
-
-      result.put(Constants.BUNDLE_VERSION_ATTRIBUTE, versionAttr.toString());
-    }
-
-    return result;
-  }
-
-  public static Map<String,String> parseFilter(String filter)
-  {
-    Map<String,String> result;
-    if (filter.startsWith("(&")) {
-      result = parseFilterList(filter.substring(2, filter.length()-1));
-    } else {
-      result = parseFilterList(filter);
-    }
-    return result;
-  }
-
-}
-

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/src/main/java/org/apache/karaf/region/persist/internal/util/ManifestHeaderUtils.java
----------------------------------------------------------------------
diff --git a/region/src/main/java/org/apache/karaf/region/persist/internal/util/ManifestHeaderUtils.java b/region/src/main/java/org/apache/karaf/region/persist/internal/util/ManifestHeaderUtils.java
deleted file mode 100644
index 8c87616..0000000
--- a/region/src/main/java/org/apache/karaf/region/persist/internal/util/ManifestHeaderUtils.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-
-package org.apache.karaf.region.persist.internal.util;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class ManifestHeaderUtils {
-
-     /**
-     *
-     * Splits a delimiter separated string, tolerating presence of non separator commas
-     * within double quoted segments.
-     *
-     * Eg.
-     * com.ibm.ws.eba.helloWorldService;version="[1.0.0, 1.0.0]" &
-     * com.ibm.ws.eba.helloWorldService;version="1.0.0"
-     * com.ibm.ws.eba.helloWorld;version="2";bundle-version="[2,30)"
-     * com.acme.foo;weirdAttr="one;two;three";weirdDir:="1;2;3"
-     *  @param value          the value to be split
-     *  @param delimiter      the delimiter string such as ',' etc.
-     *  @return List<String>  the components of the split String in a list
-     */
-    public static List<String> split(String value, String delimiter)
-    {
-      List<String> result = new ArrayList<String>();
-      if (value != null) {
-        String[] packages = value.split(delimiter);
-
-        for (int i = 0; i < packages.length; ) {
-          String tmp = packages[i++].trim();
-          // if there is a odd number of " in a string, we need to append
-          while (count(tmp, "\"") % 2 != 0) {
-            // check to see if we need to append the next package[i++]
-              if (i<packages.length)
-                tmp = tmp + delimiter + packages[i++].trim();
-              else
-                // oops. The double quotes are not paired up. We have reached to the end of the string.
-                throw new IllegalArgumentException("Unmatched double quotes: " + tmp);
-          }
-
-          result.add(tmp);
-
-        }
-      }
-      return result;
-    }
-
-    /**
-     * count the number of characters in a string
-     * @param parent The string to be searched
-     * @param subString The substring to be found
-     * @return the number of occurrence of the subString
-     */
-     private static int count(String parent, String subString) {
-
-       int count = 0 ;
-       int i = parent.indexOf(subString);
-       while (i > -1) {
-         if (parent.length() >= i+1)
-           parent = parent.substring(i+1);
-         count ++;
-         i = parent.indexOf(subString);
-       }
-       return count;
-     }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/src/main/java/org/apache/karaf/region/persist/internal/util/VersionRange.java
----------------------------------------------------------------------
diff --git a/region/src/main/java/org/apache/karaf/region/persist/internal/util/VersionRange.java b/region/src/main/java/org/apache/karaf/region/persist/internal/util/VersionRange.java
deleted file mode 100644
index 19bbc77..0000000
--- a/region/src/main/java/org/apache/karaf/region/persist/internal/util/VersionRange.java
+++ /dev/null
@@ -1,456 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-
-package org.apache.karaf.region.persist.internal.util;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.osgi.framework.Version;
-
-public final class VersionRange {
-
-    /** A string representation of the version. */
-    private String version;
-
-    /** The minimum desired version for the bundle */
-    private Version minimumVersion;
-
-    /** The maximum desired version for the bundle */
-    private Version maximumVersion;
-
-    /** True if the match is exclusive of the minimum version */
-    private boolean minimumExclusive;
-
-    /** True if the match is exclusive of the maximum version */
-    private boolean maximumExclusive;
-
-    /** A regexp to select the version */
-    private static final Pattern versionCapture = Pattern.compile("\"?(.*?)\"?$");
-
-    /**
-     *
-     * @param version
-     *            version for the verioninfo
-     */
-    public VersionRange(String version) {
-        this.version = version;
-        processVersionAttribute(version);
-    }
-
-    /**
-     * This method should be used to create a version range from a single
-     * version string.
-     * @param version
-     *            version for the versioninfo
-     * @param exactVersion
-     *            whether this is an exact version {@code true} or goes to infinity
-     *            {@code false}
-     */
-    public VersionRange(String version, boolean exactVersion) {
-
-        if (exactVersion) {
-            // Do not store this string as it might be just a version, or a range!
-            processExactVersionAttribute(version);
-        } else {
-            this.version = version;
-            processVersionAttribute(this.version);
-        }
-
-        assertInvariants();
-    }
-
-    /**
-     * Constructor designed for internal use only.
-     *
-     * @param maximumVersion
-     * @param maximumExclusive
-     * @param minimumVersion
-     * @param minimumExclusive
-     * @throws IllegalArgumentException
-     *             if parameters are not valid.
-     */
-    private VersionRange(Version maximumVersion,
-                         boolean maximumExclusive,
-                         Version minimumVersion,
-                         boolean minimumExclusive) {
-        this.maximumVersion = maximumVersion;
-        this.maximumExclusive = maximumExclusive;
-        this.minimumVersion = minimumVersion;
-        this.minimumExclusive = minimumExclusive;
-
-        assertInvariants();
-    }
-
-    /*
-     * (non-Javadoc)
-     *
-     * @see org.apache.aries.application.impl.VersionRange#toString()
-     */
-    @Override
-    public String toString() {
-        // Some constructors don't take in a string that we can return directly,
-        // so construct one if needed
-        if (version == null) {
-            if (maximumVersion == null) {
-                version = minimumVersion.toString();
-            } else {
-                version = (minimumExclusive ? "(" : "[") + minimumVersion + "," + maximumVersion
-                          + (maximumExclusive ? ")" : "]");
-            }
-        }
-        return this.version;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = 17;
-        result = 31 * result + minimumVersion.hashCode();
-        result = 31 * result + (minimumExclusive ? 1 : 0);
-        result = 31 * result + (maximumVersion != null ? maximumVersion.hashCode() : 0);
-        result = 31 * result + (maximumExclusive ? 1 : 0);
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object other) {
-        boolean result = false;
-        if (this == other) {
-            result = true;
-        } else if (other instanceof VersionRange) {
-            VersionRange vr = (VersionRange) other;
-            result = minimumVersion.equals(vr.minimumVersion)
-                     && minimumExclusive == vr.minimumExclusive
-                     && (maximumVersion == null ? vr.maximumVersion == null : maximumVersion
-                             .equals(vr.maximumVersion)) && maximumExclusive == vr.maximumExclusive;
-        }
-
-        return result;
-    }
-
-    /**
-     * this method returns the exact version from the versionInfo obj.
-     * this is used for DeploymentContent only to return a valid exact version
-     * otherwise, null is returned.
-     * @return the exact version
-     */
-    public Version getExactVersion() {
-        Version v = null;
-        if (isExactVersion()) {
-            v = getMinimumVersion();
-        }
-        return v;
-    }
-
-    /**
-     * get the maximum version
-     * @return    the maximum version
-     */
-    public Version getMaximumVersion() {
-        return maximumVersion;
-    }
-
-    /**
-     * get the minimum version
-     * @return    the minimum version
-     */
-    public Version getMinimumVersion() {
-        return minimumVersion;
-    }
-
-    /**
-     * is the maximum version exclusive
-     * @return is the max version in the range.
-     */
-    public boolean isMaximumExclusive() {
-        return maximumExclusive;
-    }
-
-    /**
-     * is the maximum version unbounded
-     * @return true if no upper bound was specified.
-     */
-    public boolean isMaximumUnbounded() {
-        boolean unbounded = maximumVersion == null;
-        return unbounded;
-    }
-
-    /**
-     * is the minimum version exclusive
-     * @return true if the min version is in range.
-     */
-    public boolean isMinimumExclusive() {
-        return minimumExclusive;
-    }
-
-    /**
-     * this is designed for deployed-version as that is the exact version.
-     *
-     * @param version
-     * @return
-     * @throws IllegalArgumentException
-     */
-    private boolean processExactVersionAttribute(String version) throws IllegalArgumentException {
-        boolean success = processVersionAttribute(version);
-
-        if (maximumVersion == null) {
-            maximumVersion = minimumVersion;
-        }
-
-        if (!minimumVersion.equals(maximumVersion)) {
-            throw new IllegalArgumentException("Version is not exact: " + version);
-        }
-
-        if (!!!isExactVersion()) {
-            throw new IllegalArgumentException("Version is not exact: " + version);
-        }
-
-        return success;
-    }
-
-    /**
-     * process the version attribute,
-     *
-     * @param version
-     *            the value to be processed
-     * @return
-     * @throws IllegalArgumentException
-     */
-    private boolean processVersionAttribute(String version) throws IllegalArgumentException {
-        boolean success = false;
-
-        if (version == null) {
-            throw new IllegalArgumentException("Version is null");
-        }
-
-        Matcher matches = versionCapture.matcher(version);
-
-        if (matches.matches()) {
-            String versions = matches.group(1);
-
-            if ((versions.startsWith("[") || versions.startsWith("("))
-                && (versions.endsWith("]") || versions.endsWith(")"))) {
-                if (versions.startsWith("["))
-                    minimumExclusive = false;
-                else if (versions.startsWith("("))
-                    minimumExclusive = true;
-
-                if (versions.endsWith("]"))
-                    maximumExclusive = false;
-                else if (versions.endsWith(")"))
-                    maximumExclusive = true;
-
-                int index = versions.indexOf(',');
-                String minVersion = versions.substring(1, index);
-                String maxVersion = versions.substring(index + 1, versions.length() - 1);
-
-                try {
-                    minimumVersion = new Version(minVersion.trim());
-                    maximumVersion = new Version(maxVersion.trim());
-                    success = true;
-                } catch (NumberFormatException nfe) {
-                    throw new IllegalArgumentException("Version cannot be decoded: " + version, nfe);
-                }
-            } else {
-                try {
-                    if (versions.trim().length() == 0)
-                        minimumVersion = new Version(0, 0, 0);
-                    else
-                        minimumVersion = new Version(versions.trim());
-                    success = true;
-                } catch (NumberFormatException nfe) {
-                    throw new IllegalArgumentException("Version cannot be decoded: " + version, nfe);
-                }
-            }
-        } else {
-            throw new IllegalArgumentException("Version cannot be decoded: " + version);
-        }
-
-        return success;
-    }
-
-    /**
-     * Assert object invariants. Called by constructors to verify that arguments
-     * were valid.
-     *
-     * @throws IllegalArgumentException
-     *             if invariants are violated.
-     */
-    private void assertInvariants() {
-        if (minimumVersion == null
-            || !isRangeValid(minimumVersion, minimumExclusive, maximumVersion, maximumExclusive)) {
-            IllegalArgumentException e = new IllegalArgumentException();
-            throw e;
-        }
-    }
-
-    /**
-     * Check if the supplied parameters describe a valid version range.
-     *
-     * @param min
-     *            the minimum version.
-     * @param minExclusive
-     *            whether the minimum version is exclusive.
-     * @param max
-     *            the maximum version.
-     * @param maxExclusive
-     *            whether the maximum version is exclusive.
-     * @return true is the range is valid; otherwise false.
-     */
-    private boolean isRangeValid(Version min,
-                                 boolean minExclusive,
-                                 Version max,
-                                 boolean maxExclusive) {
-        boolean result;
-
-        // A null maximum version is unbounded so means that minimum is smaller
-        // than
-        // maximum.
-        int minMaxCompare = (max == null ? -1 : min.compareTo(max));
-        if (minMaxCompare > 0) {
-            // Minimum larger than maximum is invalid.
-            result = false;
-        } else if (minMaxCompare == 0 && (minExclusive || maxExclusive)) {
-            // If min and max are the same, and either are exclusive, no valid
-            // range
-            // exists.
-            result = false;
-        } else {
-            // Range is valid.
-            result = true;
-        }
-
-        return result;
-    }
-
-    /**
-     * This method checks that the provided version matches the desired version.
-     *
-     * @param version
-     *            the version.
-     * @return true if the version matches, false otherwise.
-     */
-    public boolean matches(Version version) {
-        boolean result;
-        if (this.getMaximumVersion() == null) {
-            result = this.getMinimumVersion().compareTo(version) <= 0;
-        } else {
-            int minN = this.isMinimumExclusive() ? 0 : 1;
-            int maxN = this.isMaximumExclusive() ? 0 : 1;
-
-            result = (this.getMinimumVersion().compareTo(version) < minN)
-                     && (version.compareTo(this.getMaximumVersion()) < maxN);
-        }
-        return result;
-    }
-
-    /**
-     * check if the versioninfo is the exact version
-     * @return true if the range will match 1 exact version.
-     */
-    public boolean isExactVersion() {
-        return minimumVersion.equals(maximumVersion) && minimumExclusive == maximumExclusive
-               && !!!minimumExclusive;
-    }
-
-    /**
-     * Create a new version range that is the intersection of {@code this} and the argument.
-     * In other words, the largest version range that lies within both {@code this} and
-     * the parameter.
-     * @param r a version range to be intersected with {@code this}.
-     * @return a new version range, or {@code null} if no intersection is possible.
-     */
-    public VersionRange intersect(VersionRange r) {
-        // Use the highest minimum version.
-        final Version newMinimumVersion;
-        final boolean newMinimumExclusive;
-        int minCompare = minimumVersion.compareTo(r.getMinimumVersion());
-        if (minCompare > 0) {
-            newMinimumVersion = minimumVersion;
-            newMinimumExclusive = minimumExclusive;
-        } else if (minCompare < 0) {
-            newMinimumVersion = r.getMinimumVersion();
-            newMinimumExclusive = r.isMinimumExclusive();
-        } else {
-            newMinimumVersion = minimumVersion;
-            newMinimumExclusive = (minimumExclusive || r.isMinimumExclusive());
-        }
-
-        // Use the lowest maximum version.
-        final Version newMaximumVersion;
-        final boolean newMaximumExclusive;
-        // null maximum version means unbounded, so the highest possible value.
-        if (maximumVersion == null) {
-            newMaximumVersion = r.getMaximumVersion();
-            newMaximumExclusive = r.isMaximumExclusive();
-        } else if (r.getMaximumVersion() == null) {
-            newMaximumVersion = maximumVersion;
-            newMaximumExclusive = maximumExclusive;
-        } else {
-            int maxCompare = maximumVersion.compareTo(r.getMaximumVersion());
-            if (maxCompare < 0) {
-                newMaximumVersion = maximumVersion;
-                newMaximumExclusive = maximumExclusive;
-            } else if (maxCompare > 0) {
-                newMaximumVersion = r.getMaximumVersion();
-                newMaximumExclusive = r.isMaximumExclusive();
-            } else {
-                newMaximumVersion = maximumVersion;
-                newMaximumExclusive = (maximumExclusive || r.isMaximumExclusive());
-            }
-        }
-
-        VersionRange result;
-        if (isRangeValid(newMinimumVersion, newMinimumExclusive, newMaximumVersion,
-                newMaximumExclusive)) {
-            result = new VersionRange(newMaximumVersion, newMaximumExclusive, newMinimumVersion,
-                    newMinimumExclusive);
-        } else {
-            result = null;
-        }
-        return result;
-    }
-
-    /**
-     * Parse a version range..
-     *
-     * @param s
-     * @return VersionRange object.
-     * @throws IllegalArgumentException
-     *             if the String could not be parsed as a VersionRange
-     */
-    public static VersionRange parseVersionRange(String s) throws IllegalArgumentException {
-        return new VersionRange(s);
-    }
-
-    /**
-     * Parse a version range and indicate if the version is an exact version
-     *
-     * @param s
-     * @param exactVersion
-     * @return VersionRange object.
-     * @throws IllegalArgumentException
-     *             if the String could not be parsed as a VersionRange
-     */
-    public static VersionRange parseVersionRange(String s, boolean exactVersion)
-            throws IllegalArgumentException {
-        return new VersionRange(s, exactVersion);
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/src/main/resources/org/apache/karaf/region/persist/region.xsd
----------------------------------------------------------------------
diff --git a/region/src/main/resources/org/apache/karaf/region/persist/region.xsd b/region/src/main/resources/org/apache/karaf/region/persist/region.xsd
deleted file mode 100644
index 8ca26e7..0000000
--- a/region/src/main/resources/org/apache/karaf/region/persist/region.xsd
+++ /dev/null
@@ -1,109 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-    Licensed to the Apache Software Foundation (ASF) under one
-    or more contributor license agreements.  See the NOTICE file
-    distributed with this work for additional information
-    regarding copyright ownership.  The ASF licenses this file
-    to you under the Apache License, Version 2.0 (the
-    "License"); you may not use this file except in compliance
-    with the License.  You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing,
-    software distributed under the License is distributed on an
-    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-    KIND, either express or implied.  See the License for the
-    specific language governing permissions and limitations
-    under the License.
--->
-
-<!-- $Rev$ $Date$ -->
-
-<xsd:schema xmlns="http://karaf.apache.org/xmlns/region/v1.0.0"
-        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
-        targetNamespace="http://karaf.apache.org/xmlns/region/v1.0.0"
-        elementFormDefault="qualified"
-        attributeFormDefault="unqualified">
-
-
-    <xsd:annotation>
-        <xsd:documentation>
-            Defines the configuration elements for Apache Karaf region xml configuration.
-        </xsd:documentation>
-    </xsd:annotation>
-
-    <xsd:element name="regions" type="regionsType"/>
-
-
-    <xsd:complexType name="regionsType">
-        <xsd:annotation>
-            <xsd:documentation>
-                Regions element
-            </xsd:documentation>
-        </xsd:annotation>
-        <xsd:sequence>
-            <xsd:element name="region" type="regionType" minOccurs="0" maxOccurs="unbounded"/>
-            <xsd:element name="filter" type="filterType" minOccurs="0" maxOccurs="unbounded"/>
-        </xsd:sequence>
-    </xsd:complexType>
-
-    <xsd:complexType name="regionType">
-        <xsd:annotation>
-            <xsd:documentation>
-                Region element
-            </xsd:documentation>
-        </xsd:annotation>
-        <xsd:sequence>
-            <xsd:element name="bundle" type="regionBundleType" minOccurs="0" maxOccurs="unbounded"/>
-        </xsd:sequence>
-        <xsd:attribute name="name" type="xsd:string" use="required"/>
-    </xsd:complexType>
-
-
-    <xsd:complexType name="regionBundleType">
-        <xsd:sequence/>
-        <xsd:attribute name="id" type="xsd:long"/>
-        <xsd:attribute name="location" type="xsd:string"/>
-    </xsd:complexType>
-
-    <xsd:complexType name="filterBundleType">
-        <xsd:sequence>
-            <xsd:element name="attribute" type="filterAttributeType" minOccurs="0" maxOccurs="unbounded"/>
-        </xsd:sequence>
-        <xsd:attribute name="id" type="xsd:long"/>
-        <xsd:attribute name="symbolic-name" type="xsd:string"/>
-        <xsd:attribute name="version" type="xsd:string"/>
-    </xsd:complexType>
-
-    <xsd:complexType name="filterType">
-        <xsd:sequence>
-            <xsd:element name="bundle" type="filterBundleType" minOccurs="0" maxOccurs="unbounded"/>
-            <xsd:element name="package" type="filterPackageType" minOccurs="0" maxOccurs="unbounded"/>
-            <xsd:element name="namespace" type="filterNamespaceType" minOccurs="0" maxOccurs="unbounded"/>
-        </xsd:sequence>
-        <xsd:attribute name="from" type="xsd:string" use="required"/>
-        <xsd:attribute name="to" type="xsd:string" use="required"/>
-    </xsd:complexType>
-
-    <xsd:complexType name="filterPackageType">
-        <xsd:sequence>
-            <xsd:element name="attribute" type="filterAttributeType" minOccurs="0" maxOccurs="unbounded"/>
-        </xsd:sequence>
-        <xsd:attribute name="name" type="xsd:string" use="required"/>
-        <xsd:attribute name="version" type="xsd:string"/>
-    </xsd:complexType>
-
-    <xsd:complexType name="filterAttributeType">
-        <xsd:sequence/>
-        <xsd:attribute name="name" type="xsd:string" use="required"/>
-        <xsd:attribute name="value" type="xsd:string" use="required"/>
-    </xsd:complexType>
-
-    <xsd:complexType name="filterNamespaceType">
-        <xsd:sequence>
-            <xsd:element name="attribute" type="filterAttributeType" minOccurs="0" maxOccurs="unbounded"/>
-        </xsd:sequence>
-        <xsd:attribute name="name" type="xsd:string" use="required"/>
-    </xsd:complexType>
-</xsd:schema>

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/webconsole/features/src/main/java/org/apache/karaf/webconsole/features/ExtendedFeature.java
----------------------------------------------------------------------
diff --git a/webconsole/features/src/main/java/org/apache/karaf/webconsole/features/ExtendedFeature.java b/webconsole/features/src/main/java/org/apache/karaf/webconsole/features/ExtendedFeature.java
index 47052ab..890c510 100644
--- a/webconsole/features/src/main/java/org/apache/karaf/webconsole/features/ExtendedFeature.java
+++ b/webconsole/features/src/main/java/org/apache/karaf/webconsole/features/ExtendedFeature.java
@@ -26,6 +26,7 @@ import org.apache.karaf.features.ConfigFileInfo;
 import org.apache.karaf.features.Dependency;
 import org.apache.karaf.features.Feature;
 import org.apache.karaf.features.Requirement;
+import org.apache.karaf.features.Scoping;
 
 public class ExtendedFeature implements Feature {
 
@@ -139,8 +140,7 @@ public class ExtendedFeature implements Feature {
     }
 
     @Override
-    public String getRegion() {
-        return feature.getRegion();
+    public Scoping getScoping() {
+        return feature.getScoping();
     }
-
 }


[3/6] [KARAF-2923] Region support in features service

Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
index 0243dc0..84b9529 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
@@ -48,14 +48,16 @@ import org.apache.karaf.features.FeaturesListener;
 import org.apache.karaf.features.FeaturesService;
 import org.apache.karaf.features.Repository;
 import org.apache.karaf.features.RepositoryEvent;
-import org.apache.karaf.features.internal.deployment.DeploymentBuilder;
-import org.apache.karaf.features.internal.deployment.StreamProvider;
-import org.apache.karaf.features.internal.resolver.FeatureNamespace;
-import org.apache.karaf.features.internal.resolver.UriNamespace;
+import org.apache.karaf.features.internal.download.StreamProvider;
+import org.apache.karaf.features.internal.region.ResourceComparator;
+import org.apache.karaf.features.internal.region.SubsystemResolver;
 import org.apache.karaf.features.internal.util.ChecksumUtils;
 import org.apache.karaf.features.internal.util.Macro;
 import org.apache.karaf.features.internal.util.MultiException;
 import org.apache.karaf.util.collections.CopyOnWriteArrayIdentityList;
+import org.eclipse.equinox.region.Region;
+import org.eclipse.equinox.region.RegionDigraph;
+import org.eclipse.equinox.region.RegionFilterBuilder;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleException;
@@ -64,6 +66,7 @@ import org.osgi.framework.FrameworkEvent;
 import org.osgi.framework.FrameworkListener;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.Version;
+import org.osgi.framework.namespace.IdentityNamespace;
 import org.osgi.framework.startlevel.BundleStartLevel;
 import org.osgi.framework.wiring.BundleRevision;
 import org.osgi.framework.wiring.BundleWire;
@@ -76,12 +79,18 @@ import org.slf4j.LoggerFactory;
 
 import static org.apache.felix.resolver.Util.getSymbolicName;
 import static org.apache.felix.resolver.Util.getVersion;
+import static org.apache.karaf.features.internal.util.MapUtils.addToMapSet;
+import static org.apache.karaf.features.internal.util.MapUtils.copyMapSet;
+import static org.apache.karaf.features.internal.resolver.ResourceUtils.*;
+import static org.apache.karaf.features.internal.util.MapUtils.removeFromMapSet;
 
 /**
  *
  */
 public class FeaturesServiceImpl implements FeaturesService {
 
+    public static final String ROOT_REGION = "root";
+
     public static final String UPDATE_SNAPSHOTS_NONE = "none";
     public static final String UPDATE_SNAPSHOTS_CRC = "crc";
     public static final String UPDATE_SNAPSHOTS_ALWAYS = "always";
@@ -114,6 +123,7 @@ public class FeaturesServiceImpl implements FeaturesService {
     private final FeatureFinder featureFinder;
     private final EventAdminListener eventAdminListener;
     private final FeatureConfigInstaller configInstaller;
+    private final RegionDigraph digraph;
     private final String overrides;
     /**
      * Range to use when a version is specified on a feature dependency.
@@ -150,6 +160,7 @@ public class FeaturesServiceImpl implements FeaturesService {
                                FeatureFinder featureFinder,
                                EventAdminListener eventAdminListener,
                                FeatureConfigInstaller configInstaller,
+                               RegionDigraph digraph,
                                String overrides,
                                String featureResolutionRange,
                                String bundleUpdateRange,
@@ -160,6 +171,7 @@ public class FeaturesServiceImpl implements FeaturesService {
         this.featureFinder = featureFinder;
         this.eventAdminListener = eventAdminListener;
         this.configInstaller = configInstaller;
+        this.digraph = digraph;
         this.overrides = overrides;
         this.featureResolutionRange = featureResolutionRange;
         this.bundleUpdateRange = bundleUpdateRange;
@@ -221,7 +233,7 @@ public class FeaturesServiceImpl implements FeaturesService {
             Set<String> installedFeatures = new TreeSet<String>();
             synchronized (lock) {
                 repositories.addAll(state.repositories);
-                installedFeatures.addAll(state.installedFeatures);
+                installedFeatures.addAll(state.installedFeatures.keySet());
             }
             for (String uri : repositories) {
                 Repository repository = new RepositoryImpl(URI.create(uri));
@@ -547,15 +559,17 @@ public class FeaturesServiceImpl implements FeaturesService {
     public boolean isInstalled(Feature f) {
         String id = normalize(f.getId());
         synchronized (lock) {
-            return state.installedFeatures.contains(id);
+            Set<String> installed = state.installedFeatures.get(ROOT_REGION);
+            return installed != null && installed.contains(id);
         }
     }
 
     @Override
     public boolean isRequired(Feature f) {
-        String id = normalize(f.getId());
+        String id = f.getName() + "/" + new VersionRange(f.getVersion(), true);
         synchronized (lock) {
-            return state.features.contains(id);
+            Set<String> features = state.features.get(ROOT_REGION);
+            return features != null && features.contains(id);
         }
     }
 
@@ -563,27 +577,37 @@ public class FeaturesServiceImpl implements FeaturesService {
     // Installation and uninstallation of features
     //
 
+    @Override
     public void installFeature(String name) throws Exception {
         installFeature(name, EnumSet.noneOf(Option.class));
     }
 
+    @Override
     public void installFeature(String name, String version) throws Exception {
         installFeature(version != null ? name + "/" + version : name, EnumSet.noneOf(Option.class));
     }
 
+    @Override
     public void installFeature(String name, EnumSet<Option> options) throws Exception {
         installFeatures(Collections.singleton(name), options);
     }
 
+    @Override
     public void installFeature(String name, String version, EnumSet<Option> options) throws Exception {
         installFeature(version != null ? name + "/" + version : name, options);
     }
 
+    @Override
     public void installFeature(Feature feature, EnumSet<Option> options) throws Exception {
         installFeature(feature.getId());
     }
 
     @Override
+    public void installFeatures(Set<String> features, EnumSet<Option> options) throws Exception {
+        installFeatures(features, ROOT_REGION, options);
+    }
+
+    @Override
     public void uninstallFeature(String name, String version) throws Exception {
         uninstallFeature(version != null ? name + "/" + version : name);
     }
@@ -603,6 +627,11 @@ public class FeaturesServiceImpl implements FeaturesService {
         uninstallFeatures(Collections.singleton(name), options);
     }
 
+    @Override
+    public void uninstallFeatures(Set<String> features, EnumSet<Option> options) throws Exception {
+        uninstallFeatures(features, ROOT_REGION, options);
+    }
+
 
     //
     //
@@ -613,18 +642,12 @@ public class FeaturesServiceImpl implements FeaturesService {
     //
 
 
-
-
-
-
-    public void installFeatures(Set<String> features, EnumSet<Option> options) throws Exception {
-        Set<String> required;
-        Set<String> installed;
-        Set<Long> managed;
-        synchronized (lock) {
-            required = new HashSet<String>(state.features);
-            installed = new HashSet<String>(state.installedFeatures);
-            managed = new HashSet<Long>(state.managedBundles);
+    @Override
+    public void installFeatures(Set<String> features, String region, EnumSet<Option> options) throws Exception {
+        State state = copyState();
+        Map<String, Set<String>> required = copyMapSet(state.features);
+        if (region == null || region.isEmpty()) {
+            region = ROOT_REGION;
         }
         List<String> featuresToAdd = new ArrayList<String>();
         Map<String, Map<String, Feature>> featuresMap = getFeatures();
@@ -638,7 +661,8 @@ public class FeaturesServiceImpl implements FeaturesService {
                     throw new IllegalArgumentException("No matching features for " + feature);
                 }
             } else {
-                featuresToAdd.add(normalize(f.getId()));
+                String req = f.getName() + "/" + new VersionRange(f.getVersion(), true);
+                featuresToAdd.add(req);
             }
         }
         featuresToAdd = new ArrayList<String>(new LinkedHashSet<String>(featuresToAdd));
@@ -651,18 +675,25 @@ public class FeaturesServiceImpl implements FeaturesService {
             sb.append(featuresToAdd.get(i));
         }
         print(sb.toString(), options.contains(Option.Verbose));
-        required.addAll(featuresToAdd);
-        doInstallFeaturesInThread(required, installed, managed, options);
+        Set<String> fl = required.get(region);
+        if (fl == null) {
+            fl = new HashSet<String>();
+            required.put(region,fl);
+        }
+        fl.addAll(featuresToAdd);
+        doInstallFeaturesInThread(required, state, options);
     }
 
-    public void uninstallFeatures(Set<String> features, EnumSet<Option> options) throws Exception {
-        Set<String> required;
-        Set<String> installed;
-        Set<Long> managed;
-        synchronized (lock) {
-            required = new HashSet<String>(state.features);
-            installed = new HashSet<String>(state.installedFeatures);
-            managed = new HashSet<Long>(state.managedBundles);
+    public void uninstallFeatures(Set<String> features, String region, EnumSet<Option> options) throws Exception {
+        State state = copyState();
+        Map<String, Set<String>> required = copyMapSet(state.features);
+        if (region == null || region.isEmpty()) {
+            region = ROOT_REGION;
+        }
+        Set<String> fl = required.get(region);
+        if (fl == null) {
+            fl = new HashSet<String>();
+            required.put(region,fl);
         }
         List<String> featuresToRemove = new ArrayList<String>();
         for (String feature : new HashSet<String>(features)) {
@@ -670,15 +701,18 @@ public class FeaturesServiceImpl implements FeaturesService {
             feature = normalize(feature);
             if (feature.endsWith("/0.0.0")) {
                 String nameSep = feature.substring(0, feature.indexOf("/") + 1);
-                for (String f : required) {
+                for (String f : fl) {
                     if (normalize(f).startsWith(nameSep)) {
                         toRemove.add(f);
                     }
                 }
             } else {
-                toRemove.add(feature);
+                String name = feature.substring(0, feature.indexOf("/"));
+                String version = feature.substring(feature.indexOf("/") + 1);
+                String req = name + "/" + new VersionRange(version, true);
+                toRemove.add(req);
             }
-            toRemove.retainAll(required);
+            toRemove.retainAll(fl);
             if (toRemove.isEmpty()) {
                 throw new IllegalArgumentException("Feature named '" + feature + "' is not installed");
             } else if (toRemove.size() > 1) {
@@ -706,8 +740,17 @@ public class FeaturesServiceImpl implements FeaturesService {
             sb.append(featuresToRemove.get(i));
         }
         print(sb.toString(), options.contains(Option.Verbose));
-        required.removeAll(featuresToRemove);
-        doInstallFeaturesInThread(required, installed, managed, options);
+        fl.removeAll(featuresToRemove);
+        if (fl.isEmpty()) {
+            required.remove(fl);
+        }
+        doInstallFeaturesInThread(required, state, options);
+    }
+
+    private State copyState() {
+        synchronized (lock) {
+            return this.state.copy();
+        }
     }
 
     protected String normalize(String feature) {
@@ -726,16 +769,15 @@ public class FeaturesServiceImpl implements FeaturesService {
      * the command may be interrupted while waiting for the refresh to be done, leading
      * to bundles not being started after the refresh.
      */
-    public void doInstallFeaturesInThread(final Set<String> features,
-                                          final Set<String> installed,
-                                          final Set<Long> managed,
+    public void doInstallFeaturesInThread(final Map<String, Set<String>> features,
+                                          final State state,
                                           final EnumSet<Option> options) throws Exception {
         ExecutorService executor = Executors.newCachedThreadPool();
         try {
             executor.submit(new Callable<Object>() {
                 @Override
                 public Object call() throws Exception {
-                    doInstallFeatures(features, installed, managed, options);
+                    doInstallFeatures(features, state, options);
                     return null;
                 }
             }).get();
@@ -755,10 +797,9 @@ public class FeaturesServiceImpl implements FeaturesService {
         }
     }
 
-    public void doInstallFeatures(Set<String> features,    // all request features
-                                  Set<String> installed,   // installed features
-                                  Set<Long> managed,       // currently managed bundles
-                                  EnumSet<Option> options  // installation options
+    public void doInstallFeatures(Map<String, Set<String>> features,  // all request features
+                                  State                    state,     // current state
+                                  EnumSet<Option>          options    // installation options
                     ) throws Exception {
 
         boolean noRefreshUnmanaged = options.contains(Option.NoAutoRefreshUnmanagedBundles);
@@ -768,43 +809,56 @@ public class FeaturesServiceImpl implements FeaturesService {
         boolean verbose = options.contains(Option.Verbose);
         boolean simulate = options.contains(Option.Simulate);
 
+        Map<String, Set<String>> installed = state.installedFeatures;
+        Map<String, Set<Long>> managed = state.managedBundles;
+
         // Get a list of resolved and unmanaged bundles to use as capabilities during resolution
-        List<Resource> systemBundles = new ArrayList<Resource>();
+        List<BundleRevision> systemBundles = new ArrayList<BundleRevision>();
         Bundle[] bundles = systemBundleContext.getBundles();
         for (Bundle bundle : bundles) {
-            if (bundle.getState() >= Bundle.RESOLVED && !managed.contains(bundle.getBundleId())) {
-                Resource res = bundle.adapt(BundleRevision.class);
-                systemBundles.add(res);
+            if (bundle.getState() >= Bundle.RESOLVED) {
+                boolean bm = false;
+                for (Set<Long> m : managed.values()) {
+                    bm |= m.contains(bundle.getBundleId());
+                }
+                if (!bm) {
+                    BundleRevision res = bundle.adapt(BundleRevision.class);
+                    systemBundles.add(res);
+                }
             }
         }
         // Resolve
         // TODO: requirements
         // TODO: bundles
-        // TODO: regions: on isolated regions, we may need different resolution for each region
+        // TODO: overrides
         Set<String>  overrides    = Overrides.loadOverrides(this.overrides);
         Repository[] repositories = listRepositories();
-        DeploymentBuilder builder = createDeploymentBuilder(repositories);
-        builder.setFeatureRange(featureResolutionRange);
-        builder.download(features,
-                         Collections.<String>emptySet(),
-                         Collections.<String>emptySet(),
-                         overrides,
-                         Collections.<String>emptySet());
-        Map<Resource, List<Wire>> resolution = builder.resolve(systemBundles);
+
+        if (!installed.containsKey(ROOT_REGION)) {
+            installed.put(ROOT_REGION, new HashSet<String>());
+        }
+
+        SubsystemResolver resolver = new SubsystemResolver();
+        Map<Resource, List<Wire>> resolution = resolver.resolve(
+                Arrays.asList(repositories),
+                features,
+                systemBundles,
+                featureResolutionRange);
         Collection<Resource> allResources = resolution.keySet();
-        Map<String, StreamProvider> providers = builder.getProviders();
+        Map<String, StreamProvider> providers = resolver.getProviders();
+
+        Map<String, Set<String>> installedFeatures = getInstalledFeatures(resolver);
 
-        // Install conditionals
         List<String> installedFeatureIds = getFeatureIds(allResources);
         List<String> newFeatures = new ArrayList<String>(installedFeatureIds);
-        newFeatures.removeAll(installed);
-        List<String> delFeatures = new ArrayList<String>(installed);
+        newFeatures.removeAll(installed.get(ROOT_REGION));
+        List<String> delFeatures = new ArrayList<String>(installed.get(ROOT_REGION));
         delFeatures.removeAll(installedFeatureIds);
 
         //
         // Compute list of installable resources (those with uris)
         //
-        List<Resource> resources = getBundles(allResources);
+        Map<Resource, String> resources = resolver.getBundles();
 
         // Compute information for each bundle
         Map<String, BundleInfo> bundleInfos = new HashMap<String, BundleInfo>();
@@ -823,14 +877,10 @@ public class FeaturesServiceImpl implements FeaturesService {
         // Get all resources that will be used to satisfy the old features set
         Set<Resource> resourceLinkedToOldFeatures = new HashSet<Resource>();
         if (noStart) {
-            for (Resource resource : resolution.keySet()) {
-                String name = FeatureNamespace.getName(resource);
-                if (name != null) {
-                    Version version = FeatureNamespace.getVersion(resource);
-                    String id = version != null ? name + "/" + version : name;
-                    if (installed.contains(id)) {
-                        addTransitive(resource, resourceLinkedToOldFeatures, resolution);
-                    }
+            for (Resource resource : resolver.getFeatures().keySet()) {
+                String id = getFeatureId(resource);
+                if (installed.get(ROOT_REGION).contains(id)) {
+                    addTransitive(resource, resourceLinkedToOldFeatures, resolution);
                 }
             }
         }
@@ -838,15 +888,10 @@ public class FeaturesServiceImpl implements FeaturesService {
         //
         // Compute deployment
         //
-        Map<String, Long> bundleChecksums = new HashMap<String, Long>();
-        synchronized (lock) {
-            bundleChecksums.putAll(state.bundleChecksums);
-        }
-        Deployment deployment = computeDeployment(managed, bundles, providers, resources, bundleChecksums);
+        // TODO: compute bundles/region mapping to support multiple bundles and bunde moving into a different region
+        Deployment deployment = computeDeployment(resolver, state);
 
-        if (deployment.toDelete.isEmpty() &&
-                deployment.toUpdate.isEmpty() &&
-                deployment.toInstall.isEmpty()) {
+        if (deployment.regions.isEmpty()) {
             print("No deployment change.", verbose);
             return;
         }
@@ -859,8 +904,10 @@ public class FeaturesServiceImpl implements FeaturesService {
         // Compute the set of bundles to refresh
         //
         Set<Bundle> toRefresh = new HashSet<Bundle>();
-        toRefresh.addAll(deployment.toDelete);
-        toRefresh.addAll(deployment.toUpdate.keySet());
+        for (RegionDeployment regionDeployment : deployment.regions.values()) {
+            toRefresh.addAll(regionDeployment.toDelete);
+            toRefresh.addAll(regionDeployment.toUpdate.keySet());
+        }
 
         if (!noRefreshManaged) {
             int size;
@@ -907,8 +954,11 @@ public class FeaturesServiceImpl implements FeaturesService {
         if (noRefreshUnmanaged) {
             Set<Bundle> newSet = new HashSet<Bundle>();
             for (Bundle bundle : toRefresh) {
-                if (managed.contains(bundle.getBundleId())) {
-                    newSet.add(bundle);
+                for (Set<Long> m : managed.values()) {
+                    if (m.contains(bundle.getBundleId())) {
+                        newSet.add(bundle);
+                        break;
+                    }
                 }
             }
             toRefresh = newSet;
@@ -932,12 +982,14 @@ public class FeaturesServiceImpl implements FeaturesService {
         //
 
         // TODO: handle update on the features service itself
-        if (deployment.toUpdate.containsKey(bundle) ||
-                deployment.toDelete.contains(bundle)) {
+        RegionDeployment rootRegionDeployment = deployment.regions.get(ROOT_REGION);
+        if (rootRegionDeployment != null &&
+                (rootRegionDeployment.toUpdate.containsKey(bundle)
+                        || rootRegionDeployment.toDelete.contains(bundle))) {
 
             LOGGER.warn("Updating or uninstalling of the FeaturesService is not supported");
-            deployment.toUpdate.remove(bundle);
-            deployment.toDelete.remove(bundle);
+            rootRegionDeployment.toUpdate.remove(bundle);
+            rootRegionDeployment.toDelete.remove(bundle);
 
         }
 
@@ -945,10 +997,14 @@ public class FeaturesServiceImpl implements FeaturesService {
         // Perform bundle operations
         //
 
+        //
         // Stop bundles by chunks
+        //
         Set<Bundle> toStop = new HashSet<Bundle>();
-        toStop.addAll(deployment.toUpdate.keySet());
-        toStop.addAll(deployment.toDelete);
+        for (RegionDeployment regionDeployment : deployment.regions.values()) {
+            toStop.addAll(regionDeployment.toUpdate.keySet());
+            toStop.addAll(regionDeployment.toDelete);
+        }
         removeFragmentsAndBundlesInState(toStop, Bundle.UNINSTALLED | Bundle.RESOLVED | Bundle.STOPPING);
         if (!toStop.isEmpty()) {
             print("Stopping bundles:", verbose);
@@ -961,67 +1017,162 @@ public class FeaturesServiceImpl implements FeaturesService {
                 }
             }
         }
-        if (!deployment.toDelete.isEmpty()) {
+
+        //
+        // Delete bundles
+        //
+        boolean hasToDelete = false;
+        for (RegionDeployment regionDeployment : deployment.regions.values()) {
+            if ((hasToDelete = !regionDeployment.toDelete.isEmpty())) {
+                break;
+            }
+        }
+        if (hasToDelete) {
             print("Uninstalling bundles:", verbose);
-            for (Bundle bundle : deployment.toDelete) {
-                print("  " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
-                bundle.uninstall();
-                managed.remove(bundle.getBundleId());
+            for (Map.Entry<String, RegionDeployment> entry : deployment.regions.entrySet()) {
+                String name = entry.getKey();
+                RegionDeployment regionDeployment = entry.getValue();
+                for (Bundle bundle : regionDeployment.toDelete) {
+                    print("  " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
+                    bundle.uninstall();
+                    removeFromMapSet(managed, name, bundle.getBundleId());
+                }
             }
         }
-        if (!deployment.toUpdate.isEmpty()) {
-            print("Updating bundles:", verbose);
-            for (Map.Entry<Bundle, Resource> entry : deployment.toUpdate.entrySet()) {
-                Bundle bundle = entry.getKey();
-                Resource resource = entry.getValue();
-                String uri = UriNamespace.getUri(resource);
-                print("  " + uri, verbose);
-                InputStream is = getBundleInputStream(resource, providers);
-                bundle.update(is);
-                toStart.add(bundle);
-                BundleInfo bi = bundleInfos.get(uri);
-                if (bi != null && bi.getStartLevel() > 0) {
-                    bundle.adapt(BundleStartLevel.class).setStartLevel(bi.getStartLevel());
+
+        //
+        // Update regions
+        //
+        // TODO: this replace the whole digraph with the computed one
+        // TODO: we need to be smarter and allow user modifications or
+        // TODO: externally managed regions such as the one managed
+        // TODO: by aries subsystems
+        RegionDigraph clone = this.digraph.copy();
+        RegionDigraph computedDigraph = resolver.getDigraph();
+        for (Region r : clone.getRegions()) {
+            clone.removeRegion(r);
+        }
+        Map<String, String> flats = resolver.getFlatSubsystemsMap();
+        for (Region r : computedDigraph.getRegions()) {
+            if (r.getName().equals(flats.get(r.getName()))) {
+                clone.createRegion(r.getName());
+            }
+        }
+        for (Region r : computedDigraph.getRegions()) {
+            for (RegionDigraph.FilteredRegion fr : computedDigraph.getEdges(r)) {
+                String rt = flats.get(r.getName());
+                String rh = flats.get(fr.getRegion().getName());
+                if (!rh.equals(rt)) {
+                    Region tail = clone.getRegion(rt);
+                    Region head = clone.getRegion(rh);
+                    RegionFilterBuilder rfb = clone.createRegionFilterBuilder();
+                    for (Map.Entry<String, Collection<String>> entry : fr.getFilter().getSharingPolicy().entrySet()) {
+                        // Discard osgi.identity namespace
+                        if (!IdentityNamespace.IDENTITY_NAMESPACE.equals(entry.getKey())) {
+                            for (String f : entry.getValue()) {
+                                rfb.allow(entry.getKey(), f);
+                            }
+                        }
+                    }
+                    clone.connect(tail, rfb.build(), head);
                 }
-                // TODO: handle region
             }
         }
-        if (!deployment.toInstall.isEmpty()) {
-            print("Installing bundles:", verbose);
-            for (Resource resource : deployment.toInstall) {
-                String uri = UriNamespace.getUri(resource);
-                print("  " + uri, verbose);
-                InputStream is = getBundleInputStream(resource, providers);
-                Bundle bundle = systemBundleContext.installBundle(uri, is);
-                managed.add(bundle.getBundleId());
-                if (!noStart || resourceLinkedToOldFeatures.contains(resource)) {
+        // Spread bundles across regions
+        Region root = clone.getRegion(ROOT_REGION);
+        for (BundleRevision revision : systemBundles) {
+            root.addBundle(revision.getBundle());
+        }
+        for (Resource resource : resources.keySet()) {
+            Bundle bundle = deployment.resToBnd.get(resource);
+            if (bundle != null) {
+                String region = resources.get(resource);
+                clone.getRegion(region).addBundle(bundle);
+            }
+        }
+        this.digraph.replace(clone);
+
+        //
+        // Update bundles
+        //
+        boolean hasToUpdate = false;
+        for (RegionDeployment regionDeployment : deployment.regions.values()) {
+            if ((hasToUpdate = !regionDeployment.toUpdate.isEmpty())) {
+                break;
+            }
+        }
+        if (hasToUpdate) {
+            print("Updating bundles:", verbose);
+            for (RegionDeployment regionDeployment : deployment.regions.values()) {
+                for (Map.Entry<Bundle, Resource> entry : regionDeployment.toUpdate.entrySet()) {
+                    Bundle bundle = entry.getKey();
+                    Resource resource = entry.getValue();
+                    String uri = getUri(resource);
+                    print("  " + uri, verbose);
+                    InputStream is = getBundleInputStream(resource, providers);
+                    bundle.update(is);
                     toStart.add(bundle);
+                    BundleInfo bi = bundleInfos.get(uri);
+                    if (bi != null && bi.getStartLevel() > 0) {
+                        bundle.adapt(BundleStartLevel.class).setStartLevel(bi.getStartLevel());
+                    }
                 }
-                deployment.resToBnd.put(resource, bundle);
-                // save a checksum of installed snapshot bundle
-                if (UPDATE_SNAPSHOTS_CRC.equals(updateSnaphots)
-                        && isUpdateable(resource) && !deployment.newCheckums.containsKey(bundle.getLocation())) {
-                    deployment.newCheckums.put(bundle.getLocation(), ChecksumUtils.checksum(getBundleInputStream(resource, providers)));
-                }
-                BundleInfo bi = bundleInfos.get(uri);
-                if (bi != null && bi.getStartLevel() > 0) {
-                    bundle.adapt(BundleStartLevel.class).setStartLevel(bi.getStartLevel());
+            }
+        }
+        //
+        // Install bundles
+        //
+        boolean hasToInstall = false;
+        for (RegionDeployment regionDeployment : deployment.regions.values()) {
+            if ((hasToInstall = !regionDeployment.toInstall.isEmpty())) {
+                break;
+            }
+        }
+        if (hasToInstall) {
+            print("Installing bundles:", verbose);
+            for (Map.Entry<String, RegionDeployment> entry : deployment.regions.entrySet()) {
+                String name = entry.getKey();
+                Region region = digraph.getRegion(name);
+                RegionDeployment regionDeployment = entry.getValue();
+                for (Resource resource : regionDeployment.toInstall) {
+                    String uri = getUri(resource);
+                    print("  " + uri, verbose);
+                    InputStream is = getBundleInputStream(resource, providers);
+                    Bundle bundle;
+                    if (ROOT_REGION.equals(name)) {
+                        bundle = region.installBundleAtLocation(uri, is);
+                    } else {
+                        bundle = region.installBundle(uri, is);
+                    }
+                    addToMapSet(managed, name, bundle.getBundleId());
+                    if (!noStart || resourceLinkedToOldFeatures.contains(resource)) {
+                        toStart.add(bundle);
+                    }
+                    deployment.resToBnd.put(resource, bundle);
+                    // save a checksum of installed snapshot bundle
+                    if (UPDATE_SNAPSHOTS_CRC.equals(updateSnaphots)
+                            && isUpdateable(resource) && !deployment.newCheckums.containsKey(bundle.getBundleId())) {
+                        deployment.newCheckums.put(bundle.getBundleId(), ChecksumUtils.checksum(getBundleInputStream(resource, providers)));
+                    }
+                    BundleInfo bi = bundleInfos.get(uri);
+                    if (bi != null && bi.getStartLevel() > 0) {
+                        bundle.adapt(BundleStartLevel.class).setStartLevel(bi.getStartLevel());
+                    }
                 }
-                // TODO: handle region
             }
         }
 
-        //
+       //
         // Update and save state
         //
         synchronized (lock) {
-            state.bundleChecksums.putAll(deployment.newCheckums);
-            state.features.clear();
-            state.features.addAll(features);
-            state.installedFeatures.clear();
-            state.installedFeatures.addAll(installedFeatureIds);
-            state.managedBundles.clear();
-            state.managedBundles.addAll(managed);
+            this.state.bundleChecksums.putAll(deployment.newCheckums);
+            this.state.features.clear();
+            this.state.features.putAll(features);
+            this.state.installedFeatures.clear();
+            this.state.installedFeatures.putAll(installedFeatures);
+            this.state.managedBundles.clear();
+            this.state.managedBundles.putAll(managed);
             saveState();
         }
 
@@ -1134,122 +1285,145 @@ public class FeaturesServiceImpl implements FeaturesService {
         }
     }
 
-    protected void logDeployment(Deployment deployment, boolean verbose) {
+    protected void logDeployment(Deployment overallDeployment, boolean verbose) {
         print("Changes to perform:", verbose);
-        if (!deployment.toDelete.isEmpty()) {
-            print("  Bundles to uninstall:", verbose);
-            for (Bundle bundle : deployment.toDelete) {
-                print("    " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
+        for (Map.Entry<String, RegionDeployment> region : overallDeployment.regions.entrySet()) {
+            RegionDeployment deployment = region.getValue();
+            print("  Region: " + region.getKey(), verbose);
+            if (!deployment.toDelete.isEmpty()) {
+                print("    Bundles to uninstall:", verbose);
+                for (Bundle bundle : deployment.toDelete) {
+                    print("      " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
+                }
             }
-        }
-        if (!deployment.toUpdate.isEmpty()) {
-            print("  Bundles to update:", verbose);
-            for (Map.Entry<Bundle, Resource> entry : deployment.toUpdate.entrySet()) {
-                print("    " + entry.getKey().getSymbolicName() + " / " + entry.getKey().getVersion() + " with " + UriNamespace.getUri(entry.getValue()), verbose);
+            if (!deployment.toUpdate.isEmpty()) {
+                print("    Bundles to update:", verbose);
+                for (Map.Entry<Bundle, Resource> entry : deployment.toUpdate.entrySet()) {
+                    print("      " + entry.getKey().getSymbolicName() + " / " + entry.getKey().getVersion() + " with " + getUri(entry.getValue()), verbose);
+                }
             }
-        }
-        if (!deployment.toInstall.isEmpty()) {
-            print("  Bundles to install:", verbose);
-            for (Resource resource : deployment.toInstall) {
-                print("    " + UriNamespace.getUri(resource), verbose);
+            if (!deployment.toInstall.isEmpty()) {
+                print("    Bundles to install:", verbose);
+                for (Resource resource : deployment.toInstall) {
+                    print("      " + getUri(resource), verbose);
+                }
             }
         }
     }
 
     protected Deployment computeDeployment(
-                                Set<Long> managed,
-                                Bundle[] bundles,
-                                Map<String, StreamProvider> providers,
-                                List<Resource> resources,
-                                Map<String, Long> bundleChecksums) throws IOException {
-        Deployment deployment = new Deployment();
-
-        // TODO: regions
-        List<Resource> toDeploy = new ArrayList<Resource>(resources);
-
-        // First pass: go through all installed bundles and mark them
-        // as either to ignore or delete
-        for (Bundle bundle : bundles) {
-            if (bundle.getSymbolicName() != null && bundle.getBundleId() != 0) {
-                Resource resource = null;
-                for (Resource res : toDeploy) {
-                    if (bundle.getSymbolicName().equals(getSymbolicName(res))) {
-                        if (bundle.getVersion().equals(getVersion(res))) {
-                            resource = res;
-                            break;
+                                SubsystemResolver resolver,
+                                State state) throws IOException {
+
+        Deployment result = new Deployment();
+
+        Map<String, Set<Resource>> bundlesPerRegions = resolver.getBundlesPerRegions();
+
+        // Gather all regions, including old ones and new ones
+        Set<String> regions = new HashSet<String>();
+        regions.addAll(state.managedBundles.keySet());
+        regions.addAll(bundlesPerRegions.keySet());
+
+        for (String region : regions) {
+
+            RegionDeployment deployment = new RegionDeployment();
+
+            // Get the list of bundles currently assigned in the region
+            Set<Long> managed = state.managedBundles.get(region);
+            if (managed == null) {
+                managed = Collections.emptySet();
+            }
+
+            // Compute the list of resources to deploy in the region
+            Set<Resource> bundlesInRegion = bundlesPerRegions.get(region);
+            List<Resource> toDeploy = bundlesInRegion != null
+                            ? new ArrayList<Resource>(bundlesInRegion) : new ArrayList<Resource>();
+
+            // First pass: go through all installed bundles and mark them
+            // as either to ignore or delete
+            for (long bundleId : managed) {
+                // Look for the installed bundle
+                Bundle bundle = systemBundleContext.getBundle(bundleId);
+                // Bundle has been manually uninstalled ?
+                if (bundle != null) {
+                    // Look for a matching resource
+                    Resource resource = null;
+                    for (Resource res : toDeploy) {
+                        if (bundle.getSymbolicName().equals(getSymbolicName(res))) {
+                            if (bundle.getVersion().equals(getVersion(res))) {
+                                resource = res;
+                                break;
+                            }
                         }
                     }
-                }
-                // We found a matching bundle
-                if (resource != null) {
-                    // In case of snapshots, check if the snapshot is out of date
-                    // and flag it as to update
-                    if (managed.contains(bundle.getBundleId()) && isUpdateable(resource)) {
-                        // Always update snapshots
-                        if (UPDATE_SNAPSHOTS_ALWAYS.equalsIgnoreCase(updateSnaphots)) {
-                            LOGGER.debug("Update snapshot for " + bundle.getLocation());
-                            deployment.toUpdate.put(bundle, resource);
-                        }
-                        else if (UPDATE_SNAPSHOTS_CRC.equalsIgnoreCase(updateSnaphots)) {
-                            // if the checksum are different
-                            InputStream is = null;
-                            try {
-                                is = getBundleInputStream(resource, providers);
-                                long newCrc = ChecksumUtils.checksum(is);
-                                long oldCrc = bundleChecksums.containsKey(bundle.getLocation()) ? bundleChecksums.get(bundle.getLocation()) : 0l;
-                                if (newCrc != oldCrc) {
-                                    LOGGER.debug("New snapshot available for " + bundle.getLocation());
-                                    deployment.toUpdate.put(bundle, resource);
-                                    deployment.newCheckums.put(bundle.getLocation(), newCrc);
-                                }
-                            } finally {
-                                if (is != null) {
-                                    is.close();
+                    // We found a matching bundle
+                    if (resource != null) {
+                        // In case of snapshots, check if the snapshot is out of date
+                        // and flag it as to update
+                        if (isUpdateable(resource)) {
+                            // Always update snapshots
+                            if (UPDATE_SNAPSHOTS_ALWAYS.equalsIgnoreCase(updateSnaphots)) {
+                                LOGGER.debug("Update snapshot for " + bundle.getLocation());
+                                deployment.toUpdate.put(bundle, resource);
+                            } else if (UPDATE_SNAPSHOTS_CRC.equalsIgnoreCase(updateSnaphots)) {
+                                // if the checksum are different
+                                InputStream is = null;
+                                try {
+                                    is = getBundleInputStream(resource, resolver.getProviders());
+                                    long newCrc = ChecksumUtils.checksum(is);
+                                    long oldCrc = state.bundleChecksums.containsKey(bundle.getBundleId()) ? state.bundleChecksums.get(bundle.getBundleId()) : 0l;
+                                    if (newCrc != oldCrc) {
+                                        LOGGER.debug("New snapshot available for " + bundle.getLocation());
+                                        deployment.toUpdate.put(bundle, resource);
+                                        result.newCheckums.put(bundle.getBundleId(), newCrc);
+                                    }
+                                } finally {
+                                    if (is != null) {
+                                        is.close();
+                                    }
                                 }
                             }
                         }
+                        // We're done for this resource
+                        toDeploy.remove(resource);
+                        result.resToBnd.put(resource, bundle);
+                        // There's no matching resource
+                        // If the bundle is managed, we need to delete it
+                    } else if (managed.contains(bundle.getBundleId())) {
+                        deployment.toDelete.add(bundle);
                     }
-                    // We're done for this resource
-                    toDeploy.remove(resource);
-                    deployment.resToBnd.put(resource, bundle);
-                // There's no matching resource
-                // If the bundle is managed, we need to delete it
-                } else if (managed.contains(bundle.getBundleId())) {
-                    deployment.toDelete.add(bundle);
                 }
             }
-        }
 
-        // Second pass on remaining resources
-        for (Resource resource : toDeploy) {
-            TreeMap<Version, Bundle> matching = new TreeMap<Version, Bundle>();
-            VersionRange range = new VersionRange(Macro.transform(bundleUpdateRange, getVersion(resource).toString()));
-            for (Bundle bundle : deployment.toDelete) {
-                if (bundle.getSymbolicName().equals(getSymbolicName(resource)) && range.contains(bundle.getVersion())) {
-                    matching.put(bundle.getVersion(), bundle);
+            // Second pass on remaining resources
+            for (Resource resource : toDeploy) {
+                TreeMap<Version, Bundle> matching = new TreeMap<Version, Bundle>();
+                VersionRange range = new VersionRange(Macro.transform(bundleUpdateRange, getVersion(resource).toString()));
+                for (Bundle bundle : deployment.toDelete) {
+                    if (bundle.getSymbolicName().equals(getSymbolicName(resource)) && range.contains(bundle.getVersion())) {
+                        matching.put(bundle.getVersion(), bundle);
+                    }
+                }
+                if (!matching.isEmpty()) {
+                    Bundle bundle = matching.lastEntry().getValue();
+                    deployment.toUpdate.put(bundle, resource);
+                    deployment.toDelete.remove(bundle);
+                    result.resToBnd.put(resource, bundle);
+                } else {
+                    deployment.toInstall.add(resource);
                 }
             }
-            if (!matching.isEmpty()) {
-                Bundle bundle = matching.lastEntry().getValue();
-                deployment.toUpdate.put(bundle, resource);
-                deployment.toDelete.remove(bundle);
-                deployment.resToBnd.put(resource, bundle);
-            } else {
-                deployment.toInstall.add(resource);
-            }
-        }
-        return deployment;
-    }
+            Collections.sort(deployment.toInstall, new ResourceComparator());
 
-    protected List<Resource> getBundles(Collection<Resource> allResources) {
-        Map<String, Resource> deploy = new TreeMap<String, Resource>();
-        for (Resource res : allResources) {
-            String uri = UriNamespace.getUri(res);
-            if (uri != null) {
-                deploy.put(uri, res);
+            // Add this region if there is something to do
+            if (!deployment.toDelete.isEmpty()
+                    || !deployment.toUpdate.isEmpty()
+                    || !deployment.toInstall.isEmpty()) {
+                result.regions.put(region, deployment);
             }
         }
-        return new ArrayList<Resource>(deploy.values());
+
+        return result;
     }
 
     protected List<Feature> getFeatures(Repository[] repositories, List<String> featureIds) throws Exception {
@@ -1265,28 +1439,33 @@ public class FeaturesServiceImpl implements FeaturesService {
         return installedFeatures;
     }
 
+    protected Map<String, Set<String>> getInstalledFeatures(SubsystemResolver resolver) {
+        Map<String, Set<String>> installed = new HashMap<String, Set<String>>();
+        Map<String, Set<Resource>> mapping = resolver.getFeaturesPerRegions();
+        for (Map.Entry<String, Set<Resource>> entry : mapping.entrySet()) {
+            for (Resource resource : entry.getValue()) {
+                addToMapSet(installed, entry.getKey(), getFeatureId(resource));
+            }
+        }
+        return installed;
+    }
+
     protected List<String> getFeatureIds(Collection<Resource> allResources) {
         List<String> installedFeatureIds = new ArrayList<String>();
         for (Resource resource : allResources) {
-            String name = FeatureNamespace.getName(resource);
-            if (name != null) {
-                Version version = FeatureNamespace.getVersion(resource);
-                String id = version != null ? name + "/" + version : name;
+            String id = getFeatureId(resource);
+            if (id != null) {
                 installedFeatureIds.add(id);
             }
         }
         return installedFeatureIds;
     }
 
-    protected DeploymentBuilder createDeploymentBuilder(Repository[] repositories) {
-        return new DeploymentBuilder(new SimpleDownloader(), Arrays.asList(repositories));
-    }
-
-
     protected boolean isUpdateable(Resource resource) {
-        return (getVersion(resource).getQualifier().endsWith(SNAPSHOT) ||
-                UriNamespace.getUri(resource).contains(SNAPSHOT) ||
-                !UriNamespace.getUri(resource).contains(MAVEN));
+        String uri = getUri(resource);
+        return getVersion(resource).getQualifier().endsWith(SNAPSHOT) 
+                || uri.contains(SNAPSHOT) 
+                || !uri.contains(MAVEN);
     }
 
     protected List<Bundle> getBundlesToStart(Collection<Bundle> bundles) {
@@ -1378,7 +1557,7 @@ public class FeaturesServiceImpl implements FeaturesService {
     }
 
     protected InputStream getBundleInputStream(Resource resource, Map<String, StreamProvider> providers) throws IOException {
-        String uri = UriNamespace.getUri(resource);
+        String uri = getUri(resource);
         if (uri == null) {
             throw new IllegalStateException("Resource has no uri");
         }
@@ -1406,8 +1585,12 @@ public class FeaturesServiceImpl implements FeaturesService {
 
 
     static class Deployment {
-        Map<String, Long> newCheckums = new HashMap<String, Long>();
+        Map<Long, Long> newCheckums = new HashMap<Long, Long>();
         Map<Resource, Bundle> resToBnd = new HashMap<Resource, Bundle>();
+        Map<String, RegionDeployment> regions = new HashMap<String, RegionDeployment>();
+    }
+
+    static class RegionDeployment {
         List<Resource> toInstall = new ArrayList<Resource>();
         List<Bundle> toDelete = new ArrayList<Bundle>();
         Map<Bundle, Resource> toUpdate = new HashMap<Bundle, Resource>();

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/service/RepositoryImpl.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/RepositoryImpl.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/RepositoryImpl.java
index 56e5102..9c2f2b6 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/service/RepositoryImpl.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/RepositoryImpl.java
@@ -47,7 +47,7 @@ public class RepositoryImpl implements Repository {
         return features.getName();
     }
 
-    public URI[] getRepositories() throws Exception {
+    public URI[] getRepositories() throws IOException {
         load();
         URI[] result = new URI[features.getRepository().size()];
         for (int i = 0; i < features.getRepository().size(); i++) {
@@ -58,7 +58,7 @@ public class RepositoryImpl implements Repository {
         return result;
     }
 
-    public org.apache.karaf.features.Feature[] getFeatures() throws Exception {
+    public org.apache.karaf.features.Feature[] getFeatures() throws IOException {
         load();
         return features.getFeature().toArray(new org.apache.karaf.features.Feature[features.getFeature().size()]);
     }
@@ -94,9 +94,5 @@ public class RepositoryImpl implements Repository {
         }
     }
 
-    @Override
-    public boolean isValid() {
-        throw new UnsupportedOperationException();
-    }
 }
 

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/service/SimpleDownloader.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/SimpleDownloader.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/SimpleDownloader.java
deleted file mode 100644
index d1f16b9..0000000
--- a/features/core/src/main/java/org/apache/karaf/features/internal/service/SimpleDownloader.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.service;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-import org.apache.karaf.features.internal.deployment.Downloader;
-import org.apache.karaf.features.internal.deployment.StreamProvider;
-import org.apache.karaf.features.internal.util.MultiException;
-
-public class SimpleDownloader implements Downloader {
-
-    private final MultiException exception = new MultiException("Error");
-
-    @Override
-    public void await() throws InterruptedException, MultiException {
-        exception.throwIfExceptions();
-    }
-
-    @Override
-    public void download(final String location, final DownloadCallback downloadCallback) throws MalformedURLException {
-        final URL url = new URL(location);
-        try {
-            downloadCallback.downloaded(new StreamProvider() {
-                @Override
-                public InputStream open() throws IOException {
-                    return url.openStream();
-                }
-            });
-        } catch (Exception e) {
-            exception.addException(e);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/service/State.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/State.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/State.java
index c84f4e0..df4d901 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/service/State.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/State.java
@@ -22,13 +22,34 @@ import java.util.Set;
 import java.util.TreeSet;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import static org.apache.karaf.features.internal.util.MapUtils.copyMapSet;
+
 public class State {
 
     public final AtomicBoolean bootDone = new AtomicBoolean();
     public final Set<String> repositories = new TreeSet<String>();
-    public final Set<String> features = new TreeSet<String>();
-    public final Set<String> installedFeatures = new TreeSet<String>();
-    public final Set<Long> managedBundles = new TreeSet<Long>();
-    public final Map<String, Long> bundleChecksums = new HashMap<String, Long>();
+    public final Map<String, Set<String>> features = new HashMap<String, Set<String>>();
+    public final Map<String, Set<String>> installedFeatures = new HashMap<String, Set<String>>();
+    public final Map<String, Set<Long>> managedBundles = new HashMap<String, Set<Long>>();
+    public final Map<Long, Long> bundleChecksums = new HashMap<Long, Long>();
+
+    public State copy() {
+        State state = new State();
+        state.bootDone.set(bootDone.get());
+        copySet(repositories, state.repositories);
+        copyMapSet(features, state.features);
+        copyMapSet(installedFeatures, state.installedFeatures);
+        copyMapSet(managedBundles, state.managedBundles);
+        copyMap(bundleChecksums, state.bundleChecksums);
+        return state;
+    }
+
+    static <T> void copySet(Set<T> from, Set<T> to) {
+        to.addAll(from);
+    }
+
+    static <S, T> void copyMap(Map<S, T> from, Map<S, T> to) {
+        to.putAll(from);
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/service/StateStorage.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/StateStorage.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/StateStorage.java
index ac54ab0..3b3424f 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/service/StateStorage.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/StateStorage.java
@@ -20,17 +20,14 @@ import java.io.Closeable;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Enumeration;
+import java.util.Collection;
 import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
 import java.util.Map;
-import java.util.Properties;
 import java.util.Set;
 import java.util.TreeSet;
 
-import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.internal.util.JsonReader;
+import org.apache.karaf.features.internal.util.JsonWriter;
 
 public abstract class StateStorage {
 
@@ -42,14 +39,13 @@ public abstract class StateStorage {
         InputStream is = getInputStream();
         if (is != null) {
             try {
-                Properties props = new Properties();
-                props.load(is);
-                state.bootDone.set(loadBool(props, "bootDone"));
-                state.repositories.addAll(loadSet(props, "repositories."));
-                state.features.addAll(loadSet(props, "features."));
-                state.installedFeatures.addAll(loadSet(props, "installed."));
-                state.managedBundles.addAll(toLongSet(loadSet(props, "managed.")));
-                state.bundleChecksums.putAll(toStringLongMap(loadMap(props, "checksums.")));
+                Map json = (Map) JsonReader.read(is);
+                state.bootDone.set((Boolean) json.get("bootDone"));
+                state.repositories.addAll(toStringSet((Collection) json.get("repositories")));
+                state.features.putAll(toStringStringSetMap((Map) json.get("features")));
+                state.installedFeatures.putAll(toStringStringSetMap((Map) json.get("installed")));
+                state.managedBundles.putAll(toStringLongSetMap((Map) json.get("managed")));
+                state.bundleChecksums.putAll(toLongLongMap((Map) json.get("checksums")));
             } finally {
                 close(is);
             }
@@ -60,14 +56,14 @@ public abstract class StateStorage {
         OutputStream os = getOutputStream();
         if (os != null) {
             try {
-                Properties props = new Properties();
-                saveBool(props, "bootDone", state.bootDone.get());
-                saveSet(props, "repositories.", state.repositories);
-                saveSet(props, "features.", state.features);
-                saveSet(props, "installed.", state.installedFeatures);
-                saveSet(props, "managed.", toStringSet(state.managedBundles));
-                saveMap(props, "checksums.", toStringStringMap(state.bundleChecksums));
-                props.store(os, "FeaturesService State");
+                Map<String, Object> json = new HashMap<String, Object>();
+                json.put("bootDone", state.bootDone.get());
+                json.put("repositories", state.repositories);
+                json.put("features", state.features);
+                json.put("installed", state.installedFeatures);
+                json.put("managed", state.managedBundles);
+                json.put("checksums", toStringLongMap(state.bundleChecksums));
+                JsonWriter.write(os, json);
             } finally {
                 close(os);
             }
@@ -77,92 +73,63 @@ public abstract class StateStorage {
     protected abstract InputStream getInputStream() throws IOException;
     protected abstract OutputStream getOutputStream() throws IOException;
 
-    protected boolean loadBool(Properties props, String key) {
-        return Boolean.parseBoolean(props.getProperty(key));
+    protected Map<String, Set<String>> toStringStringSetMap(Map<?,?> map) {
+        Map<String, Set<String>> nm = new HashMap<String, Set<String>>();
+        for (Map.Entry entry : map.entrySet()) {
+            nm.put(entry.getKey().toString(), toStringSet((Collection) entry.getValue()));
+        }
+        return nm;
     }
 
-    protected void saveBool(Properties props, String key, boolean val) {
-        props.setProperty(key, Boolean.toString(val));
+    protected Map<String, Set<Long>> toStringLongSetMap(Map<?,?> map) {
+        Map<String, Set<Long>> nm = new HashMap<String, Set<Long>>();
+        for (Map.Entry entry : map.entrySet()) {
+            nm.put(entry.getKey().toString(), toLongSet((Collection) entry.getValue()));
+        }
+        return nm;
     }
 
-    protected Set<String> toStringSet(Set<Long> set) {
+    protected Set<String> toStringSet(Collection<?> col) {
         Set<String> ns = new TreeSet<String>();
-        for (long l : set) {
-            ns.add(Long.toString(l));
+        for (Object o : col) {
+            ns.add(o.toString());
         }
         return ns;
     }
 
-    protected Set<Long> toLongSet(Set<String> set) {
+    protected Set<Long> toLongSet(Collection<?> set) {
         Set<Long> ns = new TreeSet<Long>();
-        for (String s : set) {
-            ns.add(Long.parseLong(s));
+        for (Object o : set) {
+            ns.add(toLong(o));
         }
         return ns;
     }
 
-    protected void saveSet(Properties props, String prefix, Set<String> set) {
-        List<String> l = new ArrayList<String>(set);
-        props.put(prefix + "count", Integer.toString(l.size()));
-        for (int i = 0; i < l.size(); i++) {
-            props.put(prefix + "item." + i, l.get(i));
-        }
-    }
-
-    protected Set<String> loadSet(Properties props, String prefix) {
-        Set<String> l = new HashSet<String>();
-        String countStr = (String) props.get(prefix + "count");
-        if (countStr != null) {
-            int count = Integer.parseInt(countStr);
-            for (int i = 0; i < count; i++) {
-                l.add((String) props.get(prefix + "item." + i));
-            }
-        }
-        return l;
-    }
-
-    protected Map<String, String> toStringStringMap(Map<String, Long> map) {
-        Map<String, String> nm = new HashMap<String, String>();
-        for (Map.Entry<String, Long> entry : map.entrySet()) {
-            nm.put(entry.getKey(), Long.toString(entry.getValue()));
+    protected Map<Long, Long> toLongLongMap(Map<?,?> map) {
+        Map<Long, Long> nm = new HashMap<Long, Long>();
+        for (Map.Entry entry : map.entrySet()) {
+            nm.put(toLong(entry.getKey()), toLong(entry.getValue()));
         }
         return nm;
     }
 
-    protected Map<String, Long> toStringLongMap(Map<String, String> map) {
+    protected Map<String, Long> toStringLongMap(Map<?,?> map) {
         Map<String, Long> nm = new HashMap<String, Long>();
-        for (Map.Entry<String, String> entry : map.entrySet()) {
-            nm.put(entry.getKey(), Long.parseLong(entry.getValue()));
+        for (Map.Entry entry : map.entrySet()) {
+            nm.put(entry.getKey().toString(), toLong(entry.getValue()));
         }
         return nm;
     }
 
-
-    protected void saveMap(Properties props, String prefix, Map<String, String> map) {
-        List<Map.Entry<String, String>> l = new ArrayList<Map.Entry<String, String>>(map.entrySet());
-        props.put(prefix + "count", Integer.toString(l.size()));
-        for (int i = 0; i < l.size(); i++) {
-            props.put(prefix + "key." + i, l.get(i).getKey());
-            props.put(prefix + "val." + i, l.get(i).getValue());
-        }
-    }
-
-    protected Map<String, String> loadMap(Properties props, String prefix) {
-        Map<String, String> l = new HashMap<String, String>();
-        String countStr = (String) props.get(prefix + "count");
-        if (countStr != null) {
-            int count = Integer.parseInt(countStr);
-            for (int i = 0; i < count; i++) {
-                String key = (String) props.get(prefix + "key." + i);
-                String val = (String) props.get(prefix + "val." + i);
-                l.put(key, val);
-            }
+    static long toLong(Object o) {
+        if (o instanceof Number) {
+            return ((Number) o).longValue();
+        } else {
+            return Long.parseLong(o.toString());
         }
-        return l;
     }
 
-
-    protected void close(Closeable closeable) {
+    static void close(Closeable closeable) {
         if (closeable != null) {
             try {
                 closeable.close();

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/util/JsonWriter.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/util/JsonWriter.java b/features/core/src/main/java/org/apache/karaf/features/internal/util/JsonWriter.java
index cba27fb..78a85dc 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/util/JsonWriter.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/util/JsonWriter.java
@@ -17,6 +17,8 @@
 package org.apache.karaf.features.internal.util;
 
 import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
 import java.io.Writer;
 import java.util.Collection;
 import java.util.Map;
@@ -25,6 +27,12 @@ import java.util.Map;
  */
 public class JsonWriter {
 
+    public static void write(OutputStream stream, Object value) throws IOException {
+        Writer writer = new OutputStreamWriter(stream);
+        write(writer, value);
+        writer.flush();
+    }
+
     public static void write(Writer writer, Object value) throws IOException {
         if (value instanceof Map) {
             writeObject(writer, (Map) value);

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/util/MapUtils.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/util/MapUtils.java b/features/core/src/main/java/org/apache/karaf/features/internal/util/MapUtils.java
new file mode 100644
index 0000000..455ceda
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/util/MapUtils.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.util;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class MapUtils {
+
+    public static <S, T> Map<S, Set<T>> invert(Map<T, S> map) {
+        Map<S, Set<T>> inverted = new HashMap<S, Set<T>>();
+        for (Map.Entry<T, S> entry : map.entrySet()) {
+            addToMapSet(inverted, entry.getValue(), entry.getKey());
+        }
+        return inverted;
+    }
+
+    public static <S, T> Map<S, Set<T>> copyMapSet(Map<S, Set<T>> from) {
+        Map<S, Set<T>> to = new HashMap<S, Set<T>>();
+        copyMapSet(from, to);
+        return to;
+    }
+
+    public static <S, T> void copyMapSet(Map<S, Set<T>> from, Map<S, Set<T>> to) {
+        for (Map.Entry<S, Set<T>> entry : from.entrySet()) {
+            to.put(entry.getKey(), new HashSet<T>(entry.getValue()));
+        }
+    }
+
+    public static <S, T> void addToMapSet(Map<S, Set<T>> map, S key, T value) {
+        Set<T> values = map.get(key);
+        if (values == null) {
+            values = new HashSet<T>();
+            map.put(key, values);
+        }
+        values.add(value);
+    }
+
+    public static <S, T> void removeFromMapSet(Map<S, Set<T>> map, S key, T value) {
+        Set<T> values = map.get(key);
+        if (values != null) {
+            values.remove(value);
+            if (values.isEmpty()) {
+                map.remove(key);
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/eclipse/equinox/internal/region/DigraphHelper.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/eclipse/equinox/internal/region/DigraphHelper.java b/features/core/src/main/java/org/eclipse/equinox/internal/region/DigraphHelper.java
new file mode 100644
index 0000000..cd874b6
--- /dev/null
+++ b/features/core/src/main/java/org/eclipse/equinox/internal/region/DigraphHelper.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.equinox.internal.region;
+
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.karaf.features.internal.service.FeaturesServiceImpl;
+import org.apache.karaf.features.internal.util.JsonReader;
+import org.apache.karaf.features.internal.util.JsonWriter;
+import org.eclipse.equinox.region.Region;
+import org.eclipse.equinox.region.RegionDigraph;
+import org.eclipse.equinox.region.RegionFilterBuilder;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.hooks.bundle.CollisionHook;
+
+public class DigraphHelper {
+
+    private static final String DIGRAPH_FILE = "digraph.json";
+
+    private static final String REGIONS = "regions";
+    private static final String EDGES = "edges";
+    private static final String TAIL = "tail";
+    private static final String HEAD = "head";
+    private static final String POLICY = "policy";
+
+    public static StandardRegionDigraph loadDigraph(BundleContext bundleContext) throws BundleException, IOException, InvalidSyntaxException {
+        StandardRegionDigraph digraph;
+        ThreadLocal<Region> threadLocal = new ThreadLocal<Region>();
+        File digraphFile = bundleContext.getDataFile(DIGRAPH_FILE);
+        if (digraphFile == null || !digraphFile.exists()) {
+            digraph = new StandardRegionDigraph(bundleContext, threadLocal);
+            Region root = digraph.createRegion(FeaturesServiceImpl.ROOT_REGION);
+            for (Bundle bundle : bundleContext.getBundles()) {
+                root.addBundle(bundle);
+            }
+        } else {
+            InputStream in = new FileInputStream(digraphFile);
+            try {
+                digraph = readDigraph(new DataInputStream(in), bundleContext, threadLocal);
+            } finally {
+                in.close();
+            }
+        }
+        return digraph;
+    }
+
+    public static void saveDigraph(BundleContext bundleContext, RegionDigraph digraph) throws IOException {
+        File digraphFile = bundleContext.getDataFile(DIGRAPH_FILE);
+        FileOutputStream out = new FileOutputStream(digraphFile);
+        try {
+            saveDigraph(digraph, out);
+        } catch (Exception e) {
+            // Ignore
+        } finally {
+            try {
+                out.close();
+            } catch (IOException e) {
+                // ignore;
+            }
+        }
+    }
+
+    public static CollisionHook getCollisionHook(StandardRegionDigraph digraph) {
+        return (CollisionHook) digraph.getBundleCollisionHook();
+    }
+
+
+    @SuppressWarnings("unchecked")
+    static StandardRegionDigraph readDigraph(InputStream in, BundleContext bundleContext, ThreadLocal<Region> threadLocal) throws IOException, BundleException, InvalidSyntaxException {
+        StandardRegionDigraph digraph = new StandardRegionDigraph(bundleContext, threadLocal);
+        Map json = (Map) JsonReader.read(in);
+        Map<String, Collection<Number>> regions = (Map<String, Collection<Number>>) json.get(REGIONS);
+        for (Map.Entry<String, Collection<Number>> rmap : regions.entrySet()) {
+            String name = rmap.getKey();
+            Region region = digraph.createRegion(name);
+            for (Number b : rmap.getValue()) {
+                region.addBundle(b.longValue());
+            }
+        }
+        List<Map<String, Object>> edges = (List<Map<String, Object>>) json.get(EDGES);
+        for (Map<String, Object> e : edges) {
+            String tail = (String) e.get(TAIL);
+            String head = (String) e.get(HEAD);
+            Map<String, Collection<String>> policy = (Map<String, Collection<String>>) e.get(POLICY);
+            RegionFilterBuilder builder = digraph.createRegionFilterBuilder();
+            for (Map.Entry<String,Collection<String>> rf : policy.entrySet()) {
+                String ns = rf.getKey();
+                for (String f : rf.getValue()) {
+                    builder.allow(ns, f);
+                }
+            }
+            digraph.connect(digraph.getRegion(tail), builder.build(), digraph.getRegion(head));
+        }
+        return digraph;
+    }
+
+    static void saveDigraph(RegionDigraph digraph, OutputStream out) throws IOException {
+        Map<String, Object> json = new LinkedHashMap<String, Object>();
+        Map<String, Set<Long>> regions = new LinkedHashMap<String, Set<Long>>();
+        json.put(REGIONS, regions);
+        for (Region region : digraph.getRegions()) {
+            regions.put(region.getName(), region.getBundleIds());
+        }
+        List<Map<String, Object>> edges = new ArrayList<Map<String, Object>>();
+        json.put(EDGES, edges);
+        for (Region tail : digraph.getRegions()) {
+            for (RegionDigraph.FilteredRegion fr : digraph.getEdges(tail)) {
+                Map<String, Object> edge = new HashMap<String, Object>();
+                edge.put(TAIL, tail.getName());
+                edge.put(HEAD, fr.getRegion().getName());
+                edge.put(POLICY, fr.getFilter().getSharingPolicy());
+                edges.add(edge);
+
+            }
+        }
+        JsonWriter.write(out, json);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.3.0.xsd
----------------------------------------------------------------------
diff --git a/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.3.0.xsd b/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.3.0.xsd
index b68b1bb..e28f05f 100644
--- a/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.3.0.xsd
+++ b/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.3.0.xsd
@@ -61,23 +61,26 @@ Feature definition.
 Definition of the Feature.
             ]]></xs:documentation>
         </xs:annotation>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element name="details" minOccurs="0" type="xs:string">
-                <xs:annotation>
-                    <xs:documentation><![CDATA[
-The help text shown for this feature when using feature:info console command.
-                    ]]>
-                    </xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="config" type="tns:config" />
-            <xs:element name="configfile" type="tns:configFile" />
-            <xs:element name="feature" type="tns:dependency" />
-            <xs:element name="bundle" type="tns:bundle" />
-            <xs:element name="conditional" type="tns:conditional" />
-            <xs:element name="requirement" type="tns:requirement" />
-            <xs:element name="capability" type="tns:capability" />
-        </xs:choice>
+        <xs:sequence>
+            <xs:choice minOccurs="0" maxOccurs="unbounded">
+                <xs:element name="details" minOccurs="0" type="xs:string">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+    The help text shown for this feature when using feature:info console command.
+                        ]]>
+                        </xs:documentation>
+                    </xs:annotation>
+                </xs:element>
+                <xs:element name="config" type="tns:config" />
+                <xs:element name="configfile" type="tns:configFile" />
+                <xs:element name="feature" type="tns:dependency" />
+                <xs:element name="bundle" type="tns:bundle" />
+                <xs:element name="conditional" type="tns:conditional" />
+                <xs:element name="requirement" type="tns:requirement" />
+                <xs:element name="capability" type="tns:capability" />
+            </xs:choice>
+            <xs:element name="scoping" minOccurs="0" maxOccurs="1" type="tns:scoping" />
+        </xs:sequence>
         <xs:attribute name="name" type="tns:featureName" use="required" />
         <xs:attribute name="version" type="xs:string" default="0.0.0" />
         <xs:attribute name="description" type="xs:string" />
@@ -232,6 +235,27 @@ Additional capability of this feature.
         </xs:simpleContent>
     </xs:complexType>
 
+    <xs:complexType name="scoping">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Scoping definition for this feature.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="import" type="tns:scopeFilter"/>
+            <xs:element name="export" type="tns:scopeFilter"/>
+        </xs:choice>
+        <xs:attribute name="acceptDependencies" type="xs:boolean"/>
+    </xs:complexType>
+
+    <xs:complexType name="scopeFilter">
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute name="namespace"  type="xs:string" use="required"/>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
     <xs:simpleType name="featureName">
         <xs:annotation>
             <xs:documentation><![CDATA[

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/test/java/org/apache/karaf/features/FeaturesServiceTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/FeaturesServiceTest.java b/features/core/src/test/java/org/apache/karaf/features/FeaturesServiceTest.java
index 9f7e67b..d94d9b7 100644
--- a/features/core/src/test/java/org/apache/karaf/features/FeaturesServiceTest.java
+++ b/features/core/src/test/java/org/apache/karaf/features/FeaturesServiceTest.java
@@ -346,7 +346,7 @@ public class FeaturesServiceTest extends TestBase {
                 + "  <feature name='f2' version='0.2'><bundle>bundle2</bundle></feature>"
                 + "</features>");
 
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, null, null, null, null);
+        FeaturesServiceImpl svc = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, null, null, null, null, null);
         svc.addRepository(uri);
 
         assertEquals(feature("f2", "0.2"), svc.getFeature("f2", "[0.1,0.3)"));
@@ -366,7 +366,7 @@ public class FeaturesServiceTest extends TestBase {
         expect(bundleContext.getBundles()).andReturn(new Bundle[0]);
         replay(bundleContext);
 
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(null, bundleContext, new Storage(), null, null, null, null, null, null, null);
+        FeaturesServiceImpl svc = new FeaturesServiceImpl(null, bundleContext, new Storage(), null, null, null, null, null, null, null, null);
         svc.addRepository(uri);
         try {
             List<String> features = new ArrayList<String>();
@@ -377,7 +377,8 @@ public class FeaturesServiceTest extends TestBase {
             svc.installFeatures(new CopyOnWriteArraySet<String>(features),
                                 EnumSet.noneOf(FeaturesService.Option.class));
             fail("Call should have thrown an exception");
-        } catch (MalformedURLException e) {
+        } catch (Exception t) {
+            // Expected
         }
         verify(bundleContext);
     }
@@ -390,7 +391,7 @@ public class FeaturesServiceTest extends TestBase {
         URI uri = createTempRepo("<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
                 + "  <featur><bundle>somebundle</bundle></featur></features>");
 
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, null, null, null, null);
+        FeaturesServiceImpl svc = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, null, null, null, null, null);
         try {
             svc.addRepository(uri);
             fail("exception expected");
@@ -408,7 +409,7 @@ public class FeaturesServiceTest extends TestBase {
                 + "  <feature name='f1'><bundle>file:bundle1</bundle><bundle>file:bundle2</bundle></feature>"
                 + "</features>");
 
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, null, null, null, null);
+        FeaturesServiceImpl svc = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, null, null, null, null, null);
         svc.addRepository(uri);
         Feature feature = svc.getFeature("f1");
         Assert.assertNotNull("No feature named fi found", feature);        


[4/6] [KARAF-2923] Region support in features service

Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/region/CandidateComparator.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/region/CandidateComparator.java b/features/core/src/main/java/org/apache/karaf/features/internal/region/CandidateComparator.java
new file mode 100644
index 0000000..74c014b
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/region/CandidateComparator.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.region;
+
+import java.util.Comparator;
+
+import org.osgi.framework.Version;
+import org.osgi.framework.namespace.BundleNamespace;
+import org.osgi.framework.namespace.IdentityNamespace;
+import org.osgi.framework.namespace.PackageNamespace;
+import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.resource.Capability;
+
+public class CandidateComparator implements Comparator<Capability>
+{
+    public int compare(Capability cap1, Capability cap2)
+    {
+        int c = 0;
+        // Always prefer system bundle
+        if (cap1 instanceof BundleCapability && !(cap2 instanceof BundleCapability)) {
+            c = -1;
+        } else if (!(cap1 instanceof BundleCapability) && cap2 instanceof BundleCapability) {
+            c = 1;
+        }
+        // Compare revision capabilities.
+        if ((c == 0) && cap1.getNamespace().equals(BundleNamespace.BUNDLE_NAMESPACE))
+        {
+            c = ((Comparable) cap1.getAttributes().get(BundleNamespace.BUNDLE_NAMESPACE))
+                    .compareTo(cap2.getAttributes().get(BundleNamespace.BUNDLE_NAMESPACE));
+            if (c == 0)
+            {
+                Version v1 = (!cap1.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
+                        ? Version.emptyVersion
+                        : (Version) cap1.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
+                Version v2 = (!cap2.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
+                        ? Version.emptyVersion
+                        : (Version) cap2.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
+                // Compare these in reverse order, since we want
+                // highest version to have priority.
+                c = compareVersions(v2, v1);
+            }
+        }
+        // Compare package capabilities.
+        else if ((c == 0) && cap1.getNamespace().equals(PackageNamespace.PACKAGE_NAMESPACE))
+        {
+            c = ((Comparable) cap1.getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE))
+                    .compareTo(cap2.getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE));
+            if (c == 0)
+            {
+                Version v1 = (!cap1.getAttributes().containsKey(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE))
+                        ? Version.emptyVersion
+                        : (Version) cap1.getAttributes().get(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE);
+                Version v2 = (!cap2.getAttributes().containsKey(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE))
+                        ? Version.emptyVersion
+                        : (Version) cap2.getAttributes().get(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE);
+                // Compare these in reverse order, since we want
+                // highest version to have priority.
+                c = compareVersions(v2, v1);
+                // if same version, rather compare on the bundle version
+                if (c == 0)
+                {
+                    v1 = (!cap1.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
+                            ? Version.emptyVersion
+                            : (Version) cap1.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
+                    v2 = (!cap2.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
+                            ? Version.emptyVersion
+                            : (Version) cap2.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
+                    // Compare these in reverse order, since we want
+                    // highest version to have priority.
+                    c = compareVersions(v2, v1);
+                }
+            }
+        }
+        // Compare feature capabilities
+        else if ((c == 0) && cap1.getNamespace().equals(IdentityNamespace.IDENTITY_NAMESPACE))
+        {
+            c = ((Comparable) cap1.getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE))
+                    .compareTo(cap2.getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE));
+            if (c == 0)
+            {
+                Version v1 = (!cap1.getAttributes().containsKey(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE))
+                        ? Version.emptyVersion
+                        : (Version) cap1.getAttributes().get(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE);
+                Version v2 = (!cap2.getAttributes().containsKey(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE))
+                        ? Version.emptyVersion
+                        : (Version) cap2.getAttributes().get(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE);
+                // Compare these in reverse order, since we want
+                // highest version to have priority.
+                c = compareVersions(v2, v1);
+            }
+        }
+        return c;
+    }
+
+    private int compareVersions(Version v1, Version v2) {
+        int c = v1.getMajor() - v2.getMajor();
+        if (c != 0) {
+            return c;
+        }
+        c = v1.getMinor() - v2.getMinor();
+        if (c != 0) {
+            return c;
+        }
+        c = v1.getMicro() - v2.getMicro();
+        if (c != 0) {
+            return c;
+        }
+        return v1.getQualifier().compareTo(v2.getQualifier());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/region/ResourceComparator.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/region/ResourceComparator.java b/features/core/src/main/java/org/apache/karaf/features/internal/region/ResourceComparator.java
new file mode 100644
index 0000000..19ba529
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/region/ResourceComparator.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.region;
+
+import java.util.Comparator;
+
+import org.apache.felix.resolver.Util;
+import org.osgi.framework.Version;
+import org.osgi.resource.Resource;
+
+public class ResourceComparator implements Comparator<Resource> {
+
+    @Override
+    public int compare(Resource o1, Resource o2) {
+        String bsn1 = Util.getSymbolicName(o1);
+        String bsn2 = Util.getSymbolicName(o2);
+        int c = bsn1.compareTo(bsn2);
+        if (c == 0) {
+            Version v1 = Util.getVersion(o1);
+            Version v2 = Util.getVersion(o2);
+            c = v1.compareTo(v2);
+            if (c == 0) {
+                c = o1.hashCode() - o2.hashCode();
+            }
+        }
+        return c;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/region/Subsystem.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/region/Subsystem.java b/features/core/src/main/java/org/apache/karaf/features/internal/region/Subsystem.java
new file mode 100644
index 0000000..8d55317
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/region/Subsystem.java
@@ -0,0 +1,341 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.region;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.felix.resolver.Util;
+import org.apache.felix.utils.version.VersionRange;
+import org.apache.felix.utils.version.VersionTable;
+import org.apache.karaf.features.BundleInfo;
+import org.apache.karaf.features.Conditional;
+import org.apache.karaf.features.Dependency;
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.ScopeFilter;
+import org.apache.karaf.features.internal.download.DownloadCallback;
+import org.apache.karaf.features.internal.download.DownloadManager;
+import org.apache.karaf.features.internal.download.Downloader;
+import org.apache.karaf.features.internal.download.StreamProvider;
+import org.apache.karaf.features.internal.resolver.FeatureResource;
+import org.apache.karaf.features.internal.resolver.RequirementImpl;
+import org.apache.karaf.features.internal.resolver.ResourceBuilder;
+import org.apache.karaf.features.internal.resolver.ResourceImpl;
+import org.apache.karaf.features.internal.resolver.ResourceUtils;
+import org.eclipse.equinox.region.RegionFilter;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Version;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Requirement;
+import org.osgi.resource.Resource;
+
+import static org.apache.karaf.features.internal.resolver.ResourceUtils.TYPE_FEATURE;
+import static org.apache.karaf.features.internal.resolver.ResourceUtils.TYPE_SUBSYSTEM;
+import static org.apache.karaf.features.internal.resolver.ResourceUtils.addIdentityRequirement;
+import static org.apache.karaf.features.internal.util.MapUtils.addToMapSet;
+import static org.osgi.framework.namespace.IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE;
+import static org.osgi.framework.namespace.IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE;
+import static org.osgi.framework.namespace.IdentityNamespace.IDENTITY_NAMESPACE;
+
+public class Subsystem extends ResourceImpl {
+
+    private static final String ALL_FILTER = "(|(!(all=*))(all=*))";
+
+    private static final String SUBSYSTEM_FILTER = String.format("(%s=%s)", CAPABILITY_TYPE_ATTRIBUTE, TYPE_SUBSYSTEM);
+
+    private static final String FEATURE_FILTER = String.format("(%s=%s)", CAPABILITY_TYPE_ATTRIBUTE, TYPE_FEATURE);
+
+    private static final String SUBSYSTEM_OR_FEATURE_FILTER = String.format("(|%s%s)", SUBSYSTEM_FILTER, FEATURE_FILTER);
+
+    // Everything is visible
+    private static final Map<String, Set<String>> SHARE_ALL_POLICY =
+            Collections.singletonMap(
+                    RegionFilter.VISIBLE_ALL_NAMESPACE,
+                    Collections.singleton(ALL_FILTER));
+
+    // Nothing (but systems) is visible
+    private static final Map<String, Set<String>> SHARE_NONE_POLICY =
+            Collections.singletonMap(
+                    IDENTITY_NAMESPACE,
+                    Collections.singleton(SUBSYSTEM_FILTER));
+
+    private final String name;
+    private final boolean acceptDependencies;
+    private final Subsystem parent;
+    private final Feature feature;
+    private final List<Subsystem> children = new ArrayList<Subsystem>();
+    private final Map<String, Set<String>> importPolicy;
+    private final Map<String, Set<String>> exportPolicy;
+    private final List<Resource> installable = new ArrayList<Resource>();
+    private final Map<String, DependencyInfo> dependencies = new HashMap<String, DependencyInfo>();
+
+    public Subsystem(String name) {
+        super(name, TYPE_SUBSYSTEM, Version.emptyVersion);
+        this.name = name;
+        this.parent = null;
+        this.acceptDependencies = true;
+        this.feature = null;
+        this.importPolicy = SHARE_NONE_POLICY;
+        this.exportPolicy = SHARE_NONE_POLICY;
+    }
+
+    public Subsystem(String name, Feature feature, Subsystem parent) {
+        super(name, TYPE_SUBSYSTEM, Version.emptyVersion);
+        this.name = name;
+        this.parent = parent;
+        this.acceptDependencies = feature.getScoping() != null && feature.getScoping().acceptDependencies();
+        this.feature = feature;
+        if (feature.getScoping() != null) {
+            this.importPolicy = createPolicy(feature.getScoping().getImports());
+            this.importPolicy.put(IDENTITY_NAMESPACE, Collections.singleton(SUBSYSTEM_OR_FEATURE_FILTER));
+            this.exportPolicy = createPolicy(feature.getScoping().getExports());
+            this.exportPolicy.put(IDENTITY_NAMESPACE, Collections.singleton(SUBSYSTEM_OR_FEATURE_FILTER));
+        } else {
+            this.importPolicy = SHARE_ALL_POLICY;
+            this.exportPolicy = SHARE_ALL_POLICY;
+        }
+
+        Map<String, String> dirs = new HashMap<String, String>();
+        Map<String, Object> attrs = new HashMap<String, Object>();
+        attrs.put(IDENTITY_NAMESPACE, feature.getName());
+        attrs.put(CAPABILITY_TYPE_ATTRIBUTE, TYPE_FEATURE);
+        attrs.put(CAPABILITY_VERSION_ATTRIBUTE, new VersionRange(VersionTable.getVersion(feature.getVersion()), true));
+        Requirement requirement = new RequirementImpl(this, IDENTITY_NAMESPACE, dirs, attrs);
+        addRequirement(requirement);
+    }
+
+    public Subsystem(String name, Subsystem parent, boolean acceptDependencies) {
+        super(name, TYPE_SUBSYSTEM, Version.emptyVersion);
+        this.name = name;
+        this.parent = parent;
+        this.acceptDependencies = acceptDependencies;
+        this.feature = null;
+        this.importPolicy = SHARE_ALL_POLICY;
+        this.exportPolicy = SHARE_NONE_POLICY;
+    }
+
+    public List<Resource> getInstallable() {
+        return installable;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Subsystem getParent() {
+        return parent;
+    }
+
+    public Collection<Subsystem> getChildren() {
+        return children;
+    }
+
+    public Subsystem getChild(String name) {
+        for (Subsystem child : children) {
+            if (child.getName().equals(name)) {
+                return child;
+            }
+        }
+        return null;
+    }
+
+    public boolean isAcceptDependencies() {
+        return acceptDependencies;
+    }
+
+    public Map<String, Set<String>> getImportPolicy() {
+        return importPolicy;
+    }
+
+    public Map<String, Set<String>> getExportPolicy() {
+        return exportPolicy;
+    }
+
+    public Feature getFeature() {
+        return feature;
+    }
+
+    public Subsystem createSubsystem(String name, boolean acceptDependencies) {
+        if (feature != null) {
+            throw new UnsupportedOperationException("Can not create application subsystems inside a feature subsystem");
+        }
+        // Create subsystem
+        Subsystem as = new Subsystem(getName() + "/" + name, this, acceptDependencies);
+        children.add(as);
+        // Add a requirement to force its resolution
+        Capability identity = as.getCapabilities(IDENTITY_NAMESPACE).iterator().next();
+        Object bsn = identity.getAttributes().get(IDENTITY_NAMESPACE);
+        Requirement requirement = new RequirementImpl(this, IDENTITY_NAMESPACE,
+                Collections.<String,String>emptyMap(),
+                Collections.singletonMap(IDENTITY_NAMESPACE, bsn));
+        addRequirement(requirement);
+        // Add it to repo
+        installable.add(as);
+        return as;
+    }
+
+    public void addSystemResource(Resource resource) {
+        installable.add(resource);
+    }
+
+    public void requireFeature(String name, String range) {
+        ResourceUtils.addIdentityRequirement(this, name, TYPE_FEATURE, range);
+    }
+
+    @SuppressWarnings("InfiniteLoopStatement")
+    public void preResolve(Collection<Feature> features,
+                           DownloadManager manager,
+                           String featureResolutionRange) throws Exception {
+        for (Subsystem child : children) {
+            child.preResolve(features, manager, featureResolutionRange);
+        }
+        List<Requirement> processed = new ArrayList<Requirement>();
+        while (true) {
+            List<Requirement> requirements = getRequirements(IDENTITY_NAMESPACE);
+            requirements.removeAll(processed);
+            if (requirements.isEmpty()) {
+                break;
+            }
+            for (Requirement requirement : requirements) {
+                String name = (String) requirement.getAttributes().get(IDENTITY_NAMESPACE);
+                String type = (String) requirement.getAttributes().get(CAPABILITY_TYPE_ATTRIBUTE);
+                VersionRange range = (VersionRange) requirement.getAttributes().get(CAPABILITY_VERSION_ATTRIBUTE);
+                if (TYPE_FEATURE.equals(type)) {
+                    for (Feature feature : features) {
+                        if (feature.getName().equals(name)
+                                && (range == null || range.contains(VersionTable.getVersion(feature.getVersion())))) {
+                            if (feature != this.feature) {
+                                String ssName = this.name + "#" + (feature.hasVersion() ? feature.getName() + "-" + feature.getVersion() : feature.getName());
+                                Subsystem fs = getChild(ssName);
+                                if (fs == null) {
+                                    fs = new Subsystem(ssName, feature, this);
+                                    fs.preResolve(features, manager, featureResolutionRange);
+                                    installable.add(fs);
+                                    children.add(fs);
+                                }
+                            }
+                        }
+                    }
+                }
+                processed.add(requirement);
+            }
+        }
+        if (feature != null) {
+            final Map<String, Resource> bundles = new ConcurrentHashMap<String, Resource>();
+            final Downloader downloader = manager.createDownloader();
+            final Map<BundleInfo, Boolean> infos = new HashMap<BundleInfo, Boolean>();
+            for (Conditional cond : feature.getConditional()) {
+                for (final BundleInfo bi : cond.getBundles()) {
+                    infos.put(bi, false);
+                }
+            }
+            for (BundleInfo bi : feature.getBundles()) {
+                infos.put(bi, true);
+            }
+            for (Map.Entry<BundleInfo, Boolean> entry : infos.entrySet()) {
+                final BundleInfo bi = entry.getKey();
+                final String loc = bi.getLocation();
+                final boolean mandatory = entry.getValue();
+                downloader.download(loc, new DownloadCallback() {
+                    @Override
+                    public void downloaded(StreamProvider provider) throws Exception {
+                        ResourceImpl res = createResource(loc, provider.getMetadata());
+                        bundles.put(loc, res);
+                        if (bi.isDependency()) {
+                            addDependency(res, false);
+                        } else {
+                            doAddDependency(res, mandatory);
+                        }
+                    }
+                });
+            }
+            downloader.await();
+            for (Dependency dep : feature.getDependencies()) {
+                Subsystem ss = this;
+                while (!ss.isAcceptDependencies()) {
+                    ss = ss.getParent();
+                }
+                ss.requireFeature(dep.getName(), dep.getVersion());
+            }
+            for (Conditional cond : feature.getConditional()) {
+                FeatureResource resCond = FeatureResource.build(feature, cond, featureResolutionRange, bundles);
+                addIdentityRequirement(this, resCond, false);
+                installable.add(resCond);
+            }
+
+            FeatureResource res = FeatureResource.build(feature, featureResolutionRange, bundles);
+            addIdentityRequirement(res, this);
+            installable.add(res);
+        }
+        // Compute dependencies
+        for (DependencyInfo info : dependencies.values()) {
+            installable.add(info.resource);
+            addIdentityRequirement(info.resource, this, info.mandatory);
+       }
+    }
+
+    void addDependency(ResourceImpl resource, boolean mandatory) {
+        if (isAcceptDependencies()) {
+            doAddDependency(resource, mandatory);
+        } else {
+            parent.addDependency(resource, mandatory);
+        }
+    }
+
+    private void doAddDependency(ResourceImpl resource, boolean mandatory) {
+        String id = Util.getSymbolicName(resource) + "|" + Util.getVersion(resource);
+        DependencyInfo info = dependencies.get(id);
+        if (info == null) {
+            info = new DependencyInfo();
+            dependencies.put(id, info);
+        }
+        info.resource = resource;
+        info.mandatory |= mandatory;
+    }
+
+    class DependencyInfo {
+        ResourceImpl resource;
+        boolean mandatory;
+    }
+
+    Map<String, Set<String>> createPolicy(List<? extends ScopeFilter> filters) {
+        Map<String, Set<String>> policy = new HashMap<String, Set<String>>();
+        for (ScopeFilter filter : filters) {
+            addToMapSet(policy, filter.getNamespace(), filter.getFilter());
+        }
+        return policy;
+    }
+
+    ResourceImpl createResource(String uri, Map<String, String> headers) throws Exception {
+        try {
+            return ResourceBuilder.build(uri, headers);
+        } catch (BundleException e) {
+            throw new Exception("Unable to create resource for bundle " + uri, e);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return getName();
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolveContext.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolveContext.java b/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolveContext.java
new file mode 100644
index 0000000..e5c6532
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolveContext.java
@@ -0,0 +1,188 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.region;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.resolver.Util;
+import org.apache.karaf.features.internal.repository.StaticRepository;
+import org.eclipse.equinox.region.Region;
+import org.eclipse.equinox.region.RegionDigraph;
+import org.eclipse.equinox.region.RegionFilter;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.namespace.IdentityNamespace;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Requirement;
+import org.osgi.resource.Resource;
+import org.osgi.resource.Wiring;
+import org.osgi.service.repository.Repository;
+import org.osgi.service.resolver.HostedCapability;
+import org.osgi.service.resolver.ResolveContext;
+
+public class SubsystemResolveContext extends ResolveContext {
+
+    private final Subsystem root;
+    private final RegionDigraph digraph;
+    private final CandidateComparator candidateComparator = new CandidateComparator();
+
+    private final Map<Resource, Subsystem> resToSub = new HashMap<Resource, Subsystem>();
+    private final Repository repository;
+
+
+    public SubsystemResolveContext(Subsystem root, RegionDigraph digraph) throws BundleException {
+        this.root = root;
+        this.digraph = digraph;
+
+        prepare(root);
+        repository = new StaticRepository(resToSub.keySet());
+    }
+
+    void prepare(Subsystem subsystem) {
+        resToSub.put(subsystem, subsystem);
+        for (Resource res : subsystem.getInstallable()) {
+            resToSub.put(res, subsystem);
+        }
+        for (Subsystem child : subsystem.getChildren()) {
+            prepare(child);
+        }
+    }
+
+    @Override
+    public Collection<Resource> getMandatoryResources() {
+        return Collections.<Resource>singleton(root);
+    }
+
+    @Override
+    public List<Capability> findProviders(Requirement requirement) {
+        List<Capability> caps = new ArrayList<Capability>();
+        Region requirerRegion = getRegion(requirement.getResource());
+        if (requirerRegion != null) {
+            Map<Requirement, Collection<Capability>> resMap =
+                    repository.findProviders(Collections.singleton(requirement));
+            Collection<Capability> res = resMap != null ? resMap.get(requirement) : null;
+            if (res != null) {
+                caps.addAll(res);
+            }
+            // Use the digraph to prune non visible capabilities
+            Visitor visitor = new Visitor(caps);
+            requirerRegion.visitSubgraph(visitor);
+            Collection<Capability> allowed = visitor.getAllowed();
+            caps.retainAll(allowed);
+            // Handle cases where the same bundle is requested from both
+            // a subsystem and one of its ascendant.  In such cases, we
+            // need to remove the one from the child if it can view
+            // the parent one
+            if (caps.size() > 1) {
+                Map<String, Resource> providers = new HashMap<String, Resource>();
+                for (Capability cap : caps) {
+                    Resource resource = cap.getResource();
+                    String id = Util.getSymbolicName(resource) + "|" + Util.getVersion(resource);
+                    Resource prev = providers.get(id);
+                    if (prev != null && prev != resource) {
+                        String r1 = getRegion(prev).getName();
+                        String r2 = getRegion(resource).getName();
+                        int c = r1.compareTo(r2);
+                        if (c == 0) {
+                            // This should never happen because resource have been
+                            // de-duplicated during the pre-resolution phase.
+                            throw new IllegalStateException();
+                        }
+                        resource = c < 0 ? prev : resource;
+                    }
+                    providers.put(id, resource);
+                }
+                for (Iterator<Capability> it = caps.iterator(); it.hasNext();) {
+                    Capability cap = it.next();
+                    if (!providers.values().contains(cap.getResource())) {
+                        it.remove();
+                    }
+                }
+            }
+            // Sort caps
+            Collections.sort(caps, candidateComparator);
+        }
+        return caps;
+    }
+
+    private Subsystem getSubsystem(Resource resource) {
+        return resToSub.get(resource);
+    }
+
+    private Region getRegion(Resource resource) {
+        return digraph.getRegion(getSubsystem(resource).getName());
+    }
+
+    @Override
+    public int insertHostedCapability(List<Capability> capabilities, HostedCapability hostedCapability) {
+        int idx = Collections.binarySearch(capabilities, hostedCapability, candidateComparator);
+        if (idx < 0) {
+            idx = Math.abs(idx + 1);
+        }
+        capabilities.add(idx, hostedCapability);
+        return idx;
+    }
+
+    @Override
+    public boolean isEffective(Requirement requirement) {
+        String resolution = requirement.getDirectives().get(Constants.RESOLUTION_DIRECTIVE);
+        return requirement.getNamespace().equals(IdentityNamespace.IDENTITY_NAMESPACE)
+                || !Constants.RESOLUTION_OPTIONAL.equals(resolution);
+    }
+
+    @Override
+    public Map<Resource, Wiring> getWirings() {
+        return Collections.emptyMap();
+    }
+
+    class Visitor extends AbstractRegionDigraphVisitor<Capability> {
+
+        Visitor(Collection<Capability> candidates) {
+            super(candidates);
+        }
+
+        @Override
+        protected boolean contains(Region region, Capability candidate) {
+            return region.equals(getRegion(candidate.getResource()));
+        }
+
+        @Override
+        protected boolean isAllowed(Capability candidate, RegionFilter filter) {
+            if (filter.isAllowed(candidate.getNamespace(), candidate.getAttributes())) {
+                return true;
+            }
+            Resource resource = candidate.getResource();
+            List<Capability> identities = resource.getCapabilities(IdentityNamespace.IDENTITY_NAMESPACE);
+            if (identities != null && !identities.isEmpty()) {
+                Capability identity = identities.iterator().next();
+                Map<String, Object> attrs = new HashMap<String, Object>();
+                attrs.put(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, identity.getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE));
+                attrs.put(Constants.BUNDLE_VERSION_ATTRIBUTE, identity.getAttributes().get(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE));
+                return filter.isAllowed(RegionFilter.VISIBLE_BUNDLE_NAMESPACE, attrs);
+            }
+            return false;
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolver.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolver.java b/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolver.java
new file mode 100644
index 0000000..8a98328
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolver.java
@@ -0,0 +1,317 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.region;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.apache.felix.resolver.ResolverImpl;
+import org.apache.felix.resolver.Util;
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.features.internal.download.DownloadManager;
+import org.apache.karaf.features.internal.download.StreamProvider;
+import org.apache.karaf.features.internal.download.simple.SimpleDownloader;
+import org.apache.karaf.features.internal.resolver.CapabilitySet;
+import org.apache.karaf.features.internal.resolver.SimpleFilter;
+import org.apache.karaf.features.internal.resolver.Slf4jResolverLog;
+import org.eclipse.equinox.internal.region.StandardRegionDigraph;
+import org.eclipse.equinox.region.Region;
+import org.eclipse.equinox.region.RegionDigraph;
+import org.eclipse.equinox.region.RegionFilterBuilder;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Requirement;
+import org.osgi.resource.Resource;
+import org.osgi.resource.Wire;
+import org.osgi.service.resolver.Resolver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.karaf.features.internal.resolver.ResourceUtils.TYPE_FEATURE;
+import static org.apache.karaf.features.internal.resolver.ResourceUtils.TYPE_SUBSYSTEM;
+import static org.apache.karaf.features.internal.util.MapUtils.invert;
+import static org.osgi.framework.namespace.IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE;
+import static org.osgi.framework.namespace.IdentityNamespace.IDENTITY_NAMESPACE;
+import static org.osgi.framework.namespace.IdentityNamespace.TYPE_BUNDLE;
+import static org.osgi.framework.namespace.IdentityNamespace.TYPE_FRAGMENT;
+
+public class SubsystemResolver {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(SubsystemResolver.class);
+
+    private DownloadManager manager;
+    private RegionDigraph digraph;
+    private Subsystem root;
+    private Map<Resource, List<Wire>> wiring;
+
+    public SubsystemResolver() {
+        this(new SimpleDownloader());
+    }
+
+    public SubsystemResolver(DownloadManager manager) {
+        this.manager = manager;
+    }
+
+    public Map<Resource, List<Wire>> resolve(
+            List<Repository> repositories,
+            Map<String, Set<String>> features,
+            Collection<? extends Resource> system,
+            String featureResolutionRange
+    ) throws Exception {
+        // Build subsystems on the fly
+        for (Map.Entry<String, Set<String>> entry : features.entrySet()) {
+            String[] parts = entry.getKey().split("/");
+            if (root == null) {
+                root = new Subsystem(parts[0]);
+            } else if (!root.getName().equals(parts[0])) {
+                throw new IllegalArgumentException("Can not use multiple roots: " + root.getName() + ", " + parts[0]);
+            }
+            Subsystem ss = root;
+            for (int i = 1; i < parts.length; i++) {
+                ss = getOrCreateChild(ss, parts[i]);
+            }
+            for (String feature : entry.getValue()) {
+                String name, range;
+                int idx = feature.indexOf('/');
+                if (idx >= 0) {
+                    name = feature.substring(0, idx);
+                    range = feature.substring(idx + 1);
+                } else {
+                    name = feature;
+                    range = null;
+                }
+                ss.requireFeature(name, range);
+            }
+        }
+        if (root == null) {
+            return Collections.emptyMap();
+        }
+        // Pre-resolve
+        List<Feature> allFeatures = new ArrayList<Feature>();
+        for (Repository repo : repositories) {
+            allFeatures.addAll(Arrays.asList(repo.getFeatures()));
+        }
+        root.preResolve(allFeatures, manager, featureResolutionRange);
+
+        // Add system resources
+        for (Resource res : system) {
+            root.addSystemResource(res);
+        }
+
+        // Populate digraph and resolve
+        digraph = new StandardRegionDigraph(null, null);
+        populateDigraph(digraph, root);
+
+        Resolver resolver = new ResolverImpl(new Slf4jResolverLog(LOGGER));
+        wiring = resolver.resolve(new SubsystemResolveContext(root, digraph));
+
+        // Fragments are always wired to their host only, so create fake wiring to
+        // the subsystem the host is wired to
+        associateFragments();
+
+        return wiring;
+    }
+
+    public Map<String, StreamProvider> getProviders() {
+        return manager.getProviders();
+    }
+
+    public RegionDigraph getDigraph() {
+        return digraph;
+    }
+
+    public Map<Resource, List<Wire>> getWiring() {
+        return wiring;
+    }
+
+    public Map<String, String> getFlatSubsystemsMap() {
+        Map<String, String> toFlatten = new HashMap<String, String>();
+        findSubsystemsToFlatten(root, toFlatten);
+        return toFlatten;
+    }
+
+    public Map<String, Set<Resource>> getBundlesPerRegions() {
+        return invert(getBundles());
+    }
+
+    public Map<Resource, String> getBundles() {
+        String filter = String.format("(&(%s=*)(|(%s=%s)(%s=%s)))",
+                            IDENTITY_NAMESPACE,
+                            CAPABILITY_TYPE_ATTRIBUTE, TYPE_BUNDLE,
+                            CAPABILITY_TYPE_ATTRIBUTE, TYPE_FRAGMENT);
+        SimpleFilter sf = SimpleFilter.parse(filter);
+        return getResourceMapping(sf);
+    }
+
+    public Map<String, Set<Resource>> getFeaturesPerRegions() {
+        return invert(getFeatures());
+    }
+
+    public Map<Resource, String> getFeatures() {
+        SimpleFilter sf = createFilter(IDENTITY_NAMESPACE, "*",
+                                       CAPABILITY_TYPE_ATTRIBUTE, TYPE_FEATURE);
+        return getResourceMapping(sf);
+    }
+
+    public Map<String, Set<Resource>> getResourcesPerRegion(SimpleFilter resourceFilter) {
+        return invert(getResourceMapping(resourceFilter));
+    }
+
+    public Map<Resource, String> getResourceMapping(SimpleFilter resourceFilter) {
+        Map<String, String> flats = getFlatSubsystemsMap();
+        Map<Resource, List<Wire>> wiring = getWiring();
+        Map<Resource, String> resources = new HashMap<Resource, String>();
+        SimpleFilter sf = createFilter(IDENTITY_NAMESPACE, "*",
+                                       CAPABILITY_TYPE_ATTRIBUTE, TYPE_SUBSYSTEM);
+        for (Resource resource : wiring.keySet()) {
+            if (findMatchingCapability(resourceFilter, resource.getCapabilities(null)) != null) {
+                // Find the subsystem where this feature is installed
+                Wire wire = findMatchingWire(sf, wiring.get(resource));
+                if (wire != null) {
+                    String region = (String) wire.getCapability().getAttributes().get(IDENTITY_NAMESPACE);
+                    region = flats.get(region);
+                    resources.put(resource, region);
+                }
+            }
+        }
+        return resources;
+    }
+
+    private void associateFragments() {
+        SimpleFilter sf = createFilter(IDENTITY_NAMESPACE, "*", CAPABILITY_TYPE_ATTRIBUTE, TYPE_SUBSYSTEM);
+        for (Map.Entry<Resource, List<Wire>> entry : wiring.entrySet()) {
+            final Resource resource = entry.getKey();
+            final Requirement requirement = getSubsystemRequirement(resource);
+            if (Util.isFragment(resource)) {
+                List<Wire> wires = entry.getValue();
+                final Resource host = wires.get(0).getProvider();
+                final Wire wire = findMatchingWire(sf, wiring.get(host));
+                if (wire != null) {
+                    wires.add(new Wire() {
+                        @Override
+                        public Capability getCapability() {
+                            return wire.getCapability();
+                        }
+
+                        @Override
+                        public Requirement getRequirement() {
+                            return requirement;
+                        }
+
+                        @Override
+                        public Resource getProvider() {
+                            return wire.getProvider();
+                        }
+
+                        @Override
+                        public Resource getRequirer() {
+                            return resource;
+                        }
+                    });
+                }
+            }
+        }
+    }
+
+    private Requirement getSubsystemRequirement(Resource resource) {
+        for (Requirement requirement : resource.getRequirements(null)) {
+            if (IDENTITY_NAMESPACE.equals(requirement.getNamespace())
+                    && TYPE_SUBSYSTEM.equals(requirement.getAttributes().get(CAPABILITY_TYPE_ATTRIBUTE))) {
+                return requirement;
+            }
+        }
+        return null;
+    }
+
+    private Capability findMatchingCapability(SimpleFilter filter, Collection<Capability> caps) {
+        for (Capability cap : caps) {
+            if (CapabilitySet.matches(cap, filter)) {
+                return cap;
+            }
+        }
+        return null;
+    }
+
+    private Wire findMatchingWire(SimpleFilter filter, Collection<Wire> wires) {
+        for (Wire wire : wires) {
+            Capability cap = wire.getCapability();
+            if (CapabilitySet.matches(cap, filter)) {
+                return wire;
+            }
+        }
+        return null;
+    }
+
+    private SimpleFilter createFilter(String... s) {
+        Map<String, Object> attrs = new HashMap<String, Object>();
+        for (int i = 0; i < s.length - 1; i += 2) {
+            attrs.put(s[i], s[i+1]);
+        }
+        return SimpleFilter.convert(attrs);
+
+    }
+
+    private void findSubsystemsToFlatten(Subsystem subsystem, Map<String, String> toFlatten) {
+        Subsystem nonFlat = subsystem;
+        while (isFlat(nonFlat)) {
+            nonFlat = nonFlat.getParent();
+        }
+        toFlatten.put(subsystem.getName(), nonFlat.getName());
+        for (Subsystem child : subsystem.getChildren()) {
+            findSubsystemsToFlatten(child, toFlatten);
+        }
+    }
+
+    private boolean isFlat(Subsystem subsystem) {
+        return subsystem.getFeature() != null && subsystem.getFeature().getScoping() == null;
+    }
+
+    private Subsystem getOrCreateChild(Subsystem ss, String name) {
+        Subsystem child = ss.getChild(name);
+        return child != null ? child : ss.createSubsystem(name, true);
+    }
+
+    private void populateDigraph(RegionDigraph digraph, Subsystem subsystem) throws BundleException, InvalidSyntaxException {
+        Region region = digraph.createRegion(subsystem.getName());
+        if (subsystem.getParent() != null) {
+            Region parent = digraph.getRegion(subsystem.getParent().getName());
+            digraph.connect(region, createRegionFilterBuilder(digraph, subsystem.getImportPolicy()).build(), parent);
+            digraph.connect(parent, createRegionFilterBuilder(digraph, subsystem.getExportPolicy()).build(), region);
+        }
+        for (Subsystem child : subsystem.getChildren()) {
+            populateDigraph(digraph, child);
+        }
+    }
+
+    private RegionFilterBuilder createRegionFilterBuilder(RegionDigraph digraph, Map<String, Set<String>> sharingPolicy) throws InvalidSyntaxException {
+        RegionFilterBuilder result = digraph.createRegionFilterBuilder();
+        for (Map.Entry<String, Set<String>> entry : sharingPolicy.entrySet())
+            for (String filter : entry.getValue())
+                result.allow(entry.getKey(), filter);
+        return result;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/resolver/CandidateComparator.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/CandidateComparator.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/CandidateComparator.java
deleted file mode 100644
index ad4cc85..0000000
--- a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/CandidateComparator.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.resolver;
-
-import java.util.Comparator;
-
-import org.osgi.framework.Version;
-import org.osgi.framework.namespace.BundleNamespace;
-import org.osgi.framework.namespace.PackageNamespace;
-import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.resource.Capability;
-
-public class CandidateComparator implements Comparator<Capability>
-{
-    public int compare(Capability cap1, Capability cap2)
-    {
-        int c = 0;
-        // Always prefer system bundle
-        if (cap1 instanceof BundleCapability && !(cap2 instanceof BundleCapability)) {
-            c = -1;
-        } else if (!(cap1 instanceof BundleCapability) && cap2 instanceof BundleCapability) {
-            c = 1;
-        }
-        // Compare revision capabilities.
-        if ((c == 0) && cap1.getNamespace().equals(BundleNamespace.BUNDLE_NAMESPACE))
-        {
-            c = ((Comparable) cap1.getAttributes().get(BundleNamespace.BUNDLE_NAMESPACE))
-                    .compareTo(cap2.getAttributes().get(BundleNamespace.BUNDLE_NAMESPACE));
-            if (c == 0)
-            {
-                Version v1 = (!cap1.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
-                        ? Version.emptyVersion
-                        : (Version) cap1.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
-                Version v2 = (!cap2.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
-                        ? Version.emptyVersion
-                        : (Version) cap2.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
-                // Compare these in reverse order, since we want
-                // highest version to have priority.
-                c = compareVersions(v2, v1);
-            }
-        }
-        // Compare package capabilities.
-        else if ((c == 0) && cap1.getNamespace().equals(PackageNamespace.PACKAGE_NAMESPACE))
-        {
-            c = ((Comparable) cap1.getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE))
-                    .compareTo(cap2.getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE));
-            if (c == 0)
-            {
-                Version v1 = (!cap1.getAttributes().containsKey(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE))
-                        ? Version.emptyVersion
-                        : (Version) cap1.getAttributes().get(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE);
-                Version v2 = (!cap2.getAttributes().containsKey(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE))
-                        ? Version.emptyVersion
-                        : (Version) cap2.getAttributes().get(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE);
-                // Compare these in reverse order, since we want
-                // highest version to have priority.
-                c = compareVersions(v2, v1);
-                // if same version, rather compare on the bundle version
-                if (c == 0)
-                {
-                    v1 = (!cap1.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
-                            ? Version.emptyVersion
-                            : (Version) cap1.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
-                    v2 = (!cap2.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
-                            ? Version.emptyVersion
-                            : (Version) cap2.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
-                    // Compare these in reverse order, since we want
-                    // highest version to have priority.
-                    c = compareVersions(v2, v1);
-                }
-            }
-        }
-        // Compare feature capabilities
-        else if ((c == 0) && cap1.getNamespace().equals(FeatureNamespace.FEATURE_NAMESPACE))
-        {
-            c = ((Comparable) cap1.getAttributes().get(FeatureNamespace.FEATURE_NAMESPACE))
-                    .compareTo(cap2.getAttributes().get(FeatureNamespace.FEATURE_NAMESPACE));
-            if (c == 0)
-            {
-                Version v1 = (!cap1.getAttributes().containsKey(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE))
-                        ? Version.emptyVersion
-                        : (Version) cap1.getAttributes().get(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE);
-                Version v2 = (!cap2.getAttributes().containsKey(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE))
-                        ? Version.emptyVersion
-                        : (Version) cap2.getAttributes().get(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE);
-                // Compare these in reverse order, since we want
-                // highest version to have priority.
-                c = compareVersions(v2, v1);
-            }
-        }
-        return c;
-    }
-
-    private int compareVersions(Version v1, Version v2) {
-        int c = v1.getMajor() - v2.getMajor();
-        if (c != 0) {
-            return c;
-        }
-        c = v1.getMinor() - v2.getMinor();
-        if (c != 0) {
-            return c;
-        }
-        c = v1.getMicro() - v2.getMicro();
-        if (c != 0) {
-            return c;
-        }
-        String q1 = cleanQualifierForComparison(v1.getQualifier());
-        String q2 = cleanQualifierForComparison(v2.getQualifier());
-        return q1.compareTo(q2);
-    }
-
-    private String cleanQualifierForComparison(String qualifier) {
-        return qualifier.replaceAll("(redhat-[0-9]{3})([0-9]{3})", "$1-$2");
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureNamespace.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureNamespace.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureNamespace.java
deleted file mode 100644
index e211618..0000000
--- a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureNamespace.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.resolver;
-
-import java.util.List;
-
-import org.osgi.framework.Version;
-import org.osgi.resource.Capability;
-import org.osgi.resource.Namespace;
-import org.osgi.resource.Resource;
-
-/**
- */
-public final class FeatureNamespace extends Namespace {
-
-    public static final String FEATURE_NAMESPACE = "karaf.feature";
-
-    public static final String	CAPABILITY_VERSION_ATTRIBUTE	= "version";
-
-    /**
-     * The attribute value identifying the resource
-     * {@link org.osgi.framework.namespace.IdentityNamespace#CAPABILITY_TYPE_ATTRIBUTE type} as an OSGi bundle.
-     *
-     * @see org.osgi.framework.namespace.IdentityNamespace#CAPABILITY_TYPE_ATTRIBUTE
-     */
-    public static final String	TYPE_FEATURE = "karaf.feature";
-
-    public static String getName(Resource resource)
-    {
-        List<Capability> caps = resource.getCapabilities(null);
-        for (Capability cap : caps)
-        {
-            if (cap.getNamespace().equals(FEATURE_NAMESPACE))
-            {
-                return cap.getAttributes().get(FEATURE_NAMESPACE).toString();
-            }
-        }
-        return null;
-    }
-
-    public static Version getVersion(Resource resource)
-    {
-        List<Capability> caps = resource.getCapabilities(null);
-        for (Capability cap : caps)
-        {
-            if (cap.getNamespace().equals(FEATURE_NAMESPACE))
-            {
-                return (Version)
-                        cap.getAttributes().get(CAPABILITY_VERSION_ATTRIBUTE);
-            }
-        }
-        return null;
-    }
-
-
-    private FeatureNamespace() {
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java
index e3b0101..99e1253 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java
@@ -16,11 +16,9 @@
  */
 package org.apache.karaf.features.internal.resolver;
 
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.felix.utils.version.VersionRange;
 import org.apache.felix.utils.version.VersionTable;
 import org.apache.karaf.features.BundleInfo;
 import org.apache.karaf.features.Conditional;
@@ -28,22 +26,21 @@ import org.apache.karaf.features.Dependency;
 import org.apache.karaf.features.Feature;
 import org.apache.karaf.features.internal.util.Macro;
 import org.osgi.framework.BundleException;
-import org.osgi.framework.Constants;
-import org.osgi.framework.Version;
-import org.osgi.framework.namespace.IdentityNamespace;
-import org.osgi.resource.Capability;
 import org.osgi.resource.Requirement;
 import org.osgi.resource.Resource;
 
+import static org.apache.karaf.features.internal.resolver.ResourceUtils.TYPE_FEATURE;
+import static org.apache.karaf.features.internal.resolver.ResourceUtils.addIdentityRequirement;
+
 /**
 */
 public class FeatureResource extends ResourceImpl {
 
     private final Feature feature;
 
-    public static Resource build(Feature feature, Conditional conditional, String featureRange, Map<String, Resource> locToRes) throws BundleException {
+    public static FeatureResource build(Feature feature, Conditional conditional, String featureRange, Map<String, Resource> locToRes) throws BundleException {
         Feature fcond = conditional.asFeature(feature.getName(), feature.getVersion());
-        FeatureResource resource = (FeatureResource) build(fcond, featureRange, locToRes);
+        FeatureResource resource = build(fcond, featureRange, locToRes);
         for (String cond : conditional.getCondition()) {
             if (cond.startsWith("req:")) {
                 cond = cond.substring("req:".length());
@@ -66,29 +63,15 @@ public class FeatureResource extends ResourceImpl {
         return resource;
     }
 
-    public static Resource build(Feature feature, String featureRange, Map<String, Resource> locToRes) throws BundleException {
+    public static FeatureResource build(Feature feature, String featureRange, Map<String, Resource> locToRes) throws BundleException {
         FeatureResource resource = new FeatureResource(feature);
-        Map<String, String> dirs = new HashMap<String, String>();
-        Map<String, Object> attrs = new HashMap<String, Object>();
-        attrs.put(FeatureNamespace.FEATURE_NAMESPACE, feature.getName());
-        attrs.put(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE, VersionTable.getVersion(feature.getVersion()));
-        resource.addCapability(new CapabilityImpl(resource, FeatureNamespace.FEATURE_NAMESPACE, dirs, attrs));
         for (BundleInfo info : feature.getBundles()) {
             if (!info.isDependency()) {
                 Resource res = locToRes.get(info.getLocation());
                 if (res == null) {
                     throw new IllegalStateException("Resource not found for url " + info.getLocation());
                 }
-                List<Capability> caps = res.getCapabilities(IdentityNamespace.IDENTITY_NAMESPACE);
-                if (caps.size() != 1) {
-                    throw new IllegalStateException("Resource does not have a single " + IdentityNamespace.IDENTITY_NAMESPACE + " capability");
-                }
-                dirs = new HashMap<String, String>();
-                attrs = new HashMap<String, Object>();
-                attrs.put(IdentityNamespace.IDENTITY_NAMESPACE, caps.get(0).getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE));
-                attrs.put(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, caps.get(0).getAttributes().get(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE));
-                attrs.put(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, new VersionRange((Version) caps.get(0).getAttributes().get(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE), true));
-                resource.addRequirement(new RequirementImpl(resource, IdentityNamespace.IDENTITY_NAMESPACE, dirs, attrs));
+                addIdentityRequirement(resource, res);
             }
         }
         for (Dependency dep : feature.getDependencies()) {
@@ -104,8 +87,6 @@ public class FeatureResource extends ResourceImpl {
     }
 
     protected static void addDependency(FeatureResource resource, Dependency dep, String featureRange) {
-        Map<String, String> dirs;
-        Map<String, Object> attrs;
         String name = dep.getName();
         String version = dep.getVersion();
         if (version.equals("0.0.0")) {
@@ -113,17 +94,11 @@ public class FeatureResource extends ResourceImpl {
         } else if (!version.startsWith("[") && !version.startsWith("(")) {
             version = Macro.transform(featureRange, version);
         }
-        dirs = new HashMap<String, String>();
-        attrs = new HashMap<String, Object>();
-        attrs.put(FeatureNamespace.FEATURE_NAMESPACE, name);
-        if (version != null) {
-            attrs.put(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE, new VersionRange(version));
-        }
-        resource.addRequirement(new RequirementImpl(resource, FeatureNamespace.FEATURE_NAMESPACE, dirs, attrs));
+        addIdentityRequirement(resource, name, TYPE_FEATURE, version);
     }
 
     public FeatureResource(Feature feature) {
-        super(feature.getName(), FeatureNamespace.TYPE_FEATURE, VersionTable.getVersion(feature.getVersion()));
+        super(feature.getName(), TYPE_FEATURE, VersionTable.getVersion(feature.getVersion()));
         this.feature = feature;
     }
 

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/resolver/IdentityCapability.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/IdentityCapability.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/IdentityCapability.java
index cdc00d1..20e94fa 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/IdentityCapability.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/IdentityCapability.java
@@ -24,7 +24,7 @@ import org.osgi.framework.namespace.IdentityNamespace;
 import org.osgi.resource.Capability;
 import org.osgi.resource.Resource;
 
-class IdentityCapability extends BaseClause implements Capability
+public class IdentityCapability extends BaseClause implements Capability
 {
     private final Resource m_resource;
     private final Map<String, String> m_dirs;

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResolveContextImpl.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResolveContextImpl.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResolveContextImpl.java
deleted file mode 100644
index e2ff793..0000000
--- a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResolveContextImpl.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.resolver;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.osgi.framework.Constants;
-import org.osgi.resource.Capability;
-import org.osgi.resource.Requirement;
-import org.osgi.resource.Resource;
-import org.osgi.resource.Wiring;
-import org.osgi.service.repository.Repository;
-import org.osgi.service.resolver.HostedCapability;
-import org.osgi.service.resolver.ResolveContext;
-
-/**
-*/
-public class ResolveContextImpl extends ResolveContext {
-
-    private final Set<Resource> mandatory;
-    private final Set<Resource> optional;
-    private final Repository repository;
-    private final Map<Resource, Wiring> wirings;
-    private final boolean resolveOptional;
-
-    private final CandidateComparator candidateComparator = new CandidateComparator();
-
-    public ResolveContextImpl(Set<Resource> mandatory,
-                              Set<Resource> optional,
-                              Repository repository,
-                              boolean resolveOptional) {
-        this.mandatory = mandatory;
-        this.optional = optional;
-        this.repository = repository;
-        this.wirings = new HashMap<Resource, Wiring>();
-        this.resolveOptional = resolveOptional;
-    }
-
-    @Override
-    public Collection<Resource> getMandatoryResources() {
-        return mandatory;
-    }
-
-    @Override
-    public Collection<Resource> getOptionalResources() {
-        return optional;
-    }
-
-    @Override
-    public List<Capability> findProviders(Requirement requirement) {
-        List<Capability> caps = new ArrayList<Capability>();
-        Map<Requirement, Collection<Capability>> resMap =
-                repository.findProviders(Collections.singleton(requirement));
-        Collection<Capability> res = resMap != null ? resMap.get(requirement) : null;
-        if (res != null) {
-            caps.addAll(res);
-        }
-        Collections.sort(caps, candidateComparator);
-        return caps;
-    }
-    @Override
-    public int insertHostedCapability(List capabilities, HostedCapability hostedCapability) {
-        for (int i=0; i < capabilities.size(); i++) {
-            Capability cap = (Capability) capabilities.get(i);
-            if (candidateComparator.compare(hostedCapability, cap) <= 0) {
-                capabilities.add(i, hostedCapability);
-                return i;
-            }
-        }
-        capabilities.add(hostedCapability);
-        return capabilities.size() - 1;
-    }
-    @Override
-    public boolean isEffective(Requirement requirement) {
-        return resolveOptional ||
-                !Constants.RESOLUTION_OPTIONAL.equals(requirement.getDirectives().get(Constants.RESOLUTION_DIRECTIVE));
-    }
-    @Override
-    public Map<Resource, Wiring> getWirings() {
-        return wirings;
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceBuilder.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceBuilder.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceBuilder.java
index cb2c36a..941ed8c 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceBuilder.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceBuilder.java
@@ -35,12 +35,13 @@ import org.osgi.framework.wiring.BundleRevision;
 import org.osgi.resource.Capability;
 import org.osgi.resource.Requirement;
 import org.osgi.resource.Resource;
+import org.osgi.service.repository.ContentNamespace;
 
 public class ResourceBuilder {
 
     public static final String RESOLUTION_DYNAMIC = "dynamic";
 
-    public static Resource build(String uri, Map<String, String> headerMap)
+    public static ResourceImpl build(String uri, Map<String, String> headerMap)
             throws BundleException {
 
         // Verify that only manifest version 2 is specified.
@@ -74,8 +75,8 @@ public class ResourceBuilder {
         ResourceImpl resource = new ResourceImpl(bundleSymbolicName, type, bundleVersion);
         if (uri != null) {
             Map<String, Object> attrs = new HashMap<String, Object>();
-            attrs.put(UriNamespace.URI_NAMESPACE, uri);
-            resource.addCapability(new CapabilityImpl(resource, UriNamespace.URI_NAMESPACE, Collections.<String, String>emptyMap(), attrs));
+            attrs.put(ContentNamespace.CAPABILITY_URL_ATTRIBUTE, uri);
+            resource.addCapability(new CapabilityImpl(resource, ContentNamespace.CONTENT_NAMESPACE, Collections.<String, String>emptyMap(), attrs));
         }
 
         // Add a bundle and host capability to all

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceUtils.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceUtils.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceUtils.java
new file mode 100644
index 0000000..03d4fd9
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceUtils.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.resolver;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.utils.version.VersionRange;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Resource;
+
+import static org.osgi.framework.namespace.IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE;
+import static org.osgi.framework.namespace.IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE;
+import static org.osgi.framework.namespace.IdentityNamespace.IDENTITY_NAMESPACE;
+import static org.osgi.service.repository.ContentNamespace.CAPABILITY_URL_ATTRIBUTE;
+import static org.osgi.service.repository.ContentNamespace.CONTENT_NAMESPACE;
+
+public class ResourceUtils {
+
+    public static final String TYPE_SUBSYSTEM = "karaf.subsystem";
+
+    public static final String TYPE_FEATURE = "karaf.feature";
+
+    public static String getUri(Resource resource) {
+        List<Capability> caps = resource.getCapabilities(null);
+        for (Capability cap : caps) {
+            if (cap.getNamespace().equals(CONTENT_NAMESPACE)) {
+                return cap.getAttributes().get(CAPABILITY_URL_ATTRIBUTE).toString();
+            }
+        }
+        return null;
+    }
+
+    public static String getFeatureId(Resource resource) {
+        List<Capability> caps = resource.getCapabilities(null);
+        for (Capability cap : caps) {
+            if (cap.getNamespace().equals(IDENTITY_NAMESPACE)) {
+                Map<String, Object> attributes = cap.getAttributes();
+                if (TYPE_FEATURE.equals(attributes.get(CAPABILITY_TYPE_ATTRIBUTE))) {
+                    String name = (String) attributes.get(IDENTITY_NAMESPACE);
+                    Version version = (Version) attributes.get(CAPABILITY_VERSION_ATTRIBUTE);
+                    return version != null ? name + "/" + version : name;
+                }
+            }
+        }
+        return null;
+    }
+
+    public static void addIdentityRequirement(ResourceImpl resource, String name, String type, String range) {
+        Map<String, String> dirs = new HashMap<String, String>();
+        Map<String, Object> attrs = new HashMap<String, Object>();
+        if (name != null) {
+            attrs.put(IDENTITY_NAMESPACE, name);
+        }
+        if (type != null) {
+            attrs.put(CAPABILITY_TYPE_ATTRIBUTE, type);
+        }
+        if (range != null) {
+            attrs.put(CAPABILITY_VERSION_ATTRIBUTE, new VersionRange(range));
+        }
+        resource.addRequirement(new RequirementImpl(resource, IDENTITY_NAMESPACE, dirs, attrs));
+    }
+
+    public static void addIdentityRequirement(ResourceImpl resource, Resource required) {
+        addIdentityRequirement(resource, required, true);
+    }
+
+    public static void addIdentityRequirement(ResourceImpl resource, Resource required, boolean mandatory) {
+        for (Capability cap : required.getCapabilities(null)) {
+            if (cap.getNamespace().equals(IDENTITY_NAMESPACE)) {
+                Map<String, Object> attributes = cap.getAttributes();
+                Map<String, String> dirs = new HashMap<String, String>();
+                dirs.put(Constants.RESOLUTION_DIRECTIVE, mandatory ? Constants.RESOLUTION_MANDATORY : Constants.RESOLUTION_OPTIONAL);
+                Map<String, Object> attrs = new HashMap<String, Object>();
+                attrs.put(IDENTITY_NAMESPACE, attributes.get(IDENTITY_NAMESPACE));
+                attrs.put(CAPABILITY_TYPE_ATTRIBUTE, attributes.get(CAPABILITY_TYPE_ATTRIBUTE));
+                Version version = (Version) attributes.get(CAPABILITY_VERSION_ATTRIBUTE);
+                if (version != null) {
+                    attrs.put(CAPABILITY_VERSION_ATTRIBUTE, new VersionRange(version, true));
+                }
+                resource.addRequirement(new RequirementImpl(resource, IDENTITY_NAMESPACE, dirs, attrs));
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/resolver/UriNamespace.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/UriNamespace.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/UriNamespace.java
deleted file mode 100644
index b5158bf..0000000
--- a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/UriNamespace.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.resolver;
-
-import java.util.List;
-
-import org.osgi.resource.Capability;
-import org.osgi.resource.Namespace;
-import org.osgi.resource.Resource;
-
-/**
- */
-public final class UriNamespace extends Namespace {
-
-    public static final String URI_NAMESPACE = "karaf.uri";
-
-    public static String getUri(Resource resource)
-    {
-        List<Capability> caps = resource.getCapabilities(null);
-        for (Capability cap : caps)
-        {
-            if (cap.getNamespace().equals(UriNamespace.URI_NAMESPACE))
-            {
-                return cap.getAttributes().get(UriNamespace.URI_NAMESPACE).toString();
-            }
-        }
-        return null;
-    }
-
-
-    private UriNamespace() {
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/service/FeatureConfigInstaller.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeatureConfigInstaller.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeatureConfigInstaller.java
index 0e9038d..258b44b 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeatureConfigInstaller.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeatureConfigInstaller.java
@@ -45,6 +45,26 @@ public class FeatureConfigInstaller {
 		this.configAdmin = configAdmin;
 	}
 
+    public void installFeatureConfigs(Feature feature) throws IOException, InvalidSyntaxException {
+        for (String config : feature.getConfigurations().keySet()) {
+            Dictionary<String,String> props = new Hashtable<String, String>(feature.getConfigurations().get(config));
+            String[] pid = parsePid(config);
+            Configuration cfg = findExistingConfiguration(configAdmin, pid[0], pid[1]);
+            if (cfg == null) {
+                cfg = createConfiguration(configAdmin, pid[0], pid[1]);
+                String key = createConfigurationKey(pid[0], pid[1]);
+                props.put(CONFIG_KEY, key);
+                if (cfg.getBundleLocation() != null) {
+                    cfg.setBundleLocation(null);
+                }
+                cfg.update(props);
+            }
+        }
+        for (ConfigFileInfo configFile : feature.getConfigurationFiles()) {
+            installConfigurationFile(configFile.getLocation(), configFile.getFinalname(), configFile.isOverride());
+        }
+    }
+
     private String[] parsePid(String pid) {
         int n = pid.indexOf('-');
         if (n > 0) {
@@ -81,26 +101,6 @@ public class FeatureConfigInstaller {
         return null;
     }
 
-    void installFeatureConfigs(Feature feature) throws IOException, InvalidSyntaxException {
-        for (String config : feature.getConfigurations().keySet()) {
-            Dictionary<String,String> props = new Hashtable<String, String>(feature.getConfigurations().get(config));
-            String[] pid = parsePid(config);
-            Configuration cfg = findExistingConfiguration(configAdmin, pid[0], pid[1]);
-            if (cfg == null) {
-                cfg = createConfiguration(configAdmin, pid[0], pid[1]);
-                String key = createConfigurationKey(pid[0], pid[1]);
-                props.put(CONFIG_KEY, key);
-                if (cfg.getBundleLocation() != null) {
-                    cfg.setBundleLocation(null);
-                }
-                cfg.update(props);
-            }
-        }
-        for (ConfigFileInfo configFile : feature.getConfigurationFiles()) {
-            installConfigurationFile(configFile.getLocation(), configFile.getFinalname(), configFile.isOverride());
-        }
-    }
-
     private String createConfigurationKey(String pid, String factoryPid) {
         return factoryPid == null ? pid : pid + "-" + factoryPid;
     }


[6/6] git commit: [KARAF-2911] Small fixes to subsystem commands

Posted by gn...@apache.org.
[KARAF-2911] Small fixes to subsystem commands


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/486ad3ac
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/486ad3ac
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/486ad3ac

Branch: refs/heads/master
Commit: 486ad3aca57b364940f8d71d8f520b877ee614e2
Parents: 53ad48f
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Thu Apr 17 16:07:14 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Fri Apr 18 23:33:51 2014 +0200

----------------------------------------------------------------------
 .../org/apache/karaf/subsystem/commands/ListAction.java   | 10 ++++++++++
 .../apache/karaf/subsystem/commands/SubsystemSupport.java |  6 +++++-
 2 files changed, 15 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/486ad3ac/subsystem/src/main/java/org/apache/karaf/subsystem/commands/ListAction.java
----------------------------------------------------------------------
diff --git a/subsystem/src/main/java/org/apache/karaf/subsystem/commands/ListAction.java b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/ListAction.java
index 458ff5b..8b7ee12 100644
--- a/subsystem/src/main/java/org/apache/karaf/subsystem/commands/ListAction.java
+++ b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/ListAction.java
@@ -36,6 +36,7 @@ public class ListAction extends SubsystemSupport implements Action {
         table.column("SymbolicName");
         table.column("Version");
         table.column("State");
+        table.column("Type");
         table.column("Parents");
         table.column("Children");
 
@@ -45,6 +46,7 @@ public class ListAction extends SubsystemSupport implements Action {
                     ss.getSymbolicName(),
                     ss.getVersion(),
                     ss.getState().toString(),
+                    getType(ss),
                     getSubsytemIds(ss.getParents()),
                     getSubsytemIds(ss.getChildren())
             );
@@ -53,4 +55,12 @@ public class ListAction extends SubsystemSupport implements Action {
         return null;
     }
 
+    private String getType(Subsystem subsystem) {
+        String type = subsystem.getType();
+        if (type.startsWith("osgi.subsystem.")) {
+            type = type.substring("osgi.subsystem.".length());
+        }
+        return type;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/486ad3ac/subsystem/src/main/java/org/apache/karaf/subsystem/commands/SubsystemSupport.java
----------------------------------------------------------------------
diff --git a/subsystem/src/main/java/org/apache/karaf/subsystem/commands/SubsystemSupport.java b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/SubsystemSupport.java
index e91461e..c19ebfe 100644
--- a/subsystem/src/main/java/org/apache/karaf/subsystem/commands/SubsystemSupport.java
+++ b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/SubsystemSupport.java
@@ -104,8 +104,12 @@ public abstract class SubsystemSupport {
     protected List<Long> getSubsytemIds(Collection<Subsystem> subsystems) {
         List<Long> ids = new ArrayList<Long>();
         for (Subsystem ss : subsystems) {
-            ids.add(ss.getSubsystemId());
+            long id = ss.getSubsystemId();
+            if (!ids.contains(id)) {
+                ids.add(id);
+            }
         }
+        Collections.sort(ids);
         return ids;
     }
 


[2/6] [KARAF-2923] Region support in features service

Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/test/java/org/apache/karaf/features/internal/region/SubsystemTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/region/SubsystemTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/region/SubsystemTest.java
new file mode 100644
index 0000000..0ef26cb
--- /dev/null
+++ b/features/core/src/test/java/org/apache/karaf/features/internal/region/SubsystemTest.java
@@ -0,0 +1,213 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.region;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.features.internal.download.StreamProvider;
+import org.apache.karaf.features.internal.service.FeaturesServiceImpl;
+import org.apache.karaf.features.internal.service.RepositoryImpl;
+import org.apache.karaf.features.internal.download.simple.SimpleDownloader;
+import org.junit.Test;
+import org.osgi.framework.namespace.IdentityNamespace;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Resource;
+import org.osgi.resource.Wire;
+
+import static org.apache.karaf.features.internal.util.MapUtils.addToMapSet;
+import static org.junit.Assert.assertEquals;
+
+public class SubsystemTest {
+
+    @Test
+    public void test1() throws Exception {
+        RepositoryImpl repo = new RepositoryImpl(getClass().getResource("data1/features.xml").toURI());
+
+        Map<String, Set<String>> features = new HashMap<String, Set<String>>();
+        addToMapSet(features, "root", "f1");
+        addToMapSet(features, "root/apps1", "f2");
+
+        Map<String, Set<String>> expected = new HashMap<String, Set<String>>();
+        addToMapSet(expected, "root", "a/1.0.0");
+        addToMapSet(expected, "root", "c/1.0.0");
+        addToMapSet(expected, "root/apps1", "b/1.0.0");
+
+        SubsystemResolver resolver = new SubsystemResolver(new TestDownloadManager("data1"));
+        resolver.resolve(Collections.<Repository>singletonList(repo),
+                         features,
+                         Collections.<Resource>emptyList(),
+                         FeaturesServiceImpl.DEFAULT_FEATURE_RESOLUTION_RANGE);
+
+        verify(resolver, expected);
+    }
+
+    @Test
+    public void test2() throws Exception {
+
+        RepositoryImpl repo = new RepositoryImpl(getClass().getResource("data2/features.xml").toURI());
+
+        Map<String, Set<String>> features = new HashMap<String, Set<String>>();
+        addToMapSet(features, "root/apps1", "f1");
+        addToMapSet(features, "root/apps1", "f3");
+        addToMapSet(features, "root/apps2", "f1");
+
+        Map<String, Set<String>> expected = new HashMap<String, Set<String>>();
+        addToMapSet(expected, "root/apps1", "c/1.0.0");
+        addToMapSet(expected, "root/apps1", "b/1.0.0");
+        addToMapSet(expected, "root/apps1", "e/1.0.0");
+        addToMapSet(expected, "root/apps1#f1", "a/1.0.0");
+        addToMapSet(expected, "root/apps1#f1", "d/1.0.0");
+        addToMapSet(expected, "root/apps2", "b/1.0.0");
+        addToMapSet(expected, "root/apps2", "c/1.0.0");
+        addToMapSet(expected, "root/apps2#f1", "a/1.0.0");
+
+        SubsystemResolver resolver = new SubsystemResolver(new TestDownloadManager("data2"));
+        resolver.resolve(Collections.<Repository>singletonList(repo),
+                         features,
+                         Collections.<Resource>emptyList(),
+                         FeaturesServiceImpl.DEFAULT_FEATURE_RESOLUTION_RANGE);
+
+        verify(resolver, expected);
+    }
+
+    private void verify(SubsystemResolver resolver, Map<String, Set<String>> expected) {
+        Map<String, Set<String>> mapping = getBundleNamesPerRegions(resolver);
+        if (!expected.equals(mapping)) {
+            dumpBundles(resolver);
+            dumpWiring(resolver);
+            assertEquals("Resolution failed", expected, mapping);
+        }
+    }
+
+    private void dumpBundles(SubsystemResolver resolver) {
+        System.out.println("Bundle mapping");
+        Map<String, Set<Resource>> bundles = resolver.getBundlesPerRegions();
+        for (Map.Entry<String, Set<Resource>> entry : bundles.entrySet()) {
+            System.out.println("    " + entry.getKey());
+            for (Resource b : entry.getValue()) {
+                System.out.println("        " + b);
+            }
+        }
+    }
+
+    private Map<String, Set<String>> getBundleNamesPerRegions(SubsystemResolver resolver) {
+        Map<String, Set<String>> mapping = new HashMap<String, Set<String>>();
+        Map<String, Set<Resource>> bundles = resolver.getBundlesPerRegions();
+        for (Map.Entry<String,Set<Resource>> entry : bundles.entrySet()) {
+            for (Resource r : entry.getValue()) {
+                addToMapSet(mapping, entry.getKey(), r.toString());
+            }
+        }
+        return mapping;
+    }
+
+
+    private void dumpWiring(SubsystemResolver resolver) {
+        System.out.println("Wiring");
+        Map<Resource, List<Wire>> wiring = resolver.getWiring();
+        List<Resource> resources = new ArrayList<Resource>(wiring.keySet());
+        Collections.sort(resources, new Comparator<Resource>() {
+            @Override
+            public int compare(Resource o1, Resource o2) {
+                return getName(o1).compareTo(getName(o2));
+            }
+        });
+        for (Resource resource : resources) {
+            System.out.println("    " + getName(resource));
+            for (Wire wire : wiring.get(resource)) {
+                System.out.println("        " + wire);
+            }
+        }
+    }
+
+    private String getName(Resource resource) {
+        Capability cap = resource.getCapabilities(IdentityNamespace.IDENTITY_NAMESPACE).get(0);
+        return cap.getAttributes().get(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE) + ": "
+                + cap.getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE) + "/"
+                + cap.getAttributes().get(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE);
+    }
+
+    class TestDownloadManager extends SimpleDownloader {
+
+        private final String dir;
+
+        TestDownloadManager(String dir) {
+            this.dir = dir;
+        }
+
+        @Override
+        protected StreamProvider createProvider(String location) throws MalformedURLException {
+            return new TestProvider(location);
+        }
+
+        class TestProvider implements StreamProvider {
+            private final IOException exception;
+            private final Map<String, String> headers;
+            private final byte[] data;
+
+            TestProvider(String location) {
+                Map<String, String> headers = null;
+                byte[] data = null;
+                IOException exception = null;
+                try {
+                    Manifest man = new Manifest(getClass().getResourceAsStream(dir +"/" + location + ".mf"));
+                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                    JarOutputStream jos = new JarOutputStream(baos, man);
+                    jos.close();
+                    data = baos.toByteArray();
+                    headers = new HashMap<String, String>();
+                    for (Map.Entry attr : man.getMainAttributes().entrySet()) {
+                        headers.put(attr.getKey().toString(), attr.getValue().toString());
+                    }
+                } catch (IOException e) {
+                    exception = e;
+                }
+                this.headers = headers;
+                this.data = data;
+                this.exception = exception;
+            }
+
+            @Override
+            public InputStream open() throws IOException {
+                if (exception != null)
+                    throw exception;
+                return new ByteArrayInputStream(data);
+            }
+
+            @Override
+            public Map<String, String> getMetadata() throws IOException {
+                if (exception != null)
+                    throw exception;
+                return headers;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesServiceImplTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesServiceImplTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesServiceImplTest.java
index b8b5fc0..3627c0f 100644
--- a/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesServiceImplTest.java
+++ b/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesServiceImplTest.java
@@ -49,7 +49,7 @@ public class FeaturesServiceImplTest extends TestBase {
     public void testGetFeature() throws Exception {
         Feature transactionFeature = feature("transaction", "1.0.0");
         final Map<String, Map<String, Feature>> features = features(transactionFeature);
-        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, "", null, null, null) {
+        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, null, "", null, null, null) {
             protected Map<String,Map<String,Feature>> getFeatures() throws Exception {
                 return features;
             }
@@ -60,7 +60,7 @@ public class FeaturesServiceImplTest extends TestBase {
     
     @Test
     public void testGetFeatureStripVersion() throws Exception {
-        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, "", null, null, null) {
+        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, null, "", null, null, null) {
             protected Map<String,Map<String,Feature>> getFeatures() throws Exception {
                 return features(feature("transaction", "1.0.0"));
             }
@@ -72,7 +72,7 @@ public class FeaturesServiceImplTest extends TestBase {
     
     @Test
     public void testGetFeatureNotAvailable() throws Exception {
-        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, "", null, null, null) {
+        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, null, "", null, null, null) {
             protected Map<String,Map<String,Feature>> getFeatures() throws Exception {
                 return features(feature("transaction", "1.0.0"));
             }
@@ -86,7 +86,7 @@ public class FeaturesServiceImplTest extends TestBase {
                 feature("transaction", "1.0.0"),
                 feature("transaction", "2.0.0")
         );
-        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, "", null, null, null) {
+        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, null, "", null, null, null) {
             protected Map<String,Map<String,Feature>> getFeatures() throws Exception {
                 return features;
             }

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/test/java/org/apache/karaf/features/internal/service/OverridesTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/service/OverridesTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/service/OverridesTest.java
index c4976cf..2d4d4ae 100644
--- a/features/core/src/test/java/org/apache/karaf/features/internal/service/OverridesTest.java
+++ b/features/core/src/test/java/org/apache/karaf/features/internal/service/OverridesTest.java
@@ -16,36 +16,25 @@
  */
 package org.apache.karaf.features.internal.service;
 
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.io.Writer;
-import java.net.URI;
 import java.util.Arrays;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import org.apache.felix.utils.manifest.Clause;
 import org.apache.felix.utils.manifest.Parser;
-import org.apache.karaf.features.BundleInfo;
-import org.apache.karaf.features.internal.model.Bundle;
 import org.apache.karaf.features.internal.resolver.ResourceBuilder;
-import org.apache.karaf.features.internal.resolver.UriNamespace;
 import org.junit.Before;
 import org.junit.Test;
-import org.ops4j.pax.tinybundles.core.TinyBundles;
 import org.osgi.framework.BundleException;
 import org.osgi.resource.Resource;
 
-import static org.apache.karaf.features.internal.resolver.UriNamespace.getUri;
+import static org.apache.karaf.features.internal.resolver.ResourceUtils.getUri;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
 
 public class OverridesTest {
 

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/test/java/org/apache/karaf/features/internal/service/StateStorageTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/service/StateStorageTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/service/StateStorageTest.java
new file mode 100644
index 0000000..5bee904
--- /dev/null
+++ b/features/core/src/test/java/org/apache/karaf/features/internal/service/StateStorageTest.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.service;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class StateStorageTest {
+
+    @Test
+    public void testStoreLoad() throws Exception {
+
+        State oldState = new State();
+        oldState.bootDone.set(true);
+        oldState.bundleChecksums.put(4l, 32794l);
+        oldState.features.put("bar", Collections.singleton("f1"));
+        oldState.managedBundles.put("reg", Collections.singleton(32l));
+        oldState.managedBundles.put("reg2", new HashSet<Long>(Arrays.asList(24l, 43l)));
+        oldState.repositories.add("repo");
+
+        TestStorage storage = new TestStorage();
+
+        storage.save(oldState);
+
+        System.out.println(storage.baos.toString());
+
+        State newState = new State();
+        storage.load(newState);
+
+        assertEquals(oldState.bootDone.get(), newState.bootDone.get());
+        assertEquals(oldState.bundleChecksums, newState.bundleChecksums);
+        assertEquals(oldState.features, newState.features);
+        assertEquals(oldState.managedBundles, newState.managedBundles);
+        assertEquals(oldState.repositories, newState.repositories);
+    }
+
+    static class TestStorage extends StateStorage {
+        ByteArrayOutputStream baos;
+
+        @Override
+        protected InputStream getInputStream() throws IOException {
+            if (baos != null) {
+                return new ByteArrayInputStream(baos.toByteArray());
+            }
+            return null;
+        }
+
+        @Override
+        protected OutputStream getOutputStream() throws IOException {
+            baos = new ByteArrayOutputStream();
+            return baos;
+        }
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/test/resources/org/apache/karaf/features/internal/region/data1/a.mf
----------------------------------------------------------------------
diff --git a/features/core/src/test/resources/org/apache/karaf/features/internal/region/data1/a.mf b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data1/a.mf
new file mode 100644
index 0000000..b5e522b
--- /dev/null
+++ b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data1/a.mf
@@ -0,0 +1,6 @@
+Manifest-Version: 1
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: a
+Bundle-Version: 1.0.0
+Require-Capability: ns;filter:="(ns=c)"
+

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/test/resources/org/apache/karaf/features/internal/region/data1/b.mf
----------------------------------------------------------------------
diff --git a/features/core/src/test/resources/org/apache/karaf/features/internal/region/data1/b.mf b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data1/b.mf
new file mode 100644
index 0000000..2ee6678
--- /dev/null
+++ b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data1/b.mf
@@ -0,0 +1,6 @@
+Manifest-Version: 1
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: b
+Bundle-Version: 1.0.0
+Require-Capability: ns;filter:="(ns=c)"
+

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/test/resources/org/apache/karaf/features/internal/region/data1/c.mf
----------------------------------------------------------------------
diff --git a/features/core/src/test/resources/org/apache/karaf/features/internal/region/data1/c.mf b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data1/c.mf
new file mode 100644
index 0000000..8c731fb
--- /dev/null
+++ b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data1/c.mf
@@ -0,0 +1,6 @@
+Manifest-Version: 1
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: c
+Bundle-Version: 1.0.0
+Provide-Capability: ns;ns=c
+

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/test/resources/org/apache/karaf/features/internal/region/data1/features.xml
----------------------------------------------------------------------
diff --git a/features/core/src/test/resources/org/apache/karaf/features/internal/region/data1/features.xml b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data1/features.xml
new file mode 100644
index 0000000..72c261c
--- /dev/null
+++ b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data1/features.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements. See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License. You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<features name="test" xmlns="http://karaf.apache.org/xmlns/features/v1.3.0">
+
+    <feature name="f1">
+        <bundle dependency="true">c</bundle>
+        <bundle>a</bundle>
+    </feature>
+
+    <feature name="f2">
+        <bundle dependency="true">c</bundle>
+        <bundle>b</bundle>
+    </feature>
+
+</features>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/a.mf
----------------------------------------------------------------------
diff --git a/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/a.mf b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/a.mf
new file mode 100644
index 0000000..99ed0c4
--- /dev/null
+++ b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/a.mf
@@ -0,0 +1,7 @@
+Manifest-Version: 1
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: a
+Bundle-Version: 1.0.0
+Provide-Capability: ns;ns=a
+Require-Capability: ns;filter:="(ns=b)"
+

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/b.mf
----------------------------------------------------------------------
diff --git a/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/b.mf b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/b.mf
new file mode 100644
index 0000000..f66fd1e
--- /dev/null
+++ b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/b.mf
@@ -0,0 +1,7 @@
+Manifest-Version: 1
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: b
+Bundle-Version: 1.0.0
+Provide-Capability: ns;ns=b
+Require-Capability: ns;filter:="(ns=c)"
+

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/c.mf
----------------------------------------------------------------------
diff --git a/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/c.mf b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/c.mf
new file mode 100644
index 0000000..8c731fb
--- /dev/null
+++ b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/c.mf
@@ -0,0 +1,6 @@
+Manifest-Version: 1
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: c
+Bundle-Version: 1.0.0
+Provide-Capability: ns;ns=c
+

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/d.mf
----------------------------------------------------------------------
diff --git a/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/d.mf b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/d.mf
new file mode 100644
index 0000000..b1172fa
--- /dev/null
+++ b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/d.mf
@@ -0,0 +1,6 @@
+Manifest-Version: 1
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: d
+Bundle-Version: 1.0.0
+
+

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/e.mf
----------------------------------------------------------------------
diff --git a/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/e.mf b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/e.mf
new file mode 100644
index 0000000..42b5ff9
--- /dev/null
+++ b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/e.mf
@@ -0,0 +1,6 @@
+Manifest-Version: 1
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: e
+Bundle-Version: 1.0.0
+
+

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/features.xml
----------------------------------------------------------------------
diff --git a/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/features.xml b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/features.xml
new file mode 100644
index 0000000..b1cc8d6
--- /dev/null
+++ b/features/core/src/test/resources/org/apache/karaf/features/internal/region/data2/features.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements. See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License. You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<features name="test" xmlns="http://karaf.apache.org/xmlns/features/v1.3.0">
+    <feature name="f1">
+        <feature>f2</feature>
+        <bundle dependency="true">b</bundle>
+        <bundle>a</bundle>
+        <conditional>
+            <condition>f3</condition>
+            <bundle>d</bundle>
+        </conditional>
+        <scoping acceptDependencies="false">
+            <import namespace="ns">(ns=b)</import>
+            <export namespace="ns">(ns=a)</export>
+        </scoping>
+    </feature>
+    
+    <feature name="f2">
+        <bundle>c</bundle>
+    </feature>
+
+    <feature name="f3">
+        <bundle>e</bundle>
+    </feature>
+
+</features>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/test/resources/org/apache/karaf/features/internal/service/f07.xml
----------------------------------------------------------------------
diff --git a/features/core/src/test/resources/org/apache/karaf/features/internal/service/f07.xml b/features/core/src/test/resources/org/apache/karaf/features/internal/service/f07.xml
index b62ffda..8165d14 100644
--- a/features/core/src/test/resources/org/apache/karaf/features/internal/service/f07.xml
+++ b/features/core/src/test/resources/org/apache/karaf/features/internal/service/f07.xml
@@ -30,6 +30,17 @@
         <capability>
             service-reference;effective:=active;objectClass=org.apache.aries.proxy.ProxyManager
         </capability>
+        <scoping>
+            <export namespace="osgi.service">
+                (objectClass=org.apache.aries.proxy.ProxyManager)
+            </export>
+            <export namespace="osgi.wiring.package">
+                (|(osgi.wiring.package=org.apache.aries.proxy)(osgi.wiring.package=org.apache.aries.proxy.*))
+            </export>
+            <import namespace="org.eclipse.equinox.allow.all">
+                (|(!(all=*))(all=*))
+            </import>
+        </scoping>
     </feature>
 </features>
 

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/itests/src/test/java/org/apache/karaf/itests/RegionTest.java
----------------------------------------------------------------------
diff --git a/itests/src/test/java/org/apache/karaf/itests/RegionTest.java b/itests/src/test/java/org/apache/karaf/itests/RegionTest.java
deleted file mode 100644
index 0af20fe..0000000
--- a/itests/src/test/java/org/apache/karaf/itests/RegionTest.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.itests;
-
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.ops4j.pax.exam.junit.PaxExam;
-import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
-import org.ops4j.pax.exam.spi.reactors.PerClass;
-
-@RunWith(PaxExam.class)
-@ExamReactorStrategy(PerClass.class)
-public class RegionTest extends KarafTestSupport {
-
-    @Test
-    public void infoCommand() throws Exception {
-        installAndAssertFeature("region");
-
-        String infoOutput = executeCommand("region:info");
-        System.out.println(infoOutput);
-        assertTrue("Region org.eclipse.equinox.region.kernel should be present", infoOutput.contains("org.eclipse.equinox.region.kernel"));
-        assertTrue("Region org.apache.karaf.region.application should be present", infoOutput.contains("org.apache.karaf.region.application"));
-    }
-
-    @Test
-    public void addRegionCommand() throws Exception {
-        installAndAssertFeature("region");
-
-        System.out.println(executeCommand("region:region-add itest"));
-        String infoOutput = executeCommand("region:info");
-        System.out.println(infoOutput);
-        assertTrue("Region itest should be present", infoOutput.contains("itest"));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/itests/src/test/java/org/apache/karaf/itests/features/StandardFeaturesTest.java
----------------------------------------------------------------------
diff --git a/itests/src/test/java/org/apache/karaf/itests/features/StandardFeaturesTest.java b/itests/src/test/java/org/apache/karaf/itests/features/StandardFeaturesTest.java
index c0e2086..3a1e741 100644
--- a/itests/src/test/java/org/apache/karaf/itests/features/StandardFeaturesTest.java
+++ b/itests/src/test/java/org/apache/karaf/itests/features/StandardFeaturesTest.java
@@ -60,11 +60,6 @@ public class StandardFeaturesTest extends KarafTestSupport {
     }
     
     @Test
-    public void installRegionFeature() throws Exception {
-        installAssertAndUninstallFeatures("region");
-    }
-    
-    @Test
     public void installPackageFeature() throws Exception {
         installAssertAndUninstallFeatures("package");
     }

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 2ef129f..0cc1447 100644
--- a/pom.xml
+++ b/pom.xml
@@ -40,7 +40,6 @@
         <module>main</module>
         <module>features</module>
         <module>kar</module>
-        <module>region</module>
         <module>bundle</module>
         <module>config</module>
         <module>instance</module>
@@ -526,11 +525,6 @@
                 <artifactId>org.apache.karaf.features.command</artifactId>
                 <version>${project.version}</version>
             </dependency>
-            <dependency>
-                <groupId>org.apache.karaf.features</groupId>
-                <artifactId>org.apache.karaf.features.obr</artifactId>
-                <version>${project.version}</version>
-            </dependency>
 
             <dependency>
                 <groupId>org.apache.karaf.diagnostic</groupId>
@@ -563,12 +557,6 @@
             </dependency>
 
             <dependency>
-                <groupId>org.apache.karaf.region</groupId>
-                <artifactId>org.apache.karaf.region.core</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-
-            <dependency>
                 <groupId>org.apache.karaf.shell</groupId>
                 <artifactId>org.apache.karaf.shell.console</artifactId>
                 <version>${project.version}</version>
@@ -2248,6 +2236,8 @@
                                 <exclude>manual/**/*.css</exclude>
                                 <exclude>manual/**/*.ssp</exclude>
                                 <exclude>manual/**/*.conf</exclude>
+                                <!-- test manifests -->
+                                <exclude>**/*.mf</exclude>
                             </excludes>
                         </configuration>
                     </plugin>

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/NOTICE
----------------------------------------------------------------------
diff --git a/region/NOTICE b/region/NOTICE
deleted file mode 100644
index b70f1f9..0000000
--- a/region/NOTICE
+++ /dev/null
@@ -1,71 +0,0 @@
-Apache Karaf
-Copyright 2010-2014 The Apache Software Foundation
-
-
-I. Included Software
-
-This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-The OSGi Alliance (http://www.osgi.org/).
-Copyright (c) OSGi Alliance (2000, 2010).
-Licensed under the Apache License 2.0.
-
-This product includes software developed at
-OW2 (http://www.ow2.org/).
-Licensed under the BSD License.
-
-This product includes software developed at
-OPS4J (http://www.ops4j.org/).
-Licensed under the Apache License 2.0.
-
-This product includes software developed at
-Eclipse Foundation (http://www.eclipse.org/).
-Licensed under the EPL.
-
-This product includes software written by
-Antony Lesuisse.
-Licensed under Public Domain.
-
-
-II. Used Software
-
-This product uses software developed at
-FUSE Source (http://www.fusesource.org/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-AOP Alliance (http://aopalliance.sourceforge.net/).
-Licensed under the Public Domain.
-
-This product uses software developed at
-Tanuki Software (http://www.tanukisoftware.com/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-Jasypt (http://jasypt.sourceforge.net/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-JLine (http://jline.sourceforge.net).
-Licensed under the BSD License.
-
-This product uses software developed at
-SLF4J (http://www.slf4j.org/).
-Licensed under the MIT License.
-
-This product uses software developed at
-SpringSource (http://www.springsource.org/).
-Licensed under the Apache License 2.0.
-
-This product includes software from http://www.json.org.
-Copyright (c) 2002 JSON.org
-
-
-III. License Summary
-- Apache License 2.0
-- BSD License
-- EPL License
-- MIT License

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/pom.xml
----------------------------------------------------------------------
diff --git a/region/pom.xml b/region/pom.xml
deleted file mode 100644
index 2375fcc..0000000
--- a/region/pom.xml
+++ /dev/null
@@ -1,136 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-
-    <!--
-
-        Licensed to the Apache Software Foundation (ASF) under one or more
-        contributor license agreements.  See the NOTICE file distributed with
-        this work for additional information regarding copyright ownership.
-        The ASF licenses this file to You under the Apache License, Version 2.0
-        (the "License"); you may not use this file except in compliance with
-        the License.  You may obtain a copy of the License at
-
-           http://www.apache.org/licenses/LICENSE-2.0
-
-        Unless required by applicable law or agreed to in writing, software
-        distributed under the License is distributed on an "AS IS" BASIS,
-        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-        See the License for the specific language governing permissions and
-        limitations under the License.
-    -->
-
-    <modelVersion>4.0.0</modelVersion>
-
-    <parent>
-        <groupId>org.apache.karaf</groupId>
-        <artifactId>karaf</artifactId>
-        <version>4.0.0-SNAPSHOT</version>
-    </parent>
-
-    <groupId>org.apache.karaf.region</groupId>
-    <artifactId>org.apache.karaf.region.core</artifactId>
-    <packaging>bundle</packaging>
-    <name>Apache Karaf :: Region :: Persistence</name>
-    <description>This bundle provides an xml regions model and install/dump actions.</description>
-
-    <properties>
-        <appendedResourcesDirectory>${basedir}/../../etc/appended-resources</appendedResourcesDirectory>
-    </properties>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.core</artifactId>
-            <scope>provided</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.karaf</groupId>
-            <artifactId>org.apache.karaf.util</artifactId>
-            <scope>provided</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.compendium</artifactId>
-            <scope>provided</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-api</artifactId>
-            <scope>provided</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.karaf.features</groupId>
-            <artifactId>org.apache.karaf.features.core</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>org.eclipse.equinox</groupId>
-            <artifactId>region</artifactId>
-            <version>1.0.0.v20110506</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.karaf.shell</groupId>
-            <artifactId>org.apache.karaf.shell.core</artifactId>
-            <optional>true</optional>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.aries</groupId>
-            <artifactId>org.apache.aries.util</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>org.easymock</groupId>
-            <artifactId>easymock</artifactId>
-            <scope>test</scope>
-        </dependency>
-		<dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-jdk14</artifactId>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <resources>
-            <resource>
-                <directory>${project.basedir}/src/main/resources</directory>
-                <includes>
-                    <include>**/*</include>
-                </includes>
-            </resource>
-            <resource>
-                <directory>${project.basedir}/src/main/resources</directory>
-                <filtering>true</filtering>
-                <includes>
-                    <include>**/*.info</include>
-                </includes>
-            </resource>
-        </resources>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <configuration>
-                    <instructions>
-                        <Bundle-Activator>
-                            org.apache.karaf.region.persist.internal.Activator
-                        </Bundle-Activator>
-                        <Private-Package>
-                            org.apache.karaf.region.commands,
-                            org.apache.karaf.region.commands.util,
-                            org.apache.karaf.region.persist.internal.*,
-                            org.apache.karaf.util.tracker
-                        </Private-Package>
-                        <Karaf-Commands>*</Karaf-Commands>
-                    </instructions>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
-
-</project>

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/src/main/java/org/apache/karaf/region/commands/AddBundleCommand.java
----------------------------------------------------------------------
diff --git a/region/src/main/java/org/apache/karaf/region/commands/AddBundleCommand.java b/region/src/main/java/org/apache/karaf/region/commands/AddBundleCommand.java
deleted file mode 100644
index 30af1e0..0000000
--- a/region/src/main/java/org/apache/karaf/region/commands/AddBundleCommand.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.region.commands;
-
-import java.util.List;
-
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.eclipse.equinox.region.Region;
-import org.eclipse.equinox.region.RegionDigraph;
-import org.osgi.framework.Bundle;
-
-@Command(scope = "region", name = "bundle-add", description = "Adds a list of known bundles by id to a specified region.")
-@Service
-public class AddBundleCommand extends RegionCommandSupport {
-
-    @Argument(index = 0, name = "region", description = "Region to add the bundles to", required = true, multiValued = false)
-    String region;
-
-    @Argument(index = 1, name = "bundles", description = "Bundles by id to add to the region", required = true, multiValued = true)
-    List<Long> ids;
-
-    protected void doExecute(RegionDigraph regionDigraph) throws Exception {
-        Region r = getRegion(regionDigraph, region);
-        for (Long id : ids) {
-            for (Region existing: regionDigraph.getRegions()) {
-                if (existing.contains(id)) {
-                    Bundle b = bundleContext.getBundle(id);
-                    System.out.println("Removing bundle " + id + " from region " + existing.getName());
-                    existing.removeBundle(b);
-                    break;
-                }
-            }
-            r.addBundle(id);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/src/main/java/org/apache/karaf/region/commands/AddFilterCommand.java
----------------------------------------------------------------------
diff --git a/region/src/main/java/org/apache/karaf/region/commands/AddFilterCommand.java b/region/src/main/java/org/apache/karaf/region/commands/AddFilterCommand.java
deleted file mode 100644
index ec3766d..0000000
--- a/region/src/main/java/org/apache/karaf/region/commands/AddFilterCommand.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.region.commands;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.aries.util.VersionRange;
-import org.apache.aries.util.manifest.ManifestHeaderProcessor;
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.eclipse.equinox.region.Region;
-import org.eclipse.equinox.region.RegionDigraph;
-import org.eclipse.equinox.region.RegionFilter;
-import org.eclipse.equinox.region.RegionFilterBuilder;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-
-@Command(scope = "region", name = "filter-add", description = "Adds a filter between two regions.")
-@Service
-public class AddFilterCommand extends RegionCommandSupport {
-
-    @Argument(index = 0, name = "from", description = "The from region.", required = true, multiValued = false)
-    String fromRegion;
-
-    @Argument(index = 1, name = "to", description = "The to region.", required = true, multiValued = false)
-    String toRegion;
-
-    @Argument(index = 2, name = "items", description = "The bundles by id and packages with version to allow.", required = false, multiValued = true)
-    List<String> items;
-
-    protected void doExecute(RegionDigraph regionDigraph) throws Exception {
-        Region rFrom = getRegion(regionDigraph, fromRegion);
-        Region rTo = getRegion(regionDigraph, toRegion);
-        RegionFilterBuilder builder = regionDigraph.createRegionFilterBuilder();
-        BundleContext framework = bundleContext.getBundle(0).getBundleContext();
-        if (items != null) {
-            for (String item : items) {
-                try {
-                    long id = Long.parseLong(item);
-                    Bundle b = framework.getBundle(id);
-                    builder.allow("osgi.wiring.bundle", "(osgi.wiring.bundle=" + b.getSymbolicName() + ")");
-                } catch (NumberFormatException e) {
-                    for (Map.Entry<String, Map<String, String>> parsed: ManifestHeaderProcessor.parseImportString(item).entrySet()) {
-                        String packageName = parsed.getKey();
-                        Map<String, String> attributes = new HashMap<String, String>(parsed.getValue());
-                        attributes.put("osgi.wiring.package", packageName);
-                        String filter = generateFilter(attributes);
-                        System.out.println("adding filter " + filter);
-                        builder.allow("osgi.wiring.package", filter);
-                    }
-                }
-
-            }
-        }
-        RegionFilter f = builder.build();
-        regionDigraph.connect(rFrom, f, rTo);
-    }
-
-    //from aries util, with obr specific weirdness removed
-    public static String generateFilter(Map<String, String> attribs) {
-        StringBuilder filter = new StringBuilder("(&");
-        boolean realAttrib = false;
-        StringBuffer realAttribs = new StringBuffer();
-
-        if (attribs == null) {
-            attribs = new HashMap<String, String>();
-        }
-
-        for (Map.Entry<String, String> attrib : attribs.entrySet()) {
-            String attribName = attrib.getKey();
-
-            if (attribName.endsWith(":")) {
-                // skip all directives. It is used to affect the attribs on the
-                // filter xml.
-            } else if ((Constants.VERSION_ATTRIBUTE.equals(attribName))
-                    || (Constants.BUNDLE_VERSION_ATTRIBUTE.equals(attribName))) {
-                // version and bundle-version attrib requires special
-                // conversion.
-                realAttrib = true;
-
-                VersionRange vr = ManifestHeaderProcessor
-                        .parseVersionRange(attrib.getValue());
-
-                filter.append("(" + attribName + ">=" + vr.getMinimumVersion());
-
-                if (vr.getMaximumVersion() != null) {
-                    filter.append(")(" + attribName + "<=");
-                    filter.append(vr.getMaximumVersion());
-                }
-
-                if (vr.getMaximumVersion() != null && vr.isMinimumExclusive()) {
-                    filter.append(")(!(" + attribName + "=");
-                    filter.append(vr.getMinimumVersion());
-                    filter.append(")");
-                }
-
-                if (vr.getMaximumVersion() != null && vr.isMaximumExclusive()) {
-                    filter.append(")(!(" + attribName + "=");
-                    filter.append(vr.getMaximumVersion());
-                    filter.append(")");
-                }
-                filter.append(")");
-
-            } else if (Constants.OBJECTCLASS.equals(attribName)) {
-                realAttrib = true;
-                // objectClass has a "," separated list of interfaces
-                String[] values = attrib.getValue().split(",");
-                for (String s : values)
-                    filter.append("(" + Constants.OBJECTCLASS + "=" + s + ")");
-
-            } else {
-                // attribName was not version..
-                realAttrib = true;
-
-                filter.append("(" + attribName + "=" + attrib.getValue() + ")");
-                // store all attributes in order to build up the mandatory
-                // filter and separate them with ", "
-                // skip bundle-symbolic-name in the mandatory directive query
-                if (!!!Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE
-                        .equals(attribName)) {
-                    realAttribs.append(attribName);
-                    realAttribs.append(", ");
-                }
-            }
-        }
-
-        // Prune (& off the front and ) off end
-        String filterString = filter.toString();
-        int openBraces = 0;
-        for (int i = 0; openBraces < 3; i++) {
-            i = filterString.indexOf('(', i);
-            if (i == -1) {
-                break;
-            } else {
-                openBraces++;
-            }
-        }
-        if (openBraces < 3 && filterString.length() > 2) {
-            filter.delete(0, 2);
-        } else {
-            filter.append(")");
-        }
-
-        String result = "";
-        if (realAttrib != false) {
-            result = filter.toString();
-        }
-        return result;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/src/main/java/org/apache/karaf/region/commands/AddRegionCommand.java
----------------------------------------------------------------------
diff --git a/region/src/main/java/org/apache/karaf/region/commands/AddRegionCommand.java b/region/src/main/java/org/apache/karaf/region/commands/AddRegionCommand.java
deleted file mode 100644
index 22c817b..0000000
--- a/region/src/main/java/org/apache/karaf/region/commands/AddRegionCommand.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.region.commands;
-
-import java.util.List;
-
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.eclipse.equinox.region.RegionDigraph;
-
-@Command(scope = "region", name = "region-add", description = "Adds a list of regions to the region digraph service.")
-@Service
-public class AddRegionCommand extends RegionCommandSupport {
-
-    @Argument(index = 0, name = "name", description = "Regions to add to the region digraph service separated by whitespaces.", required = true, multiValued = true)
-    List<String> regions;
-
-    protected void doExecute(RegionDigraph regionDigraph) throws Exception {
-        for (String region : regions) {
-            regionDigraph.createRegion(region);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/src/main/java/org/apache/karaf/region/commands/InfoCommand.java
----------------------------------------------------------------------
diff --git a/region/src/main/java/org/apache/karaf/region/commands/InfoCommand.java b/region/src/main/java/org/apache/karaf/region/commands/InfoCommand.java
deleted file mode 100644
index 7c71e36..0000000
--- a/region/src/main/java/org/apache/karaf/region/commands/InfoCommand.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.region.commands;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Option;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.eclipse.equinox.region.Region;
-import org.eclipse.equinox.region.RegionDigraph;
-import org.eclipse.equinox.region.RegionFilter;
-import org.osgi.framework.Bundle;
-
-@Command(scope = "region", name = "info", description = "Prints information about region digraph.")
-@Service
-public class InfoCommand extends RegionCommandSupport {
-
-    @Option(name = "-v", aliases = "--verbose", required = false, description = "Show all info.")
-    boolean verbose;
-
-    @Option(name = "-b", aliases = "--bundles", required = false, description = "Show bundles in each region.")
-    boolean bundles;
-
-    @Option(name = "-f", aliases = "--filters", required = false, description = "Show filters.")
-    boolean filters;
-
-    @Option(name = "-n", aliases = "--namespaces", required = false, description = "Show namespaces in each filter.")
-    boolean namespaces;
-
-    @Argument(index = 0, name = "regions", description = "Regions to provide detailed info for.", required = false, multiValued = true)
-    List<String> regions;
-
-    protected void doExecute(RegionDigraph regionDigraph) throws Exception {
-        System.out.println("Regions");
-        if (regions == null) {
-            for (Region region : regionDigraph.getRegions()) {
-                showRegion(region);
-            }
-        } else {
-            bundles = true;
-            filters = true;
-            namespaces = true;
-            for (String regionName : regions) {
-                Region region = regionDigraph.getRegion(regionName);
-                if (region == null) {
-                    System.out.println("No region " + regionName);
-                } else {
-                    showRegion(region);
-                }
-            }
-        }
-    }
-
-    private void showRegion(Region region) {
-        System.out.println(region.getName());
-        if (verbose || bundles) {
-            for (Long id : region.getBundleIds()) {
-                Bundle b = bundleContext.getBundle(id);
-                System.out.println("  " + id + "  " + getStateString(b) + b);
-            }
-        }
-        if (verbose || filters || namespaces) {
-            for (RegionDigraph.FilteredRegion f : region.getEdges()) {
-                System.out.println("  filter to " + f.getRegion().getName());
-                if (verbose || namespaces) {
-                    RegionFilter rf = f.getFilter();
-                    for (Map.Entry<String, Collection<String>> policy : rf.getSharingPolicy().entrySet()) {
-                        String namespace = policy.getKey();
-                        System.out.println("  namespace: " + namespace);
-                        for (String e : policy.getValue()) {
-                            System.out.println("    " + e);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    public String getStateString(Bundle bundle) {
-        if (bundle == null) {
-            return "Bundle null";
-        }
-        int state = bundle.getState();
-        if (state == Bundle.ACTIVE) {
-            return "Active     ";
-        } else if (state == Bundle.INSTALLED) {
-            return "Installed  ";
-        } else if (state == Bundle.RESOLVED) {
-            return "Resolved   ";
-        } else if (state == Bundle.STARTING) {
-            return "Starting   ";
-        } else if (state == Bundle.STOPPING) {
-            return "Stopping   ";
-        } else {
-            return "Unknown    ";
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/src/main/java/org/apache/karaf/region/commands/RegionCommandSupport.java
----------------------------------------------------------------------
diff --git a/region/src/main/java/org/apache/karaf/region/commands/RegionCommandSupport.java b/region/src/main/java/org/apache/karaf/region/commands/RegionCommandSupport.java
deleted file mode 100644
index bcdfb6c..0000000
--- a/region/src/main/java/org/apache/karaf/region/commands/RegionCommandSupport.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.region.commands;
-
-import java.io.PrintStream;
-
-import org.apache.karaf.shell.api.action.Action;
-import org.apache.karaf.shell.api.action.lifecycle.Reference;
-import org.eclipse.equinox.region.Region;
-import org.eclipse.equinox.region.RegionDigraph;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.ServiceReference;
-
-public abstract class RegionCommandSupport implements Action {
-
-    protected static final char VERSION_DELIM = ',';
-
-    @Reference
-    BundleContext bundleContext;
-
-    @Override
-    public Object execute() throws Exception {
-        // Get repository instance service.
-        ServiceReference ref = bundleContext.getServiceReference(RegionDigraph.class.getName());
-        if (ref == null) {
-            System.out.println("RegionDigraph service is unavailable.");
-            return null;
-        }
-        try {
-            RegionDigraph admin = (RegionDigraph) bundleContext.getService(ref);
-            if (admin == null) {
-                System.out.println("RegionDigraph service is unavailable.");
-                return null;
-            }
-
-            doExecute(admin);
-        }
-        finally {
-            bundleContext.ungetService(ref);
-        }
-        return null;
-    }
-
-    abstract void doExecute(RegionDigraph admin) throws Exception;
-
-    protected void printUnderline(PrintStream out, int length)
-    {
-        for (int i = 0; i < length; i++)
-        {
-            out.print('-');
-        }
-        out.println("");
-    }
-
-
-    protected Region getRegion(RegionDigraph regionDigraph, String region) throws BundleException {
-        Region r = regionDigraph.getRegion(region);
-        if (r == null) {
-            System.out.println("No region: " + region + ", creating it");
-            r = regionDigraph.createRegion(region);
-        }
-        return r;
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/src/main/java/org/apache/karaf/region/commands/util/FileUtil.java
----------------------------------------------------------------------
diff --git a/region/src/main/java/org/apache/karaf/region/commands/util/FileUtil.java b/region/src/main/java/org/apache/karaf/region/commands/util/FileUtil.java
deleted file mode 100644
index 07c39e9..0000000
--- a/region/src/main/java/org/apache/karaf/region/commands/util/FileUtil.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.karaf.region.commands.util;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintStream;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.jar.JarEntry;
-import java.util.jar.JarInputStream;
-
-public class FileUtil
-{
-    public static void downloadSource(
-        PrintStream out, PrintStream err,
-        URL srcURL, String dirStr, boolean extract)
-    {
-        // Get the file name from the URL.
-        String fileName = (srcURL.getFile().lastIndexOf('/') > 0)
-            ? srcURL.getFile().substring(srcURL.getFile().lastIndexOf('/') + 1)
-            : srcURL.getFile();
-
-        try
-        {
-            out.println("Connecting...");
-
-            File dir = new File(dirStr);
-            if (!dir.exists())
-            {
-                err.println("Destination directory does not exist.");
-            }
-            File file = new File(dir, fileName);
-
-            OutputStream os = new FileOutputStream(file);
-            URLConnection conn = srcURL.openConnection();
-            int total = conn.getContentLength();
-            InputStream is = conn.getInputStream();
-
-            if (total > 0)
-            {
-                out.println("Downloading " + fileName
-                    + " ( " + total + " bytes ).");
-            }
-            else
-            {
-                out.println("Downloading " + fileName + ".");
-            }
-            byte[] buffer = new byte[4096];
-            int count = 0;
-            for (int len = is.read(buffer); len > 0; len = is.read(buffer))
-            {
-                count += len;
-                os.write(buffer, 0, len);
-            }
-
-            os.close();
-            is.close();
-
-            if (extract)
-            {
-                is = new FileInputStream(file);
-                JarInputStream jis = new JarInputStream(is);
-                out.println("Extracting...");
-                unjar(jis, dir);
-                jis.close();
-                file.delete();
-            }
-        }
-        catch (Exception ex)
-        {
-            err.println(ex);
-        }
-    }
-
-    public static void unjar(JarInputStream jis, File dir)
-        throws IOException
-    {
-        // Reusable buffer.
-        byte[] buffer = new byte[4096];
-
-        // Loop through JAR entries.
-        for (JarEntry je = jis.getNextJarEntry();
-             je != null;
-             je = jis.getNextJarEntry())
-        {
-            if (je.getName().startsWith("/"))
-            {
-                throw new IOException("JAR resource cannot contain absolute paths.");
-            }
-
-            File target = new File(dir, je.getName());
-
-            // Check to see if the JAR entry is a directory.
-            if (je.isDirectory())
-            {
-                if (!target.exists())
-                {
-                    if (!target.mkdirs())
-                    {
-                        throw new IOException("Unable to create target directory: "
-                            + target);
-                    }
-                }
-                // Just continue since directories do not have content to copy.
-                continue;
-            }
-
-            int lastIndex = je.getName().lastIndexOf('/');
-            String name = (lastIndex >= 0) ?
-                je.getName().substring(lastIndex + 1) : je.getName();
-            String destination = (lastIndex >= 0) ?
-                je.getName().substring(0, lastIndex) : "";
-
-            // JAR files use '/', so convert it to platform separator.
-            destination = destination.replace('/', File.separatorChar);
-            copy(jis, dir, name, destination, buffer);
-        }
-    }
-
-    public static void copy(
-        InputStream is, File dir, String destName, String destDir, byte[] buffer)
-        throws IOException
-    {
-        if (destDir == null)
-        {
-            destDir = "";
-        }
-
-        // Make sure the target directory exists and
-        // that is actually a directory.
-        File targetDir = new File(dir, destDir);
-        if (!targetDir.exists())
-        {
-            if (!targetDir.mkdirs())
-            {
-                throw new IOException("Unable to create target directory: "
-                    + targetDir);
-            }
-        }
-        else if (!targetDir.isDirectory())
-        {
-            throw new IOException("Target is not a directory: "
-                + targetDir);
-        }
-
-        BufferedOutputStream bos = new BufferedOutputStream(
-            new FileOutputStream(new File(targetDir, destName)));
-        int count = 0;
-        while ((count = is.read(buffer)) > 0)
-        {
-            bos.write(buffer, 0, count);
-        }
-        bos.close();
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/src/main/java/org/apache/karaf/region/persist/internal/Activator.java
----------------------------------------------------------------------
diff --git a/region/src/main/java/org/apache/karaf/region/persist/internal/Activator.java b/region/src/main/java/org/apache/karaf/region/persist/internal/Activator.java
deleted file mode 100644
index aa7215f..0000000
--- a/region/src/main/java/org/apache/karaf/region/persist/internal/Activator.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-
-package org.apache.karaf.region.persist.internal;
-
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.apache.karaf.features.RegionsPersistence;
-import org.apache.karaf.util.tracker.SingleServiceTracker;
-import org.eclipse.equinox.region.RegionDigraph;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class Activator implements BundleActivator {
-
-    private static final Logger log = LoggerFactory.getLogger(Activator.class);
-
-    private SingleServiceTracker<RegionDigraph> tracker;
-    private final AtomicReference<RegionsPersistenceImpl> persistence = new AtomicReference<RegionsPersistenceImpl>();
-    private final AtomicReference<RegionsBundleTracker> bundleTracker = new AtomicReference<RegionsBundleTracker>();
-    private ServiceRegistration<RegionsPersistence> reg;
-
-    @Override
-    public void start(final BundleContext bundleContext) throws Exception {
-        tracker = new SingleServiceTracker<RegionDigraph>(bundleContext, RegionDigraph.class, new SingleServiceTracker.SingleServiceListener() {
-            public void serviceFound() {
-                log.debug("Found RegionDigraph service, initializing");
-                RegionDigraph regionDigraph = tracker.getService();
-                Bundle framework = bundleContext.getBundle(0);
-                RegionsPersistenceImpl persistence = null;
-                try {
-                    persistence = new RegionsPersistenceImpl(regionDigraph, framework);
-                    reg = bundleContext.registerService(RegionsPersistence.class, persistence, null);
-
-                    RegionsBundleTracker bundleTracker = new RegionsBundleTracker();
-                    bundleTracker.start(bundleContext, persistence);
-                    Activator.this.bundleTracker.set(bundleTracker);
-                } catch (Exception e) {
-                    log.info("Could not create RegionsPersistenceImpl", e);
-                }
-                Activator.this.persistence.set(persistence);
-            }
-
-            public void serviceLost() {
-                if (reg != null) {
-                    reg.unregister();
-                    reg = null;
-                }
-                Activator.this.persistence.set(null);
-                Activator.this.bundleTracker.set(null);
-            }
-
-            public void serviceReplaced() {
-                //??
-            }
-        });
-        tracker.open();
-    }
-
-    @Override
-    public void stop(BundleContext bundleContext) throws Exception {
-        tracker.close();
-        persistence.set(null);
-        RegionsBundleTracker tracker = bundleTracker.getAndSet(null);
-        if (tracker != null) {
-            tracker.stop();
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/src/main/java/org/apache/karaf/region/persist/internal/RegionsBundleTracker.java
----------------------------------------------------------------------
diff --git a/region/src/main/java/org/apache/karaf/region/persist/internal/RegionsBundleTracker.java b/region/src/main/java/org/apache/karaf/region/persist/internal/RegionsBundleTracker.java
deleted file mode 100644
index 7035303..0000000
--- a/region/src/main/java/org/apache/karaf/region/persist/internal/RegionsBundleTracker.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-
-package org.apache.karaf.region.persist.internal;
-
-import org.apache.karaf.features.RegionsPersistence;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleEvent;
-import org.osgi.framework.BundleException;
-import org.osgi.util.tracker.BundleTracker;
-import org.osgi.util.tracker.BundleTrackerCustomizer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class RegionsBundleTracker {
-    private static final Logger log = LoggerFactory.getLogger(RegionsBundleTracker.class);
-
-    private BundleTracker bundleTracker;
-    private RegionsPersistence regionsPersistence;
-
-    void start(BundleContext bundleContext, RegionsPersistence regionsPersistence) {
-        this.regionsPersistence = regionsPersistence;
-        int stateMask = Bundle.INSTALLED;
-        bundleTracker = new BundleTracker<Bundle>(bundleContext, stateMask, new BundleTrackerCustomizer<Bundle>() {
-            @Override
-            public Bundle addingBundle(Bundle bundle, BundleEvent bundleEvent) {
-                return RegionsBundleTracker.this.addingBundle(bundle);
-            }
-
-            @Override
-            public void modifiedBundle(Bundle bundle, BundleEvent bundleEvent, Bundle o) {
-            }
-
-            @Override
-            public void removedBundle(Bundle bundle, BundleEvent bundleEvent, Bundle o) {
-            }
-        });
-        bundleTracker.open();
-    }
-
-    private Bundle addingBundle(Bundle bundle) {
-        String region = bundle.getHeaders().get("Region");
-        if (region != null) {
-            try {
-                regionsPersistence.install(bundle, region);
-                log.debug("Installed bundle " + bundle + " in region " + region);
-                return bundle;
-            } catch (BundleException e) {
-                log.info("Could not install bundle " + bundle + " in region " + region, e);
-            }
-        }
-        return null;
-    }
-
-    void stop() {
-        bundleTracker.close();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/region/src/main/java/org/apache/karaf/region/persist/internal/RegionsPersistenceImpl.java
----------------------------------------------------------------------
diff --git a/region/src/main/java/org/apache/karaf/region/persist/internal/RegionsPersistenceImpl.java b/region/src/main/java/org/apache/karaf/region/persist/internal/RegionsPersistenceImpl.java
deleted file mode 100644
index dcf5d26..0000000
--- a/region/src/main/java/org/apache/karaf/region/persist/internal/RegionsPersistenceImpl.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.karaf.region.persist.internal;
-
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.Reader;
-import java.io.Writer;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Marshaller;
-import javax.xml.bind.Unmarshaller;
-
-import org.apache.karaf.features.RegionsPersistence;
-import org.apache.karaf.region.persist.internal.model.FilterAttributeType;
-import org.apache.karaf.region.persist.internal.model.FilterBundleType;
-import org.apache.karaf.region.persist.internal.model.FilterNamespaceType;
-import org.apache.karaf.region.persist.internal.model.FilterPackageType;
-import org.apache.karaf.region.persist.internal.model.FilterType;
-import org.apache.karaf.region.persist.internal.model.RegionBundleType;
-import org.apache.karaf.region.persist.internal.model.RegionType;
-import org.apache.karaf.region.persist.internal.model.RegionsType;
-import org.apache.karaf.region.persist.internal.util.ManifestHeaderProcessor;
-import org.eclipse.equinox.region.Region;
-import org.eclipse.equinox.region.RegionDigraph;
-import org.eclipse.equinox.region.RegionFilterBuilder;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.framework.wiring.BundleRevision;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class RegionsPersistenceImpl implements RegionsPersistence {
-
-    private static final Logger log = LoggerFactory.getLogger(RegionsPersistenceImpl.class);
-
-    private JAXBContext jaxbContext;
-    private RegionDigraph regionDigraph;
-    private Region kernel;
-    private Bundle framework;
-
-    public RegionsPersistenceImpl(RegionDigraph regionDigraph, Bundle framework) throws JAXBException, BundleException, IOException, InvalidSyntaxException {
-        log.info("Loading region digraph persistence");
-        this.framework = framework;
-        this.regionDigraph = regionDigraph;
-        kernel = regionDigraph.getRegion(0);
-        jaxbContext = JAXBContext.newInstance(RegionsType.class);
-        load();
-    }
-
-    @Override
-    public void install(Bundle b, String regionName) throws BundleException {
-        Region region = regionDigraph.getRegion(regionName);
-        if (region == null) {
-            region = regionDigraph.createRegion(regionName);
-        }
-        kernel.removeBundle(b);
-        region.addBundle(b);
-    }
-
-    void save(RegionsType regionsType, Writer out) throws JAXBException {
-        Marshaller marshaller = jaxbContext.createMarshaller();
-        marshaller.marshal(regionsType, out);
-    }
-
-    void load() throws IOException, BundleException, JAXBException, InvalidSyntaxException {
-        if (this.regionDigraph.getRegions().size() <= 1) {
-            File etc = new File(System.getProperty("karaf.etc"));
-            File regionsConfig = new File(etc, "regions-config.xml");
-            if (regionsConfig.exists()) {
-                log.info("initializing region digraph from etc/regions-config.xml");
-                Reader in = new FileReader(regionsConfig);
-                try {
-                        load(this.regionDigraph, in);
-                    } finally {
-                        in.close();
-                    }
-            } else {
-                log.info("no regions config file");
-            }
-        }
-
-    }
-
-    void  load(RegionDigraph regionDigraph, Reader in) throws JAXBException, BundleException, InvalidSyntaxException {
-        RegionsType regionsType = load(in);
-        load(regionsType, regionDigraph);
-    }
-
-    RegionsType load(Reader in) throws JAXBException {
-        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
-        return (RegionsType) unmarshaller.unmarshal(in);
-    }
-
-    void load(RegionsType regionsType, RegionDigraph regionDigraph) throws BundleException, InvalidSyntaxException {
-        BundleContext frameworkContext = framework.getBundleContext();
-        for (RegionType regionType: regionsType.getRegion()) {
-            String name = regionType.getName();
-            log.debug("Creating region: " + name);
-            Region region = regionDigraph.createRegion(name);
-            for (RegionBundleType bundleType: regionType.getBundle()) {
-                if (bundleType.getId() != null) {
-                    region.addBundle(bundleType.getId());
-                } else {
-                    Bundle b = frameworkContext.getBundle(bundleType.getLocation());
-                    region.addBundle(b);
-                }
-            }
-        }
-        for (FilterType filterType: regionsType.getFilter()) {
-            Region from = regionDigraph.getRegion(filterType.getFrom());
-            Region to = regionDigraph.getRegion(filterType.getTo());
-            log.debug("Creating filter between " + from.getName() + " to " + to.getName());
-            RegionFilterBuilder builder = regionDigraph.createRegionFilterBuilder();
-            for (FilterBundleType bundleType: filterType.getBundle()) {
-                String symbolicName = bundleType.getSymbolicName();
-                String version = bundleType.getVersion();
-                if (bundleType.getId() != null) {
-                    Bundle b = frameworkContext.getBundle(bundleType.getId());
-                    symbolicName = b.getSymbolicName();
-                    version = b.getVersion().toString();
-                }
-                String namespace = BundleRevision.BUNDLE_NAMESPACE;
-                List<FilterAttributeType> attributeTypes = bundleType.getAttribute();
-                buildFilter(symbolicName, version, namespace, attributeTypes, builder);
-            }
-            for (FilterPackageType packageType: filterType.getPackage()) {
-                String packageName = packageType.getName();
-                String version = packageType.getVersion();
-                String namespace = BundleRevision.PACKAGE_NAMESPACE;
-                List<FilterAttributeType> attributeTypes = packageType.getAttribute();
-                buildFilter(packageName, version, namespace, attributeTypes, builder);
-            }
-            if (to == kernel) {
-                //add framework exports
-                BundleRevision rev = framework.adapt(BundleRevision.class);
-                List<BundleCapability> caps = rev.getDeclaredCapabilities(BundleRevision.PACKAGE_NAMESPACE);
-                for (BundleCapability cap : caps) {
-                    String filter = ManifestHeaderProcessor.generateFilter(filter(cap.getAttributes()));
-                    builder.allow(BundleRevision.PACKAGE_NAMESPACE, filter);
-                }
-            }
-            //TODO explicit services?
-            for (FilterNamespaceType namespaceType: filterType.getNamespace()) {
-                String namespace = namespaceType.getName();
-                HashMap<String, Object> attributes = new HashMap<String, Object>();
-                for (FilterAttributeType attributeType: namespaceType.getAttribute()) {
-                    attributes.put(attributeType.getName(), attributeType.getValue());
-                }
-                String filter = ManifestHeaderProcessor.generateFilter(attributes);
-                builder.allow(namespace, filter);
-            }
-            regionDigraph.connect(from, builder.build(), to);
-        }
-    }
-
-    private Map<String, Object> filter(Map<String, Object> attributes) {
-        Map<String, Object> result = new HashMap<String, Object>(attributes);
-        result.remove("bundle-version");
-        result.remove("bundle-symbolic-name");
-        return result;
-    }
-
-    private void buildFilter(String packageName, String version, String namespace, List<FilterAttributeType> attributeTypes, RegionFilterBuilder builder) throws InvalidSyntaxException {
-        HashMap<String, Object> attributes = new HashMap<String, Object>();
-        if (namespace != null) {
-            attributes.put(namespace, packageName);
-        }
-        if (version != null) {
-            attributes.put("version", version);
-        }
-        for (FilterAttributeType attributeType: attributeTypes) {
-            attributes.put(attributeType.getName(), attributeType.getValue());
-        }
-        String filter = ManifestHeaderProcessor.generateFilter(attributes);
-        builder.allow(namespace, filter);
-    }
-
-}


[5/6] git commit: [KARAF-2923] Region support in features service

Posted by gn...@apache.org.
[KARAF-2923] Region support in features service


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/2705ad88
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/2705ad88
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/2705ad88

Branch: refs/heads/master
Commit: 2705ad8894a2af462487774c705066ef7de13f25
Parents: 486ad3a
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Fri Apr 18 21:16:02 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Fri Apr 18 23:33:51 2014 +0200

----------------------------------------------------------------------
 assemblies/features/standard/pom.xml            |  17 -
 .../standard/src/main/feature/feature.xml       |   6 -
 features/command/pom.xml                        |   5 +
 .../features/command/InstallFeatureCommand.java |   5 +-
 .../features/command/RegionInfoCommand.java     | 129 ++++
 .../command/UninstallFeatureCommand.java        |   5 +-
 features/core/pom.xml                           |  18 +-
 .../java/org/apache/karaf/features/Feature.java |   4 +-
 .../apache/karaf/features/FeaturesService.java  |   4 +
 .../karaf/features/RegionsPersistence.java      |  26 -
 .../org/apache/karaf/features/Repository.java   |   2 -
 .../org/apache/karaf/features/Resolver.java     |  25 -
 .../org/apache/karaf/features/ScopeFilter.java  |  25 +
 .../java/org/apache/karaf/features/Scoping.java |  29 +
 .../internal/deployment/DeploymentBuilder.java  | 354 ----------
 .../internal/deployment/Downloader.java         |  35 -
 .../internal/deployment/StreamProvider.java     |  26 -
 .../internal/download/DownloadCallback.java     |  23 +
 .../internal/download/DownloadManager.java      |  27 +
 .../features/internal/download/Downloader.java  |  29 +
 .../internal/download/StreamProvider.java       |  29 +
 .../download/simple/SimpleDownloader.java       | 120 ++++
 .../karaf/features/internal/model/Feature.java  |  23 +-
 .../karaf/features/internal/model/JaxbUtil.java |  33 +-
 .../features/internal/model/ScopeFilter.java    |  56 ++
 .../karaf/features/internal/model/Scoping.java  |  70 ++
 .../karaf/features/internal/osgi/Activator.java |  73 +-
 .../region/AbstractRegionDigraphVisitor.java    | 121 ++++
 .../internal/region/CandidateComparator.java    | 125 ++++
 .../internal/region/ResourceComparator.java     |  43 ++
 .../features/internal/region/Subsystem.java     | 341 ++++++++++
 .../region/SubsystemResolveContext.java         | 188 ++++++
 .../internal/region/SubsystemResolver.java      | 317 +++++++++
 .../internal/resolver/CandidateComparator.java  | 129 ----
 .../internal/resolver/FeatureNamespace.java     |  72 --
 .../internal/resolver/FeatureResource.java      |  43 +-
 .../internal/resolver/IdentityCapability.java   |   2 +-
 .../internal/resolver/ResolveContextImpl.java   | 102 ---
 .../internal/resolver/ResourceBuilder.java      |   7 +-
 .../internal/resolver/ResourceUtils.java        | 103 +++
 .../internal/resolver/UriNamespace.java         |  47 --
 .../service/FeatureConfigInstaller.java         |  40 +-
 .../internal/service/FeaturesServiceImpl.java   | 667 ++++++++++++-------
 .../internal/service/RepositoryImpl.java        |   8 +-
 .../internal/service/SimpleDownloader.java      |  51 --
 .../karaf/features/internal/service/State.java  |  29 +-
 .../features/internal/service/StateStorage.java | 131 ++--
 .../features/internal/util/JsonWriter.java      |   8 +
 .../karaf/features/internal/util/MapUtils.java  |  65 ++
 .../equinox/internal/region/DigraphHelper.java  | 149 +++++
 .../karaf/features/karaf-features-1.3.0.xsd     |  58 +-
 .../karaf/features/FeaturesServiceTest.java     |  11 +-
 .../features/internal/region/SubsystemTest.java | 213 ++++++
 .../service/FeaturesServiceImplTest.java        |   8 +-
 .../internal/service/OverridesTest.java         |  13 +-
 .../internal/service/StateStorageTest.java      |  80 +++
 .../karaf/features/internal/region/data1/a.mf   |   6 +
 .../karaf/features/internal/region/data1/b.mf   |   6 +
 .../karaf/features/internal/region/data1/c.mf   |   6 +
 .../features/internal/region/data1/features.xml |  31 +
 .../karaf/features/internal/region/data2/a.mf   |   7 +
 .../karaf/features/internal/region/data2/b.mf   |   7 +
 .../karaf/features/internal/region/data2/c.mf   |   6 +
 .../karaf/features/internal/region/data2/d.mf   |   6 +
 .../karaf/features/internal/region/data2/e.mf   |   6 +
 .../features/internal/region/data2/features.xml |  42 ++
 .../karaf/features/internal/service/f07.xml     |  11 +
 .../org/apache/karaf/itests/RegionTest.java     |  48 --
 .../itests/features/StandardFeaturesTest.java   |   5 -
 pom.xml                                         |  14 +-
 region/NOTICE                                   |  71 --
 region/pom.xml                                  | 136 ----
 .../karaf/region/commands/AddBundleCommand.java |  52 --
 .../karaf/region/commands/AddFilterCommand.java | 169 -----
 .../karaf/region/commands/AddRegionCommand.java |  38 --
 .../karaf/region/commands/InfoCommand.java      | 117 ----
 .../region/commands/RegionCommandSupport.java   |  79 ---
 .../karaf/region/commands/util/FileUtil.java    | 177 -----
 .../region/persist/internal/Activator.java      |  91 ---
 .../persist/internal/RegionsBundleTracker.java  |  77 ---
 .../internal/RegionsPersistenceImpl.java        | 203 ------
 .../internal/model/FilterAttributeType.java     |  94 ---
 .../internal/model/FilterBundleType.java        | 156 -----
 .../internal/model/FilterNamespaceType.java     | 102 ---
 .../internal/model/FilterPackageType.java       | 129 ----
 .../persist/internal/model/FilterType.java      | 195 ------
 .../persist/internal/model/ObjectFactory.java   | 116 ----
 .../internal/model/RegionBundleType.java        |  94 ---
 .../persist/internal/model/RegionType.java      | 106 ---
 .../persist/internal/model/RegionsType.java     | 112 ----
 .../persist/internal/model/package-info.java    |   9 -
 .../internal/util/ManifestHeaderProcessor.java  | 661 ------------------
 .../internal/util/ManifestHeaderUtils.java      |  85 ---
 .../persist/internal/util/VersionRange.java     | 456 -------------
 .../org/apache/karaf/region/persist/region.xsd  | 109 ---
 .../webconsole/features/ExtendedFeature.java    |   6 +-
 96 files changed, 3127 insertions(+), 5083 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/assemblies/features/standard/pom.xml
----------------------------------------------------------------------
diff --git a/assemblies/features/standard/pom.xml b/assemblies/features/standard/pom.xml
index f050441..bad1015 100644
--- a/assemblies/features/standard/pom.xml
+++ b/assemblies/features/standard/pom.xml
@@ -162,11 +162,6 @@
             <classifier>uber</classifier>
             <scope>provided</scope>
         </dependency>
-        <dependency>
-            <groupId>org.apache.karaf.features</groupId>
-            <artifactId>org.apache.karaf.features.obr</artifactId>
-            <scope>provided</scope>
-        </dependency>
 
         <!-- config deps -->
         <dependency>
@@ -175,18 +170,6 @@
             <scope>provided</scope>
         </dependency>
 
-        <!-- region deps -->
-        <dependency>
-            <groupId>org.eclipse.equinox</groupId>
-            <artifactId>org.eclipse.equinox.region</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.karaf.region</groupId>
-            <artifactId>org.apache.karaf.region.core</artifactId>
-            <scope>provided</scope>
-        </dependency>
-
         <!-- jetty deps -->
         <dependency>
             <groupId>org.apache.servicemix.specs</groupId>

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/assemblies/features/standard/src/main/feature/feature.xml
----------------------------------------------------------------------
diff --git a/assemblies/features/standard/src/main/feature/feature.xml b/assemblies/features/standard/src/main/feature/feature.xml
index f50cd65..e7d77c5 100644
--- a/assemblies/features/standard/src/main/feature/feature.xml
+++ b/assemblies/features/standard/src/main/feature/feature.xml
@@ -147,12 +147,6 @@
         <bundle start-level="30" start="true">mvn:org.apache.karaf.log/org.apache.karaf.log.core/${project.version}</bundle>
     </feature>
 
-    <feature name="region" description="Provide Region Support" version="${project.version}">
-        <bundle dependency="true" start-level="20">mvn:org.apache.aries/org.apache.aries.util/${aries.util.version}</bundle>
-        <bundle start-level="30">mvn:org.eclipse.equinox/org.eclipse.equinox.region/${equinox.region.version}</bundle>
-        <bundle start-level="30">mvn:org.apache.karaf.region/org.apache.karaf.region.core/${project.version}</bundle>
-    </feature>
-
     <feature name="package" version="${project.version}" description="Package commands and mbeans">
         <bundle start-level="30">mvn:org.apache.karaf.package/org.apache.karaf.package.core/${project.version}</bundle>
     </feature>

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/command/pom.xml
----------------------------------------------------------------------
diff --git a/features/command/pom.xml b/features/command/pom.xml
index 4f49bb1..5978b38 100644
--- a/features/command/pom.xml
+++ b/features/command/pom.xml
@@ -56,6 +56,11 @@
             <groupId>org.apache.karaf.shell</groupId>
             <artifactId>org.apache.karaf.shell.core</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.eclipse.equinox</groupId>
+            <artifactId>org.eclipse.equinox.region</artifactId>
+            <scope>provided</scope>
+        </dependency>
     </dependencies>
 
     <build>

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/command/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java
index b7f8184..ccd869a 100644
--- a/features/command/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java
+++ b/features/command/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java
@@ -50,6 +50,9 @@ public class InstallFeatureCommand extends FeaturesCommandSupport {
     @Option(name = "-t", aliases = "--simulate", description = "Perform a simulation only", required = false, multiValued = false)
     boolean simulate;
 
+    @Option(name = "-g", aliases = "--region", description = "Region to install to")
+    String region;
+
     protected void doExecute(FeaturesService admin) throws Exception {
         EnumSet<FeaturesService.Option> options = EnumSet.noneOf(FeaturesService.Option.class);
         if (simulate) {
@@ -64,6 +67,6 @@ public class InstallFeatureCommand extends FeaturesCommandSupport {
         if (verbose) {
             options.add(FeaturesService.Option.Verbose);
         }
-        admin.installFeatures(new HashSet<String>(features), options);
+        admin.installFeatures(new HashSet<String>(features), region, options);
     }
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/command/src/main/java/org/apache/karaf/features/command/RegionInfoCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/RegionInfoCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/RegionInfoCommand.java
new file mode 100644
index 0000000..8a3e73e
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/RegionInfoCommand.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.command;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeSet;
+
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.eclipse.equinox.region.Region;
+import org.eclipse.equinox.region.RegionDigraph;
+import org.eclipse.equinox.region.RegionFilter;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+@Command(scope = "feature", name = "regions", description = "Prints information about region digraph.")
+@Service
+public class RegionInfoCommand implements Action {
+
+    @Option(name = "-v", aliases = "--verbose", required = false, description = "Show all info.")
+    boolean verbose;
+
+    @Option(name = "-b", aliases = "--bundles", required = false, description = "Show bundles in each region.")
+    boolean bundles;
+
+    @Option(name = "-f", aliases = "--filters", required = false, description = "Show filters.")
+    boolean filters;
+
+    @Option(name = "-n", aliases = "--namespaces", required = false, description = "Show namespaces in each filter.")
+    boolean namespaces;
+
+    @Argument(index = 0, name = "regions", description = "Regions to provide detailed info for.", required = false, multiValued = true)
+    List<String> regions;
+
+    @Reference
+    RegionDigraph regionDigraph;
+
+    @Reference
+    BundleContext bundleContext;
+
+    public Object execute() throws Exception {
+        System.out.println("Regions");
+        if (regions == null) {
+            for (Region region : regionDigraph.getRegions()) {
+                showRegion(region);
+            }
+        } else {
+            bundles = true;
+            filters = true;
+            namespaces = true;
+            for (String regionName : regions) {
+                Region region = regionDigraph.getRegion(regionName);
+                if (region == null) {
+                    System.out.println("No region " + regionName);
+                } else {
+                    showRegion(region);
+                }
+            }
+        }
+        return null;
+    }
+
+    private void showRegion(Region region) {
+        BundleContext bundleContext = this.bundleContext.getBundle(0).getBundleContext();
+        System.out.println(region.getName());
+        if (verbose || bundles) {
+            for (Long id : new TreeSet<Long>(region.getBundleIds())) {
+                Bundle b = bundleContext.getBundle(id);
+                System.out.println(String.format("  %3d  %s%s", id, getStateString(b), b));
+            }
+        }
+        if (verbose || filters || namespaces) {
+            for (RegionDigraph.FilteredRegion f : region.getEdges()) {
+                System.out.println("  filter to " + f.getRegion().getName());
+                if (verbose || namespaces) {
+                    RegionFilter rf = f.getFilter();
+                    for (Map.Entry<String, Collection<String>> policy : rf.getSharingPolicy().entrySet()) {
+                        String namespace = policy.getKey();
+                        System.out.println("    namespace: " + namespace);
+                        for (String e : policy.getValue()) {
+                            System.out.println("      " + e);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public String getStateString(Bundle bundle) {
+        if (bundle == null) {
+            return "Bundle null ";
+        }
+        int state = bundle.getState();
+        if (state == Bundle.ACTIVE) {
+            return "Active      ";
+        } else if (state == Bundle.INSTALLED) {
+            return "Installed   ";
+        } else if (state == Bundle.RESOLVED) {
+            return "Resolved    ";
+        } else if (state == Bundle.STARTING) {
+            return "Starting    ";
+        } else if (state == Bundle.STOPPING) {
+            return "Stopping    ";
+        } else {
+            return "Unknown     ";
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/command/src/main/java/org/apache/karaf/features/command/UninstallFeatureCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/UninstallFeatureCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/UninstallFeatureCommand.java
index e62f697..0fb7d14 100644
--- a/features/command/src/main/java/org/apache/karaf/features/command/UninstallFeatureCommand.java
+++ b/features/command/src/main/java/org/apache/karaf/features/command/UninstallFeatureCommand.java
@@ -45,6 +45,9 @@ public class UninstallFeatureCommand extends FeaturesCommandSupport {
     @Option(name = "-t", aliases = "--simulate", description = "Perform a simulation only", required = false, multiValued = false)
     boolean simulate;
 
+    @Option(name = "-g", aliases = "--region", description = "Region to install to")
+    String region;
+
     protected void doExecute(FeaturesService admin) throws Exception {
         // iterate in the provided feature
         EnumSet<FeaturesService.Option> options = EnumSet.noneOf(FeaturesService.Option.class);
@@ -57,6 +60,6 @@ public class UninstallFeatureCommand extends FeaturesCommandSupport {
         if (verbose) {
             options.add(FeaturesService.Option.Verbose);
         }
-        admin.uninstallFeatures(new HashSet<String>(features), options);
+        admin.uninstallFeatures(new HashSet<String>(features), region, options);
     }
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/pom.xml
----------------------------------------------------------------------
diff --git a/features/core/pom.xml b/features/core/pom.xml
index d8a2620..8998ba9 100644
--- a/features/core/pom.xml
+++ b/features/core/pom.xml
@@ -72,6 +72,12 @@
         </dependency>
 
         <dependency>
+            <groupId>org.eclipse.equinox</groupId>
+            <artifactId>org.eclipse.equinox.region</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-jdk14</artifactId>
             <scope>test</scope>
@@ -110,8 +116,15 @@
                             org.apache.karaf.features;
                             org.apache.karaf.features.management;
                             org.apache.karaf.features.management.codec;
-                                -noimport:=true
+                                -noimport:=true,
+                            org.osgi.service.resolver;-split-package:=merge-first,
+                            org.osgi.service.repository,
+                            org.eclipse.equinox.region.*
                         </Export-Package>
+                        <Import-Package>
+                            !org.eclipse.osgi.service.resolver,
+                            *
+                        </Import-Package>
                         <Provide-Capability>
                             service-reference;effective:=active;objectClass=org.apache.karaf.features.FeaturesService
                         </Provide-Capability>
@@ -123,8 +136,7 @@
                             org.apache.karaf.util.collections,
                             org.apache.karaf.util.json,
                             org.apache.karaf.util.tracker,
-                            org.osgi.service.resolver,
-                            org.osgi.service.repository
+                            org.eclipse.equinox.internal.region.*;-split-package:=merge-first,
                         </Private-Package>
                         <Embed-Dependency>
                             org.apache.karaf.util;inline="org/apache/karaf/util/XmlUtils*.class"

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/Feature.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/Feature.java b/features/core/src/main/java/org/apache/karaf/features/Feature.java
index 2f9f001..06235e2 100644
--- a/features/core/src/main/java/org/apache/karaf/features/Feature.java
+++ b/features/core/src/main/java/org/apache/karaf/features/Feature.java
@@ -54,10 +54,10 @@ public interface Feature {
     
     int getStartLevel();
 
-    String getRegion();
-
     List<? extends Capability> getCapabilities();
 
     List<? extends Requirement> getRequirements();
 
+    Scoping getScoping();
+
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/FeaturesService.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/FeaturesService.java b/features/core/src/main/java/org/apache/karaf/features/FeaturesService.java
index ef3dbcf..7bb3cf8 100644
--- a/features/core/src/main/java/org/apache/karaf/features/FeaturesService.java
+++ b/features/core/src/main/java/org/apache/karaf/features/FeaturesService.java
@@ -71,6 +71,8 @@ public interface FeaturesService {
 
     void installFeatures(Set<String> features, EnumSet<Option> options) throws Exception;
 
+    void installFeatures(Set<String> features, String region, EnumSet<Option> options) throws Exception;
+
     void uninstallFeature(String name, EnumSet<Option> options) throws Exception;
 
     void uninstallFeature(String name) throws Exception;
@@ -81,6 +83,8 @@ public interface FeaturesService {
 
     void uninstallFeatures(Set<String> features, EnumSet<Option> options) throws Exception;
 
+    void uninstallFeatures(Set<String> features, String region, EnumSet<Option> options) throws Exception;
+
     Feature[] listFeatures() throws Exception;
 
     Feature[] listRequiredFeatures() throws Exception;

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/RegionsPersistence.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/RegionsPersistence.java b/features/core/src/main/java/org/apache/karaf/features/RegionsPersistence.java
deleted file mode 100644
index 96ca7da..0000000
--- a/features/core/src/main/java/org/apache/karaf/features/RegionsPersistence.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.karaf.features;
-
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleException;
-
-public interface RegionsPersistence {
-    void install(Bundle b, String regionName) throws BundleException;
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/Repository.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/Repository.java b/features/core/src/main/java/org/apache/karaf/features/Repository.java
index 3ea12ec..84d4a50 100644
--- a/features/core/src/main/java/org/apache/karaf/features/Repository.java
+++ b/features/core/src/main/java/org/apache/karaf/features/Repository.java
@@ -32,6 +32,4 @@ public interface Repository {
 
     Feature[] getFeatures() throws Exception;
     
-    boolean isValid();
-
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/Resolver.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/Resolver.java b/features/core/src/main/java/org/apache/karaf/features/Resolver.java
deleted file mode 100644
index d2fa941..0000000
--- a/features/core/src/main/java/org/apache/karaf/features/Resolver.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features;
-
-import java.util.List;
-
-public interface Resolver {
-
-    List<BundleInfo> resolve(Feature feature) throws Exception;
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/ScopeFilter.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/ScopeFilter.java b/features/core/src/main/java/org/apache/karaf/features/ScopeFilter.java
new file mode 100644
index 0000000..c4ddbfe
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/ScopeFilter.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features;
+
+public interface ScopeFilter {
+
+    String getNamespace();
+
+    String getFilter();
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/Scoping.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/Scoping.java b/features/core/src/main/java/org/apache/karaf/features/Scoping.java
new file mode 100644
index 0000000..b97e6f2
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/Scoping.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features;
+
+import java.util.List;
+
+public interface Scoping {
+
+    boolean acceptDependencies();
+
+    List<? extends ScopeFilter> getImports();
+
+    List<? extends ScopeFilter> getExports();
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/deployment/DeploymentBuilder.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/deployment/DeploymentBuilder.java b/features/core/src/main/java/org/apache/karaf/features/internal/deployment/DeploymentBuilder.java
deleted file mode 100644
index c3ac2b7..0000000
--- a/features/core/src/main/java/org/apache/karaf/features/internal/deployment/DeploymentBuilder.java
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.deployment;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.jar.Attributes;
-import java.util.jar.Manifest;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
-import org.apache.felix.resolver.ResolverImpl;
-import org.apache.felix.utils.version.VersionRange;
-import org.apache.felix.utils.version.VersionTable;
-import org.apache.karaf.features.BundleInfo;
-import org.apache.karaf.features.Conditional;
-import org.apache.karaf.features.Dependency;
-import org.apache.karaf.features.Feature;
-import org.apache.karaf.features.Repository;
-import org.apache.karaf.features.internal.repository.AggregateRepository;
-import org.apache.karaf.features.internal.repository.StaticRepository;
-import org.apache.karaf.features.internal.resolver.FeatureNamespace;
-import org.apache.karaf.features.internal.resolver.FeatureResource;
-import org.apache.karaf.features.internal.resolver.RequirementImpl;
-import org.apache.karaf.features.internal.resolver.ResolveContextImpl;
-import org.apache.karaf.features.internal.resolver.ResourceBuilder;
-import org.apache.karaf.features.internal.resolver.ResourceImpl;
-import org.apache.karaf.features.internal.resolver.Slf4jResolverLog;
-import org.apache.karaf.features.internal.service.Overrides;
-import org.apache.karaf.features.internal.util.Macro;
-import org.apache.karaf.features.internal.util.MultiException;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.Version;
-import org.osgi.framework.namespace.IdentityNamespace;
-import org.osgi.resource.Capability;
-import org.osgi.resource.Requirement;
-import org.osgi.resource.Resource;
-import org.osgi.resource.Wire;
-import org.osgi.service.resolver.ResolutionException;
-import org.osgi.service.resolver.ResolveContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- */
-public class DeploymentBuilder {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(DeploymentBuilder.class);
-
-    public static final String REQ_PROTOCOL = "req:";
-
-    private final Collection<Repository> repositories;
-
-    private final List<org.osgi.service.repository.Repository> resourceRepos;
-
-    String featureRange = "${range;[====,====]}";
-
-    Downloader downloader;
-    ResourceImpl requirements;
-    Map<String, Resource> resources;
-    Set<Resource> optionals;
-    Map<String, StreamProvider> providers;
-
-    Set<Feature> featuresToRegister = new HashSet<Feature>();
-
-    public DeploymentBuilder(Downloader downloader,
-                             Collection<Repository> repositories) {
-        this.downloader = downloader;
-        this.repositories = repositories;
-        this.resourceRepos = new ArrayList<org.osgi.service.repository.Repository>();
-    }
-
-    public void addResourceRepository(org.osgi.service.repository.Repository repository) {
-        resourceRepos.add(repository);
-    }
-
-    public Map<String, StreamProvider> getProviders() {
-        return providers;
-    }
-
-    public void setFeatureRange(String featureRange) {
-        this.featureRange = featureRange;
-    }
-
-    public Map<String, Resource> download(
-                         Set<String> features,
-                         Set<String> bundles,
-                         Set<String> reqs,
-                         Set<String> overrides,
-                         Set<String> optionals)
-                throws IOException, MultiException, InterruptedException, ResolutionException, BundleException {
-        this.resources = new ConcurrentHashMap<String, Resource>();
-        this.optionals = new HashSet<Resource>();
-        this.providers = new ConcurrentHashMap<String, StreamProvider>();
-        this.requirements = new ResourceImpl("dummy", "dummy", Version.emptyVersion);
-        // First, gather all bundle resources
-        for (String feature : features) {
-            registerMatchingFeatures(feature);
-        }
-        for (String bundle : bundles) {
-            downloadAndBuildResource(bundle);
-        }
-        for (String req : reqs) {
-            buildRequirement(req);
-        }
-        for (String override : overrides) {
-            // TODO: ignore download failures for overrides
-            downloadAndBuildResource(Overrides.extractUrl(override));
-        }
-        for (String optional : optionals) {
-            downloadAndBuildResource(optional);
-        }
-        // Wait for all resources to be created
-        downloader.await();
-        // Do override replacement
-        Overrides.override(resources, overrides);
-        // Build features resources
-        for (Feature feature : featuresToRegister) {
-            Resource resource = FeatureResource.build(feature, featureRange, resources);
-            resources.put("feature:" + feature.getName() + "/" + feature.getVersion(), resource);
-            for (Conditional cond : feature.getConditional()) {
-                this.optionals.add(FeatureResource.build(feature, cond, featureRange, resources));
-            }
-        }
-        // Build requirements
-        for (String feature : features) {
-            requireFeature(feature);
-        }
-        for (String bundle : bundles) {
-            requireResource(bundle);
-        }
-        for (String req : reqs) {
-            requireResource(REQ_PROTOCOL + req);
-        }
-        return resources;
-    }
-
-    public Map<Resource, List<Wire>> resolve(List<Resource> systemBundles) throws ResolutionException {
-        // Resolve
-        for (int i = 0; i < systemBundles.size(); i++) {
-            resources.put("system-bundle-" + i, systemBundles.get(i));
-        }
-
-        List<org.osgi.service.repository.Repository> repos = new ArrayList<org.osgi.service.repository.Repository>();
-        repos.add(new StaticRepository(resources.values()));
-        repos.addAll(resourceRepos);
-
-        ResolverImpl resolver = new ResolverImpl(new Slf4jResolverLog(LOGGER));
-        ResolveContext context = new ResolveContextImpl(
-                Collections.<Resource>singleton(requirements),
-                Collections.<Resource>emptySet(),
-                new AggregateRepository(repos),
-                false);
-        Map<Resource, List<Wire>> best = resolver.resolve(context);
-
-        // TODO: we actually need to use multiple passes for conditionals
-        // TODO: but it may be optimized by passing the old wiring instead
-        // TODO: of computing everything again
-        Set<Resource> resources = new HashSet<Resource>();
-        resources.add(requirements);
-        for (Resource optional : optionals) {
-            try {
-                Set<Resource> newSet = new HashSet<Resource>(resources);
-                newSet.add(optional);
-                context = new ResolveContextImpl(
-                        newSet,
-                        Collections.<Resource>emptySet(),
-                        new AggregateRepository(repos),
-                        false);
-                best = resolver.resolve(context);
-                resources = newSet;
-            } catch (ResolutionException e) {
-                // Ignore this resource
-            }
-        }
-        return best;
-    }
-
-    public void requireFeature(String feature) throws IOException {
-        // Find name and version range
-        String[] split = feature.split("/");
-        String name = split[0].trim();
-        String version = (split.length > 1) ? split[1].trim() : null;
-        if (version != null && !version.equals("0.0.0") && !version.startsWith("[") && !version.startsWith("(")) {
-            version = Macro.transform(featureRange, version);
-        }
-        VersionRange range = version != null ? new VersionRange(version) : VersionRange.ANY_VERSION;
-        // Add requirement
-        Map<String, Object> attrs = new HashMap<String, Object>();
-        attrs.put(IdentityNamespace.IDENTITY_NAMESPACE, name);
-        attrs.put(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, FeatureNamespace.TYPE_FEATURE);
-        attrs.put(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, range);
-        requirements.addRequirement(
-                new RequirementImpl(requirements, IdentityNamespace.IDENTITY_NAMESPACE,
-                        Collections.<String, String>emptyMap(), attrs)
-        );
-    }
-
-    public void requireResource(String location) {
-        Resource res = resources.get(location);
-        if (res == null) {
-            throw new IllegalStateException("Could not find resource for " + location);
-        }
-        List<Capability> caps = res.getCapabilities(IdentityNamespace.IDENTITY_NAMESPACE);
-        if (caps.size() != 1) {
-            throw new IllegalStateException("Resource does not have a single " + IdentityNamespace.IDENTITY_NAMESPACE + " capability");
-        }
-        Capability cap = caps.get(0);
-        // Add requirement
-        Map<String, Object> attrs = new HashMap<String, Object>();
-        attrs.put(IdentityNamespace.IDENTITY_NAMESPACE, cap.getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE));
-        attrs.put(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, cap.getAttributes().get(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE));
-        attrs.put(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, new VersionRange((Version) cap.getAttributes().get(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE), true));
-        requirements.addRequirement(
-                new RequirementImpl(requirements, IdentityNamespace.IDENTITY_NAMESPACE,
-                        Collections.<String, String>emptyMap(), attrs));
-
-    }
-
-    public void registerMatchingFeatures(String feature) throws IOException {
-        // Find name and version range
-        String[] split = feature.split("/");
-        String name = split[0].trim();
-        String version = (split.length > 1)
-                ? split[1].trim() : Version.emptyVersion.toString();
-        // Register matching features
-        registerMatchingFeatures(name, new VersionRange(version));
-    }
-
-    public void registerMatchingFeatures(String name, String version) throws IOException {
-        if (version != null && !version.equals("0.0.0") && !version.startsWith("[") && !version.startsWith("(")) {
-            version = Macro.transform(featureRange, version);
-        }
-        registerMatchingFeatures(name, version != null ? new VersionRange(version) : VersionRange.ANY_VERSION);
-    }
-
-    public void registerMatchingFeatures(String name, VersionRange range) throws IOException {
-        for (Repository repo : repositories) {
-            Feature[] features;
-            try {
-                features = repo.getFeatures();
-            } catch (Exception e) {
-                // This should not happen as the repository has been loaded already
-                throw new IllegalStateException(e);
-            }
-            for (Feature f : features) {
-                if (name.equals(f.getName())) {
-                    Version v = VersionTable.getVersion(f.getVersion());
-                    if (range.contains(v)) {
-                        featuresToRegister.add(f);
-                        for (Dependency dep : f.getDependencies()) {
-                            registerMatchingFeatures(dep.getName(), dep.getVersion());
-                        }
-                        for (BundleInfo bundle : f.getBundles()) {
-                            downloadAndBuildResource(bundle.getLocation());
-                        }
-                        for (Conditional cond : f.getConditional()) {
-                            Feature c = cond.asFeature(f.getName(), f.getVersion());
-                            featuresToRegister.add(c);
-                            for (BundleInfo bundle : c.getBundles()) {
-                                downloadAndBuildResource(bundle.getLocation());
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    public void buildRequirement(String requirement) {
-        try {
-            String location = REQ_PROTOCOL + requirement;
-            ResourceImpl resource = new ResourceImpl(location, "dummy", Version.emptyVersion);
-            for (Requirement req : ResourceBuilder.parseRequirement(resource, requirement)) {
-                resource.addRequirement(req);
-            }
-            resources.put(location, resource);
-        } catch (BundleException e) {
-            throw new IllegalArgumentException("Error parsing requirement: " + requirement, e);
-        }
-    }
-
-    public void downloadAndBuildResource(final String location) throws IOException {
-        if (!resources.containsKey(location)) {
-            downloader.download(location, new Downloader.DownloadCallback() {
-                @Override
-                public void downloaded(StreamProvider provider) throws Exception {
-                    manageResource(location, provider);
-                }
-            });
-        }
-    }
-
-    private void manageResource(String location, StreamProvider provider) throws Exception {
-        if (!resources.containsKey(location)) {
-            Attributes attributes = getAttributes(location, provider);
-            Resource resource = createResource(location, attributes);
-            resources.put(location, resource);
-            providers.put(location, provider);
-        }
-    }
-
-    private Resource createResource(String uri, Attributes attributes) throws Exception {
-        Map<String, String> headers = new HashMap<String, String>();
-        for (Map.Entry attr : attributes.entrySet()) {
-            headers.put(attr.getKey().toString(), attr.getValue().toString());
-        }
-        try {
-            return ResourceBuilder.build(uri, headers);
-        } catch (BundleException e) {
-            throw new Exception("Unable to create resource for bundle " + uri, e);
-        }
-    }
-
-    protected Attributes getAttributes(String uri, StreamProvider provider) throws Exception {
-        InputStream is = provider.open();
-        try {
-            ZipInputStream zis = new ZipInputStream(is);
-            ZipEntry entry;
-            while ( (entry = zis.getNextEntry()) != null ) {
-                if ("META-INF/MANIFEST.MF".equals(entry.getName())) {
-                    return new Manifest(zis).getMainAttributes();
-                }
-            }
-        } finally {
-            is.close();
-        }
-        throw new IllegalArgumentException("Resource " + uri + " does not contain a manifest");
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/deployment/Downloader.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/deployment/Downloader.java b/features/core/src/main/java/org/apache/karaf/features/internal/deployment/Downloader.java
deleted file mode 100644
index 2d5dd98..0000000
--- a/features/core/src/main/java/org/apache/karaf/features/internal/deployment/Downloader.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.deployment;
-
-import java.net.MalformedURLException;
-
-import org.apache.karaf.features.internal.util.MultiException;
-
-public interface Downloader {
-
-    void await() throws InterruptedException, MultiException;
-
-    void download(String location, DownloadCallback downloadCallback) throws MalformedURLException;
-
-    interface DownloadCallback {
-
-        void downloaded(StreamProvider provider) throws Exception;
-
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/deployment/StreamProvider.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/deployment/StreamProvider.java b/features/core/src/main/java/org/apache/karaf/features/internal/deployment/StreamProvider.java
deleted file mode 100644
index 60a3dfc..0000000
--- a/features/core/src/main/java/org/apache/karaf/features/internal/deployment/StreamProvider.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.deployment;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-public interface StreamProvider {
-
-    InputStream open() throws IOException;
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/download/DownloadCallback.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/download/DownloadCallback.java b/features/core/src/main/java/org/apache/karaf/features/internal/download/DownloadCallback.java
new file mode 100644
index 0000000..b8fda6a
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/download/DownloadCallback.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.download;
+
+public interface DownloadCallback {
+
+    void downloaded(StreamProvider provider) throws Exception;
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/download/DownloadManager.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/download/DownloadManager.java b/features/core/src/main/java/org/apache/karaf/features/internal/download/DownloadManager.java
new file mode 100644
index 0000000..0bac194
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/download/DownloadManager.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.download;
+
+import java.util.Map;
+
+public interface DownloadManager {
+
+    Downloader createDownloader();
+
+    Map<String,StreamProvider> getProviders();
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/download/Downloader.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/download/Downloader.java b/features/core/src/main/java/org/apache/karaf/features/internal/download/Downloader.java
new file mode 100644
index 0000000..baf71a0
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/download/Downloader.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.download;
+
+import java.net.MalformedURLException;
+
+import org.apache.karaf.features.internal.util.MultiException;
+
+public interface Downloader {
+
+    void await() throws InterruptedException, MultiException;
+
+    void download(String location, DownloadCallback downloadCallback) throws MalformedURLException;
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/download/StreamProvider.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/download/StreamProvider.java b/features/core/src/main/java/org/apache/karaf/features/internal/download/StreamProvider.java
new file mode 100644
index 0000000..c25fa43
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/download/StreamProvider.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.download;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+public interface StreamProvider {
+
+    InputStream open() throws IOException;
+
+    Map<String, String> getMetadata() throws IOException;
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/download/simple/SimpleDownloader.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/download/simple/SimpleDownloader.java b/features/core/src/main/java/org/apache/karaf/features/internal/download/simple/SimpleDownloader.java
new file mode 100644
index 0000000..4569fe2
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/download/simple/SimpleDownloader.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.download.simple;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import org.apache.karaf.features.internal.download.DownloadCallback;
+import org.apache.karaf.features.internal.download.DownloadManager;
+import org.apache.karaf.features.internal.download.Downloader;
+import org.apache.karaf.features.internal.download.StreamProvider;
+import org.apache.karaf.features.internal.util.MultiException;
+
+public class SimpleDownloader implements DownloadManager, Downloader {
+
+    protected final MultiException exception = new MultiException("Error");
+
+    protected final ConcurrentMap<String, StreamProvider> providers = new ConcurrentHashMap<String, StreamProvider>();
+
+    @Override
+    public Downloader createDownloader() {
+        return this;
+    }
+
+    @Override
+    public void await() throws InterruptedException, MultiException {
+        exception.throwIfExceptions();
+    }
+
+    @Override
+    public void download(final String location, final DownloadCallback downloadCallback) throws MalformedURLException {
+        if (!providers.containsKey(location)) {
+            providers.putIfAbsent(location, createProvider(location));
+        }
+        try {
+            downloadCallback.downloaded(providers.get(location));
+        } catch (Exception e) {
+            exception.addException(e);
+        }
+    }
+
+    protected StreamProvider createProvider(String location) throws MalformedURLException {
+        return new UrlProvider(new URL(location));
+    }
+
+    public Map<String, StreamProvider> getProviders() {
+        return providers;
+    }
+
+    static class UrlProvider implements StreamProvider {
+        private final URL url;
+        private volatile Map<String, String> metadata;
+
+        UrlProvider(URL url) {
+            this.url = url;
+        }
+
+        @Override
+        public InputStream open() throws IOException {
+            return url.openStream();
+        }
+
+        @Override
+        public Map<String, String> getMetadata() throws IOException {
+            if (metadata == null) {
+                synchronized (this) {
+                    if (metadata == null) {
+                        metadata = doGetMetadata();
+                    }
+                }
+            }
+            return metadata;
+        }
+
+        protected Map<String, String> doGetMetadata() throws IOException {
+            InputStream is = open();
+            try {
+                ZipInputStream zis = new ZipInputStream(is);
+                ZipEntry entry;
+                while ((entry = zis.getNextEntry()) != null) {
+                    if ("META-INF/MANIFEST.MF".equals(entry.getName())) {
+                        Attributes attributes = new Manifest(zis).getMainAttributes();
+                        Map<String, String> headers = new HashMap<String, String>();
+                        for (Map.Entry attr : attributes.entrySet()) {
+                            headers.put(attr.getKey().toString(), attr.getValue().toString());
+                        }
+                        return headers;
+                    }
+                }
+            } finally {
+                is.close();
+            }
+            throw new IllegalArgumentException("Resource " + url + " does not contain a manifest");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/model/Feature.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/model/Feature.java b/features/core/src/main/java/org/apache/karaf/features/internal/model/Feature.java
index 46580da..0aa5eb5 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/model/Feature.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/model/Feature.java
@@ -75,7 +75,8 @@ import javax.xml.bind.annotation.XmlType;
     "bundle",
     "conditional",
     "capability",
-    "requirement"
+    "requirement",
+    "scoping"
 })
 public class Feature extends Content implements org.apache.karaf.features.Feature {
     public static String SPLIT_FOR_NAME_AND_VERSION = "/";
@@ -95,11 +96,10 @@ public class Feature extends Content implements org.apache.karaf.features.Featur
     protected String install;
     @XmlAttribute(name = "start-level")
     protected Integer startLevel;
-    @XmlAttribute
-    protected String region;
     protected List<Conditional> conditional;
     protected List<Capability> capability;
     protected List<Requirement> requirement;
+    protected Scoping scoping;
 
     public Feature() {
     }
@@ -280,15 +280,6 @@ public class Feature extends Content implements org.apache.karaf.features.Featur
         this.startLevel = value;
     }
 
-
-    public String getRegion() {
-        return region;
-    }
-
-    public void setRegion(String region) {
-        this.region = region;
-    }
-
     /**
      * Gets the value of the conditional property.
      * <p/>
@@ -330,6 +321,14 @@ public class Feature extends Content implements org.apache.karaf.features.Featur
         return this.requirement;
     }
 
+    public Scoping getScoping() {
+        return scoping;
+    }
+
+    public void setScoping(Scoping scoping) {
+        this.scoping = scoping;
+    }
+
     public String toString() {
     	return getId();
     }

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java b/features/core/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
index 2036452..9b5d7b6 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
@@ -41,6 +41,8 @@ import javax.xml.validation.SchemaFactory;
 
 import org.apache.karaf.features.FeaturesNamespaces;
 import org.apache.karaf.util.XmlUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
@@ -53,6 +55,7 @@ import org.xml.sax.helpers.XMLFilterImpl;
 
 public class JaxbUtil {
 
+    private static final Logger LOGGER = LoggerFactory.getLogger(JaxbUtil.class);
     private static final JAXBContext FEATURES_CONTEXT;
     static {
         try {
@@ -112,11 +115,16 @@ public class JaxbUtil {
                 doc = XmlUtils.parse(uri);
             }
 
-            Schema schema = getSchema(doc.getDocumentElement().getNamespaceURI());
-            try {
-                schema.newValidator().validate(new DOMSource(doc));
-            } catch (SAXException e) {
-                throw new IllegalArgumentException("Unable to validate " + uri, e);
+            String nsuri = doc.getDocumentElement().getNamespaceURI();
+            if (nsuri == null) {
+                LOGGER.warn("Old style feature file without namespace found (URI: {}). This format is deprecated and support for it will soon be removed", uri);
+            } else {
+                Schema schema = getSchema(nsuri);
+                try {
+                    schema.newValidator().validate(new DOMSource(doc));
+                } catch (SAXException e) {
+                    throw new IllegalArgumentException("Unable to validate " + uri, e);
+                }
             }
 
             fixDom(doc, doc.getDocumentElement());
@@ -162,12 +170,14 @@ public class JaxbUtil {
 
 
     private static void fixDom(Document doc, Node node) {
-        if (node.getNamespaceURI() != null && !FeaturesNamespaces.URI_CURRENT.equals(node.getNamespaceURI())) {
-            doc.renameNode(node, FeaturesNamespaces.URI_CURRENT, node.getLocalName());
-        }
-        NodeList children = node.getChildNodes();
-        for (int i = 0; i < children.getLength(); i++) {
-            fixDom(doc, children.item(i));
+        if (node.getNodeType() == Node.ELEMENT_NODE) {
+            if (!FeaturesNamespaces.URI_CURRENT.equals(node.getNamespaceURI())) {
+                doc.renameNode(node, FeaturesNamespaces.URI_CURRENT, node.getLocalName());
+            }
+            NodeList children = node.getChildNodes();
+            for (int i = 0; i < children.getLength(); i++) {
+                fixDom(doc, children.item(i));
+            }
         }
     }
 
@@ -177,7 +187,6 @@ public class JaxbUtil {
             XMLFilter xmlFilter = new NoSourceAndNamespaceFilter(XmlUtils.xmlReader());
             xmlFilter.setContentHandler(unmarshaller.getUnmarshallerHandler());
 
-
             InputSource is = new InputSource(uri);
             if (stream != null) {
                 is.setByteStream(stream);

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/model/ScopeFilter.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/model/ScopeFilter.java b/features/core/src/main/java/org/apache/karaf/features/internal/model/ScopeFilter.java
new file mode 100644
index 0000000..4b81fed
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/model/ScopeFilter.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.model;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "scopeFilter", propOrder = {
+        "value"
+})
+public class ScopeFilter implements org.apache.karaf.features.ScopeFilter {
+
+    @XmlAttribute(required = true)
+    protected String namespace;
+    @XmlValue
+    protected String value;
+
+    public String getNamespace() {
+        return namespace;
+    }
+
+    public void setNamespace(String namespace) {
+        this.namespace = namespace;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    @Override
+    public String getFilter() {
+        return getValue();
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/model/Scoping.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/model/Scoping.java b/features/core/src/main/java/org/apache/karaf/features/internal/model/Scoping.java
new file mode 100644
index 0000000..6773995
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/model/Scoping.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "scoping", propOrder = {
+        "imports",
+        "exports"
+})
+public class Scoping implements org.apache.karaf.features.Scoping {
+
+    @XmlAttribute
+    boolean acceptDependencies;
+    @XmlElement(name = "import")
+    List<ScopeFilter> imports;
+    @XmlElement(name = "export")
+    List<ScopeFilter> exports;
+
+    public List<ScopeFilter> getImport() {
+        if (imports == null) {
+            imports = new ArrayList<ScopeFilter>();
+        }
+        return imports;
+    }
+
+    public List<ScopeFilter> getExport() {
+        if (exports == null) {
+            exports = new ArrayList<ScopeFilter>();
+        }
+        return exports;
+    }
+
+    @Override
+    public boolean acceptDependencies() {
+        return acceptDependencies;
+    }
+
+    @Override
+    public List<? extends org.apache.karaf.features.ScopeFilter> getImports() {
+        return getImport();
+    }
+
+    @Override
+    public List<? extends org.apache.karaf.features.ScopeFilter> getExports() {
+        return getExport();
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/osgi/Activator.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/osgi/Activator.java b/features/core/src/main/java/org/apache/karaf/features/internal/osgi/Activator.java
index be0da05..0551d21 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/osgi/Activator.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/osgi/Activator.java
@@ -27,8 +27,10 @@ import java.util.Dictionary;
 import java.util.Hashtable;
 import java.util.Properties;
 
+import org.apache.felix.resolver.ResolverImpl;
 import org.apache.karaf.features.FeaturesListener;
 import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.internal.resolver.Slf4jResolverLog;
 import org.apache.karaf.features.internal.service.EventAdminListener;
 import org.apache.karaf.features.internal.service.FeatureConfigInstaller;
 import org.apache.karaf.features.internal.service.FeatureFinder;
@@ -36,25 +38,35 @@ import org.apache.karaf.features.internal.service.BootFeaturesInstaller;
 import org.apache.karaf.features.internal.service.FeaturesServiceImpl;
 import org.apache.karaf.features.internal.service.StateStorage;
 import org.apache.karaf.features.internal.management.FeaturesServiceMBeanImpl;
-import org.apache.karaf.features.RegionsPersistence;
 import org.apache.karaf.util.tracker.BaseActivator;
 import org.apache.karaf.util.tracker.SingleServiceTracker;
+import org.eclipse.equinox.internal.region.DigraphHelper;
+import org.eclipse.equinox.internal.region.StandardRegionDigraph;
+import org.eclipse.equinox.internal.region.management.StandardManageableRegionDigraph;
+import org.eclipse.equinox.region.RegionDigraph;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
+import org.osgi.framework.hooks.bundle.CollisionHook;
+import org.osgi.framework.hooks.resolver.ResolverHookFactory;
 import org.osgi.service.cm.ConfigurationAdmin;
 import org.osgi.service.cm.ManagedService;
+import org.osgi.service.resolver.Resolver;
 import org.osgi.service.url.URLStreamHandlerService;
 import org.osgi.util.tracker.ServiceTracker;
 import org.osgi.util.tracker.ServiceTrackerCustomizer;
+import org.slf4j.LoggerFactory;
 
 public class Activator extends BaseActivator {
 
     public static final String FEATURES_REPOS_PID = "org.apache.karaf.features.repos";
     public static final String FEATURES_SERVICE_CONFIG_FILE = "org.apache.karaf.features.cfg";
 
+    private static final String STATE_FILE = "state.json";
+
     private ServiceTracker<FeaturesListener, FeaturesListener> featuresListenerTracker;
     private FeaturesServiceImpl featuresService;
-    private SingleServiceTracker<RegionsPersistence> regionsTracker;
+    private StandardRegionDigraph digraph;
+    private StandardManageableRegionDigraph digraphMBean;
 
     public Activator() {
         // Special case here, as we don't want the activator to wait for current job to finish,
@@ -87,32 +99,28 @@ public class Activator extends BaseActivator {
             return;
         }
 
+        // Resolver
+        register(Resolver.class, new ResolverImpl(new Slf4jResolverLog(LoggerFactory.getLogger(ResolverImpl.class))));
+
+        // RegionDigraph
+        digraph = DigraphHelper.loadDigraph(bundleContext);
+        register(ResolverHookFactory.class, digraph.getResolverHookFactory());
+        register(CollisionHook.class, DigraphHelper.getCollisionHook(digraph));
+        register(org.osgi.framework.hooks.bundle.FindHook.class, digraph.getBundleFindHook());
+        register(org.osgi.framework.hooks.bundle.EventHook.class, digraph.getBundleEventHook());
+        register(org.osgi.framework.hooks.service.FindHook.class, digraph.getServiceFindHook());
+        register(org.osgi.framework.hooks.service.EventHook.class, digraph.getServiceEventHook());
+        register(RegionDigraph.class, digraph);
+        digraphMBean = new StandardManageableRegionDigraph(digraph, "org.apache.karaf", bundleContext);
+        digraphMBean.registerMBean();
+
+
         FeatureFinder featureFinder = new FeatureFinder();
         Hashtable<String, Object> props = new Hashtable<String, Object>();
         props.put(Constants.SERVICE_PID, FEATURES_REPOS_PID);
         register(ManagedService.class, featureFinder, props);
 
-        // TODO: region support
-//        final BundleManager bundleManager = new BundleManager(bundleContext);
-//        regionsTracker = new SingleServiceTracker<RegionsPersistence>(bundleContext, RegionsPersistence.class,
-//                new SingleServiceTracker.SingleServiceListener() {
-//                    @Override
-//                    public void serviceFound() {
-//                        bundleManager.setRegionsPersistence(regionsTracker.getService());
-//                    }
-//                    @Override
-//                    public void serviceLost() {
-//                        serviceFound();
-//                    }
-//                    @Override
-//                    public void serviceReplaced() {
-//                        serviceFound();
-//                    }
-//                });
-//        regionsTracker.open();
-
-
-        FeatureConfigInstaller configInstaller = new FeatureConfigInstaller(configurationAdmin);
+       FeatureConfigInstaller configInstaller = new FeatureConfigInstaller(configurationAdmin);
         // TODO: honor respectStartLvlDuringFeatureStartup and respectStartLvlDuringFeatureUninstall
 //        boolean respectStartLvlDuringFeatureStartup = getBoolean("respectStartLvlDuringFeatureStartup", true);
 //        boolean respectStartLvlDuringFeatureUninstall = getBoolean("respectStartLvlDuringFeatureUninstall", true);
@@ -123,7 +131,7 @@ public class Activator extends BaseActivator {
         StateStorage stateStorage = new StateStorage() {
             @Override
             protected InputStream getInputStream() throws IOException {
-                File file = bundleContext.getDataFile("FeaturesServiceState.properties");
+                File file = bundleContext.getDataFile(STATE_FILE);
                 if (file.exists()) {
                     return new FileInputStream(file);
                 } else {
@@ -133,7 +141,7 @@ public class Activator extends BaseActivator {
 
             @Override
             protected OutputStream getOutputStream() throws IOException {
-                File file = bundleContext.getDataFile("FeaturesServiceState.properties");
+                File file = bundleContext.getDataFile(STATE_FILE);
                 return new FileOutputStream(file);
             }
         };
@@ -150,6 +158,7 @@ public class Activator extends BaseActivator {
                                 featureFinder,
                                 eventAdminListener,
                                 configInstaller,
+                                digraph,
                                 overrides,
                                 featureResolutionRange,
                                 bundleUpdateRange,
@@ -191,9 +200,9 @@ public class Activator extends BaseActivator {
     }
 
     protected void doStop() {
-        if (regionsTracker != null) {
-            regionsTracker.close();
-            regionsTracker = null;
+        if (digraphMBean != null) {
+            digraphMBean.unregisterMbean();
+            digraphMBean = null;
         }
         if (featuresListenerTracker != null) {
             featuresListenerTracker.close();
@@ -203,6 +212,14 @@ public class Activator extends BaseActivator {
         if (featuresService != null) {
             featuresService = null;
         }
+        if (digraph != null) {
+            try {
+                DigraphHelper.saveDigraph(bundleContext, digraph);
+            } catch (Exception e) {
+                // Ignore
+            }
+            digraph = null;
+        }
     }
 
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/region/AbstractRegionDigraphVisitor.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/region/AbstractRegionDigraphVisitor.java b/features/core/src/main/java/org/apache/karaf/features/internal/region/AbstractRegionDigraphVisitor.java
new file mode 100644
index 0000000..3ad2325
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/region/AbstractRegionDigraphVisitor.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.region;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.equinox.region.Region;
+import org.eclipse.equinox.region.RegionDigraphVisitor;
+import org.eclipse.equinox.region.RegionFilter;
+
+/**
+ * {@link AbstractRegionDigraphVisitor} is an abstract base class for {@link RegionDigraphVisitor} implementations
+ */
+public abstract class AbstractRegionDigraphVisitor<C> implements RegionDigraphVisitor {
+
+    private final Collection<C> allCandidates;
+    private final Deque<Set<C>> allowedDeque = new ArrayDeque<Set<C>>();
+    private final Deque<Collection<C>> filteredDeque = new ArrayDeque<Collection<C>>();
+    private Set<C> allowed = new HashSet<C>();
+
+    public AbstractRegionDigraphVisitor(Collection<C> candidates) {
+        this.allCandidates = candidates;
+    }
+
+    public Collection<C> getAllowed() {
+        return allowed;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean visit(Region region) {
+        Collection<C> candidates = filteredDeque.isEmpty() ? allCandidates : filteredDeque.peek();
+        for (C candidate : candidates) {
+            if (contains(region, candidate)) {
+                allowed.add(candidate);
+            }
+        }
+        // there is no need to traverse edges of this region,
+        // it contains all the remaining filtered candidates
+        return !allowed.containsAll(candidates);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean preEdgeTraverse(RegionFilter regionFilter) {
+        // Find the candidates filtered by the previous edge
+        Collection<C> filtered = filteredDeque.isEmpty() ? allCandidates : filteredDeque.peek();
+        Collection<C> candidates = new ArrayList<C>(filtered);
+        // remove any candidates contained in the current region
+        candidates.removeAll(allowed);
+        // apply the filter across remaining candidates
+        Iterator<C> i = candidates.iterator();
+        while (i.hasNext()) {
+            C candidate = i.next();
+            if (!isAllowed(candidate, regionFilter)) {
+                i.remove();
+            }
+        }
+        if (candidates.isEmpty())
+            return false; // this filter does not apply; avoid traversing this edge
+        // push the filtered candidates for the next region
+        filteredDeque.push(candidates);
+        // push the allowed
+        allowedDeque.push(allowed);
+        allowed = new HashSet<C>();
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void postEdgeTraverse(RegionFilter regionFilter) {
+        filteredDeque.poll();
+        Collection<C> candidates = allowed;
+        allowed = allowedDeque.pop();
+        allowed.addAll(candidates);
+    }
+
+    /**
+     * Determines whether the given region contains the given candidate.
+     *
+     * @param region the {@link Region}
+     * @param candidate the candidate
+     * @return <code>true</code> if and only if the given region contains the given candidate
+     */
+    protected abstract boolean contains(Region region, C candidate);
+
+    /**
+     * Determines whether the given candidate is allowed by the given {@link RegionFilter}.
+     *
+     * @param candidate the candidate
+     * @param filter the filter
+     * @return <code>true</code> if and only if the given candidate is allowed by the given filter
+     */
+    protected abstract boolean isAllowed(C candidate, RegionFilter filter);
+}
\ No newline at end of file