Author: jawi
Date: Fri Jan 15 13:34:41 2016
New Revision: 1724802

URL: http://svn.apache.org/viewvc?rev=1724802&view=rev
Log:
Code review:

- cleaned up the code to use more recent Java constructs, such as foreach
  loops;
- cleaned up the test cases to make them a bit more readable and easier to
  maintain by folding some duplicate code into helper methods;
- fixed a corner case in which an AutoConf resource drops a configuration while
  updating existing ones at the same time. A NPE could be thrown in this
  situation due ConfigurationAdmin not being present;
- fixed a corner case in which a resource is dropped twice. A IOException could
  be thrown;
- moved some really specific MetaType code to a utility class;
- added some test cases for PersistencyManager;
- applied the code formatting guidelines for Apache Felix.


Added:
    
felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/MetaTypeUtil.java
   (with props)
    
felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/PersistencyManagerTest.java
   (with props)
Modified:
    felix/trunk/deploymentadmin/autoconf/pom.xml
    
felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/Activator.java
    
felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/AutoConfResource.java
    
felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/AutoConfResourceProcessor.java
    
felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/PersistencyManager.java
    
felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/AutoConfResourceProcessorTest.java
    
felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/DefaultNullObject.java
    
felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/Utils.java

Modified: felix/trunk/deploymentadmin/autoconf/pom.xml
URL: 
http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/autoconf/pom.xml?rev=1724802&r1=1724801&r2=1724802&view=diff
==============================================================================
--- felix/trunk/deploymentadmin/autoconf/pom.xml (original)
+++ felix/trunk/deploymentadmin/autoconf/pom.xml Fri Jan 15 13:34:41 2016
@@ -85,9 +85,19 @@
                         <Bundle-Name>Apache Felix AutoConf Resource 
Processor</Bundle-Name>
                         <Bundle-Description>A customizer bundle that publishes 
a Resource Processor service that processes configuration resources shipped in 
a Deployment Package.</Bundle-Description>
                         <Bundle-Vendor>The Apache Software 
Foundation</Bundle-Vendor>
-                        
<Private-Package>org.apache.felix.deployment.rp.autoconf, 
org.apache.felix.metatype, org.apache.felix.metatype.internal.l10n, 
org.apache.felix.metatype.internal, org.kxml2.io;-split-package:=merge-first, 
org.xmlpull.v1;-split-package:=merge-first, 
org.osgi.service.metatype;-split-package:=merge-first</Private-Package>
-                        
<Import-Package>org.apache.felix.dm,org.osgi.service.deploymentadmin,org.osgi.service.deploymentadmin.spi,org.osgi.service.event,org.osgi.service.log,*</Import-Package>
-                        
<Export-Package>org.osgi.service.deploymentadmin.spi;version="1.0",org.osgi.service.metatype;version="1.2"</Export-Package>
+                        <Private-Package>
+                               org.apache.felix.deployment.rp.autoconf,
+                               org.apache.felix.metatype,
+                               org.apache.felix.metatype.internal.l10n,
+                               org.apache.felix.metatype.internal,
+                               org.kxml2.io; -split-package:=merge-first,
+                               org.xmlpull.v1; -split-package:=merge-first,
+                               org.osgi.service.metatype; 
-split-package:=merge-first
+                               </Private-Package>
+                        <Export-Package>
+                               org.osgi.service.deploymentadmin.spi; 
-split-package:=merge-last;version="1.0",
+                               org.osgi.service.metatype; 
-split-package:=merge-last;version="1.2"
+                               </Export-Package>
                         
<DeploymentPackage-Customizer>true</DeploymentPackage-Customizer>
                         
<Deployment-ProvidesResourceProcessor>org.osgi.deployment.rp.autoconf</Deployment-ProvidesResourceProcessor>
                     </instructions>

Modified: 
felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/Activator.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/Activator.java?rev=1724802&r1=1724801&r2=1724802&view=diff
==============================================================================
--- 
felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/Activator.java
 (original)
+++ 
felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/Activator.java
 Fri Jan 15 13:34:41 2016
@@ -38,7 +38,7 @@ public class Activator extends Dependenc
     public void init(BundleContext context, DependencyManager manager) throws 
