UNOMI-202 : Simplified and centralize patch files handling
diff --git a/api/src/main/java/org/apache/unomi/api/Patch.java b/api/src/main/java/org/apache/unomi/api/Patch.java
index 9380ef8..77d25b8 100644
--- a/api/src/main/java/org/apache/unomi/api/Patch.java
+++ b/api/src/main/java/org/apache/unomi/api/Patch.java
@@ -50,6 +50,8 @@
 
     private String patchedItemId;
 
+    private String patchedItemType;
+
     private String operation;
 
     private Object data;
@@ -64,6 +66,14 @@
         this.patchedItemId = patchedItemId;
     }
 
+    public String getPatchedItemType() {
+        return patchedItemType;
+    }
+
+    public void setPatchedItemType(String patchedItemType) {
+        this.patchedItemType = patchedItemType;
+    }
+
     public String getOperation() {
         return operation;
     }
diff --git a/api/src/main/java/org/apache/unomi/api/services/PatchService.java b/api/src/main/java/org/apache/unomi/api/services/PatchService.java
index 47f53ca..a9261e8 100644
--- a/api/src/main/java/org/apache/unomi/api/services/PatchService.java
+++ b/api/src/main/java/org/apache/unomi/api/services/PatchService.java
@@ -25,10 +25,6 @@
 public interface PatchService {
     Patch load(String id);
 
-    void patch(Enumeration<URL> urls, Class<? extends Item> type);
-
-    void patch(URL patchUrl, Class<? extends Item> type);
-
-    <T extends Item> T patch(Patch patch, Class<T> type) ;
+    Item patch(Patch patch) ;
 }
 
diff --git a/rest/src/main/java/org/apache/unomi/rest/PatchServiceEndPoint.java b/rest/src/main/java/org/apache/unomi/rest/PatchServiceEndPoint.java
index 20f7cd8..b7d7a9c 100644
--- a/rest/src/main/java/org/apache/unomi/rest/PatchServiceEndPoint.java
+++ b/rest/src/main/java/org/apache/unomi/rest/PatchServiceEndPoint.java
@@ -45,15 +45,13 @@
 
     /**
      * Apply a patch on an item
-     *
-     * @param type the type of item to patch
      */
     @POST
-    @Path("/apply/{type}")
-    public void setPatch(Patch patch, @PathParam("type") String type, @QueryParam("force") Boolean force) {
+    @Path("/apply")
+    public void setPatch(Patch patch, @QueryParam("force") Boolean force) {
         Patch previous = (force == null || !force) ? patchService.load(patch.getItemId()) : null;
         if (previous == null) {
-            patchService.patch(patch, Patch.PATCHABLE_TYPES.get(type));
+            patchService.patch(patch);
         }
     }
 
diff --git a/services/src/main/java/org/apache/unomi/services/services/DefinitionsServiceImpl.java b/services/src/main/java/org/apache/unomi/services/services/DefinitionsServiceImpl.java
index 0daaf5b..a6c2e15 100644
--- a/services/src/main/java/org/apache/unomi/services/services/DefinitionsServiceImpl.java
+++ b/services/src/main/java/org/apache/unomi/services/services/DefinitionsServiceImpl.java
@@ -133,26 +133,21 @@
             return;
         }
 
