diff --git a/product/ERP5/bootstrap/erp5_core/PortalTypeTemplateItem/portal_types/Extension%20Component.xml b/product/ERP5/bootstrap/erp5_core/PortalTypeTemplateItem/portal_types/Extension%20Component.xml
index 0d9fe94b59e9142a1bfb787417c52435994e6756..7fc1cfd037a82352a16bfbf39c9821aff4c81746 100644
--- a/product/ERP5/bootstrap/erp5_core/PortalTypeTemplateItem/portal_types/Extension%20Component.xml
+++ b/product/ERP5/bootstrap/erp5_core/PortalTypeTemplateItem/portal_types/Extension%20Component.xml
@@ -82,7 +82,7 @@
         </item>
         <item>
             <key> <string>type_class</string> </key>
-            <value> <string>DocumentComponent</string> </value>
+            <value> <string>ExtensionComponent</string> </value>
         </item>
         <item>
             <key> <string>type_interface</string> </key>
diff --git a/product/ERP5/bootstrap/erp5_core/bt/change_log b/product/ERP5/bootstrap/erp5_core/bt/change_log
index 601d29024bacf76b420fb3e1ac7d6870b437bdbc..d60b3ca3777a640add9ae7079f65308d7d1026f0 100644
--- a/product/ERP5/bootstrap/erp5_core/bt/change_log
+++ b/product/ERP5/bootstrap/erp5_core/bt/change_log
@@ -1,3 +1,6 @@
+2012-01-19 arnaud.fontaine
+* Extension Component has now its own class (meaningful for importing from filesystem).
+
 2012-01-18 arnaud.fontaine
 * Complete ComponentTool view.
 * Implement Extension Component.
diff --git a/product/ERP5/bootstrap/erp5_core/bt/revision b/product/ERP5/bootstrap/erp5_core/bt/revision
index edb471677f7d9720689b8c3fe0d2ce324931cb54..4f07dde62323fd97738215c3369ce36ec0875223 100644
--- a/product/ERP5/bootstrap/erp5_core/bt/revision
+++ b/product/ERP5/bootstrap/erp5_core/bt/revision
@@ -1 +1 @@
-40990
\ No newline at end of file
+40991
\ No newline at end of file
diff --git a/product/ERP5Type/Core/ExtensionComponent.py b/product/ERP5Type/Core/ExtensionComponent.py
new file mode 100644
index 0000000000000000000000000000000000000000..6700f741e7b46b1deee31cd09d698dc44d0fa576
--- /dev/null
+++ b/product/ERP5Type/Core/ExtensionComponent.py
@@ -0,0 +1,96 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2012 Nexedi SA and Contributors. All Rights Reserved.
+#                    Arnaud Fontaine <arnaud.fontaine@nexedi.com>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsibility of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# guarantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+#
+##############################################################################
+
+import os.path
+
+from Products.ERP5Type.Core.DocumentComponent import DocumentComponent
+from AccessControl import ClassSecurityInfo
+from Products.ERP5Type import Permissions
+
+from zLOG import LOG, INFO                           
+
+class ExtensionComponent(DocumentComponent):
+  # CMF Type Definition
+  meta_type = 'ERP5 Extension Component'
+  portal_type = 'Extension Component'
+
+  # Declarative security
+  security = ClassSecurityInfo()
+  security.declareObjectProtected(Permissions.AccessContentsInformation)
+
+  security.declareProtected(Permissions.ModifyPortalContent,
+                            'importAllFromFilesystem')
+  @classmethod
+  def importAllFromFilesystem(cls, context):
+    """
+    Try to import all Extensions as found in INSTANCEHOME/Extensions and
+    returns error as a dict if any
+    """
+    from App.config import getConfiguration
+    extension_path_pattern = "%s%s%s/*" % (getConfiguration().instancehome,
+                                           os.path.sep,
+                                           'Extensions')
+
+    LOG("ERP5Type.Core.ExtensionComponent", INFO,
+        "Importing from %s" % extension_path_pattern)
+
+    import glob
+    failed_import_dict = {}
+    for extension_path in glob.iglob(extension_path_pattern):
+      try:
+        cls.importFromFilesystem(context, extension_path)
+      except Exception, e:
+        failed_import_dict[extension_path] = str(e)
+      else:
+        LOG("ERP5Type.Core.ExtensionComponent", INFO,
+            "Imported %s" % extension_path)
+
+    return failed_import_dict
+
+  security.declareProtected(Permissions.ModifyPortalContent,
+                            'importFromFilesystem')
+  @classmethod
+  def importFromFilesystem(cls, context, path):
+    """
+    Import an Extension from the given path into ZODB after checking that the
+    source code is valid
+    """
+    with open(path) as extension_file:
+      source_code = extension_file.read()
+
+    # Try to load it first
+    namespace_dict = {}
+    exec source_code in namespace_dict
+
+    class_name = os.path.basename(path).replace('.py', '')
+    return context.newContent(id='erp5.component.extension.%s' % class_name,
+                              # XXX-arnau: useless field?
+                              reference=class_name,
+                              text_content=source_code,
+                              portal_type=cls.portal_type)
diff --git a/product/ERP5Type/Tool/ComponentTool.py b/product/ERP5Type/Tool/ComponentTool.py
index 37eccc766a25c5c13eee05df412fcac08c4d6584..a393bafd83795af58dbac5211ec14fe179cc3749 100644
--- a/product/ERP5Type/Tool/ComponentTool.py
+++ b/product/ERP5Type/Tool/ComponentTool.py
@@ -31,7 +31,7 @@ from AccessControl import ClassSecurityInfo
 from Products.ERP5Type.Tool.BaseTool import BaseTool
 from Products.ERP5Type import Permissions
 
-from zLOG import LOG, INFO
+from zLOG import LOG, INFO, WARNING
 
 class ComponentTool(BaseTool):
   """
@@ -75,3 +75,40 @@ class ComponentTool(BaseTool):
                 "Global reset of %s.%s" % (module_name, name))
 
             delattr(module, name)
+
+  security.declareProtected(Permissions.ManagePortal,
+                            'createAllComponentFromFilesystem')
+  def createAllComponentFromFilesystem(self, erase_existing=False,
+                                       REQUEST=None):
+    """
+
+    XXX-arnau: only Extensions for now
+    """
+    portal = self.getPortalObject()
+
+    import erp5.portal_type
+    type_tool = portal.portal_types
+    failed_import_dict = {}
+    for content_portal_type in getattr(type_tool,
+                                       self.portal_type).getTypeAllowedContentTypeList():
+      try:
+        failed_import_dict.update(getattr(erp5.portal_type,
+                                          content_portal_type).importAllFromFilesystem(self))
+      except AttributeError:
+        LOG("ERP5Type.Tool.ComponentTool", WARNING, "Could not import %ss" % \
+              content_portal_type)
+
+    if REQUEST:
+      if failed_import_dict:
+        failed_import_formatted_list = []
+        for name, error in failed_import_dict.iteritems():
+          failed_import_formatted_list.append("%s (%s)" % (name, error))
+
+        message = "The following component could not be imported: %s" % \
+            ', '.join(failed_import_formatted_list)
+      else:
+        message = "All components were successfully imported " \
+            "from filesystem to ZODB."
+
+      return self.Base_redirect('view',
+                                keep_items={'portal_status_message': message})