Exception {
        Dictionary properties = new Properties();
         properties.put(Constants.SERVICE_PID, 
"org.osgi.deployment.rp.autoconf");
-        
+
         AutoConfResourceProcessor processor = new AutoConfResourceProcessor();
         manager.add(createComponent()
             .setInterface(ResourceProcessor.class.getName(), properties)

Modified: 
felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/AutoConfResource.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/AutoConfResource.java?rev=1724802&r1=1724801&r2=1724802&view=diff
==============================================================================
--- 
felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/AutoConfResource.java
 (original)
+++ 
felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/AutoConfResource.java
 Fri Jan 15 13:34:41 2016
@@ -18,95 +18,146 @@
  */
 package org.apache.felix.deployment.rp.autoconf;
 
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.io.Serializable;
 import java.util.Dictionary;
 
-public class AutoConfResource implements Serializable {
-
-       private static final long serialVersionUID = 1L;
-       
-       private final String m_pid;
-       private final String m_factoryPid;
-       private final Dictionary m_properties;
-       private final String m_bundleLoc;
-       private final boolean m_merge;
-       private final String m_name;
-       private final String m_filter;
-
-       private String m_alias = null;
-
-       
-       public AutoConfResource(String name, String pid, String factoryPid, 
String bundleLocation, boolean merge, Dictionary properties, String filter) {
-               m_name = name;
-               m_pid = pid;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+
+public class AutoConfResource implements Serializable
+{
+    private static final long serialVersionUID = 1L;
+
+    private final String m_pid;
+    private final String m_factoryPid;
+    private final Dictionary m_properties;
+    private final String m_bundleLoc;
+    private final boolean m_merge;
+    private final String m_name;
+
+    private transient Filter m_filter;
+    private String m_alias = null;
+
+    public AutoConfResource(String name, String pid, String factoryPid, String 
bundleLocation, boolean merge, Dictionary properties, Filter filter)
+    {
+        m_name = name;
+        m_pid = pid;
         m_filter = filter;
-               m_factoryPid = (factoryPid == null) ? "" : factoryPid;
-               m_bundleLoc = bundleLocation;
-               m_merge = merge;
-               m_properties = properties;
-       }
-
-       public String getName() {
-               return m_name;
-       }
-       
-       public String getPid() {
-               return m_pid;
-       }
-       
-       public String getFilter() {
+        m_factoryPid = (factoryPid == null) ? "" : factoryPid;
+        m_bundleLoc = bundleLocation;
+        m_merge = merge;
+        m_properties = properties;
+    }
+
+    public String getName()
+    {
+        return m_name;
+    }
+
+    public String getPid()
+    {
+        return m_pid;
+    }
+
+    public Filter getFilter()
+    {
         return m_filter;
     }
 
-       /**
-        * Returns empty string if this configuration is not a factory 
configuration, otherwise the factory
-        * PID is returned.
-        * 
-        * @return Empty string if this is not a factory configuration 
resource, else the factory PID is returned.
-        */
-       public String getFactoryPid() {
-               return m_factoryPid;
-       }
-
-       public Dictionary getProperties() {
-               return m_properties;
-       }
-       
-       public String getBundleLocation() {
-               return m_bundleLoc;
-       }
-       
-       public boolean isMerge() {
-               return m_merge;
-       }
-       
-       public boolean isFactoryConfig() {
-               return !(m_factoryPid == null || "".equals(m_factoryPid));
-       }
-       
-       public void setGeneratedPid(String alias) {
-               m_alias = alias;
-       }
-       
-       public String getGeneratedPid() {
-               if (m_alias == null) {
-                       throw new IllegalStateException("Must set an alias 
first.");
-               }
-               return m_alias;
-       }
-       
-       /**
-        * Determine if the specified <code>AutoConfResource</code> is meant to 
be used for the same <code>Configuration</code> as this object.
-        *  
-        * @param resource The <code>AutoConfResource</code> to compare with.
-        * @return Returns <code>true</code> if the two resources are meant to 
be used for the same <code>Configuration</code> object, false otherwise.
-        */
-       public boolean equalsTargetConfiguration(AutoConfResource resource) {
-               if (isFactoryConfig()) {
-                       return m_pid.equals(resource.getPid()) && 
m_factoryPid.equals(resource.getFactoryPid());
-               }
-               else {
-                       return m_pid.equals(resource.getPid());
-               }
-       }
+    /**
+     * Returns empty string if this configuration is not a factory 
configuration, otherwise the factory
+     * PID is returned.
+     * 
+     * @return Empty string if this is not a factory configuration resource, 
else the factory PID is returned.
+     */
+    public String getFactoryPid()
+    {
+        return m_factoryPid;
+    }
+
+    public Dictionary getProperties()
+    {
+        return m_properties;
+    }
+
+    public String getBundleLocation()
+    {
+        return m_bundleLoc;
+    }
+
+    public boolean isMerge()
+    {
+        return m_merge;
+    }
+
+    public boolean isFactoryConfig()
+    {
+        return !(m_factoryPid == null || "".equals(m_factoryPid));
+    }
+
+    public void setGeneratedPid(String alias)
+    {
+        m_alias = alias;
+    }
+
+    public String getGeneratedPid()
+    {
+        if (m_alias == null)
+        {
+            throw new IllegalStateException("Must set an alias first.");
+        }
+        return m_alias;
+    }
+
+    /**
+     * Determine if the specified <code>AutoConfResource</code> is meant to be 
used for the same <code>Configuration</code> as this object.
+     *  
+     * @param resource The <code>AutoConfResource</code> to compare with.
+     * @return Returns <code>true</code> if the two resources are meant to be 
used for the same <code>Configuration</code> object, false otherwise.
+     */
+    public boolean equalsTargetConfiguration(AutoConfResource resource)
+    {
+        if (isFactoryConfig())
+        {
+            return m_pid.equals(resource.getPid()) && 
m_factoryPid.equals(resource.getFactoryPid());
+        }
+        else
+        {
+            return m_pid.equals(resource.getPid());
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException
+    {
+        out.defaultWriteObject();
+        if (m_filter != null)
+        {
+            out.writeUTF(m_filter.toString());
+        }
+        else
+        {
+            out.writeUTF("");
+        }
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, 
ClassNotFoundException
+    {
+        in.defaultReadObject();
+        String filter = in.readUTF();
+        if (!"".equals(filter))
+        {
+            try
+            {
+                m_filter = FrameworkUtil.createFilter(filter);
+            }
+            catch (InvalidSyntaxException e)
+            {
+                throw new IOException("Unable to parse serialized filter: " + 
e.getMessage());
+            }
+        }
+    }
 }

Modified: 
felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/AutoConfResourceProcessor.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/AutoConfResourceProcessor.java?rev=1724802&r1=1724801&r2=1724802&view=diff
==============================================================================
--- 
felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/AutoConfResourceProcessor.java
 (original)
+++ 
felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/AutoConfResourceProcessor.java
 Fri Jan 15 13:34:41 2016
@@ -18,33 +18,32 @@
  */
 package org.apache.felix.deployment.rp.autoconf;
 
+import static 
org.osgi.service.deploymentadmin.spi.ResourceProcessorException.CODE_OTHER_ERROR;
+
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.Dictionary;
 import java.util.Enumeration;
 import java.util.HashMap;
-import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
-import java.util.Set;
-import java.util.Vector;
+import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.felix.dm.Component;
 import org.apache.felix.dm.DependencyManager;
-import org.apache.felix.metatype.Attribute;
 import org.apache.felix.metatype.Designate;
+import org.apache.felix.metatype.DesignateObject;
 import org.apache.felix.metatype.MetaData;
 import org.apache.felix.metatype.MetaDataReader;
 import org.apache.felix.metatype.OCD;
 import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
 import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.cm.Configuration;
@@ -56,386 +55,495 @@ import org.osgi.service.event.Event;
 import org.osgi.service.event.EventConstants;
 import org.osgi.service.event.EventHandler;
 import org.osgi.service.log.LogService;
-import org.osgi.service.metatype.AttributeDefinition;
 import org.osgi.service.metatype.MetaTypeInformation;
 import org.osgi.service.metatype.MetaTypeService;
 import org.osgi.service.metatype.ObjectClassDefinition;
 
-public class AutoConfResourceProcessor implements ResourceProcessor, 
EventHandler {
-    private static final int CODE_OTHER_ERROR = 
ResourceProcessorException.CODE_OTHER_ERROR;
-    private static final String LOCATION_PREFIX = "osgi-dp:";
+public class AutoConfResourceProcessor implements ResourceProcessor, 
EventHandler
+{
     public static final String CONFIGURATION_ADMIN_FILTER_ATTRIBUTE = "filter";
 
-       // dependencies injected by Dependency Manager
-       private volatile LogService m_log;
-       private volatile ConfigurationAdmin m_configAdmin;
-       private volatile MetaTypeService m_metaService;
-       private volatile BundleContext m_bc;
+    private static final String LOCATION_PREFIX = "osgi-dp:";
+
+    // dependencies injected by Dependency Manager
+    private volatile LogService m_log;
+    private volatile MetaTypeService m_metaService;
     private volatile DependencyManager m_dm;
-    
-       private Component m_component;
-       
-       private final Object m_lock = new Object(); // protects the members 
below
-
-       private DeploymentSession m_session = null;
-       private final Map m_toBeInstalled = new HashMap(); // Map<String, 
List<AutoConfResource>>
-       private final Map m_toBeDeleted = new HashMap();
-       
-       private PersistencyManager m_persistencyManager;
-
-       public void start() throws IOException {
-               File root = m_bc.getDataFile("");
-               if (root == null) {
-                       throw new IOException("No file system support");
-               }
-               m_persistencyManager = new PersistencyManager(root);
-       }
-       
-    public void begin(DeploymentSession session) {
+    // Locally managed
+    private Component m_component;
+    private PersistencyManager m_persistencyManager;
+
+    private final Object m_lock; // protects the members below
+    private final Map<String, List<AutoConfResource>> m_toBeInstalled;
+    private final Map<String, List<AutoConfResource>> m_toBeDeleted;
+    private final AtomicReference<DeploymentSession> m_sessionRef;
+    private final List<ConfigurationAdminTask> m_configurationAdminTasks;
+    private final List<PostCommitTask> m_postCommitTasks;
+
+    public AutoConfResourceProcessor()
+    {
+        m_lock = new Object();
+        m_sessionRef = new AtomicReference<DeploymentSession>();
+        m_toBeInstalled = new HashMap<String, List<AutoConfResource>>();
+        m_toBeDeleted = new HashMap<String, List<AutoConfResource>>();
+        m_configurationAdminTasks = new ArrayList<ConfigurationAdminTask>();
+        m_postCommitTasks = new ArrayList<PostCommitTask>();
+    }
+
+    /**
+     * Called by Felix DM for the component created in {@link #commit()}.
+     */
+    public void addConfigurationAdmin(ServiceReference ref, ConfigurationAdmin 
ca)
+    {
+        m_log.log(LogService.LOG_DEBUG, "found configuration admin " + ref);
+
+        List<ConfigurationAdminTask> configAdminTasks;
+        synchronized (m_lock)
+        {
+            configAdminTasks = new 
ArrayList<ConfigurationAdminTask>(m_configurationAdminTasks);
+        }
+
+        for (ConfigurationAdminTask task : configAdminTasks)
+        {
+            try
+            {
+                Filter filter = task.getFilter();
+                if ((filter == null) || (filter != null && filter.match(ref)))
+                {
+                    task.run(m_persistencyManager, ca);
+                }
+            }
+            catch (Exception e)
+            {
+                m_log.log(LogService.LOG_ERROR, "Exception during 
configuration to " + ca + ". Trying to continue.", e);
+            }
+        }
+
+        m_log.log(LogService.LOG_DEBUG, "found configuration admin " + ref + " 
done");
+    }
+
+    public void begin(DeploymentSession session)
+    {
         m_log.log(LogService.LOG_DEBUG, "beginning session " + session);
-        synchronized (m_lock) {
-            if (m_session != null) {
+
+        synchronized (m_lock)
+        {
+            DeploymentSession current = m_sessionRef.get();
+            if (current != null)
+            {
                 throw new IllegalArgumentException("Trying to begin new 
deployment session while already in one.");
             }
-            if (session == null) {
+            if (session == null)
+            {
                 throw new IllegalArgumentException("Trying to begin new 
deployment session with a null session.");
             }
-            if (!m_toBeInstalled.isEmpty() || !m_toBeDeleted.isEmpty() || 
!m_configurationAdminTasks.isEmpty() || !m_postCommitTasks.isEmpty() || 
m_component != null) {
+            if (!m_toBeInstalled.isEmpty() || !m_toBeDeleted.isEmpty() || 
!m_configurationAdminTasks.isEmpty() || !m_postCommitTasks.isEmpty() || 
m_component != null)
+            {
                 throw new IllegalStateException("State not reset correctly at 
start of session.");
             }
-            m_session = session;
+            m_sessionRef.set(session);
         }
     }
- 
-    public void process(String name, InputStream stream) throws 
ResourceProcessorException {
-        m_log.log(LogService.LOG_DEBUG, "processing " + name);
-        // initial validation
-        synchronized (m_lock) {
-            if (m_session == null) {
-                throw new ResourceProcessorException(CODE_OTHER_ERROR, "Can 
not process resource without a Deployment Session");
+
+    public void cancel()
+    {
+        m_log.log(LogService.LOG_DEBUG, "cancel");
+        rollback();
+    }
+
+    public void commit()
+    {
+        m_log.log(LogService.LOG_DEBUG, "commit");
+
+        Dictionary properties = new Properties();
+        properties.put(EventConstants.EVENT_TOPIC, 
org.apache.felix.deploymentadmin.Constants.EVENTTOPIC_COMPLETE);
+        m_component = m_dm.createComponent()
+            .setInterface(EventHandler.class.getName(), properties)
+            .setImplementation(this)
+            .setCallbacks(null, null, null, null)
+            .setAutoConfig(Component.class, false)
+            .add(m_dm.createServiceDependency()
+                    .setService(ConfigurationAdmin.class)
+                    .setCallbacks("addConfigurationAdmin", null)
+                    .setRequired(false)
+        );
+        m_dm.add(m_component);
+
+        m_log.log(LogService.LOG_DEBUG, "commit done");
+    }
+
+    public void dropAllResources() throws ResourceProcessorException
+    {
+        m_log.log(LogService.LOG_DEBUG, "drop all resources");
+
+        assertInDeploymentSession("Can not drop all resources without a 
Deployment Session");
+
+        for (String name : m_persistencyManager.getResourceNames())
+        {
+            dropped(name);
+        }
+
+        m_log.log(LogService.LOG_DEBUG, "drop all resources done");
+    }
+
+    public void dropped(String name) throws ResourceProcessorException
+    {
+        m_log.log(LogService.LOG_DEBUG, "dropped " + name);
+
+        assertInDeploymentSession("Can not drop resource without a Deployment 
Session");
+
+        Map<String, List<AutoConfResource>> toBeDeleted;
+        synchronized (m_lock)
+        {
+            toBeDeleted = new HashMap<String, 
List<AutoConfResource>>(m_toBeDeleted);
+        }
+
+        try
+        {
+            List<AutoConfResource> resources = m_persistencyManager.load(name);
+
+            if (!toBeDeleted.containsKey(name))
+            {
+                toBeDeleted.put(name, new ArrayList());
             }
+            toBeDeleted.get(name).addAll(resources);
         }
-        MetaDataReader reader = new MetaDataReader();
-        MetaData data = null;
-        try {
-            data = reader.parse(stream);
+        catch (IOException ioe)
+        {
+            throw new ResourceProcessorException(CODE_OTHER_ERROR, "Unable to 
drop resource: " + name, ioe);
         }
-        catch (IOException e) {
-            throw new ResourceProcessorException(CODE_OTHER_ERROR, "Unable to 
process resource.", e);
+
+        synchronized (m_lock)
+        {
+            m_toBeDeleted.putAll(toBeDeleted);
         }
-        if (data == null) {
-            throw new ResourceProcessorException(CODE_OTHER_ERROR, "Supplied 
configuration is not conform the metatype xml specification.");
+
+        m_log.log(LogService.LOG_DEBUG, "dropped " + name + " done");
+    }
+
+    public void handleEvent(Event event)
+    {
+        // regardless of the outcome, we simply invoke postcommit
+        postcommit();
+    }
+
+    public void postcommit()
+    {
+        m_log.log(LogService.LOG_DEBUG, "post commit");
+
+        List<PostCommitTask> postCommitTasks;
+        synchronized (m_lock)
+        {
+            postCommitTasks = new ArrayList<PostCommitTask>(m_postCommitTasks);
         }
-        // process resources
-        String filter = null;
-        Map optionalAttributes = data.getOptionalAttributes();
-        if (optionalAttributes != null) {
-            filter = (String) 
optionalAttributes.get(AutoConfResourceProcessor.CONFIGURATION_ADMIN_FILTER_ATTRIBUTE);
+
+        for (PostCommitTask task : postCommitTasks)
+        {
+            try
+            {
+                task.run(m_persistencyManager);
+            }
+            catch (Exception e)
+            {
+                m_log.log(LogService.LOG_ERROR, "Exception during post commit 
wrap-up. Trying to continue.", e);
+            }
+        }
+
+        endSession();
+
+        m_log.log(LogService.LOG_DEBUG, "post commit done");
+    }
+
+    public void prepare() throws ResourceProcessorException
+    {
+        m_log.log(LogService.LOG_DEBUG, "prepare");
+
+        assertInDeploymentSession("Can not prepare resource without a 
Deployment Session");
+
+        Map<String, List<AutoConfResource>> toBeDeleted;
+        Map<String, List<AutoConfResource>> toBeInstalled;
+        synchronized (m_lock)
+        {
+            toBeDeleted = new HashMap<String, 
List<AutoConfResource>>(m_toBeDeleted);
+            toBeInstalled = new HashMap<String, 
List<AutoConfResource>>(m_toBeInstalled);
+        }
+
+        List<ConfigurationAdminTask> configAdminTasks = new 
ArrayList<ConfigurationAdminTask>();
+        List<PostCommitTask> postCommitTasks = new ArrayList<PostCommitTask>();
+
+        m_log.log(LogService.LOG_DEBUG, "prepare delete");
+        // delete dropped resources
+        for (Map.Entry<String, List<AutoConfResource>> entry : 
toBeDeleted.entrySet())
+        {
+            String name = entry.getKey();
+            for (AutoConfResource resource : entry.getValue())
+            {
+                configAdminTasks.add(new DropResourceTask(resource));
+            }
+            postCommitTasks.add(new DeleteResourceTask(name));
+        }
+
+        m_log.log(LogService.LOG_DEBUG, "prepare install/update");
+        // install new/updated resources
+        for (Map.Entry<String, List<AutoConfResource>> entry : 
toBeInstalled.entrySet())
+        {
+            String name = entry.getKey();
+
+            List<AutoConfResource> existingResources = null;
+            try
+            {
+                existingResources = m_persistencyManager.load(name);
+            }
+            catch (IOException ioe)
+            {
+                throw new 
ResourceProcessorException(ResourceProcessorException.CODE_PREPARE, "Unable to 
read existing resources for resource " + name, ioe);
+            }
+
+            List<AutoConfResource> resources = entry.getValue();
+            for (AutoConfResource resource : resources)
+            {
+                // When updating existing configurations, make sure that we 
delete the ones that have become obsolete... 
+                if (existingResources != null)
+                {
+                    Iterator<AutoConfResource> iter = 
existingResources.iterator();
+                    while (iter.hasNext())
+                    {
+                        AutoConfResource existing = iter.next();
+                        if (existing.equalsTargetConfiguration(resource))
+                        {
+                            iter.remove();
+                        }
+                    }
+                }
+
+                configAdminTasks.add(new 
InstallOrUpdateResourceTask(resource));
+            }
+            // remove existing configurations that were not in the new version 
of the resource
+            for (AutoConfResource existingResource : existingResources)
+            {
+                configAdminTasks.add(new DropResourceTask(existingResource));
+            }
+
+            postCommitTasks.add(new StoreResourceTask(name, resources));
+        }
+
+        synchronized (m_lock)
+        {
+            m_configurationAdminTasks.addAll(configAdminTasks);
+            m_postCommitTasks.addAll(postCommitTasks);
+        }
+
+        m_log.log(LogService.LOG_DEBUG, "prepare done");
+    }
+
+    public void process(String name, InputStream stream) throws 
ResourceProcessorException
+    {
+        m_log.log(LogService.LOG_DEBUG, "processing " + name);
+
+        // initial validation
+        assertInDeploymentSession("Can not process resource without a 
Deployment Session");
+
+        Map<String, List<AutoConfResource>> toBeInstalled;
+        synchronized (m_lock)
+        {
+            toBeInstalled = new HashMap<String, 
List<AutoConfResource>>(m_toBeInstalled);
         }
+
+        MetaData data = parseAutoConfResource(stream);
+        // process resources
+        Filter filter = getFilter(data);
+
         // add to session data
-        if (!m_toBeInstalled.containsKey(name)) {
-            m_toBeInstalled.put(name, new ArrayList());
+        if (!toBeInstalled.containsKey(name))
+        {
+            toBeInstalled.put(name, new ArrayList<AutoConfResource>());
         }
-        List designates = data.getDesignates();
-        if (designates == null || designates.isEmpty()) {
+
+        List<Designate> designates = data.getDesignates();
+        if (designates == null || designates.isEmpty())
+        {
             // if there are no designates, there's nothing to process
             m_log.log(LogService.LOG_INFO, "No designates found in the 
resource, so there's nothing to process.");
             return;
         }
-        Map localOcds = data.getObjectClassDefinitions();
-        if (localOcds == null) {
-            localOcds = Collections.EMPTY_MAP;
-        }
-        Iterator i = designates.iterator();
-        while (i.hasNext()) {
-            Designate designate = (Designate) i.next();
-            
+
+        Map<String, OCD> localOcds = data.getObjectClassDefinitions();
+        if (localOcds == null)
+        {
+            localOcds = Collections.emptyMap();
+        }
+
+        for (Designate designate : designates)
+        {
             // check object
-            if (designate.getObject() == null) {
+            DesignateObject objectDef = designate.getObject();
+            if (objectDef == null)
+            {
                 throw new ResourceProcessorException(CODE_OTHER_ERROR, 
"Designate Object child missing or invalid");
             }
-            
+
             // check attributes
-            if (designate.getObject().getAttributes() == null || 
designate.getObject().getAttributes().size() == 0) {
+            if (objectDef.getAttributes() == null || 
objectDef.getAttributes().isEmpty())
+            {
                 throw new ResourceProcessorException(CODE_OTHER_ERROR, "Object 
Attributes child missing or invalid");
             }
-            
+
             // check ocdRef
-            String ocdRef = designate.getObject().getOcdRef();
-            if (ocdRef == null || "".equals(ocdRef)) {
+            String ocdRef = objectDef.getOcdRef();
+            if (ocdRef == null || "".equals(ocdRef))
+            {
                 throw new ResourceProcessorException(CODE_OTHER_ERROR, "Object 
ocdRef attribute missing or invalid");
             }
 
             // determine OCD
             ObjectClassDefinition ocd = null;
-            OCD localOcd = (OCD) localOcds.get(ocdRef);
+            OCD localOcd = localOcds.get(ocdRef);
             // ask meta type service for matching OCD if no local OCD has been 
defined
             ocd = (localOcd != null) ? new ObjectClassDefinitionImpl(localOcd) 
: getMetaTypeOCD(data, designate);
-            if (ocd == null) {
+            if (ocd == null)
+            {
                 throw new ResourceProcessorException(CODE_OTHER_ERROR, "No 
Object Class Definition found with id=" + ocdRef);
             }
+
             // determine configuration data based on the values and their type 
definition
-            Dictionary dict = getProperties(designate, ocd);
-            if (dict == null) {
+            Dictionary dict = MetaTypeUtil.getProperties(designate, ocd);
+            if (dict == null)
+            {
                 // designate does not match it's definition, but was marked 
optional, ignore it
                 continue;
             }
-            List resources = (List) m_toBeInstalled.get(name);
-            resources.add(new AutoConfResource(name, designate.getPid(), 
designate.getFactoryPid(), designate.getBundleLocation(), designate.isMerge(), 
dict, filter));
-        }
-        m_log.log(LogService.LOG_DEBUG, "processing " + name + " done");
-    }
 
-    public void dropped(String name) throws ResourceProcessorException {
-        m_log.log(LogService.LOG_DEBUG, "dropped " + name);
-        synchronized (m_lock) {
-               if (m_session == null) {
-                       throw new ResourceProcessorException(CODE_OTHER_ERROR, 
"Can not process resource without a Deployment Session");
-               }
-        }
-       try {
-               List resources = m_persistencyManager.load(name);
-               if (!m_toBeDeleted.containsKey(name)) {
-                       m_toBeDeleted.put(name, new ArrayList());
-               }
-               ((List) m_toBeDeleted.get(name)).addAll(resources);
-       }
-       catch (IOException ioe) {
-               throw new ResourceProcessorException(CODE_OTHER_ERROR, "Unable 
to drop resource: " + name, ioe);
-       }
-        m_log.log(LogService.LOG_DEBUG, "dropped " + name + " done");
-    }
+            AutoConfResource resource = new AutoConfResource(name, 
designate.getPid(), designate.getFactoryPid(), designate.getBundleLocation(), 
designate.isMerge(), dict, filter);
+            
+            toBeInstalled.get(name).add(resource);
+        }
 
-    public void dropAllResources() throws ResourceProcessorException {
-        m_log.log(LogService.LOG_DEBUG, "drop all resources");
-        synchronized (m_lock) {
-               if (m_session == null) {
-                       throw new ResourceProcessorException(CODE_OTHER_ERROR, 
"Can not drop all resources without a Deployment Session");
-               }
-        }
-
-       File basedir = m_bc.getDataFile("");
-       if (basedir != null && basedir.isDirectory()) {
-               String[] files = basedir.list();
-               for (int i = 0; i < files.length; i++) {
-                       dropped(files[i]);
-               }
-       }
-       else {
-               throw new ResourceProcessorException(CODE_OTHER_ERROR, "Unable 
to drop resources, data area is not accessible");
-       }
-        m_log.log(LogService.LOG_DEBUG, "drop all resources done");
-    }
-    
-    private List m_configurationAdminTasks = new ArrayList();
-    private List m_postCommitTasks = new ArrayList();
+        synchronized (m_lock)
+        {
+            m_toBeInstalled.putAll(toBeInstalled);
+        }
 
-    public void prepare() throws ResourceProcessorException {
-        m_log.log(LogService.LOG_DEBUG, "prepare");
-        synchronized (m_lock) {
-               if (m_session == null) {
-                       throw new ResourceProcessorException(CODE_OTHER_ERROR, 
"Can not process resource without a Deployment Session");
-               }
-        }
-       try {
-            m_log.log(LogService.LOG_DEBUG, "prepare delete");
-               // delete dropped resources
-               for (Iterator i = m_toBeDeleted.keySet().iterator(); 
i.hasNext();) {
-                       String name = (String) i.next();
-                       List resources = (List) m_toBeDeleted.get(name);
-                       for (Iterator j = resources.iterator(); j.hasNext();) {
-                               AutoConfResource resource = (AutoConfResource) 
j.next();
-                               m_configurationAdminTasks.add(new 
DropResourceTask(resource));
-                       }
-                       m_postCommitTasks.add(new DeleteResourceTask(name));
-               }
-
-            m_log.log(LogService.LOG_DEBUG, "prepare install/update");
-               // install new/updated resources
-               for (Iterator j = m_toBeInstalled.keySet().iterator(); 
j.hasNext();) {
-                       String name = (String) j.next();
-                       List existingResources = null;
-                       try {
-                               existingResources = 
m_persistencyManager.load(name);
-                       }
-                       catch (IOException ioe) {
-                               throw new 
ResourceProcessorException(ResourceProcessorException.CODE_PREPARE, "Unable to 
read existing resources for resource " + name, ioe);
-                       }
-                       List resources = (List) m_toBeInstalled.get(name);
-                       for (Iterator iterator = resources.iterator(); 
iterator.hasNext();) {
-                               AutoConfResource resource = (AutoConfResource) 
iterator.next();
-                               m_configurationAdminTasks.add(new 
InstallOrUpdateResourceTask(resource));
-                       }
-                       // remove existing configurations that were not in the 
new version of the resource
-                       for (Iterator i = existingResources.iterator(); 
i.hasNext();) {
-                               AutoConfResource existingResource = 
(AutoConfResource) i.next();
-                               Configuration configuration = null;
-                               if (existingResource.isFactoryConfig()) {
-                                       configuration = 
m_configAdmin.getConfiguration(existingResource.getGeneratedPid(), 
existingResource.getBundleLocation());
-                               } else {
-                                       configuration = 
m_configAdmin.getConfiguration(existingResource.getPid(), 
existingResource.getBundleLocation());
-                               }
-                               configuration.delete();
-                       }
-                       m_postCommitTasks.add(new StoreResourceTask(name, 
resources));
-               }
-       }
-       catch (IOException ioe) {
-               m_toBeInstalled.clear();
-               throw new 
ResourceProcessorException(ResourceProcessorException.CODE_PREPARE, "Unable to 
prepare for commit for resource", ioe);
-       }
-        m_log.log(LogService.LOG_DEBUG, "prepare done");
+        m_log.log(LogService.LOG_DEBUG, "processing " + name + " done");
     }
 
-    public synchronized void commit() {
-        m_log.log(LogService.LOG_DEBUG, "commit");
+    public void rollback()
+    {
+        m_log.log(LogService.LOG_DEBUG, "rollback");
 
-        Dictionary properties = new Properties();
-        properties.put(EventConstants.EVENT_TOPIC, 
org.apache.felix.deploymentadmin.Constants.EVENTTOPIC_COMPLETE);
-        m_component = m_dm.createComponent()
-            .setInterface(EventHandler.class.getName(), properties)
-            .setImplementation(this)
-            .setCallbacks(null, null, null, null)
-            .setAutoConfig(Component.class, false)
-            .add(m_dm.createServiceDependency()
-                .setService(ConfigurationAdmin.class)
-                .setCallbacks("addConfigurationAdmin", null)
-                .setRequired(false));
-        m_dm.add(m_component);
+        Map<String, List<AutoConfResource>> toBeInstalled;
+        synchronized (m_lock)
+        {
+            toBeInstalled = new HashMap<String, 
List<AutoConfResource>>(m_toBeInstalled);
+        }
 
-        m_log.log(LogService.LOG_DEBUG, "commit done");
-    }
-    
-    public void addConfigurationAdmin(ServiceReference ref, ConfigurationAdmin 
ca) {
-        m_log.log(LogService.LOG_DEBUG, "found configuration admin " + ref);
-        Iterator iterator = m_configurationAdminTasks.iterator();
-        while (iterator.hasNext()) {
-            ConfigurationAdminTask task = (ConfigurationAdminTask) 
iterator.next();
-            try {
-                Filter filter = null;
-                String filterString = task.getFilter();
-                if (filterString != null) {
-                    try {
-                        filter = m_bc.createFilter(filterString);
-                    }
-                    catch (InvalidSyntaxException e) {
-                        m_log.log(LogService.LOG_ERROR, "Could not parse 
filter, ignoring it: " + filterString, e);
-                    }
+        for (Map.Entry<String, List<AutoConfResource>> entry : 
toBeInstalled.entrySet())
+        {
+            for (AutoConfResource resource : entry.getValue())
+            {
+                String name = resource.getName();
+                try
+                {
+                    dropped(name);
                 }
-                if (filter == null || filter != null && filter.match(ref)) {
-                    task.run(m_persistencyManager, ca);
+                catch (ResourceProcessorException e)
+                {
+                    m_log.log(LogService.LOG_ERROR, "Unable to roll back 
resource '" + name + "', reason: " + e.getMessage() + ", caused by: " + 
e.getCause().getMessage());
                 }
-            }
-            catch (Exception e) {
-                m_log.log(LogService.LOG_ERROR, "Exception during 
configuration to " + ca + ". Trying to continue.", e);
-            }
-        }
-        m_log.log(LogService.LOG_DEBUG, "found configuration admin " + ref + " 
done");
-    }
-    
-    public void postcommit() {
-        m_log.log(LogService.LOG_DEBUG, "post commit");
-        Iterator iterator = m_postCommitTasks.iterator();
-        while (iterator.hasNext()) {
-            PostCommitTask task = (PostCommitTask) iterator.next();
-            try {
-                task.run(m_persistencyManager);
-            }
-            catch (Exception e) {
-                m_log.log(LogService.LOG_ERROR, "Exception during post commit 
wrap-up. Trying to continue.", e);
+                break;
             }
         }
+
         endSession();
-        m_log.log(LogService.LOG_DEBUG, "post commit done");
+
+        m_log.log(LogService.LOG_DEBUG, "rollback done");
     }
 
-    private void endSession() {
-        if (m_component != null) {
-               m_dm.remove(m_component);
-            m_component = null;
+    /**
+     * Called by Felix DM when starting this component.
+     */
+    public void start() throws IOException
+    {
+        File root = m_dm.getBundleContext().getDataFile("");
+        if (root == null)
+        {
+            throw new IOException("No file system support");
         }
-        m_toBeInstalled.clear();
-        m_toBeDeleted.clear();
-        m_postCommitTasks.clear();
-        m_configurationAdminTasks.clear();
-        m_session = null;
+        m_persistencyManager = new PersistencyManager(root);
     }
 
-    public void rollback() {
-        m_log.log(LogService.LOG_DEBUG, "rollback");
-       Set keys = m_toBeInstalled.keySet();
-       for (Iterator i = keys.iterator(); i.hasNext();) {
-               List configs = (List) m_toBeInstalled.get(i.next());
-               for (Iterator j = configs.iterator(); j.hasNext();) {
-                       AutoConfResource resource = (AutoConfResource) j.next();
-                       String name = resource.getName();
-                       try {
-                               dropped(name);
-                       }
-                       catch (ResourceProcessorException e) {
-                               m_log.log(LogService.LOG_ERROR, "Unable to roll 
back resource '" + name + "', reason: " + e.getMessage() + ", caused by: " + 
e.getCause().getMessage());
-                       }
-                       break;
-               }
-       }
-       endSession();
-        m_log.log(LogService.LOG_DEBUG, "rollback done");
+    private void assertInDeploymentSession(String msg) throws 
ResourceProcessorException
+    {
+        synchronized (m_lock)
+        {
+            DeploymentSession current = m_sessionRef.get();
+            if (current == null)
+            {
+                throw new ResourceProcessorException(CODE_OTHER_ERROR, msg);
+            }
+        }
     }
 
-    public void cancel() {
-        m_log.log(LogService.LOG_DEBUG, "cancel");
-       rollback();
+    private void endSession()
+    {
+        if (m_component != null)
+        {
+            m_dm.remove(m_component);
+            m_component = null;
+        }
+        synchronized (m_lock)
+        {
+            m_toBeInstalled.clear();
+            m_toBeDeleted.clear();
+            m_postCommitTasks.clear();
+            m_configurationAdminTasks.clear();
+            m_sessionRef.set(null);
+        }
     }
 
-    /**
-     * Determines the actual configuration data based on the specified 
designate and object class definition
-     * 
-     * @param designate The designate object containing the values for the 
properties
-     * @param ocd The object class definition
-     * @return A dictionary containing data as described in the designate and 
ocd objects, or <code>null</code> if the designate does not match it's
-     * definition and the designate was marked as optional.
-     * @throws ResourceProcessorException If the designate does not match the 
ocd and the designate is not marked as optional.
-     */
-    private Dictionary getProperties(Designate designate, 
ObjectClassDefinition ocd) throws ResourceProcessorException {
-       Dictionary properties = new Hashtable();
-       AttributeDefinition[] attributeDefs = 
ocd.getAttributeDefinitions(ObjectClassDefinition.ALL);
-       List attributes = designate.getObject().getAttributes();
-
-       for (Iterator i = attributes.iterator(); i.hasNext();) {
-               Attribute attribute = (Attribute) i.next();
-
-               String adRef = attribute.getAdRef();
-               boolean found = false;
-               for(int j = 0; j < attributeDefs.length; j++) {
-                       AttributeDefinition ad = attributeDefs[j];
-                       if (adRef.equals(ad.getID())) {
-                               // found attribute definition
-                               Object value = getValue(attribute, ad);
-                               if (value == null) {
-                                       if (designate.isOptional()) {
-                                               properties = null;
-                                               break;
-                                       }
-                                       else {
-                                               throw new 
ResourceProcessorException(CODE_OTHER_ERROR, "Could not match attribute to it's 
definition: adref=" + adRef);
-                                       }
-                               }
-                               properties.put(adRef, value);
-                               found = true;
-                               break;
-                       }
-               }
-               if (!found) {
-                       if (designate.isOptional()) {
-                               properties = null;
-                               break;
-                       } else {
-                               throw new 
ResourceProcessorException(CODE_OTHER_ERROR, "Could not find attribute 
definition: adref=" + adRef);
-                       }
-               }
-       }
+    private Bundle getBundle(String bundleLocation, boolean isFactory) throws 
ResourceProcessorException
+    {
+        Bundle bundle = null;
+        if (!isFactory)
+        {
+            // singleton configuration, no foreign bundles allowed, use source 
deployment package to find specified bundle
+            if (bundleLocation.startsWith(LOCATION_PREFIX))
+            {
+                DeploymentSession session = m_sessionRef.get();
+                bundle = 
session.getSourceDeploymentPackage().getBundle(bundleLocation.substring(LOCATION_PREFIX.length()));
+            }
+        }
+        else
+        {
+            // factory configuration, foreign bundles allowed, use bundle 
context to find the specified bundle
+            Bundle[] bundles = m_dm.getBundleContext().getBundles();
+            for (int i = 0; i < bundles.length; i++)
+            {
+                String location = bundles[i].getLocation();
+                if (bundleLocation.equals(location))
+                {
+                    bundle = bundles[i];
+                    break;
+                }
+            }
+        }
+        return bundle;
+    }
 
-       return properties;
+    private Filter getFilter(MetaData data) throws ResourceProcessorException
+    {
+        Map optionalAttributes = data.getOptionalAttributes();
+        if (optionalAttributes != null)
+        {
+            try
+            {
+                return FrameworkUtil.createFilter((String) 
optionalAttributes.get(AutoConfResourceProcessor.CONFIGURATION_ADMIN_FILTER_ATTRIBUTE));
+            }
+            catch (InvalidSyntaxException e)
+            {
+                throw new ResourceProcessorException(CODE_OTHER_ERROR, "Unable 
to create filter!", e);
+            }
+        }
+        return null;
     }
 
     /**
@@ -446,198 +554,112 @@ public class AutoConfResourceProcessor i
      * @return
      * @throws ResourceProcessorException
      */
-    private ObjectClassDefinition getMetaTypeOCD(MetaData data, Designate 
designate) throws ResourceProcessorException {
-       ObjectClassDefinition ocd = null;
-       String ocdRef = designate.getObject().getOcdRef();
-       Bundle bundle = getBundle(designate.getBundleLocation(), 
isFactoryConfig(designate));
-       if (bundle != null) {
-               MetaTypeInformation mti = 
m_metaService.getMetaTypeInformation(bundle);
-               if (mti != null) {
-                       String pid = isFactoryConfig(designate) ? pid = 
designate.getFactoryPid() : designate.getPid();
-                       try {
-                               ObjectClassDefinition tempOcd = 
mti.getObjectClassDefinition(pid, null);
-                               // tempOcd will always have a value, if pid was 
not known IAE will be thrown
-                               if (ocdRef.equals(tempOcd.getID())) {
-                                       ocd = tempOcd;
-                               }
-                       }
-                       catch (IllegalArgumentException iae) {
-                               // let null be returned
-                       }
-               }
-       }
-       return ocd;
-    }
-
-    private boolean isFactoryConfig(Designate designate) {
-       String factoryPid = designate.getFactoryPid();
-       return (factoryPid != null && !"".equals(factoryPid));
-    }
-
-    private Bundle getBundle(String bundleLocation, boolean isFactory) throws 
ResourceProcessorException {
-       Bundle bundle = null;
-       if (!isFactory) {
-               // singleton configuration, no foreign bundles allowed, use 
source deployment package to find specified bundle
-               if (bundleLocation.startsWith(LOCATION_PREFIX)) {
-                       bundle = 
m_session.getSourceDeploymentPackage().getBundle(bundleLocation.substring(LOCATION_PREFIX.length()));
-               }
-       }
-       else {
-               // factory configuration, foreign bundles allowed, use bundle 
context to find the specified bundle
-               Bundle[] bundles = m_bc.getBundles();                           
                                                    
-               for (int i = 0; i < bundles.length; i++) {
-                       String location = bundles[i].getLocation();
-                       if (bundleLocation.equals(location)) {
-                               bundle = bundles[i];
-                               break;
-                       }
-               }
-       }
-       return bundle;
+    private ObjectClassDefinition getMetaTypeOCD(MetaData data, Designate 
designate) throws ResourceProcessorException
+    {
+        boolean isFactoryConfig = isFactoryConfig(designate);
+
+        Bundle bundle = getBundle(designate.getBundleLocation(), 
isFactoryConfig);
+        if (bundle == null)
+        {
+            return null;
+        }
+
+        MetaTypeInformation mti = m_metaService.getMetaTypeInformation(bundle);
+        if (mti == null)
+        {
+            return null;
+        }
+
+        String pid = isFactoryConfig ? pid = designate.getFactoryPid() : 
designate.getPid();
+        try
+        {
+            ObjectClassDefinition tempOcd = mti.getObjectClassDefinition(pid, 
null);
+            // tempOcd will always have a value, if pid was not known IAE will 
be thrown
+            String ocdRef = designate.getObject().getOcdRef();
+            if (ocdRef.equals(tempOcd.getID()))
+            {
+                return tempOcd;
+            }
+        }
+        catch (IllegalArgumentException iae)
+        {
+            // let null be returned
+        }
+
+        return null;
     }
 
-    /**
-     * Determines the value of an attribute based on an attribute definition
-     * 
-     * @param attribute The attribute containing value(s)
-     * @param ad The attribute definition
-     * @return An <code>Object</code> reflecting what was specified in the 
attribute and it's definition or <code>null</code> if the value did not match 
it's definition.
-     * @throws ResourceProcessorException in case we're unable to parse the 
value of an attribute.
-     */
-    private Object getValue(Attribute attribute, AttributeDefinition ad) 
throws ResourceProcessorException {
-       if (attribute == null || ad == null || 
!attribute.getAdRef().equals(ad.getID())) {
-               // wrong attribute or definition
-               return null;
-       }
-       String[] content = attribute.getContent();
-
-       // verify correct type of the value(s)
-       int type = ad.getType();
-       Object[] typedContent = null;
-       try {
-               for (int i = 0; i < content.length; i++) {
-                       String value = content[i];
-                       switch (type) {
-                               case AttributeDefinition.BOOLEAN:
-                                       typedContent = (typedContent == null) ? 
new Boolean[content.length] : typedContent;
-                                       typedContent[i] = 
Boolean.valueOf(value);       
-                                       break;
-                               case AttributeDefinition.BYTE:
-                                       typedContent = (typedContent == null) ? 
new Byte[content.length] : typedContent;
-                                       typedContent[i] = Byte.valueOf(value);
-                                       break;
-                               case AttributeDefinition.CHARACTER:
-                                       typedContent = (typedContent == null) ? 
new Character[content.length] : typedContent;
-                                       char[] charArray = value.toCharArray();
-                                       if (charArray.length == 1) {
-                                               typedContent[i] = new 
Character(charArray[0]);
-                                       }
-                                       else {
-                                   throw new 
ResourceProcessorException(CODE_OTHER_ERROR, "Unable to parse value for 
definition: adref=" + ad.getID());
-                                       }
-                                       break;
-                               case AttributeDefinition.DOUBLE:
-                                       typedContent = (typedContent == null) ? 
new Double[content.length] : typedContent;
-                                       typedContent[i] = Double.valueOf(value);
-                                       break;
-                               case AttributeDefinition.FLOAT:
-                                       typedContent = (typedContent == null) ? 
new Float[content.length] : typedContent;
-                                       typedContent[i] = Float.valueOf(value);
-                                       break;
-                               case AttributeDefinition.INTEGER:
-                                       typedContent = (typedContent == null) ? 
new Integer[content.length] : typedContent;
-                                       typedContent[i] = 
Integer.valueOf(value);
-                                       break;
-                               case AttributeDefinition.LONG:
-                                       typedContent = (typedContent == null) ? 
new Long[content.length] : typedContent;
-                                       typedContent[i] = Long.valueOf(value);
-                                       break;
-                               case AttributeDefinition.SHORT:
-                                       typedContent = (typedContent == null) ? 
new Short[content.length] : typedContent;
-                                       typedContent[i] = Short.valueOf(value);
-                                       break;
-                               case AttributeDefinition.STRING:
-                                       typedContent = (typedContent == null) ? 
new String[content.length] : typedContent;
-                                       typedContent[i] = value;
-                                       break;
-                               default:
-                                       // unsupported type
-                        throw new ResourceProcessorException(CODE_OTHER_ERROR, 
"Unsupported value-type for definition: adref=" + ad.getID());
-                       }
-               }
-       }
-       catch (NumberFormatException nfe) {
-            throw new ResourceProcessorException(CODE_OTHER_ERROR, "Unable to 
parse value for definition: adref=" + ad.getID());
-       }
-
-       // verify cardinality of value(s)
-       int cardinality = ad.getCardinality();
-       Object result = null;
-       if (cardinality == 0) {
-               if (typedContent.length == 1) {
-                       result = typedContent[0];
-               }
-               else {
-                       result = null;
-               }
-       }
-       else if (cardinality == Integer.MIN_VALUE) {
-               result = new Vector(Arrays.asList(typedContent));
-       }
-       else if (cardinality == Integer.MAX_VALUE) {
-               result = typedContent;
-       }
-       else if (cardinality < 0) {
-            if (typedContent.length <= Math.abs(cardinality)) {
-                       result = new Vector(Arrays.asList(typedContent));
-               }
-               else {
-                       result = null;
-               }
-       }
-       else if (cardinality > 0) {
-               if (typedContent.length <= cardinality) {
-                       result = typedContent;
-               }
-               else {
-                       result = null;
-               }
-       }
-       return result;
-    }
-
-    public void handleEvent(Event event) {
-       // regardless of the outcome, we simply invoke postcommit
-       postcommit();
+    private boolean isFactoryConfig(Designate designate)
+    {
+        String factoryPid = designate.getFactoryPid();
+        return (factoryPid != null && !"".equals(factoryPid));
+    }
+
+    private MetaData parseAutoConfResource(InputStream stream) throws 
ResourceProcessorException
+    {
+        MetaDataReader reader = new MetaDataReader();
+        MetaData data = null;
+        try
+        {
+            data = reader.parse(stream);
+        }
+        catch (IOException e)
+        {
+            throw new ResourceProcessorException(CODE_OTHER_ERROR, "Unable to 
process resource.", e);
+        }
+        if (data == null)
+        {
+            throw new ResourceProcessorException(CODE_OTHER_ERROR, "Supplied 
configuration is not conform the metatype xml specification.");
+        }
+        return data;
     }
 }
 
-interface ConfigurationAdminTask {
-    public String getFilter();
+interface ConfigurationAdminTask
+{
+    public Filter getFilter();
+
     public void run(PersistencyManager persistencyManager, ConfigurationAdmin 
configAdmin) throws Exception;
 }
 
-interface PostCommitTask {
-    public void run(PersistencyManager manager) throws Exception;
+class DeleteResourceTask implements PostCommitTask
+{
+    private final String m_name;
+
+    public DeleteResourceTask(String name)
+    {
+        m_name = name;
+    }
+
+    public void run(PersistencyManager manager) throws Exception
+    {
+        manager.delete(m_name);
+    }
 }
 
-class DropResourceTask implements ConfigurationAdminTask {
+class DropResourceTask implements ConfigurationAdminTask
+{
     private final AutoConfResource m_resource;
 
-    public DropResourceTask(AutoConfResource resource) {
+    public DropResourceTask(AutoConfResource resource)
+    {
         m_resource = resource;
     }
-    
-    public String getFilter() {
+
+    public Filter getFilter()
+    {
         return m_resource.getFilter();
     }
 
-    public void run(PersistencyManager persistencyManager, ConfigurationAdmin 
configAdmin) throws Exception {
+    public void run(PersistencyManager persistencyManager, ConfigurationAdmin 
configAdmin) throws Exception
+    {
         String pid;
-        if (m_resource.isFactoryConfig()) {
+        if (m_resource.isFactoryConfig())
+        {
             pid = m_resource.getGeneratedPid();
         }
-        else {
+        else
+        {
             pid = m_resource.getPid();
         }
         Configuration configuration = configAdmin.getConfiguration(pid, 
m_resource.getBundleLocation());
@@ -645,69 +667,87 @@ class DropResourceTask implements Config
     }
 }
 
-class InstallOrUpdateResourceTask implements ConfigurationAdminTask {
+class InstallOrUpdateResourceTask implements ConfigurationAdminTask
+{
     private final AutoConfResource m_resource;
 
-    public InstallOrUpdateResourceTask(AutoConfResource resource) {
+    public InstallOrUpdateResourceTask(AutoConfResource resource)
+    {
         m_resource = resource;
     }
 
-    public String getFilter() {
+    public Filter getFilter()
+    {
         return m_resource.getFilter();
     }
 
-    public void run(PersistencyManager persistencyManager, ConfigurationAdmin 
configAdmin) throws Exception {
+    public void run(PersistencyManager persistencyManager, ConfigurationAdmin 
configAdmin) throws Exception
+    {
         String name = m_resource.getName();
         Dictionary properties = m_resource.getProperties();
         String bundleLocation = m_resource.getBundleLocation();
         Configuration configuration = null;
 
         List existingResources = null;
-        try {
+        try
+        {
             existingResources = persistencyManager.load(name);
         }
-        catch (IOException ioe) {
+        catch (IOException ioe)
+        {
             throw new 
ResourceProcessorException(ResourceProcessorException.CODE_PREPARE, "Unable to 
read existing resources for resource " + name, ioe);
         }
-        
+
         // update configuration
-        if (m_resource.isFactoryConfig()) {
+        if (m_resource.isFactoryConfig())
+        {
             // check if this is an factory config instance update
-            for (Iterator i = existingResources.iterator(); i.hasNext();) {
+            for (Iterator i = existingResources.iterator(); i.hasNext();)
+            {
                 AutoConfResource existingResource = (AutoConfResource) 
i.next();
-                if (m_resource.equalsTargetConfiguration(existingResource)) {
+                if (m_resource.equalsTargetConfiguration(existingResource))
+                {
                     // existing instance found
                     configuration = 
configAdmin.getConfiguration(existingResource.getGeneratedPid(), 
bundleLocation);
                     existingResources.remove(existingResource);
                     break;
                 }
             }
-            if (configuration == null) {
+            if (configuration == null)
+            {
                 // no existing instance, create new
                 configuration = 
configAdmin.createFactoryConfiguration(m_resource.getFactoryPid(), 
bundleLocation);
             }
             m_resource.setGeneratedPid(configuration.getPid());
         }
-        else {
-            for (Iterator i = existingResources.iterator(); i.hasNext();) {
+        else
+        {
+            for (Iterator i = existingResources.iterator(); i.hasNext();)
+            {
                 AutoConfResource existingResource = (AutoConfResource) 
i.next();
-                if (m_resource.getPid().equals(existingResource.getPid())) {
+                if (m_resource.getPid().equals(existingResource.getPid()))
+                {
                     // existing resource found
                     existingResources.remove(existingResource);
                     break;
                 }
             }
             configuration = configAdmin.getConfiguration(m_resource.getPid(), 
bundleLocation);
-            if (!bundleLocation.equals(configuration.getBundleLocation())) {
+            if (!bundleLocation.equals(configuration.getBundleLocation()))
+            {
                 // an existing configuration exists that is bound to a 
different location, which is not allowed
-                throw new 
ResourceProcessorException(ResourceProcessorException.CODE_PREPARE, "Existing 
configuration was bound to " + configuration.getBundleLocation() + " instead of 
" + bundleLocation);
+                throw new 
ResourceProcessorException(ResourceProcessorException.CODE_PREPARE,
+                    "Existing configuration was bound to " + 
configuration.getBundleLocation() + " instead of " + bundleLocation);
             }
         }
-        if (m_resource.isMerge()) {
+        if (m_resource.isMerge())
+        {
             Dictionary existingProperties = configuration.getProperties();
-            if (existingProperties != null) {
+            if (existingProperties != null)
+            {
                 Enumeration keys = existingProperties.keys();
-                while (keys.hasMoreElements()) {
+                while (keys.hasMoreElements())
+                {
                     Object key = keys.nextElement();
                     properties.put(key, existingProperties.get(key));
                 }
@@ -717,28 +757,24 @@ class InstallOrUpdateResourceTask implem
     }
 }
 
-class DeleteResourceTask implements PostCommitTask {
-    private final String m_name;
-
-    public DeleteResourceTask(String name) {
-        m_name = name;
-    }
-
-    public void run(PersistencyManager manager) throws Exception {
-        manager.delete(m_name);
-    }
+interface PostCommitTask
+{
+    public void run(PersistencyManager manager) throws Exception;
 }
 
-class StoreResourceTask implements PostCommitTask {
+class StoreResourceTask implements PostCommitTask
+{
     private final String m_name;
     private final List m_resources;
 
-    public StoreResourceTask(String name, List resources) {
+    public StoreResourceTask(String name, List resources)
+    {
         m_name = name;
         m_resources = resources;
     }
 
-    public void run(PersistencyManager manager) throws Exception {
+    public void run(PersistencyManager manager) throws Exception
+    {
         manager.store(m_name, m_resources);
     }
 }
\ No newline at end of file

Added: 
felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/MetaTypeUtil.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/MetaTypeUtil.java?rev=1724802&view=auto
==============================================================================
--- 
felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/MetaTypeUtil.java
 (added)
+++ 
felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/MetaTypeUtil.java
 Fri Jan 15 13:34:41 2016
@@ -0,0 +1,233 @@
+/*
+ * 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.felix.deployment.rp.autoconf;
+
+import static 
org.osgi.service.deploymentadmin.spi.ResourceProcessorException.CODE_OTHER_ERROR;
+
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Vector;
+
+import org.apache.felix.metatype.Attribute;
+import org.apache.felix.metatype.Designate;
+import org.osgi.service.deploymentadmin.spi.ResourceProcessorException;
+import org.osgi.service.metatype.AttributeDefinition;
+import org.osgi.service.metatype.ObjectClassDefinition;
+
+/**
+ * Convenience methods to work with MetaType structures.
+ */
+public class MetaTypeUtil
+{
+    private MetaTypeUtil()
+    {
+        // Nop
+    }
+
+    /**
+     * Determines the actual configuration data based on the specified 
designate and object class definition
+     * 
+     * @param designate The designate object containing the values for the 
properties
+     * @param ocd The object class definition
+     * @return A dictionary containing data as described in the designate and 
ocd objects, or <code>null</code> if the designate does not match it's
+     * definition and the designate was marked as optional.
+     * @throws ResourceProcessorException If the designate does not match the 
ocd and the designate is not marked as optional.
+     */
+    public static Dictionary getProperties(Designate designate, 
ObjectClassDefinition ocd) throws ResourceProcessorException
+    {
+        Dictionary properties = new Hashtable();
+        AttributeDefinition[] attributeDefs = 
ocd.getAttributeDefinitions(ObjectClassDefinition.ALL);
+
+        List<Attribute> attributes = designate.getObject().getAttributes();
+        for (Attribute attribute : attributes)
+        {
+            String adRef = attribute.getAdRef();
+            boolean found = false;
+            for (int j = 0; j < attributeDefs.length; j++)
+            {
+                AttributeDefinition ad = attributeDefs[j];
+                if (adRef.equals(ad.getID()))
+                {
+                    // found attribute definition
+                    Object value = getValue(attribute, ad);
+                    if (value == null)
+                    {
+                        if (designate.isOptional())
+                        {
+                            properties = null;
+                            break;
+                        }
+                        else
+                        {
+                            throw new 
ResourceProcessorException(CODE_OTHER_ERROR, "Could not match attribute to it's 
definition: adref=" + adRef);
+                        }
+                    }
+                    properties.put(adRef, value);
+                    found = true;
+                    break;
+                }
+            }
+            if (!found)
+            {
+                if (designate.isOptional())
+                {
+                    properties = null;
+                    break;
+                }
+                else
+                {
+                    throw new ResourceProcessorException(CODE_OTHER_ERROR, 
"Could not find attribute definition: adref=" + adRef);
+                }
+            }
+        }
+
+        return properties;
+    }
+
+    /**
+     * Determines the value of an attribute based on an attribute definition
+     * 
+     * @param attribute The attribute containing value(s)
+     * @param ad The attribute definition
+     * @return An <code>Object</code> reflecting what was specified in the 
attribute and it's definition or <code>null</code> if the value did not match 
it's definition.
+     * @throws ResourceProcessorException in case we're unable to parse the 
value of an attribute.
+     */
+    private static Object getValue(Attribute attribute, AttributeDefinition 
ad) throws ResourceProcessorException
+    {
+        if (attribute == null || ad == null || 
!attribute.getAdRef().equals(ad.getID()))
+        {
+            // wrong attribute or definition
+            return null;
+        }
+        String[] content = attribute.getContent();
+
+        // verify correct type of the value(s)
+        int type = ad.getType();
+        Object[] typedContent = null;
+        try
+        {
+            for (int i = 0; i < content.length; i++)
+            {
+                String value = content[i];
+                switch (type)
+                {
+                    case AttributeDefinition.BOOLEAN:
+                        typedContent = (typedContent == null) ? new 
Boolean[content.length] : typedContent;
+                        typedContent[i] = Boolean.valueOf(value);
+                        break;
+                    case AttributeDefinition.BYTE:
+                        typedContent = (typedContent == null) ? new 
Byte[content.length] : typedContent;
+                        typedContent[i] = Byte.valueOf(value);
+                        break;
+                    case AttributeDefinition.CHARACTER:
+                        typedContent = (typedContent == null) ? new 
Character[content.length] : typedContent;
+                        char[] charArray = value.toCharArray();
+                        if (charArray.length == 1)
+                        {
+                            typedContent[i] = new Character(charArray[0]);
+                        }
+                        else
+                        {
+                            throw new 
ResourceProcessorException(CODE_OTHER_ERROR, "Unable to parse value for 
definition: adref=" + ad.getID());
+                        }
+                        break;
+                    case AttributeDefinition.DOUBLE:
+                        typedContent = (typedContent == null) ? new 
Double[content.length] : typedContent;
+                        typedContent[i] = Double.valueOf(value);
+                        break;
+                    case AttributeDefinition.FLOAT:
+                        typedContent = (typedContent == null) ? new 
Float[content.length] : typedContent;
+                        typedContent[i] = Float.valueOf(value);
+                        break;
+                    case AttributeDefinition.INTEGER:
+                        typedContent = (typedContent == null) ? new 
Integer[content.length] : typedContent;
+                        typedContent[i] = Integer.valueOf(value);
+                        break;
+                    case AttributeDefinition.LONG:
+                        typedContent = (typedContent == null) ? new 
Long[content.length] : typedContent;
+                        typedContent[i] = Long.valueOf(value);
+                        break;
+                    case AttributeDefinition.SHORT:
+                        typedContent = (typedContent == null) ? new 
Short[content.length] : typedContent;
+                        typedContent[i] = Short.valueOf(value);
+                        break;
+                    case AttributeDefinition.STRING:
+                        typedContent = (typedContent == null) ? new 
String[content.length] : typedContent;
+                        typedContent[i] = value;
+                        break;
+                    default:
+                        // unsupported type
+                        throw new ResourceProcessorException(CODE_OTHER_ERROR, 
"Unsupported value-type for definition: adref=" + ad.getID());
+                }
+            }
+        }
+        catch (NumberFormatException nfe)
+        {
+            throw new ResourceProcessorException(CODE_OTHER_ERROR, "Unable to 
parse value for definition: adref=" + ad.getID());
+        }
+
+        // verify cardinality of value(s)
+        int cardinality = ad.getCardinality();
+        Object result = null;
+        if (cardinality == 0)
+        {
+            if (typedContent.length == 1)
+            {
+                result = typedContent[0];
+            }
+            else
+            {
+                result = null;
+            }
+        }
+        else if (cardinality == Integer.MIN_VALUE)
+        {
+            result = new Vector(Arrays.asList(typedContent));
+        }
+        else if (cardinality == Integer.MAX_VALUE)
+        {
+            result = typedContent;
+        }
+        else if (cardinality < 0)
+        {
+            if (typedContent.length <= Math.abs(cardinality))
+            {
+                result = new Vector(Arrays.asList(typedContent));
+            }
+            else
+            {
+                result = null;
+            }
+        }
+        else if (cardinality > 0)
+        {
+            if (typedContent.length <= cardinality)
+            {
+                result = typedContent;
+            }
+            else
+            {
+                result = null;
+            }
+        }
+        return result;
+    }
+}

Propchange: 
felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/MetaTypeUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/PersistencyManager.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/PersistencyManager.java?rev=1724802&r1=1724801&r2=1724802&view=diff
==============================================================================
--- 
felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/PersistencyManager.java
 (original)
+++ 
felix/trunk/deploymentadmin/autoconf/src/main/java/org/apache/felix/deployment/rp/autoconf/PersistencyManager.java
 Fri Jan 15 13:34:41 2016
@@ -19,6 +19,7 @@
 package org.apache.felix.deployment.rp.autoconf;
 
 import java.io.File;
+import java.io.FileFilter;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
@@ -28,104 +29,155 @@ import java.io.ObjectOutputStream;
 import java.util.ArrayList;
 import java.util.List;
 
-public class PersistencyManager {
-       
-       private final File m_root;
-
-       public PersistencyManager(File root) {
-               m_root = root;
-       }
-
-       /**
-        * Stores a resource.
-        * 
-        * @param name Name of the resource.
-        * @param configs List of <code>AutoConfResource</code>s representing 
the specified resource.
-        * @throws IOException If the resource could not be stored.
-        */
-       public void store(String name, List configs) throws IOException {
-               File targetDir = m_root;
-               name = name.replace('/', File.separatorChar);
-               
-               if (name.startsWith(File.separator)) {
-                       name = name.substring(1);
-               }
-               int lastSeparator = name.lastIndexOf(File.separator);
-               File target = null;
-               if (lastSeparator != -1) {
-                       targetDir = new File(targetDir, name.substring(0, 
lastSeparator));
-                       targetDir.mkdirs();
-               }
-               target = new File(targetDir, name.substring(lastSeparator + 1));
-
-               ObjectOutputStream out = null;
-               try {
-                       out = new ObjectOutputStream(new 
FileOutputStream(target));
-                       out.writeObject(configs);
-               }
-               finally {
-                       if (out != null) {
-                               try {
-                                       out.close();
-                               } catch (Exception e) {
-                                       // not much we can do
-                               }
-                       }
-               }
-       }
-
-       /**
-        * Deletes a resource.
-        * 
-        * @param name Name of the resource.
-        * @throws IOException If the resource could not be deleted.
-        */
-       public void delete(String name) throws IOException {
-               name = name.replace('/', File.separatorChar);
-               File target = new File(m_root, name);
-               if (!target.delete()) {
-                       throw new IOException("Unable to delete file: " + 
target.getAbsolutePath());
-               }
-               while (target.getParentFile().list().length == 0 && 
!target.getParentFile().getAbsolutePath().equals(m_root.getAbsolutePath())) {
-                       target = target.getParentFile();
-                       target.delete();
-               }
-       }
-
-       /**
-        * Loads a stored resource.
-        * 
-        * @param name Name of the resource.
-        * @return List of <code>AutoConfResource</code>s representing the 
specified resource, if the resource is unknown an empty list is returned.
-        * @throws IOException If the resource could not be properly read.
-        */
-       public List load(String name) throws IOException {
-               name = name.replace('/', File.separatorChar);
-               List resources = new ArrayList();
-               File resourcesFile = new File(m_root, name);
-               if (resourcesFile.exists()) {
-                       ObjectInputStream in = null;
-                       try {
-                               in = new ObjectInputStream(new 
FileInputStream(resourcesFile));
-                               resources = (List) in.readObject();
-                       } 
-                       catch (FileNotFoundException fnfe) {
-                               throw new IOException("Resource does not exist: 
" + name);
-                       } 
-                       catch (ClassNotFoundException cnfe) {
-                               throw new IOException("Unable to recreate 
persisted object from file: " + name);
-                       } 
-                       finally {
-                               if (in != null) {
-                                       try {
-                                               in.close();
-                                       } 
-                                       catch (Exception e) {
-                                               // not much we can do
-                                       }
-                               }
-                       }
-               }
-               return resources;
-       }
+public class PersistencyManager
+{
+    private static final FileFilter FILES_ONLY_FILTER = new FileFilter()
+    {
+        public boolean accept(File pathname)
+        {
+            return pathname.isFile();
+        }
+    };
+
+    private final File m_root;
+
+    public PersistencyManager(File root)
+    {
+        m_root = root;
+    }
+
+    /**
+     * Deletes a resource.
+     * 
+     * @param name Name of the resource.
+     * @throws IOException If the resource could not be deleted.
+     */
+    public void delete(String name) throws IOException
+    {
+        name = name.replace('/', File.separatorChar);
+        File target = new File(m_root, name);
+        if (target.exists() && !target.delete())
+        {
+            throw new IOException("Unable to delete file: " + 
target.getAbsolutePath());
+        }
+        while (target.getParentFile().list().length == 0 && 
!target.getParentFile().getAbsolutePath().equals(m_root.getAbsolutePath()))
+        {
+            target = target.getParentFile();
+            target.delete();
+        }
+    }
+
+    /**
+     * Returns the names of all persisted resources.
+     * @return a list of resource names, never <code>null</code>.
+     */
+    public List<String> getResourceNames()
+    {
+        List<String> result = new ArrayList<String>();
+
+        File[] list = m_root.listFiles(FILES_ONLY_FILTER);
+        if (list != null && list.length > 0)
+        {
+            for (File resource : list)
+            {
+                result.add(resource.getName());
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Loads a stored resource.
+     * 
+     * @param name Name of the resource.
+     * @return List of <code>AutoConfResource</code>s representing the 
specified resource, if the resource is unknown an empty list is returned.
+     * @throws IOException If the resource could not be properly read.
+     */
+    public List<AutoConfResource> load(String name) throws IOException
+    {
+        List<AutoConfResource> resources = new ArrayList<AutoConfResource>();
+        name = name.replace('/', File.separatorChar);
+        File resourcesFile = new File(m_root, name);
+        if (!resourcesFile.exists())
+        {
+            return resources;
+        }
+
+        ObjectInputStream in = null;
+        try
+        {
+            in = new ObjectInputStream(new FileInputStream(resourcesFile));
+            resources = (List<AutoConfResource>) in.readObject();
+        }
+        catch (FileNotFoundException e)
+        {
+            throw new IOException("Resource does not exist: " + name);
+        }
+        catch (ClassNotFoundException e)
+        {
+            throw new IOException("Unable to recreate persisted object from 
file: " + name);
+        }
+        finally
+        {
+            if (in != null)
+            {
+                try
+                {
+                    in.close();
+                }
+                catch (Exception e)
+                {
+                    // not much we can do
+                }
+            }
+        }
+        return resources;
+    }
+
+    /**
+     * Stores a resource.
+     * 
+     * @param name Name of the resource.
+     * @param configs List of <code>AutoConfResource</code>s representing the 
specified resource.
+     * @throws IOException If the resource could not be stored.
+     */
+    public void store(String name, List<AutoConfResource> configs) throws 
IOException
+    {
+        File targetDir = m_root;
+        name = name.replace('/', File.separatorChar);
+
+        if (name.startsWith(File.separator))
+        {
+            name = name.substring(1);
+        }
+        int lastSeparator = name.lastIndexOf(File.separator);
+        File target = null;
+        if (lastSeparator != -1)
+        {
+            targetDir = new File(targetDir, name.substring(0, lastSeparator));
+            targetDir.mkdirs();
+        }
+        target = new File(targetDir, name.substring(lastSeparator + 1));
+
+        ObjectOutputStream out = null;
+        try
+        {
+            out = new ObjectOutputStream(new FileOutputStream(target));
+            out.writeObject(configs);
+        }
+        finally
+        {
+            if (out != null)
+            {
+                try
+                {
+                    out.close();
+                }
+                catch (Exception e)
+                {
+                    // not much we can do
+                }
+            }
+        }
+    }
 }


Reply via email to