-        // First apply patches on existing items
-        patchService.patch(bundleContext.getBundle().findEntries("META-INF/cxs/conditions", "*-patch.json", true), ConditionType.class);
-
         while (predefinedConditionEntries.hasMoreElements()) {
             URL predefinedConditionURL = predefinedConditionEntries.nextElement();
-            if (!predefinedConditionURL.getFile().endsWith("-patch.json")) {
-                logger.debug("Found predefined condition at " + predefinedConditionURL + ", loading... ");
+            logger.debug("Found predefined condition at " + predefinedConditionURL + ", loading... ");
 
-                try {
-                    ConditionType conditionType = CustomObjectMapper.getObjectMapper().readValue(predefinedConditionURL, ConditionType.class);
-                    // Register only if condition type does not exist yet
-                    if (getConditionType(conditionType.getMetadata().getId()) == null) {
-                        setConditionType(conditionType);
-                        logger.info("Predefined condition type with id {} registered", conditionType.getMetadata().getId());
-                    } else {
-                        logger.info("The predefined condition type with id {} is already registered, this condition type will be skipped", conditionType.getMetadata().getId());
-                    }
-                } catch (IOException e) {
-                    logger.error("Error while loading condition definition " + predefinedConditionURL, e);
+            try {
+                ConditionType conditionType = CustomObjectMapper.getObjectMapper().readValue(predefinedConditionURL, ConditionType.class);
+                // Register only if condition type does not exist yet
+                if (getConditionType(conditionType.getMetadata().getId()) == null) {
+                    setConditionType(conditionType);
+                    logger.info("Predefined condition type with id {} registered", conditionType.getMetadata().getId());
+                } else {
+                    logger.info("The predefined condition type with id {} is already registered, this condition type will be skipped", conditionType.getMetadata().getId());
                 }
+            } catch (IOException e) {
+                logger.error("Error while loading condition definition " + predefinedConditionURL, e);
             }
         }
     }
@@ -163,27 +158,22 @@
             return;
         }
 
-        // First apply patches on existing items
-        patchService.patch(bundleContext.getBundle().findEntries("META-INF/cxs/actions", "*-patch.json", true), ActionType.class);
-
         ArrayList<PluginType> pluginTypeArrayList = (ArrayList<PluginType>) pluginTypes.get(bundleContext.getBundle().getBundleId());
         while (predefinedActionsEntries.hasMoreElements()) {
             URL predefinedActionURL = predefinedActionsEntries.nextElement();
-            if (!predefinedActionURL.getFile().endsWith("-patch.json")) {
-                logger.debug("Found predefined action at " + predefinedActionURL + ", loading... ");
+            logger.debug("Found predefined action at " + predefinedActionURL + ", loading... ");
 
-                try {
-                    ActionType actionType = CustomObjectMapper.getObjectMapper().readValue(predefinedActionURL, ActionType.class);
-                    // Register only if action type does not exist yet
-                    if (getActionType(actionType.getMetadata().getId()) == null) {
-                        setActionType(actionType);
-                        logger.info("Predefined action type with id {} registered", actionType.getMetadata().getId());
-                    } else {
-                        logger.info("The predefined action type with id {} is already registered, this action type will be skipped", actionType.getMetadata().getId());
-                    }
-                } catch (Exception e) {
-                    logger.error("Error while loading action definition " + predefinedActionURL, e);
+            try {
+                ActionType actionType = CustomObjectMapper.getObjectMapper().readValue(predefinedActionURL, ActionType.class);
+                // Register only if action type does not exist yet
+                if (getActionType(actionType.getMetadata().getId()) == null) {
+                    setActionType(actionType);
+                    logger.info("Predefined action type with id {} registered", actionType.getMetadata().getId());
+                } else {
+                    logger.info("The predefined action type with id {} is already registered, this action type will be skipped", actionType.getMetadata().getId());
                 }
+            } catch (Exception e) {
+                logger.error("Error while loading action definition " + predefinedActionURL, e);
             }
         }
 
diff --git a/services/src/main/java/org/apache/unomi/services/services/GoalsServiceImpl.java b/services/src/main/java/org/apache/unomi/services/services/GoalsServiceImpl.java
index 0de6c64..f7d8ba7 100644
--- a/services/src/main/java/org/apache/unomi/services/services/GoalsServiceImpl.java
+++ b/services/src/main/java/org/apache/unomi/services/services/GoalsServiceImpl.java
@@ -117,29 +117,24 @@
             return;
         }
 
-        // First apply patches on existing items
-        patchService.patch(bundleContext.getBundle().findEntries("META-INF/cxs/goals", "*-patch.json", true), Goal.class);
-
         while (predefinedRuleEntries.hasMoreElements()) {
             URL predefinedGoalURL = predefinedRuleEntries.nextElement();
-            if (!predefinedGoalURL.getFile().endsWith("-patch.json")) {
-                logger.debug("Found predefined goals at " + predefinedGoalURL + ", loading... ");
+            logger.debug("Found predefined goals at " + predefinedGoalURL + ", loading... ");
 
-                try {
-                    Goal goal = CustomObjectMapper.getObjectMapper().readValue(predefinedGoalURL, Goal.class);
-                    if (goal.getMetadata().getScope() == null) {
-                        goal.getMetadata().setScope("systemscope");
-                    }
-                    // Register only if goal does not exist yet
-                    if (getGoal(goal.getMetadata().getId()) == null) {
-                        setGoal(goal);
-                        logger.info("Predefined goal with id {} registered", goal.getMetadata().getId());
-                    } else {
-                        logger.info("The predefined goal with id {} is already registered, this goal will be skipped", goal.getMetadata().getId());
-                    }
-                } catch (IOException e) {
-                    logger.error("Error while loading segment definition " + predefinedGoalURL, e);
+            try {
+                Goal goal = CustomObjectMapper.getObjectMapper().readValue(predefinedGoalURL, Goal.class);
+                if (goal.getMetadata().getScope() == null) {
+                    goal.getMetadata().setScope("systemscope");
                 }
+                // Register only if goal does not exist yet
+                if (getGoal(goal.getMetadata().getId()) == null) {
+                    setGoal(goal);
+                    logger.info("Predefined goal with id {} registered", goal.getMetadata().getId());
+                } else {
+                    logger.info("The predefined goal with id {} is already registered, this goal will be skipped", goal.getMetadata().getId());
+                }
+            } catch (IOException e) {
+                logger.error("Error while loading segment definition " + predefinedGoalURL, e);
             }
         }
     }
@@ -271,26 +266,21 @@
             return;
         }
 
-        // First apply patches on existing items
-        patchService.patch(bundleContext.getBundle().findEntries("META-INF/cxs/campaigns", "*-patch.json", true), Campaign.class);
-
         while (predefinedRuleEntries.hasMoreElements()) {
             URL predefinedCampaignURL = predefinedRuleEntries.nextElement();
-            if (!predefinedCampaignURL.getFile().endsWith("-patch.json")) {
-                logger.debug("Found predefined campaigns at " + predefinedCampaignURL + ", loading... ");
+            logger.debug("Found predefined campaigns at " + predefinedCampaignURL + ", loading... ");
 
-                try {
-                    Campaign campaign = CustomObjectMapper.getObjectMapper().readValue(predefinedCampaignURL, Campaign.class);
-                    // Register only if campaign does not exist yet
-                    if (getCampaign(campaign.getMetadata().getId()) == null) {
-                        setCampaign(campaign);
-                        logger.info("Predefined campaign with id {} registered", campaign.getMetadata().getId());
-                    } else {
-                        logger.info("The predefined campaign with id {} is already registered, this campaign will be skipped", campaign.getMetadata().getId());
-                    }
-                } catch (IOException e) {
-                    logger.error("Error while loading segment definition " + predefinedCampaignURL, e);
+            try {
+                Campaign campaign = CustomObjectMapper.getObjectMapper().readValue(predefinedCampaignURL, Campaign.class);
+                // Register only if campaign does not exist yet
+                if (getCampaign(campaign.getMetadata().getId()) == null) {
+                    setCampaign(campaign);
+                    logger.info("Predefined campaign with id {} registered", campaign.getMetadata().getId());
+                } else {
+                    logger.info("The predefined campaign with id {} is already registered, this campaign will be skipped", campaign.getMetadata().getId());
                 }
+            } catch (IOException e) {
+                logger.error("Error while loading segment definition " + predefinedCampaignURL, e);
             }
         }
     }
diff --git a/services/src/main/java/org/apache/unomi/services/services/PatchServiceImpl.java b/services/src/main/java/org/apache/unomi/services/services/PatchServiceImpl.java
index c6a8b77..0ee58e0 100644
--- a/services/src/main/java/org/apache/unomi/services/services/PatchServiceImpl.java
+++ b/services/src/main/java/org/apache/unomi/services/services/PatchServiceImpl.java
@@ -19,13 +19,14 @@
 import com.fasterxml.jackson.databind.JsonNode;
 import com.github.fge.jsonpatch.JsonPatch;
 import com.github.fge.jsonpatch.JsonPatchException;
-import org.apache.unomi.api.Item;
-import org.apache.unomi.api.Patch;
-import org.apache.unomi.api.PropertyType;
+import org.apache.unomi.api.*;
 import org.apache.unomi.api.services.PatchService;
 import org.apache.unomi.persistence.spi.CustomObjectMapper;
 import org.apache.unomi.persistence.spi.PersistenceService;
+import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.SynchronousBundleListener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -34,9 +35,9 @@
 import java.util.Date;
 import java.util.Enumeration;
 
-public class PatchServiceImpl implements PatchService {
+public class PatchServiceImpl implements PatchService, SynchronousBundleListener {
 
-    private static final Logger logger = LoggerFactory.getLogger(ProfileServiceImpl.class.getName());
+    private static final Logger logger = LoggerFactory.getLogger(PatchServiceImpl.class.getName());
 
     private BundleContext bundleContext;
 
@@ -50,36 +51,75 @@
         this.persistenceService = persistenceService;
     }
 
+    public void postConstruct() {
+        logger.debug("postConstruct {" + bundleContext.getBundle() + "}");
+
+        processBundleStartup(bundleContext);
+        for (Bundle bundle : bundleContext.getBundles()) {
+            if (bundle.getBundleContext() != null && bundle.getBundleId() != bundleContext.getBundle().getBundleId()) {
+                processBundleStartup(bundle.getBundleContext());
+            }
+        }
+        bundleContext.addBundleListener(this);
+        logger.info("Patch service initialized.");
+    }
+
+    public void preDestroy() {
+        bundleContext.removeBundleListener(this);
+        logger.info("Patch service shutdown.");
+    }
+
+    @Override
+    public void bundleChanged(BundleEvent event) {
+        switch (event.getType()) {
+            case BundleEvent.STARTED:
+                processBundleStartup(event.getBundle().getBundleContext());
+                break;
+        }
+    }
+
+    private void processBundleStartup(BundleContext bundleContext) {
+        if (bundleContext == null) {
+            return;
+        }
+        loadPredefinedPatches(bundleContext);
+    }
+
+    private void loadPredefinedPatches(BundleContext bundleContext) {
+        if (bundleContext == null) {
+            return;
+        }
+
+        // First apply patches on existing items
+        Enumeration<URL> urls = bundleContext.getBundle().findEntries("META-INF/cxs/patches", "*.json", true);
+        if (urls != null) {
+            while (urls.hasMoreElements()) {
+                URL patchUrl = urls.nextElement();
+                try {
+                    Patch patch = CustomObjectMapper.getObjectMapper().readValue(patchUrl, Patch.class);
+                    if (persistenceService.load(patch.getItemId(), Patch.class) == null) {
+                        patch(patch);
+                    }
+                } catch (IOException e) {
+                    logger.error("Error while loading patch " + patchUrl, e);
+                }
+            }
+        }
+    }
+
     @Override
     public Patch load(String id) {
         return persistenceService.load(id, Patch.class);
     }
 
-    public void patch(Enumeration<URL> urls, Class<? extends Item> type) {
-        if (urls != null) {
-            while (urls.hasMoreElements()) {
-                patch(urls.nextElement(), type);
-            }
-        }
-    }
+    public Item patch(Patch patch) {
+        Class<? extends Item> type = Patch.PATCHABLE_TYPES.get(patch.getPatchedItemType());
 
-    public  void patch(URL patchUrl, Class<? extends Item> type) {
-        try {
-            Patch patch = CustomObjectMapper.getObjectMapper().readValue(patchUrl, Patch.class);
-            if (persistenceService.load(patch.getItemId(), Patch.class) == null) {
-                patch(patch, type);
-            }
-        } catch (IOException e) {
-            logger.error("Error while loading patch " + patchUrl, e);
-        }
-    }
-
-    public <T extends Item> T patch(Patch patch, Class<T> type) {
         if (type == null) {
             throw new IllegalArgumentException("Must specify valid type");
         }
 
-        T item = persistenceService.load(patch.getPatchedItemId(), type);
+        Item item = persistenceService.load(patch.getPatchedItemId(), type);
 
         if (item != null && patch.getOperation() != null) {
             logger.info("Applying patch " + patch.getItemId());
diff --git a/services/src/main/java/org/apache/unomi/services/services/ProfileServiceImpl.java b/services/src/main/java/org/apache/unomi/services/services/ProfileServiceImpl.java
index 57ebf94..1a5bff9 100644
--- a/services/src/main/java/org/apache/unomi/services/services/ProfileServiceImpl.java
+++ b/services/src/main/java/org/apache/unomi/services/services/ProfileServiceImpl.java
@@ -923,34 +923,29 @@
             return;
         }
 
-        // First apply patches on existing items
-        patchService.patch(bundleContext.getBundle().findEntries("META-INF/cxs/personas", "*-patch.json", true), Persona.class);
-
         while (predefinedPersonaEntries.hasMoreElements()) {
             URL predefinedPersonaURL = predefinedPersonaEntries.nextElement();
-            if (!predefinedPersonaURL.getFile().endsWith("-patch.json")) {
-                logger.debug("Found predefined persona at " + predefinedPersonaURL + ", loading... ");
+            logger.debug("Found predefined persona at " + predefinedPersonaURL + ", loading... ");
 
-                try {
-                    PersonaWithSessions persona = getObjectMapper().readValue(predefinedPersonaURL, PersonaWithSessions.class);
+            try {
+                PersonaWithSessions persona = getObjectMapper().readValue(predefinedPersonaURL, PersonaWithSessions.class);
 
-                    String itemId = persona.getPersona().getItemId();
-                    // Register only if persona does not exist yet
-                    if (persistenceService.load(itemId, Persona.class) == null) {
-                        persistenceService.save(persona.getPersona());
+                String itemId = persona.getPersona().getItemId();
+                // Register only if persona does not exist yet
+                if (persistenceService.load(itemId, Persona.class) == null) {
+                    persistenceService.save(persona.getPersona());
 
-                        List<PersonaSession> sessions = persona.getSessions();
-                        for (PersonaSession session : sessions) {
-                            session.setProfile(persona.getPersona());
-                            persistenceService.save(session);
-                        }
-                        logger.info("Predefined persona with id {} registered", itemId);
-                    } else {
-                        logger.info("The predefined persona with id {} is already registered, this persona will be skipped", itemId);
+                    List<PersonaSession> sessions = persona.getSessions();
+                    for (PersonaSession session : sessions) {
+                        session.setProfile(persona.getPersona());
+                        persistenceService.save(session);
                     }
-                } catch (IOException e) {
-                    logger.error("Error while loading persona " + predefinedPersonaURL, e);
+                    logger.info("Predefined persona with id {} registered", itemId);
+                } else {
+                    logger.info("The predefined persona with id {} is already registered, this persona will be skipped", itemId);
                 }
+            } catch (IOException e) {
+                logger.error("Error while loading persona " + predefinedPersonaURL, e);
             }
         }
     }
@@ -961,32 +956,26 @@
             return;
         }
 
-        // First apply patches on existing items
-
-        patchService.patch(bundleContext.getBundle().findEntries("META-INF/cxs/properties", "*-patch.json", true), PropertyType.class);
-
         List<PropertyType> bundlePropertyTypes = new ArrayList<>();
         while (predefinedPropertyTypeEntries.hasMoreElements()) {
             URL predefinedPropertyTypeURL = predefinedPropertyTypeEntries.nextElement();
-            if (!predefinedPropertyTypeURL.getFile().endsWith("-patch.json")) {
-                logger.debug("Found predefined property type at " + predefinedPropertyTypeURL + ", loading... ");
+            logger.debug("Found predefined property type at " + predefinedPropertyTypeURL + ", loading... ");
 
-                try {
-                    PropertyType propertyType = CustomObjectMapper.getObjectMapper().readValue(predefinedPropertyTypeURL, PropertyType.class);
-                    // Register only if property type does not exist yet
-                    if (getPropertyType(propertyType.getMetadata().getId()) == null) {
+            try {
+                PropertyType propertyType = CustomObjectMapper.getObjectMapper().readValue(predefinedPropertyTypeURL, PropertyType.class);
+                // Register only if property type does not exist yet
+                if (getPropertyType(propertyType.getMetadata().getId()) == null) {
 
-                        setPropertyTypeTarget(predefinedPropertyTypeURL, propertyType);
+                    setPropertyTypeTarget(predefinedPropertyTypeURL, propertyType);
 
-                        persistenceService.save(propertyType);
-                        bundlePropertyTypes.add(propertyType);
-                        logger.info("Predefined property type with id {} registered", propertyType.getMetadata().getId());
-                    } else {
-                        logger.info("The predefined property type with id {} is already registered, this property type will be skipped", propertyType.getMetadata().getId());
-                    }
-                } catch (IOException e) {
-                    logger.error("Error while loading properties " + predefinedPropertyTypeURL, e);
+                    persistenceService.save(propertyType);
+                    bundlePropertyTypes.add(propertyType);
+                    logger.info("Predefined property type with id {} registered", propertyType.getMetadata().getId());
+                } else {
+                    logger.info("The predefined property type with id {} is already registered, this property type will be skipped", propertyType.getMetadata().getId());
                 }
+            } catch (IOException e) {
+                logger.error("Error while loading properties " + predefinedPropertyTypeURL, e);
             }
         }
         propertyTypes = propertyTypes.with(bundlePropertyTypes);
diff --git a/services/src/main/java/org/apache/unomi/services/services/RulesServiceImpl.java b/services/src/main/java/org/apache/unomi/services/services/RulesServiceImpl.java
index 3f63a31..69a37ff 100644
--- a/services/src/main/java/org/apache/unomi/services/services/RulesServiceImpl.java
+++ b/services/src/main/java/org/apache/unomi/services/services/RulesServiceImpl.java
@@ -146,26 +146,21 @@
             return;
         }
 
-        // First apply patches on existing items
-        patchService.patch(bundleContext.getBundle().findEntries("META-INF/cxs/rules", "*-patch.json", true), Rule.class);
-
         while (predefinedRuleEntries.hasMoreElements()) {
             URL predefinedRuleURL = predefinedRuleEntries.nextElement();
-            if (!predefinedRuleURL.getFile().endsWith("-patch.json")) {
-                logger.debug("Found predefined rule at " + predefinedRuleURL + ", loading... ");
+            logger.debug("Found predefined rule at " + predefinedRuleURL + ", loading... ");
 
-                try {
-                    Rule rule = CustomObjectMapper.getObjectMapper().readValue(predefinedRuleURL, Rule.class);
-                    // Register only if rule does not exist yet
-                    if (getRule(rule.getMetadata().getId()) == null) {
-                        setRule(rule);
-                        logger.info("Predefined rule with id {} registered", rule.getMetadata().getId());
-                    } else {
-                        logger.info("The predefined rule with id {} is already registered, this rule will be skipped", rule.getMetadata().getId());
-                    }
-                } catch (IOException e) {
-                    logger.error("Error while loading rule definition " + predefinedRuleURL, e);
+            try {
+                Rule rule = CustomObjectMapper.getObjectMapper().readValue(predefinedRuleURL, Rule.class);
+                // Register only if rule does not exist yet
+                if (getRule(rule.getMetadata().getId()) == null) {
+                    setRule(rule);
+                    logger.info("Predefined rule with id {} registered", rule.getMetadata().getId());
+                } else {
+                    logger.info("The predefined rule with id {} is already registered, this rule will be skipped", rule.getMetadata().getId());
                 }
+            } catch (IOException e) {
+                logger.error("Error while loading rule definition " + predefinedRuleURL, e);
             }
         }
     }
diff --git a/services/src/main/java/org/apache/unomi/services/services/SegmentServiceImpl.java b/services/src/main/java/org/apache/unomi/services/services/SegmentServiceImpl.java
index 5b92a48..0fe5f2e 100644
--- a/services/src/main/java/org/apache/unomi/services/services/SegmentServiceImpl.java
+++ b/services/src/main/java/org/apache/unomi/services/services/SegmentServiceImpl.java
@@ -131,29 +131,24 @@
             return;
         }
 
-        // First apply patches on existing items
-        patchService.patch(bundleContext.getBundle().findEntries("META-INF/cxs/segments", "*-patch.json", true), Segment.class);
-
         while (predefinedSegmentEntries.hasMoreElements()) {
             URL predefinedSegmentURL = predefinedSegmentEntries.nextElement();
-            if (!predefinedSegmentURL.getFile().endsWith("-patch.json")) {
-                logger.debug("Found predefined segment at " + predefinedSegmentURL + ", loading... ");
+            logger.debug("Found predefined segment at " + predefinedSegmentURL + ", loading... ");
 
-                try {
-                    Segment segment = CustomObjectMapper.getObjectMapper().readValue(predefinedSegmentURL, Segment.class);
-                    if (segment.getMetadata().getScope() == null) {
-                        segment.getMetadata().setScope("systemscope");
-                    }
-                    // Register only if segment does not exist yet
-                    if (getSegmentDefinition(segment.getMetadata().getId()) == null) {
-                        setSegmentDefinition(segment);
-                        logger.info("Predefined segment with id {} registered", segment.getMetadata().getId());
-                    } else {
-                        logger.info("The predefined segment with id {} is already registered, this segment will be skipped", segment.getMetadata().getId());
-                    }
-                } catch (IOException e) {
-                    logger.error("Error while loading segment definition " + predefinedSegmentURL, e);
+            try {
+                Segment segment = CustomObjectMapper.getObjectMapper().readValue(predefinedSegmentURL, Segment.class);
+                if (segment.getMetadata().getScope() == null) {
+                    segment.getMetadata().setScope("systemscope");
                 }
+                // Register only if segment does not exist yet
+                if (getSegmentDefinition(segment.getMetadata().getId()) == null) {
+                    setSegmentDefinition(segment);
+                    logger.info("Predefined segment with id {} registered", segment.getMetadata().getId());
+                } else {
+                    logger.info("The predefined segment with id {} is already registered, this segment will be skipped", segment.getMetadata().getId());
+                }
+            } catch (IOException e) {
+                logger.error("Error while loading segment definition " + predefinedSegmentURL, e);
             }
         }
     }
@@ -164,29 +159,24 @@
             return;
         }
 
-        // First apply patches on existing items
-        patchService.patch(bundleContext.getBundle().findEntries("META-INF/cxs/scoring", "*-patch.json", true), Scoring.class);
-
         while (predefinedScoringEntries.hasMoreElements()) {
             URL predefinedScoringURL = predefinedScoringEntries.nextElement();
-            if (!predefinedScoringURL.getFile().endsWith("-patch.json")) {
-                logger.debug("Found predefined scoring at " + predefinedScoringURL + ", loading... ");
+            logger.debug("Found predefined scoring at " + predefinedScoringURL + ", loading... ");
 
-                try {
-                    Scoring scoring = CustomObjectMapper.getObjectMapper().readValue(predefinedScoringURL, Scoring.class);
-                    if (scoring.getMetadata().getScope() == null) {
-                        scoring.getMetadata().setScope("systemscope");
-                    }
-                    // Register only if scoring plan does not exist yet
-                    if (getScoringDefinition(scoring.getMetadata().getId()) == null) {
-                        setScoringDefinition(scoring);
-                        logger.info("Predefined scoring with id {} registered", scoring.getMetadata().getId());
-                    } else {
-                        logger.info("The predefined scoring with id {} is already registered, this scoring will be skipped", scoring.getMetadata().getId());
-                    }
-                } catch (IOException e) {
-                    logger.error("Error while loading segment definition " + predefinedScoringURL, e);
+            try {
+                Scoring scoring = CustomObjectMapper.getObjectMapper().readValue(predefinedScoringURL, Scoring.class);
+                if (scoring.getMetadata().getScope() == null) {
+                    scoring.getMetadata().setScope("systemscope");
                 }
+                // Register only if scoring plan does not exist yet
+                if (getScoringDefinition(scoring.getMetadata().getId()) == null) {
+                    setScoringDefinition(scoring);
+                    logger.info("Predefined scoring with id {} registered", scoring.getMetadata().getId());
+                } else {
+                    logger.info("The predefined scoring with id {} is already registered, this scoring will be skipped", scoring.getMetadata().getId());
+                }
+            } catch (IOException e) {
+                logger.error("Error while loading segment definition " + predefinedScoringURL, e);
             }
         }
     }
diff --git a/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml
index 438c7d0..eed06f2 100644
--- a/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml
+++ b/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -214,7 +214,8 @@
     </bean>
     <service id="personalizationService" ref="personalizationServiceImpl" interface="org.apache.unomi.api.services.PersonalizationService" />
 
-    <bean id="patchServiceImpl" class="org.apache.unomi.services.services.PatchServiceImpl">
+    <bean id="patchServiceImpl" class="org.apache.unomi.services.services.PatchServiceImpl"
+          init-method="postConstruct" destroy-method="preDestroy">
         <property name="persistenceService" ref="persistenceService"/>
         <property name="bundleContext" ref="blueprintBundleContext"/>
     </bean>
diff --git a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/DeployDefinitionCommand.java b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/DeployDefinitionCommand.java
index 587ec7f..e89d37d 100644
--- a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/DeployDefinitionCommand.java
+++ b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/DeployDefinitionCommand.java
@@ -24,7 +24,6 @@
 import org.apache.unomi.api.*;
 import org.apache.unomi.api.actions.ActionType;
 import org.apache.unomi.api.campaigns.Campaign;
-import org.apache.unomi.api.conditions.Condition;
 import org.apache.unomi.api.conditions.ConditionType;
 import org.apache.unomi.api.goals.Goal;
 import org.apache.unomi.api.rules.Rule;
@@ -51,7 +50,7 @@
     private SegmentService segmentService;
     private PatchService patchService;
 
-    private final static List<String> definitionTypes = Arrays.asList("condition", "action", "goal", "campaign", "persona", "property", "rule", "segment", "scoring");
+    private final static List<String> definitionTypes = Arrays.asList("condition", "action", "goal", "campaign", "persona", "property", "rule", "segment", "scoring", "patch");
 
 
     @Argument(index = 0, name = "bundleId", description = "The bundle identifier where to find the definition", multiValued = false)
@@ -120,9 +119,7 @@
         }
         if (fileName.startsWith("*")) {
             for (URL url : values) {
-                if (!url.getFile().endsWith("-patch.json")) {
-                    updateDefinition(definitionType, url);
-                }
+                updateDefinition(definitionType, url);
             }
         } else {
             if (!fileName.contains("/")) {
@@ -135,11 +132,7 @@
             Optional<URL> optionalURL = values.stream().filter(u -> u.getFile().endsWith(fileName)).findFirst();
             if (optionalURL.isPresent()) {
                 URL url = optionalURL.get();
-                if (!url.getFile().endsWith("-patch.json")) {
-                    updateDefinition(definitionType, url);
-                } else {
-                    deployPatch(definitionType, url);
-                }
+                updateDefinition(definitionType, url);
             } else {
                 System.out.println("Couldn't find file " + fileName);
                 return null;
@@ -211,6 +204,10 @@
                     Scoring scoring = CustomObjectMapper.getObjectMapper().readValue(definitionURL, Scoring.class);
                     segmentService.setScoringDefinition(scoring);
                     break;
+                case "patch":
+                    Patch patch = CustomObjectMapper.getObjectMapper().readValue(definitionURL, Patch.class);
+                    patchService.patch(patch);
+                    break;
             }
             System.out.println("Predefined definition registered : "+definitionURL.getFile());
         } catch (IOException e) {
@@ -219,23 +216,6 @@
         }
     }
 
-    private void deployPatch(String definitionType, URL patchURL) {
-        try {
-            Patch patch = CustomObjectMapper.getObjectMapper().readValue(patchURL, Patch.class);
-            Class<? extends Item> type = Patch.PATCHABLE_TYPES.get(definitionType);
-            if (type != null) {
-                patchService.patch(patch, type);
-            }
-
-            System.out.println("Definition patched : "+ patch.getItemId() + " by : " + patchURL.getFile());
-        } catch (IOException e) {
-            System.out.println("Error while saving definition " + patchURL);
-            System.out.println(e.getMessage());
-        }
-    }
-
-
-
     private String getDefinitionTypePath(String definitionType) {
         StringBuilder path = new StringBuilder("META-INF/cxs/");
         switch (definitionType) {
@@ -266,6 +246,9 @@
             case "scoring":
                 path.append("scoring");
                 break;
+            case "patch":
+                path.append("patches");
+                break;
         }
 
         return path.toString();