Index: main/plugin-web/scripts/derby/jdbc_cache_mon.sql
===================================================================
--- main/plugin-web/scripts/derby/jdbc_cache_mon.sql	(revision 0)
+++ main/plugin-web/scripts/derby/jdbc_cache_mon.sql	(revision 0)
@@ -0,0 +1,106 @@
+--
+--  Copyright 2013 Anyware Services
+--
+--  Licensed under the Apache License, Version 2.0 (the "License");
+--  you may not use this file except in compliance with the License.
+--  You may obtain a copy of the License at
+--
+--      http://www.apache.org/licenses/LICENSE-2.0
+--
+--  Unless required by applicable law or agreed to in writing, software
+--  distributed under the License is distributed on an "AS IS" BASIS,
+--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+--  See the License for the specific language governing permissions and
+--  limitations under the License.
+--
+CREATE TABLE Cache_RA_HTTPServer (
+  Unique_Id VARCHAR(31) NOT NULL,
+  Site VARCHAR(255) NOT NULL,
+  Request_Date TIMESTAMP NOT NULL,
+  Method VARCHAR(15) NOT NULL,
+  Path VARCHAR(255) NOT NULL,
+  Query_String VARCHAR(255) NOT NULL,
+  Ori_Status_Code CHAR(3) NOT NULL,
+  Ret_Status_Code CHAR(3) NOT NULL,
+  Cache_Hit SMALLINT NOT NULL,
+  Created_At TIMESTAMP NOT NULL,
+  Processed SMALLINT NOT NULL DEFAULT 0,
+  PRIMARY KEY (Unique_Id)
+);
+
+CREATE TABLE Cache_RA_Front (
+  Unique_Id VARCHAR(31) NOT NULL,
+  Internal_Uuid VARCHAR(63) NOT NULL,
+  Site VARCHAR(255) NOT NULL,
+  Ametys_Path VARCHAR(255) NOT NULL,
+  Cacheable SMALLINT NOT NULL,
+  Cache_Hit_1 SMALLINT NOT NULL,
+  Cache_Hit_2 SMALLINT NOT NULL,
+  Created_At TIMESTAMP NOT NULL,
+  Processed SMALLINT NOT NULL DEFAULT 0
+);
+
+CREATE TABLE Cache_RA_Back (
+  Internal_Uuid VARCHAR(63) NOT NULL,
+  Page_Id VARCHAR(63) NOT NULL,
+  Page_Path VARCHAR(63) NOT NULL,
+  Rendering_Context VARCHAR(15) NOT NULL,
+  Workspace_JCR VARCHAR(15) NOT NULL,
+  Cacheable SMALLINT NOT NULL,
+  Created_At TIMESTAMP NOT NULL,
+  Processed SMALLINT NOT NULL DEFAULT 0
+);
+
+CREATE TABLE Cache_RA_Back_Page_Element (
+  Internal_Uuid VARCHAR(63) NOT NULL,
+  Page_Element_Id VARCHAR(63) NOT NULL,
+  Page_Element_Type VARCHAR(31) NOT NULL,
+  Page_Id VARCHAR(63) NOT NULL,
+  Rendering_Context VARCHAR(15) NOT NULL,
+  Workspace_JCR VARCHAR(15) NOT NULL,
+  Cacheable SMALLINT NOT NULL,
+  Cache_Hit SMALLINT NOT NULL,
+  Created_At TIMESTAMP NOT NULL,
+  Processed SMALLINT NOT NULL DEFAULT 0
+);
+
+CREATE TABLE Cache_Stats_Front (
+  Server_Site VARCHAR(255) NOT NULL DEFAULT '-',
+  Server_Path VARCHAR(255) NOT NULL DEFAULT '-',
+  Server_Hits INT NOT NULL DEFAULT 0,
+  Server_Cache_Hits INT NOT NULL DEFAULT 0,
+  Front_Site VARCHAR(255) NOT NULL DEFAULT '-',
+  Front_Path VARCHAR(255) NOT NULL DEFAULT '-',
+  Front_Cacheable SMALLINT NOT NULL DEFAULT 0,
+  Front_Hits INT NOT NULL DEFAULT 0,
+  Front_Cache_Hits_1 INT NOT NULL DEFAULT 0,
+  Front_Cache_Hits_2 INT NOT NULL DEFAULT 0,
+  Created_At TIMESTAMP NOT NULL,
+  Updated_At TIMESTAMP NOT NULL,
+  UNIQUE (Server_Site, Server_Path, Front_Site, Front_Path)
+);
+
+CREATE TABLE Cache_Stats_Back (
+  Page_Id VARCHAR(63) NOT NULL,
+  Page_Path VARCHAR(63) NOT NULL,
+  Rendering_Context VARCHAR(15) NOT NULL,
+  Workspace_JCR VARCHAR(15) NOT NULL,
+  Cacheable SMALLINT NOT NULL,
+  Hits INT NOT NULL,
+  Created_At TIMESTAMP NOT NULL,
+  Updated_At TIMESTAMP NOT NULL,
+  PRIMARY KEY (Page_Id, Rendering_Context, Workspace_JCR)
+);
+
+CREATE TABLE Cache_Stats_Back_Page_Element (
+  Page_Element_Id VARCHAR(63) NOT NULL,
+  Page_Id VARCHAR(63) NOT NULL,
+  Rendering_Context VARCHAR(15) NOT NULL,
+  Workspace_JCR VARCHAR(15) NOT NULL,
+  Cacheable SMALLINT NOT NULL,
+  Hits INT NOT NULL,
+  Cache_Hits INT NOT NULL,
+  Created_At TIMESTAMP NOT NULL,
+  Updated_At TIMESTAMP NOT NULL,
+  PRIMARY KEY (Page_Element_Id, Page_Id, Rendering_Context, Workspace_JCR)
+);
Index: main/plugin-web/scripts/oracle/jdbc_cache_mon.sql
===================================================================
--- main/plugin-web/scripts/oracle/jdbc_cache_mon.sql	(revision 0)
+++ main/plugin-web/scripts/oracle/jdbc_cache_mon.sql	(revision 0)
@@ -0,0 +1,107 @@
+--
+--  Copyright 2013 Anyware Services
+--
+--  Licensed under the Apache License, Version 2.0 (the "License");
+--  you may not use this file except in compliance with the License.
+--  You may obtain a copy of the License at
+--
+--      http://www.apache.org/licenses/LICENSE-2.0
+--
+--  Unless required by applicable law or agreed to in writing, software
+--  distributed under the License is distributed on an "AS IS" BASIS,
+--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+--  See the License for the specific language governing permissions and
+--  limitations under the License.
+--
+CREATE TABLE Cache_RA_HTTPServer (
+  Unique_Id VARCHAR(31) NOT NULL,
+  Site VARCHAR(255) NOT NULL,
+  Request_Date TIMESTAMP NOT NULL,
+  Method VARCHAR(15) NOT NULL,
+  Path VARCHAR(255) NOT NULL,
+  Query_String VARCHAR(255) NOT NULL,
+  Ori_Status_Code CHAR(3) NOT NULL,
+  Ret_Status_Code CHAR(3) NOT NULL,
+  Cache_Hit NUMBER(1) NOT NULL,
+  Created_At TIMESTAMP NOT NULL,
+  Processed NUMBER(1) DEFAULT 0 NOT NULL,
+  PRIMARY KEY (Unique_Id)
+);
+
+
+CREATE TABLE Cache_RA_Front (
+  Unique_Id VARCHAR(31) NOT NULL,
+  Internal_Uuid VARCHAR(63) NOT NULL,
+  Site VARCHAR(255) NOT NULL,
+  Ametys_Path VARCHAR(255) NOT NULL,
+  Cacheable NUMBER(1) NOT NULL,
+  Cache_Hit_1 NUMBER(1) NOT NULL,
+  Cache_Hit_2 NUMBER(1) NOT NULL,
+  Created_At TIMESTAMP NOT NULL,
+  Processed NUMBER(1) DEFAULT 0 NOT NULL
+);
+
+CREATE TABLE Cache_RA_Back (
+  Internal_Uuid VARCHAR(63) NOT NULL,
+  Page_Id VARCHAR(63) NOT NULL,
+  Page_Path VARCHAR(63) NOT NULL,
+  Rendering_Context VARCHAR(15) NOT NULL,
+  Workspace_JCR VARCHAR(15) NOT NULL,
+  Cacheable NUMBER(1) NOT NULL,
+  Created_At TIMESTAMP NOT NULL,
+  Processed NUMBER(1) DEFAULT 0 NOT NULL
+);
+
+CREATE TABLE Cache_RA_Back_Page_Element (
+  Internal_Uuid VARCHAR(63) NOT NULL,
+  Page_Element_Id VARCHAR(63) NOT NULL,
+  Page_Element_Type VARCHAR(31) NOT NULL,
+  Page_Id VARCHAR(63) NOT NULL,
+  Rendering_Context VARCHAR(15) NOT NULL,
+  Workspace_JCR VARCHAR(15) NOT NULL,
+  Cacheable NUMBER(1) NOT NULL,
+  Cache_Hit NUMBER(1) NOT NULL,
+  Created_At TIMESTAMP NOT NULL,
+  Processed NUMBER(1) DEFAULT 0 NOT NULL
+);
+
+CREATE TABLE Cache_Stats_Front (
+  Server_Site VARCHAR(255) DEFAULT '-' NOT NULL,
+  Server_Path VARCHAR(255) DEFAULT '-' NOT NULL,
+  Server_Hits INT DEFAULT 0 NOT NULL,
+  Server_Cache_Hits INT DEFAULT 0 NOT NULL,
+  Front_Site VARCHAR(255) DEFAULT '-' NOT NULL,
+  Front_Path VARCHAR(255) DEFAULT '-' NOT NULL,
+  Front_Cacheable NUMBER(1) DEFAULT 0 NOT NULL,
+  Front_Hits INT DEFAULT 0 NOT NULL,
+  Front_Cache_Hits_1 INT DEFAULT 0 NOT NULL,
+  Front_Cache_Hits_2 INT DEFAULT 0 NOT NULL,
+  Created_At TIMESTAMP NOT NULL,
+  Updated_At TIMESTAMP NOT NULL,
+  UNIQUE (Server_Site, Server_Path, Front_Site, Front_Path)
+);
+
+CREATE TABLE Cache_Stats_Back (
+  Page_Id VARCHAR(63) NOT NULL,
+  Page_Path VARCHAR(63) NOT NULL,
+  Rendering_Context VARCHAR(15) NOT NULL,
+  Workspace_JCR VARCHAR(15) NOT NULL,
+  Cacheable NUMBER(1) NOT NULL,
+  Hits INT NOT NULL,
+  Created_At TIMESTAMP NOT NULL,
+  Updated_At TIMESTAMP NOT NULL,
+  PRIMARY KEY (Page_Id, Rendering_Context, Workspace_JCR)
+);
+
+CREATE TABLE Cache_Stats_Back_Page_Element (
+  Page_Element_Id VARCHAR(63) NOT NULL,
+  Page_Id VARCHAR(63) NOT NULL,
+  Rendering_Context VARCHAR(15) NOT NULL,
+  Workspace_JCR VARCHAR(15) NOT NULL,
+  Cacheable NUMBER(1) NOT NULL,
+  Hits INT NOT NULL,
+  Cache_Hits INT NOT NULL,
+  Created_At TIMESTAMP NOT NULL,
+  Updated_At TIMESTAMP NOT NULL,
+  PRIMARY KEY (Page_Element_Id, Page_Id, Rendering_Context, Workspace_JCR)
+);
Index: main/plugin-web/scripts/postgresql/jdbc_cache_mon.sql
===================================================================
--- main/plugin-web/scripts/postgresql/jdbc_cache_mon.sql	(revision 0)
+++ main/plugin-web/scripts/postgresql/jdbc_cache_mon.sql	(revision 0)
@@ -0,0 +1,119 @@
+--
+--  Copyright 2013 Anyware Services
+--
+--  Licensed under the Apache License, Version 2.0 (the "License");
+--  you may not use this file except in compliance with the License.
+--  You may obtain a copy of the License at
+--
+--      http://www.apache.org/licenses/LICENSE-2.0
+--
+--  Unless required by applicable law or agreed to in writing, software
+--  distributed under the License is distributed on an "AS IS" BASIS,
+--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+--  See the License for the specific language governing permissions and
+--  limitations under the License.
+--
+
+BEGIN;
+
+drop table if exists Cache_RA_HTTPServer;
+CREATE TABLE Cache_RA_HTTPServer (
+  Unique_Id VARCHAR(31) NOT NULL,
+  Site VARCHAR(255) NOT NULL,
+  Request_Date TIMESTAMP NOT NULL,
+  Method VARCHAR(15) NOT NULL,
+  Path VARCHAR(255) NOT NULL,
+  Query_String VARCHAR(255) NOT NULL,
+  Ori_Status_Code CHAR(3) NOT NULL,
+  Ret_Status_Code CHAR(3) NOT NULL,
+  Cache_Hit SMALLINT NOT NULL,
+  Created_At TIMESTAMP NOT NULL, -- The DEFAULT clause prevents weird auto update (See Mysql doc)
+  Processed SMALLINT NOT NULL DEFAULT 0,
+  PRIMARY KEY (Unique_Id)
+);
+
+
+drop table if exists Cache_RA_Front;
+CREATE TABLE Cache_RA_Front (
+  Unique_Id VARCHAR(31) NOT NULL,
+  Internal_Uuid VARCHAR(63) NOT NULL,
+  Site VARCHAR(255) NOT NULL,
+  Ametys_Path VARCHAR(255) NOT NULL,
+  Cacheable SMALLINT NOT NULL,
+  Cache_Hit_1 SMALLINT NOT NULL,
+  Cache_Hit_2 SMALLINT NOT NULL,
+  Created_At TIMESTAMP NOT NULL, -- The DEFAULT clause prevents weird auto update (See Mysql doc)
+  Processed SMALLINT NOT NULL DEFAULT 0
+);
+
+drop table if exists Cache_RA_Back;
+CREATE TABLE Cache_RA_Back (
+  Internal_Uuid VARCHAR(63) NOT NULL,
+  Page_Id VARCHAR(63) NOT NULL,
+  Page_Path VARCHAR(63) NOT NULL,
+  Rendering_Context VARCHAR(15) NOT NULL,
+  Workspace_JCR VARCHAR(15) NOT NULL,
+  Cacheable SMALLINT NOT NULL,
+  Created_At TIMESTAMP NOT NULL, -- The DEFAULT clause prevents weird auto update (See Mysql doc)
+  Processed SMALLINT NOT NULL DEFAULT 0
+);
+
+drop table if exists Cache_RA_Back_Page_Element;
+CREATE TABLE Cache_RA_Back_Page_Element (
+  Internal_Uuid VARCHAR(63) NOT NULL,
+  Page_Element_Id VARCHAR(63) NOT NULL,
+  Page_Element_Type VARCHAR(31) NOT NULL,
+  Page_Id VARCHAR(63) NOT NULL,
+  Rendering_Context VARCHAR(15) NOT NULL,
+  Workspace_JCR VARCHAR(15) NOT NULL,
+  Cacheable SMALLINT NOT NULL,
+  Cache_Hit SMALLINT NOT NULL,
+  Created_At TIMESTAMP NOT NULL,
+  Processed SMALLINT NOT NULL DEFAULT 0
+);
+
+drop table if exists Cache_Stats_Front;
+CREATE TABLE Cache_Stats_Front (
+  Server_Site VARCHAR(255) NOT NULL DEFAULT '-',
+  Server_Path VARCHAR(255) NOT NULL DEFAULT '-',
+  Server_Hits INT NOT NULL DEFAULT 0,
+  Server_Cache_Hits INT NOT NULL DEFAULT 0,
+  Front_Site VARCHAR(255) NOT NULL DEFAULT '-',
+  Front_Path VARCHAR(255) NOT NULL DEFAULT '-',
+  Front_Cacheable SMALLINT NOT NULL DEFAULT 0,
+  Front_Hits INT NOT NULL DEFAULT 0,
+  Front_Cache_Hits_1 INT NOT NULL DEFAULT 0,
+  Front_Cache_Hits_2 INT NOT NULL DEFAULT 0,
+  Created_At TIMESTAMP NOT NULL,
+  Updated_At TIMESTAMP NOT NULL,
+  UNIQUE (Server_Site, Server_Path, Front_Site, Front_Path)
+);
+
+drop table if exists Cache_Stats_Back;
+CREATE TABLE Cache_Stats_Back (
+  Page_Id VARCHAR(63) NOT NULL,
+  Page_Path VARCHAR(63) NOT NULL,
+  Rendering_Context VARCHAR(15) NOT NULL,
+  Workspace_JCR VARCHAR(15) NOT NULL,
+  Cacheable SMALLINT NOT NULL,
+  Hits INT NOT NULL,
+  Created_At TIMESTAMP NOT NULL,
+  Updated_At TIMESTAMP NOT NULL,
+  PRIMARY KEY (Page_Id, Rendering_Context, Workspace_JCR)
+);
+
+drop table if exists Cache_Stats_Back_Page_Element;
+CREATE TABLE Cache_Stats_Back_Page_Element (
+  Page_Element_Id VARCHAR(63) NOT NULL,
+  Page_Id VARCHAR(63) NOT NULL,
+  Rendering_Context VARCHAR(15) NOT NULL,
+  Workspace_JCR VARCHAR(15) NOT NULL,
+  Cacheable SMALLINT NOT NULL,
+  Hits INT NOT NULL,
+  Cache_Hits INT NOT NULL,
+  Created_At TIMESTAMP NOT NULL,
+  Updated_At TIMESTAMP NOT NULL,
+  PRIMARY KEY (Page_Element_Id, Page_Id, Rendering_Context, Workspace_JCR)
+);
+
+COMMIT;
Index: main/plugin-web/scripts/mysql/jdbc_cache_mon.sql
===================================================================
--- main/plugin-web/scripts/mysql/jdbc_cache_mon.sql	(revision 0)
+++ main/plugin-web/scripts/mysql/jdbc_cache_mon.sql	(revision 0)
@@ -0,0 +1,114 @@
+--
+--  Copyright 2013 Anyware Services
+--
+--  Licensed under the Apache License, Version 2.0 (the "License");
+--  you may not use this file except in compliance with the License.
+--  You may obtain a copy of the License at
+--
+--      http://www.apache.org/licenses/LICENSE-2.0
+--
+--  Unless required by applicable law or agreed to in writing, software
+--  distributed under the License is distributed on an "AS IS" BASIS,
+--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+--  See the License for the specific language governing permissions and
+--  limitations under the License.
+--
+drop table if exists Cache_RA_HTTPServer;
+CREATE TABLE Cache_RA_HTTPServer (
+  Unique_Id VARCHAR(31) NOT NULL,
+  Site VARCHAR(255) NOT NULL,
+  Request_Date TIMESTAMP NOT NULL,
+  Method VARCHAR(15) NOT NULL,
+  Path VARCHAR(255) NOT NULL,
+  Query_String VARCHAR(255) NOT NULL,
+  Ori_Status_Code CHAR(3) NOT NULL,
+  Ret_Status_Code CHAR(3) NOT NULL,
+  Cache_Hit TINYINT(1) NOT NULL,
+  Created_At TIMESTAMP NOT NULL DEFAULT 0, -- The DEFAULT clause prevents weird auto update (See Mysql doc)
+  Processed TINYINT(1) NOT NULL DEFAULT 0,
+  PRIMARY KEY (Unique_Id)
+) ENGINE=InnoDB;
+
+
+drop table if exists Cache_RA_Front;
+CREATE TABLE Cache_RA_Front (
+  Unique_Id VARCHAR(31) NOT NULL,
+  Internal_Uuid VARCHAR(63) NOT NULL,
+  Site VARCHAR(255) NOT NULL,
+  Ametys_Path VARCHAR(255) NOT NULL,
+  Cacheable TINYINT(1) NOT NULL,
+  Cache_Hit_1 TINYINT(1) NOT NULL,
+  Cache_Hit_2 TINYINT(1) NOT NULL,
+  Created_At TIMESTAMP NOT NULL DEFAULT 0, -- The DEFAULT clause prevents weird auto update (See Mysql doc)
+  Processed TINYINT(1) NOT NULL DEFAULT 0
+) ENGINE=InnoDB;
+
+drop table if exists Cache_RA_Back;
+CREATE TABLE Cache_RA_Back (
+  Internal_Uuid VARCHAR(63) NOT NULL,
+  Page_Id VARCHAR(63) NOT NULL,
+  Page_Path VARCHAR(63) NOT NULL,
+  Rendering_Context VARCHAR(15) NOT NULL,
+  Workspace_JCR VARCHAR(15) NOT NULL,
+  Cacheable TINYINT(1) NOT NULL,
+  Created_At TIMESTAMP NOT NULL DEFAULT 0, -- The DEFAULT clause prevents weird auto update (See Mysql doc)
+  Processed TINYINT(1) NOT NULL DEFAULT 0
+) ENGINE=InnoDB;
+
+drop table if exists Cache_RA_Back_Page_Element;
+CREATE TABLE Cache_RA_Back_Page_Element (
+  Internal_Uuid VARCHAR(63) NOT NULL,
+  Page_Element_Id VARCHAR(63) NOT NULL,
+  Page_Element_Type VARCHAR(31) NOT NULL,
+  Page_Id VARCHAR(63) NOT NULL,
+  Rendering_Context VARCHAR(15) NOT NULL,
+  Workspace_JCR VARCHAR(15) NOT NULL,
+  Cacheable TINYINT(1) NOT NULL,
+  Cache_Hit TINYINT(1) NOT NULL,
+  Created_At TIMESTAMP NOT NULL DEFAULT 0, -- The DEFAULT clause prevents weird auto update (See Mysql doc)
+  Processed TINYINT(1) NOT NULL DEFAULT 0
+) ENGINE=InnoDB;
+
+drop table if exists Cache_Stats_Front;
+CREATE TABLE Cache_Stats_Front (
+  Server_Site VARCHAR(255) NOT NULL DEFAULT '-',
+  Server_Path VARCHAR(255) NOT NULL DEFAULT '-',
+  Server_Hits INT NOT NULL DEFAULT 0,
+  Server_Cache_Hits INT NOT NULL DEFAULT 0,
+  Front_Site VARCHAR(255) NOT NULL DEFAULT '-',
+  Front_Path VARCHAR(255) NOT NULL DEFAULT '-',
+  Front_Cacheable TINYINT(1) NOT NULL DEFAULT 0,
+  Front_Hits INT NOT NULL DEFAULT 0,
+  Front_Cache_Hits_1 INT NOT NULL DEFAULT 0,
+  Front_Cache_Hits_2 INT NOT NULL DEFAULT 0,
+  Created_At TIMESTAMP NOT NULL DEFAULT 0, -- The DEFAULT clause prevents weird auto update (See Mysql doc)
+  Updated_At TIMESTAMP NOT NULL DEFAULT 0, -- The DEFAULT clause prevents weird auto update (See Mysql doc)
+  UNIQUE KEY (Server_Site, Server_Path, Front_Site, Front_Path)
+) ENGINE=InnoDB;
+
+drop table if exists Cache_Stats_Back;
+CREATE TABLE Cache_Stats_Back (
+  Page_Id VARCHAR(63) NOT NULL,
+  Page_Path VARCHAR(63) NOT NULL,
+  Rendering_Context VARCHAR(15) NOT NULL,
+  Workspace_JCR VARCHAR(15) NOT NULL,
+  Cacheable TINYINT(1) NOT NULL,
+  Hits INT NOT NULL,
+  Created_At TIMESTAMP NOT NULL DEFAULT 0, -- The DEFAULT clause prevents weird auto update (See Mysql doc)
+  Updated_At TIMESTAMP NOT NULL DEFAULT 0, -- The DEFAULT clause prevents weird auto update (See Mysql doc)
+  PRIMARY KEY (Page_Id, Rendering_Context, Workspace_JCR)
+) ENGINE=InnoDB;
+
+drop table if exists Cache_Stats_Back_Page_Element;
+CREATE TABLE Cache_Stats_Back_Page_Element (
+  Page_Element_Id VARCHAR(63) NOT NULL,
+  Page_Id VARCHAR(63) NOT NULL,
+  Rendering_Context VARCHAR(15) NOT NULL,
+  Workspace_JCR VARCHAR(15) NOT NULL,
+  Cacheable TINYINT(1) NOT NULL,
+  Hits INT NOT NULL,
+  Cache_Hits INT NOT NULL,
+  Created_At TIMESTAMP NOT NULL DEFAULT 0, -- The DEFAULT clause prevents weird auto update (See Mysql doc)
+  Updated_At TIMESTAMP NOT NULL DEFAULT 0, -- The DEFAULT clause prevents weird auto update (See Mysql doc)
+  PRIMARY KEY (Page_Element_Id, Page_Id, Rendering_Context, Workspace_JCR)
+) ENGINE=InnoDB;
Index: main/plugin-web/i18n/messages_en.xml
===================================================================
--- main/plugin-web/i18n/messages_en.xml	(revision 20673)
+++ main/plugin-web/i18n/messages_en.xml	(working copy)
@@ -290,6 +290,20 @@
     <message key="PLUGINS_WEB_FO_LOGIN_NO_ACCOUNT">You don't have an account?</message>
     
 	<!-- +
+		 | CACHE MONITORING
+		 + -->
+    <message key="PLUGINS_WEB_CONFIG_CACHE_MONITORING_CATEGORY">Cache Monitoring</message>
+    <message key="PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_GROUP">Monitoring database connection</message>
+    <message key="PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_DRIVER_LABEL">Driver</message>
+    <message key="PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_DRIVER_DESCRIPTION">JDBC Driver fully qualified class name</message>
+    <message key="PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_URL_LABEL">Url</message>
+    <message key="PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_URL_DESCRIPTION">JDBC URL for connecting to the database</message>
+    <message key="PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_USER_LABEL">User</message>
+    <message key="PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_USER_DESCRIPTION">User name for connecting to the database</message>
+    <message key="PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_PASSWORD_LABEL">Password</message>
+    <message key="PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_PASSWORD_DESCRIPTION">Password associated with the user name for connecting to the database</message>
+    
+	<!-- +
 		 | SITES CONFIGURATION
 		 + -->
     <message key="PLUGINS_WEB_SITE_INFORMATION_CATEGORY">General information</message>
@@ -326,6 +340,8 @@
 	<message key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_CONFIG">Configure</message>
 	<message key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_STATISTICS">Site statistics</message>
     <message key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_GLOBAL_STATISTICS">Global statistics</message>
+    <message key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_CACHE_BACK_STATISTICS">Cache back statistics</message>
+    <message key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_CACHE_SERVERS_STATISTICS">Cache front statistics</message>
 	<message key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_DELETE">Delete</message>
 	<message key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_OPEN">Open website as a contributor</message>
 	<message key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_NEW">New site</message>
@@ -449,7 +465,47 @@
     <message key="PLUGINS_WEB_ADMINISTRATOR_GLOBAL_STATISTICS_VALUE_CONTENTS_SITECONTENTS">Content count in all the sites</message>
     <message key="PLUGINS_WEB_ADMINISTRATOR_GLOBAL_STATISTICS_RESOURCES">Resource explorer</message>
     <message key="PLUGINS_WEB_ADMINISTRATOR_GLOBAL_STATISTICS_PAGES">Pages</message>
-    
+    <message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_STATISTICS_LOAD_MESSAGE">Loading statistics, please wait...</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_STATISTICS_HANDLE">Actions</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_STATISTICS_HANDLE_REINITIALIZE">Reinitialize the statistics</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_STATISTICS_HANDLE_QUIT">Quit</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_STATISTICS_HELP">Help</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_TITLE">Statistics of the caches for the site {name} (back)</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_RELOAD_BTN_LABEL">Reload</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_HELP_TEXT">This screen displays some statistics about pages and page elements on the back-office.&lt;br/&gt;&lt;br/&gt; \
+	Statistics can be filtered by context (couple rendering context - workspace JCR).&lt;br/&gt;Thus, it is possible to select  or deselect contexts and then reload the table by clicking on the 'reload' bouton.&lt;br/&gt;&lt;br/&gt; \
+	Statistics columns are grouped by category ('page' or 'page element').&lt;br/&gt;The 'cacheable' column represent the rate of page elements that are cacheable, weighted by element hits.&lt;br/&gt;This way, the rates 'cacheable' and 'efficiency' can be directly compared.</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_FIRST_ROWHD_PAGE">Pages</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_FIRST_ROWHD_PAGE_ELEMENT">Page elements</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_COL_FIRST">Title</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_COL_PAGE_HITS">Hits</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_COL_CACHEABLE">Cacheable</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_COL_EFFICIENCY">Efficiency</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_COL_HITS">Hits</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_COL_CACHE_HITS">Cache hits</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_TITLE">Statistics of the caches for the site {name} (front)</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_HELP_TEXT">This screen displays statistics of the caches use on the front-office.&lt;br/&gt;&lt;br/&gt; \
+	It is possible to get more information by clicking on the appropriate button in the action menu.&lt;br/&gt;You will get the detailed statistics for Apache and the front-offiche.&lt;br/&gt;&lt;br/&gt; \
+	As it is for the back-office statistics, the 'cacheable' rate  is weighted by the number of hits.</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_HANDLE_DISPLAY_HIDE">Display/Hide details</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_FIRST_ROWHD_FIRST">Main</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_FIRST_ROWHD_EFFICIENCY">Efficiency</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_FIRST_ROWHD_HITS">Hits</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_FIRST_ROWHD_CACHE_HITS">Cache hits</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_FIRST_ROWHD_BACK">Back</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_FIRST">Titre</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_CACHEABLE">Cacheable</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_EFFICIENCY_TOTAL">Total</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_EFFICIENCY_APACHE">Apache</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_EFFICIENCY_FRONT">Front</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_HITS_TOTAL">Total</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_HITS_APACHE">Apache</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_HITS_FRONT">Front</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_CACHE_HITS_TOTAL">Total</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_CACHE_HITS_APACHE">Apache</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_CACHE_HITS_FRONT">Front</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_HITS_BACK">Hits</message>
+	
     <!-- +
 		 | SKIN ADMINISTRATION
 		 + -->
@@ -457,6 +513,7 @@
 	<message key="PLUGINS_WEB_ADMINISTRATOR_SKINS_DESCRIPTION">Skins management</message>
 	<message key="PLUGINS_WEB_ADMINISTRATOR_SKINS_TITLE">Skins management</message>
     <message key="PLUGINS_WEB_ADMINISTRATOR_SKINS_HANDLE">Actions</message>
+    
 	<message key="PLUGINS_WEB_ADMINISTRATOR_SKINS_HANDLE_IMPORT_ZIP">Import a Ametys skin</message>
 	<message key="PLUGINS_WEB_ADMINISTRATOR_SKINS_HANDLE_IMPORT_ZIP_DESC">Import a Ametys skin from a ZIP file</message>
 	<message key="PLUGINS_WEB_ADMINISTRATOR_SKINS_HANDLE_EXPORT_ZIP">Export to ZIP format</message>
Index: main/plugin-web/i18n/messages_fr.xml
===================================================================
--- main/plugin-web/i18n/messages_fr.xml	(revision 20673)
+++ main/plugin-web/i18n/messages_fr.xml	(working copy)
@@ -290,6 +290,20 @@
 	<message key="PLUGINS_WEB_FO_LOGIN_NO_ACCOUNT">Vous n'avez pas de compte ?</message>
 	
 	<!-- +
+		 | CACHE MONITORING
+		 + -->
+    <message key="PLUGINS_WEB_CONFIG_CACHE_MONITORING_CATEGORY">Monitoring Cache</message>
+    <message key="PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_GROUP">Connexion à la base de données de monitoring</message>
+    <message key="PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_DRIVER_LABEL">Pilote</message>
+    <message key="PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_DRIVER_DESCRIPTION">Nom complet de la classe driver JDBC à charger</message>
+    <message key="PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_URL_LABEL">Url</message>
+    <message key="PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_URL_DESCRIPTION">Url JDBC de connexion au serveur de base de données</message>
+    <message key="PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_USER_LABEL">Utilisateur</message>
+    <message key="PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_USER_DESCRIPTION">Nom d'utilisateur à utiliser lors de la connexion au serveur de base de données</message>
+    <message key="PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_PASSWORD_LABEL">Mot de passe</message>
+    <message key="PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_PASSWORD_DESCRIPTION">Mot de passe associé au nom d'utilisateur à utiliser lors de la connexion au serveur de base de données</message>
+	
+	<!-- +
 		 | SITES CONFIGURATION
 		 + -->
 	<message key="PLUGINS_WEB_SITE_INFORMATION_CATEGORY">Informations générales</message>
@@ -326,6 +340,8 @@
 	<message key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_CONFIG">Configurer</message>
 	<message key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_STATISTICS">Statistiques du site</message>
 	<message key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_GLOBAL_STATISTICS">Statistiques globales</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_CACHE_BACK_STATISTICS">Statistiques du cache (back)</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_CACHE_SERVERS_STATISTICS">Statistiques du cache (front)</message>
 	<message key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_DELETE">Supprimer</message>
 	<message key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_OPEN">Ouvrir dans le CMS</message>
 	<message key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_NEW">Nouveau site</message>
@@ -449,6 +465,46 @@
     <message key="PLUGINS_WEB_ADMINISTRATOR_GLOBAL_STATISTICS_VALUE_CONTENTS_SITECONTENTS">Nombre de contenus dans l'ensemble des sites</message>
     <message key="PLUGINS_WEB_ADMINISTRATOR_GLOBAL_STATISTICS_RESOURCES">Explorateur de ressources</message>
     <message key="PLUGINS_WEB_ADMINISTRATOR_GLOBAL_STATISTICS_PAGES">Pages</message>
+    <message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_STATISTICS_LOAD_MESSAGE">Chargement des statistiques, veuillez patienter...</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_STATISTICS_HANDLE">Actions</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_STATISTICS_HANDLE_REINITIALIZE">Réinitialiser les stats</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_STATISTICS_HANDLE_QUIT">Quitter</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_STATISTICS_HELP">Aide</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_TITLE">Statistiques des caches pour le site {name} (back)</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_RELOAD_BTN_LABEL">Recharger</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_HELP_TEXT">Ce tableau centralise les statistiques d'accès aux pages et éléments des pages sur le back-office.&lt;br/&gt;&lt;br/&gt; \
+	Les statistiques peuvent être filtrées par contexte (couple contexte de rendu - workspace JCR).&lt;br/&gt;Ainsi il est possible de sélectionner ou désélectionner des contextes puis de recharger le tableau à l'aide du bouton 'recharger'.&lt;br/&gt;&lt;br/&gt; \
+	Les statistiques sont regroupées selon qu'elles se rapportent aux pages ou aux éléments des pages.&lt;br/&gt;La colonne 'cacheable' représente le taux d'éléments des pages qui sont cacheables, pondéré par le nombre de hits par élément.&lt;br/&gt;En conséquence, les taux 'cacheable' et 'efficacité' peuvent être comparés directement.</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_FIRST_ROWHD_PAGE">Pages</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_FIRST_ROWHD_PAGE_ELEMENT">Eléments des pages</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_COL_FIRST">Titre</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_COL_PAGE_HITS">Hits</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_COL_CACHEABLE">Cacheable</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_COL_EFFICIENCY">Efficacité</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_COL_HITS">Hits</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_COL_CACHE_HITS">Cache hits</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_TITLE">Statistiques des caches pour le site {name} (front)</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_HELP_TEXT">Ce tableau centralise les statistiques d'utilisation des caches côté front-office.&lt;br/&gt;&lt;br/&gt; \
+	Il est possible d'afficher plus d'informations en cliquant sur le bouton approprié dans le menu des actions.&lt;br/&gt;Vous obtiendrez le détails des statistiques pour Apache et le front-office.&lt;br/&gt;&lt;br/&gt; \
+	Comme pour les statistique côté back-office, le taux 'cacheable' est pondéré par le nombre de hits.</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_HANDLE_DISPLAY_HIDE">Afficher/Masquer détails</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_FIRST_ROWHD_FIRST">Général</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_FIRST_ROWHD_EFFICIENCY">Efficacité</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_FIRST_ROWHD_HITS">Hits</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_FIRST_ROWHD_CACHE_HITS">Cache hits</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_FIRST_ROWHD_BACK">Back</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_FIRST">Titre</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_CACHEABLE">Cacheable</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_EFFICIENCY_TOTAL">Total</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_EFFICIENCY_APACHE">Apache</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_EFFICIENCY_FRONT">Front</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_HITS_TOTAL">Total</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_HITS_APACHE">Apache</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_HITS_FRONT">Front</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_CACHE_HITS_TOTAL">Total</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_CACHE_HITS_APACHE">Apache</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_CACHE_HITS_FRONT">Front</message>
+	<message key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_HITS_BACK">Hits</message>
     
     <!-- +
 		 | SKIN ADMINISTRATION
Index: main/plugin-web/resources/js/org/ametys/web/administration/CacheStatisticsBack.i18n.js
===================================================================
--- main/plugin-web/resources/js/org/ametys/web/administration/CacheStatisticsBack.i18n.js	(revision 0)
+++ main/plugin-web/resources/js/org/ametys/web/administration/CacheStatisticsBack.i18n.js	(revision 0)
@@ -0,0 +1,226 @@
+/*
+ *  Copyright 2012 Anyware Services
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+Ext.namespace('org.ametys.web.administration');
+
+org.ametys.web.administration.CacheStatisticsBack = function () {}
+
+org.ametys.web.administration.CacheStatisticsBack.init = function (pluginName, siteName, sitePath)
+{
+	this.pluginName = pluginName;
+	this.siteName = siteName;
+	this.sitePath = sitePath;
+	
+	// Contexts (that can be filtered)
+	this._contexts = [
+	                'back-default',
+	                'front-live',
+	                'preview-default',
+	                'preview-live'
+	];
+	
+	// init tb
+	var toolbar = this._initToolbar();
+	
+	// init loader
+	this._loader = new Ext.ux.tree.XmlTreeLoader({
+		dataUrl: getPluginDirectUrl(this.pluginName) + '/administrator/sites/' + siteName + '/cache-statistics-back-tree.xml',
+		baseParams: {
+			contexts : this._contexts.join('#')
+		}
+	});
+	
+	// loader listeners
+	this._loader.on('beforeload', this._beforeLoadStats, this);
+	this._loader.on('load', this._loadStats, this);
+	
+	
+	this._grid = new org.ametys.web.administration.cacheStatistics.DoubleHeaderTreeGrid({
+		/* width: 610,*/
+		region: 'center',
+		enableDD: false,
+		enableHdMenu: false,
+		enableSort: false,
+		border: false,
+		firstRowHd:[
+		                {colspan: 1, align: 'center'},
+		                {header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_FIRST_ROWHD_PAGE"/>", colspan: 1, align: 'center'},
+		                {header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_FIRST_ROWHD_PAGE_ELEMENT"/>", colspan: 4, align: 'center'}
+		],
+        columns:[
+                 // total width must be 590
+                 {header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_COL_FIRST"/>", dataIndex: 'label', width: 280},
+                 {header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_COL_PAGE_HITS"/>", dataIndex: 'pageHits', align: 'center', width: 50},
+                 {header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_COL_CACHEABLE"/>", dataIndex: 'cacheable', align: 'center', width: 70},
+                 {header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_COL_EFFICIENCY"/>", dataIndex: 'eff', align: 'center', width: 70},
+                 {header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_COL_HITS"/>", dataIndex: 'hits', align: 'center', width: 50},
+                 {header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_COL_CACHE_HITS"/>", dataIndex: 'cacheHits', align: 'center', width: 70}
+		],
+        loader: this._loader,
+        tbar: toolbar
+	}); 
+	
+	this._centerPanel = new Ext.Panel({
+		region:'center',
+		layout: 'border',
+		baseCls: 'transparent-panel',
+		border: false,
+		autoScroll : true,
+		height: 'auto',
+		items: [this._grid]
+	});		
+	
+	// Handle box
+	this._handle = new org.ametys.ActionsPanel({title: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_STATISTICS_HANDLE"/>"});
+	// Not available currenlty.
+//	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_STATISTICS_HANDLE_REINITIALIZE"/>", getPluginResourcesUrl(this.pluginName) + "/img/administrator/sites/cachestats/reinitialize.png", org.ametys.web.administration.cacheStatistics._reinitializeStats);
+	// Quit action
+	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_STATISTICS_HANDLE_QUIT"/>", getPluginResourcesUrl('core') + '/img/administrator/config/quit.png', org.ametys.web.administration.cacheStatistics._goBack.createDelegate(this));
+	
+	// Help box
+	var help = new org.ametys.TextPanel({title: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_STATISTICS_HELP"/>"});
+	help.addText("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_HELP_TEXT"/>");
+	
+	this._rightPanel = new org.ametys.HtmlContainer({
+		region:'east',
+		border: false,
+		cls: 'admin-right-panel',
+		width: 277,
+	    items: [this._handle, help]
+	});
+}
+
+org.ametys.web.administration.CacheStatisticsBack._initToolbar = function()
+{
+	var self = this;
+	
+	// Toolbar btn abstraction
+	var ContextItem = function(context, pressed) {
+		var res = context.split('-'),
+			renderingCtx = res[0],
+			workspace= res[1];
+			
+		return new Ext.Button({
+			text: renderingCtx + '/' + workspace,
+			enableToggle: true,
+			toggleHandler: self._onContextItemToggle,
+			scope: self,
+			'context': context,
+			'renderingCtx': renderingCtx,
+			'workspace': workspace,
+			'pressed': pressed
+		});
+	}
+	
+	// Construct toolbar btn depending on contexts.
+	var items = [];
+	for (var c in this._contexts) {
+		if (Object.prototype.hasOwnProperty.call(this._contexts, c)) {
+			if (c > 0) items.push(' '); // toolbar spacer 
+			items.push(ContextItem(this._contexts[c], true));
+		}
+	}
+	
+	// Reload stats btn
+	items.push('-');
+	items.push(new Ext.Button({
+		text: '<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_RELOAD_BTN_LABEL"/>',
+		handler: this._reload,
+		scope: this
+	}));
+	
+    return new Ext.Toolbar({
+    	items: items
+    });
+}
+
+org.ametys.web.administration.CacheStatisticsBack._onContextItemToggle = function(item, pressed)
+{
+	// add/remove context in the contexts array
+	if (pressed) {
+		if (this._contexts.indexOf(item.context) === -1) {
+			this._contexts.push(item.context);
+		} 
+	} 
+	else {
+		// Array.remove shim
+		var index = this._contexts.indexOf(item.context);
+		if (index !== -1) {
+			this._contexts.splice(index, 1);
+		}
+	}
+}
+
+org.ametys.web.administration.CacheStatisticsBack._reload = function(button, event)
+{
+	this._loader.load(this._grid.getRootNode());
+}
+
+org.ametys.web.administration.CacheStatisticsBack._beforeLoadStats = function(loader, node)
+{
+    this._statsMask = new org.ametys.msg.Mask(Ext.get('admin-panel'), "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_STATISTICS_LOAD_MESSAGE"/>");
+    
+    // remember selected node to be able to re-expand it.
+    this._selectedNodeId = (this._grid.getSelectionModel().getSelectedNode() || {}).id 
+    
+    // contexts param passed to the server.
+    this._loader.baseParams.contexts = this._contexts.join('#');
+};
+
+org.ametys.web.administration.CacheStatisticsBack._loadStats = function(loader, node)
+{
+	if (this._statsMask)
+	{
+		this._statsMask.hide();
+	}
+    
+	// Recursive expand for node that are marked as recursive in the loaded XML.
+    if (node.isRoot)
+    {
+    	org.ametys.web.administration.cacheStatistics._recursiveExpand(node);
+    }
+    
+    // Recursive expand to the node that was selected before a reload (if still existing).
+    // This node is also selected again.
+    if (this._selectedNodeId)
+    {
+    	var selectedNode = this._grid.getNodeById(this._selectedNodeId);
+    	var selectedParentNode = (selectedNode || {}).parentNode;
+    	
+    	if (selectedParentNode)
+    	{
+    		this._recursiveExpandToSelected(selectedParentNode);
+   		}
+   		
+   		if (selectedNode)
+   		{
+   			this._grid.getSelectionModel().select(selectedNode);
+   		}
+    }
+};
+
+org.ametys.web.administration.CacheStatisticsBack._recursiveExpandToSelected = function(node) 
+{
+	if (node !== null &amp;&amp; node !== undefined)
+	{
+		this._recursiveExpandToSelected(node.parentNode);
+		
+		if (!node.isExpanded() &amp;&amp; node !== this._grid.getRootNode())
+		{
+			node.expand(false, true);
+		}
+	}
+};
Index: main/plugin-web/resources/js/org/ametys/web/administration/CacheStatisticsServers.i18n.js
===================================================================
--- main/plugin-web/resources/js/org/ametys/web/administration/CacheStatisticsServers.i18n.js	(revision 0)
+++ main/plugin-web/resources/js/org/ametys/web/administration/CacheStatisticsServers.i18n.js	(revision 0)
@@ -0,0 +1,164 @@
+/*
+ *  Copyright 2012 Anyware Services
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+Ext.namespace('org.ametys.web.administration');
+
+org.ametys.web.administration.CacheStatisticsServers = function () {}
+
+org.ametys.web.administration.CacheStatisticsServers.init = function (pluginName, siteName, sitePath)
+{
+	this.pluginName = pluginName;
+	this.siteName = siteName;
+	this.sitePath = sitePath;
+	
+	// init loader
+	this._loader = new Ext.ux.tree.XmlTreeLoader({
+		dataUrl: getPluginDirectUrl(this.pluginName) + '/administrator/sites/' + siteName + '/cache-statistics-servers-tree.xml'
+	});
+	
+	// loader listeners
+	this._loader.on('beforeload', this._beforeLoadStats, this);
+	this._loader.on('load', this._loadStats, this);
+	
+	var columns = [
+         // total width must be 590
+		{ header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_FIRST"/>", dataIndex: 'label', width: 260},
+		{ header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_CACHEABLE"/>", dataIndex: 'cacheable', align: 'center', width: 70},
+		
+		{ header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_EFFICIENCY_TOTAL"/>", dataIndex: 'eff', align: 'center', width: 70},
+		{ header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_EFFICIENCY_APACHE"/>", dataIndex: 'effA', align: 'center', width: 50, hidden: true},
+		{ header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_EFFICIENCY_FRONT"/>", dataIndex: 'effF', align: 'center', width: 50, hidden: true},
+		
+		{ header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_HITS_TOTAL"/>", dataIndex: 'hits', align: 'center', width: 70},
+		{ header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_HITS_APACHE"/>", dataIndex: 'hitsA', align: 'center', width: 50, hidden: true},
+		{ header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_HITS_FRONT"/>", dataIndex: 'hitsF', align: 'center', width: 50, hidden: true},
+		
+		{ header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_CACHE_HITS_TOTAL"/>", dataIndex: 'cacheHits', align: 'center', width: 70},
+		{ header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_CACHE_HITS_APACHE"/>", dataIndex: 'cacheHitsA', align: 'center', width: 50, hidden: true},
+		{ header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_CACHE_HITS_FRONT"/>", dataIndex: 'cacheHitsF', align: 'center', width: 50, hidden: true},
+		
+		{ header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_COL_HITS_BACK"/>", dataIndex: 'hitsB', align: 'center', width: 50}
+	];
+	
+	this._detailsColsIndex = [];
+	this._detailsVisible = false; // Indicates whether the 'details' columns are visible. 
+	
+	// Populate the _detailsColsIndex with the index of the hidden columns.
+	// This means that these column are 'details' column. A special action
+	// button will be created to be able to display/hide details columns.
+	Ext.each(columns, function(item, index) {
+		if (item.hidden === true) this._detailsColsIndex.push(index);
+	}, this);
+	
+	// maps colspan attributes of the td of the firstrow given the boolean this._detailsVisible.
+	/*
+	this._firstRowColspans = {
+		'false': [2, 1, 1, 1, 1],
+		'true': [2, 3, 3, 3, 1]
+	}
+	*/
+	
+	this._grid = new org.ametys.web.administration.cacheStatistics.DoubleHeaderTreeGrid({
+		/* width: 610,*/
+		region: 'center',
+		enableDD: false,
+		enableHdMenu: false,
+		enableSort: false,
+		border: false,
+		firstRowHd:[
+               		{header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_FIRST_ROWHD_FIRST"/>", colspan: 2, align: 'center'},
+               		{header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_FIRST_ROWHD_EFFICIENCY"/>", colspan: 3, align: 'center'},
+               		{header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_FIRST_ROWHD_HITS"/>", colspan: 3, align: 'center'},
+               		{header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_FIRST_ROWHD_CACHE_HITS"/>", colspan: 3, align: 'center'},
+               		{header: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_FIRST_ROWHD_BACK"/>", colspan: 1, align: 'center'}
+		],
+        columns: columns,
+        loader: this._loader
+	});
+	
+	this._centerPanel = new Ext.Panel({
+		region:'center',
+		layout: 'border',
+		baseCls: 'transparent-panel',
+		border: false,
+		autoScroll : true,
+		height: 'auto',
+		items: [this._grid]
+	});		
+	
+	// Handle box
+	this._handle = new org.ametys.ActionsPanel({title: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_STATISTICS_HANDLE"/>"});
+	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_HANDLE_DISPLAY_HIDE"/>", getPluginResourcesUrl(this.pluginName) + "/img/administrator/sites/cachestats/displayhide.png", org.ametys.web.administration.CacheStatisticsServers._displayHideDetails.createDelegate(this));
+	// Not available currenlty.
+//	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_STATISTICS_HANDLE_REINITIALIZE"/>", getPluginResourcesUrl(this.pluginName) + "/img/administrator/sites/cachestats/reinitialize.png", org.ametys.web.administration.cacheStatistics._reinitializeStats);
+	// Quit action
+	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_STATISTICS_HANDLE_QUIT"/>", getPluginResourcesUrl('core') + '/img/administrator/config/quit.png', org.ametys.web.administration.cacheStatistics._goBack.createDelegate(this));
+	
+	// Help box
+	var help = new org.ametys.TextPanel({title: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_STATISTICS_HELP"/>"});
+	help.addText("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_HELP_TEXT"/>");
+	
+	this._rightPanel = new org.ametys.HtmlContainer({
+		region:'east',
+		border: false,
+		cls: 'admin-right-panel',
+		width: 277,
+	    items: [this._handle, help]
+	});
+}
+
+org.ametys.web.administration.CacheStatisticsServers._reload = function(button, event)
+{
+	this._loader.load(this._grid.getRootNode());
+}
+
+org.ametys.web.administration.CacheStatisticsServers._beforeLoadStats = function(loader, node)
+{
+    this._statsMask = new org.ametys.msg.Mask(Ext.get('admin-panel'), "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_STATISTICS_LOAD_MESSAGE"/>");
+};
+
+org.ametys.web.administration.CacheStatisticsServers._loadStats = function(loader, node)
+{
+	if (this._statsMask)
+	{
+		this._statsMask.hide();
+	}
+    
+	// Recursive expand for node that are marked as recursive in the loaded XML.
+    if (node.isRoot)
+    {
+    	org.ametys.web.administration.cacheStatistics._recursiveExpand(node);
+    }
+};
+
+/**-----------------------------------------------------------*/
+
+org.ametys.web.administration.CacheStatisticsServers._displayHideDetails = function()
+{
+	this._detailsVisible = !this._detailsVisible;
+	
+	Ext.each(this._detailsColsIndex, function(detailsColIndex) {
+		this._grid.setColumnVisible(detailsColIndex, this._detailsVisible);
+	}, this);
+	
+	// updating colspans of the first hd row
+	/*
+	var colspanMapping = this._firstRowColspans['' + this._detailsVisible];
+	Ext.each(this._grid.body.query('.custom-hd-row'), function(td, index) {
+		td.setAttribute('colspan', colspanMapping[index]);
+	});
+	*/
+}
Index: main/plugin-web/resources/js/org/ametys/web/administration/CacheStatistics.i18n.js
===================================================================
--- main/plugin-web/resources/js/org/ametys/web/administration/CacheStatistics.i18n.js	(revision 0)
+++ main/plugin-web/resources/js/org/ametys/web/administration/CacheStatistics.i18n.js	(revision 0)
@@ -0,0 +1,164 @@
+/*
+ *  Copyright 2012 Anyware Services
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+Ext.namespace('org.ametys.web.administration.cacheStatistics');
+
+org.ametys.web.administration.cacheStatistics._recursiveExpand = function(node) 
+{
+	var cs = node.childNodes,
+		i,
+		len = cs.length;
+		
+	for (i = 0; i &lt; len; i++)
+	{
+		if (cs[i].attributes.expanded == 'true')
+		{
+			cs[i].expand(false, true, org.ametys.web.administration.cacheStatistics._recursiveExpand);
+		}
+	}
+};
+
+org.ametys.web.administration.cacheStatistics._reinitializeStats = function()
+{
+	Ext.Msg.show({
+		title: "Not available",
+		msg: "This feature is not implemented yet.",
+		buttons: Ext.Msg.OK,
+		icon: Ext.Msg.WARNING
+	});
+}
+
+org.ametys.web.administration.cacheStatistics._goBack = function()
+{
+	document.location.href = getPluginWrappedUrl('web') + '/administrator/sites/view.html' + (this.sitePath ? '?path=' + this.sitePath : '');
+}
+
+org.ametys.web.administration.cacheStatistics.DoubleHeaderTreeGrid = Ext.extend(Ext.ux.tree.TreeGrid, {
+    firstRowHd : [],
+
+    initComponent : function() {
+        this.internalTpl = new Ext.XTemplate(
+            '&lt;div class="x-grid3-header"&gt;',
+                '&lt;div class="x-treegrid-header-inner"&gt;',
+                    '&lt;div class="x-grid3-header-offset"&gt;',
+                        '&lt;table style="table-layout: fixed;" cellspacing="0" cellpadding="0" border="0"&gt;&lt;colgroup&gt;&lt;tpl for="columns"&gt;&lt;col /&gt;&lt;/tpl&gt;&lt;/colgroup&gt;',
+                            '&lt;thead&gt;&lt;tr class="x-grid3-hd-row"&gt;',
+
+                            // Template modification, adding a new header row, that will be filled with the 'firstRowHd' array.
+                            '&lt;tpl for="firstRowHd"&gt;',
+                                '&lt;td class="custom-hd-row" style="text-align: {align};" colspan="{colspan}" &gt;',
+                                    '&lt;div class="x-grid3-hd-inner x-treegrid-hd-inner" unselectable="on"&gt;',
+                                        '{header}',
+                                    '&lt;/div&gt;',
+                                '&lt;/td&gt;&lt;/tpl&gt;',
+                            '&lt;/tr&gt;',
+
+                            '&lt;tr class="x-grid3-hd-row"&gt;',
+                            '&lt;tpl for="columns"&gt;',
+                            	// adding the 'standard-hd-row' class (used in the overridden method updateColumnWidths, see below)
+                                '&lt;td class="standard-hd-row x-grid3-hd x-grid3-cell x-treegrid-hd" style="text-align: {align};" id="', this.id, '-xlhd-{#}"&gt;',
+                                    '&lt;div class="x-grid3-hd-inner x-treegrid-hd-inner" unselectable="on"&gt;',
+                                        this.enableHdMenu ? '&lt;a class="x-grid3-hd-btn" href="#"&gt;&lt;/a&gt;' : '',
+                                        '{header}&lt;img class="x-grid3-sort-icon" src="', Ext.BLANK_IMAGE_URL, '" /&gt;',
+                                    '&lt;/div&gt;',
+                                '&lt;/td&gt;&lt;/tpl&gt;',
+                            '&lt;/tr&gt;&lt;/thead&gt;',
+                        '&lt;/table&gt;',
+                '&lt;/div&gt;&lt;/div&gt;',
+            '&lt;/div&gt;',
+            '&lt;div class="x-treegrid-root-node"&gt;',
+                '&lt;table class="x-treegrid-root-table" cellpadding="0" cellspacing="0" style="table-layout: fixed;"&gt;&lt;/table&gt;',
+            '&lt;/div&gt;'
+        );
+
+        org.ametys.web.administration.cacheStatistics.DoubleHeaderTreeGrid.superclass.initComponent.call(this);
+    },
+
+    onRender : function() {
+        Ext.tree.TreePanel.superclass.onRender.apply(this, arguments);
+
+        this.el.addClass('x-treegrid');
+        
+        this.outerCt = this.body.createChild({
+            cls:'x-tree-root-ct x-treegrid-ct ' + (this.useArrows ? 'x-tree-arrows' : this.lines ? 'x-tree-lines' : 'x-tree-no-lines')
+        });
+        
+        // Adding firstRowHd to the template
+        this.internalTpl.overwrite(this.outerCt, {columns: this.columns, firstRowHd: this.firstRowHd});
+        
+        this.mainHd = Ext.get(this.outerCt.dom.firstChild);
+        this.innerHd = Ext.get(this.mainHd.dom.firstChild);
+        this.innerBody = Ext.get(this.outerCt.dom.lastChild);
+        this.innerCt = Ext.get(this.innerBody.dom.firstChild);
+        
+        this.colgroupTpl.insertFirst(this.innerCt, {columns: this.columns});
+        
+        if(this.hideHeaders){
+            this.el.child('.x-grid3-header').setDisplayed('none');
+        }
+        else if(this.enableHdMenu !== false){
+            this.hmenu = new Ext.menu.Menu({id: this.id + '-hctx'});
+            if(this.enableColumnHide !== false){
+                this.colMenu = new Ext.menu.Menu({id: this.id + '-hcols-menu'});
+                this.colMenu.on({
+                    scope: this,
+                    beforeshow: this.beforeColMenuShow,
+                    itemclick: this.handleHdMenuClick
+                });
+                this.hmenu.add({
+                    itemId:'columns',
+                    hideOnClick: false,
+                    text: this.columnsText,
+                    menu: this.colMenu,
+                    iconCls: 'x-cols-icon'
+                });
+            }
+            this.hmenu.on('itemclick', this.handleHdMenuClick, this);
+        }
+    },
+    
+    updateColumnWidths : function() {
+        var cols = this.columns,
+            colCount = cols.length,
+            groups = this.outerCt.query('colgroup'),
+            groupCount = groups.length,
+            c, g, i, j;
+
+        for(i = 0; i &lt; colCount; i++) {
+            c = cols[i];
+            for(j = 0; j &lt; groupCount; j++) {
+                g = groups[j];
+                g.childNodes[i].style.width = (c.hidden ? 0 : c.width) + 'px';
+            }
+        }
+        
+        // Adding the class standard-hd-row in the query, to avoid issue when hidding standard column.
+        for(i = 0, groups = this.innerHd.query('td.standard-hd-row'), len = groups.length; i &lt; len; i++) {
+            c = Ext.fly(groups[i]);
+            if(cols[i] &amp;&amp; cols[i].hidden) {
+                c.addClass('x-treegrid-hd-hidden');
+            }
+            else {
+                c.removeClass('x-treegrid-hd-hidden');
+            }
+        }
+
+        var tcw = this.getTotalColumnWidth();
+        Ext.fly(this.innerHd.dom.firstChild).setWidth(tcw + (this.scrollOffset || 0));
+        this.outerCt.select('table').setWidth(tcw);
+        this.syncHeaderScroll();    
+    }
+});
Index: main/plugin-web/resources/js/org/ametys/web/administration/Sites.i18n.js
===================================================================
--- main/plugin-web/resources/js/org/ametys/web/administration/Sites.i18n.js	(revision 20673)
+++ main/plugin-web/resources/js/org/ametys/web/administration/Sites.i18n.js	(working copy)
@@ -35,15 +35,17 @@
 	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_OPEN"/>", getPluginResourcesUrl(this.pluginName) + "/img/administrator/sites/open_site.png", org.ametys.web.administration.site.Open);// 1
 	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_CONFIG"/>", getPluginResourcesUrl(this.pluginName) + "/img/administrator/sites/config_site.png", org.ametys.web.administration.site.Config);// 2
 	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_STATISTICS"/>", getPluginResourcesUrl(this.pluginName) + "/img/administrator/sites/stats_site.png", org.ametys.web.administration.site.OpenStats);// 3
-	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_GLOBAL_STATISTICS"/>", getPluginResourcesUrl(this.pluginName) + "/img/administrator/sites/stats_global.png", org.ametys.web.administration.site.OpenGlobalStats);// 4
-	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_SUPERUSER"/>", getPluginResourcesUrl(this.pluginName) + "/img/administrator/sites/super_user.png", org.ametys.web.administration.site.SuperAdministrator);// 5
-	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_BUILDPREVIEW"/>", getPluginResourcesUrl(this.pluginName) + "/img/administrator/sites/build_preview.png", org.ametys.web.administration.site.BuildPreview);// 6
-	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_BUILDALL_LABEL"/>", getPluginResourcesUrl(this.pluginName) + "/img/administrator/sites/build_preview_all.png", org.ametys.web.administration.site.BuildAll);// 7
-	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_CLEARCACHE"/>", getPluginResourcesUrl(this.pluginName) + "/img/administrator/sites/clear_cache.png", org.ametys.web.administration.site.ClearCache);// 8
-	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_CLEARCACHEALL_LABEL"/>", getPluginResourcesUrl(this.pluginName) + "/img/administrator/sites/clear_cache_all.png", org.ametys.web.administration.site.ClearCacheAll);// 9
-	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_DELETE"/>", getPluginResourcesUrl(this.pluginName) + "/img/administrator/sites/delete.png", org.ametys.web.administration.site.Delete);// 10
+	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_GLOBAL_STATISTICS"/>", getPluginResourcesUrl(this.pluginName) + "/img/administrator/sites/stats_global.png", org.ametys.web.administration.site.OpenGlobalStats);// 4 
+	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_CACHE_BACK_STATISTICS"/>", getPluginResourcesUrl(this.pluginName) + "/img/administrator/sites/stats_global.png", org.ametys.web.administration.site.OpenCacheBackStats);// 5
+	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_CACHE_SERVERS_STATISTICS"/>", getPluginResourcesUrl(this.pluginName) + "/img/administrator/sites/stats_global.png", org.ametys.web.administration.site.OpenCacheServersStats);// 6
+	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_SUPERUSER"/>", getPluginResourcesUrl(this.pluginName) + "/img/administrator/sites/super_user.png", org.ametys.web.administration.site.SuperAdministrator);// 7
+	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_BUILDPREVIEW"/>", getPluginResourcesUrl(this.pluginName) + "/img/administrator/sites/build_preview.png", org.ametys.web.administration.site.BuildPreview);// 8
+	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_BUILDALL_LABEL"/>", getPluginResourcesUrl(this.pluginName) + "/img/administrator/sites/build_preview_all.png", org.ametys.web.administration.site.BuildAll);// 9
+	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_CLEARCACHE"/>", getPluginResourcesUrl(this.pluginName) + "/img/administrator/sites/clear_cache.png", org.ametys.web.administration.site.ClearCache);// 10
+	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_CLEARCACHEALL_LABEL"/>", getPluginResourcesUrl(this.pluginName) + "/img/administrator/sites/clear_cache_all.png", org.ametys.web.administration.site.ClearCacheAll);// 11
+	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_DELETE"/>", getPluginResourcesUrl(this.pluginName) + "/img/administrator/sites/delete.png", org.ametys.web.administration.site.Delete);// 12
 	// Quit action
-	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_QUIT"/>", getPluginResourcesUrl('core') + '/img/administrator/config/quit.png', org.ametys.web.administration.site.goBack);// 9
+	this._handle.addAction("<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_QUIT"/>", getPluginResourcesUrl('core') + '/img/administrator/config/quit.png', org.ametys.web.administration.site.goBack);// 13
 	
 	// Help box
 	var help = new org.ametys.TextPanel({title: "<i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_SITES_HELP"/>"});
@@ -54,8 +56,10 @@
 	this._handle.hideElt(3);
 	this._handle.hideElt(5);
 	this._handle.hideElt(6);
+	this._handle.hideElt(7);
 	this._handle.hideElt(8);
 	this._handle.hideElt(10);
+	this._handle.hideElt(12);
 	
 	this._rightPanel = new org.ametys.HtmlContainer({
 		region:'east',
@@ -152,8 +156,10 @@
 		this._handle.hideElt(3);
 		this._handle.hideElt(5);
 		this._handle.hideElt(6);
+		this._handle.hideElt(7);
 		this._handle.hideElt(8);
 		this._handle.hideElt(10);
+		this._handle.hideElt(12);
 	}
 	else
 	{
@@ -162,8 +168,10 @@
 		this._handle.showElt(3);
 		this._handle.showElt(5);
 		this._handle.showElt(6);
+		this._handle.showElt(7);
 		this._handle.showElt(8);
 		this._handle.showElt(10);
+		this._handle.showElt(12);
 	}
 }
 
@@ -241,6 +249,18 @@
     window.location.href = getPluginWrappedUrl('web') + '/administrator/sites/global-statistics.html';
 }
 /**-----------------------------------------------------------*/
+org.ametys.web.administration.site.OpenCacheBackStats = function()
+{
+	var node = org.ametys.web.administration.Site._sites.getSelectionModel().getSelectedNode();
+    window.location.href = getPluginWrappedUrl('web') + '/administrator/sites/' + node.attributes.name + '/cache-statistics-back.html';
+}
+/**-----------------------------------------------------------*/
+org.ametys.web.administration.site.OpenCacheServersStats = function()
+{
+	var node = org.ametys.web.administration.Site._sites.getSelectionModel().getSelectedNode();
+    window.location.href = getPluginWrappedUrl('web') + '/administrator/sites/' + node.attributes.name + '/cache-statistics-servers.html';
+}
+/**-----------------------------------------------------------*/
 org.ametys.web.administration.site.Open = function ()
 {
 	var node = org.ametys.web.administration.Site._sites.getSelectionModel().getSelectedNode();
Index: main/plugin-web/plugin.xml
===================================================================
--- main/plugin-web/plugin.xml	(revision 20673)
+++ main/plugin-web/plugin.xml	(working copy)
@@ -8634,4 +8634,91 @@
 	        </param>
         </config>
     </feature>
+    
+	<!-- +
+         | CACHE MONITORING
+         + -->
+    <feature name="cache.monitoring.datasource">
+    	<!-- Monitoring Datasource -->
+		<config>
+	        <param id="cache.monitoring.datasource.jdbc.driver" type="string">
+	            <label i18n="true">PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_DRIVER_LABEL</label>
+	            <description i18n="true">PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_DRIVER_DESCRIPTION</description>
+	            <validation>
+	                <mandatory/>
+	            </validation>
+	            <default-value>com.mysql.jdbc.Driver</default-value>
+	            <category i18n="true">PLUGINS_WEB_CONFIG_CACHE_MONITORING_CATEGORY</category>
+	            <group i18n="true">PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_GROUP</group>
+	            <order>10</order>
+	        </param>
+	        <param id="cache.monitoring.datasource.jdbc.url" type="string">
+	            <label i18n="true">PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_URL_LABEL</label>
+	            <description i18n="true">PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_URL_DESCRIPTION</description>
+	            <validation>
+	                <mandatory/>
+	            </validation>
+	            <default-value>jdbc:mysql://servername/basename</default-value>
+	            <category i18n="true">PLUGINS_WEB_CONFIG_CACHE_MONITORING_CATEGORY</category>
+	            <group i18n="true">PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_GROUP</group>
+	            <order>20</order>
+	        </param>
+	        <param id="cache.monitoring.datasource.jdbc.user" type="string">
+	            <label i18n="true">PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_USER_LABEL</label>
+	            <description i18n="true">PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_USER_DESCRIPTION</description>
+	            <default-value>username</default-value>
+	            <category i18n="true">PLUGINS_WEB_CONFIG_CACHE_MONITORING_CATEGORY</category>
+	            <group i18n="true">PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_GROUP</group>
+	            <order>30</order>
+	        </param>
+	        <param id="cache.monitoring.datasource.jdbc.passwd" type="password">
+	            <label i18n="true">PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_PASSWORD_LABEL</label>
+	            <description i18n="true">PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_PASSWORD_DESCRIPTION</description>
+	            <default-value>password</default-value>
+	            <category i18n="true">PLUGINS_WEB_CONFIG_CACHE_MONITORING_CATEGORY</category>
+	            <group i18n="true">PLUGINS_WEB_CONFIG_CACHE_MONITORING_DATASOURCE_JDBC_GROUP</group>
+	            <order>40</order>
+	        </param>
+	    </config>
+        
+        <extensions>
+            <extension point="org.ametys.runtime.datasource.DataSourceExtensionPoint" 
+                       id="cache.monitoring.datasource"
+                       logger="org.ametys.cache.monitoring.datasource">
+                <driver runtime-config-parameter="cache.monitoring.datasource.jdbc.driver"/>
+                <dburl runtime-config-parameter="cache.monitoring.datasource.jdbc.url"/>
+                <user runtime-config-parameter="cache.monitoring.datasource.jdbc.user"/>
+                <password runtime-config-parameter="cache.monitoring.datasource.jdbc.passwd"/>
+            </extension>
+        </extensions>
+    </feature>
+    
+    <feature name="cache.monitoring.schedulers">
+        <config>
+            <param id="cache.monitoring.schedulers.enable" type="boolean">
+                <label i18n="true">PLUGINS_WEB_CONFIG_CACHE_MONITORING_HANDLING_ENABLE_LABEL</label>
+                <description i18n="true">PLUGINS_WEB_CONFIG_CACHE_MONITORING_HANDLING_ENABLE_DESCRIPTION</description>
+                <validation>
+                    <mandatory/>
+                </validation>
+                <default-value>false</default-value>
+                <category i18n="true">PLUGINS_WEB_CONFIG_CACHE_MONITORING_CATEGORY</category>
+                <group i18n="true">PLUGINS_WEB_CONFIG_CACHE_MONITORING_HANDLING_GROUP</group>
+            </param>
+        </config>
+    
+    	<components>
+	        <component role="org.ametys.web.cache.monitoring.process.access.ResourceAccessComponent"
+	                   class="org.ametys.web.cache.monitoring.process.access.ResourceAccessComponent"
+	                   logger="org.ametys.web.cache.monitoring.process.access.ResourceAccessComponent" />
+	                   
+	        <component role="org.ametys.web.cache.monitoring.process.statistics.ResourceStatisticsComponent"
+	                   class="org.ametys.web.cache.monitoring.process.statistics.ResourceStatisticsComponent"
+	                   logger="org.ametys.web.cache.monitoring.process.statistics.ResourceStatisticsComponent" />
+	                   
+	        <component role="org.ametys.web.cache.monitoring.process.CacheMonitoringScheduler"
+	                   class="org.ametys.web.cache.monitoring.process.CacheMonitoringScheduler"
+	                   logger="org.ametys.web.cache.monitoring.process.CacheMonitoringScheduler" />
+		</components>
+    </feature>
 </plugin>
Index: main/plugin-web/src/org/ametys/web/cache/monitoring/ui/PageElementCacheStatsGenerator.java
===================================================================
--- main/plugin-web/src/org/ametys/web/cache/monitoring/ui/PageElementCacheStatsGenerator.java	(revision 20673)
+++ main/plugin-web/src/org/ametys/web/cache/monitoring/ui/PageElementCacheStatsGenerator.java	(working copy)
@@ -35,6 +35,7 @@
 import org.apache.cocoon.generation.ServiceableGenerator;
 import org.apache.cocoon.xml.AttributesImpl;
 import org.apache.cocoon.xml.XMLUtils;
+import org.apache.commons.lang.BooleanUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.builder.EqualsBuilder;
 import org.apache.commons.lang.builder.HashCodeBuilder;
@@ -120,7 +121,7 @@
         
         List<String> contexts = _getContextsFilter(parameters.getParameter("contexts", null));
         
-        Long start = null;
+        long start = 0;
         if (getLogger().isDebugEnabled())
         {
             start = System.currentTimeMillis();
@@ -139,12 +140,9 @@
         
         if (getLogger().isDebugEnabled())
         {
-            if (start != null)
-            {
-                long end = System.currentTimeMillis();
-                String duration = PeriodFormat.getDefault().print(new Duration(end - start).toPeriod());
-                getLogger().debug(String.format("The SAX process of the back-office cache statistics took %s", duration));
-            }
+            long end = System.currentTimeMillis();
+            String duration = PeriodFormat.getDefault().print(new Duration(end - start).toPeriod());
+            getLogger().debug(String.format("The SAX process of the back-office cache statistics took %s", duration));
         }
     }
     
@@ -186,10 +184,10 @@
     {
         StringBuilder sb = new StringBuilder();
         
-        sb.append(" SELECT p.Page_Id, p.Rendering_Context, p.Workspace_JCR, p.Cacheable AS P_Cacheable, p.Hits AS P_Hits,");
-        sb.append("     pe.Page_Element_Id, pe.Cacheable AS PE_Cacheable, pe.Hits AS PE_Hits, pe.Cache_Hits AS PE_Cache_Hits");
-        sb.append(" FROM CACHE_BACK_STATS p");
-        sb.append(" LEFT OUTER JOIN Cache_Back_Page_Element_Stats pe");
+        sb.append(" SELECT p.Page_Id, p.Rendering_Context, p.Workspace_JCR, p.Cacheable AS \"P_Cacheable\", p.Hits AS \"P_Hits\",");
+        sb.append("     pe.Page_Element_Id, pe.Cacheable AS \"PE_Cacheable\", pe.Hits AS \"PE_Hits\", pe.Cache_Hits AS \"PE_Cache_Hits\"");
+        sb.append(" FROM ").append(Constants.__SQL_TABLE_NAME_PAGE_STATISTICS).append(" p");
+        sb.append(" INNER JOIN ").append(Constants.__SQL_TABLE_NAME_PAGE_ELEMENTS_STATISTICS).append(" pe");
         sb.append("     ON p.Page_Id = pe.Page_Id AND p.Rendering_Context = pe.Rendering_Context AND p.Workspace_JCR = pe.Workspace_JCR");
         
         return sb.toString();
@@ -202,7 +200,7 @@
         
         for (int i = 0; i < cols.length; i++)
         {
-            cols[i] = meta.getColumnLabel(i + 1);
+            cols[i] = meta.getColumnLabel(i + 1).toUpperCase();
         }
         
         while (rs.next())
@@ -445,33 +443,62 @@
     /**
      * Object model representing an entry of stats for a Page
      */
-    @SuppressWarnings("javadoc")
     protected class PageStatsEntry
     {
+        /** page id */
         protected final String _pageId;
+        /** rendering context */
         protected final String _renderingContext;
+        /** workspace JCR */
         protected final String _workspaceJCR;
+        /** is cacheable */
         protected final boolean _cacheable;
+        /** hits */
         protected final int _hits;
         
         /**
          * Ctor
+         * @param data map of raw data object.
          */
         protected PageStatsEntry(Map<String, Object> data)
         {
-            _pageId = (String) data.get("Page_Id");
-            _renderingContext = (String) data.get("Rendering_Context");
-            _workspaceJCR = (String) data.get("Workspace_JCR");
-            _cacheable = (Boolean) data.get("P_Cacheable");
-            _hits = __toInteger(data.get("P_Hits"));
+            _pageId = (String) data.get("PAGE_ID");
+            _renderingContext = (String) data.get("RENDERING_CONTEXT");
+            _workspaceJCR = (String) data.get("WORKSPACE_JCR");
+            _cacheable = __toBool(data.get("P_CACHEABLE"));
+            _hits = __toInt(data.get("P_HITS"));
         }
         
-        private Integer __toInteger(Object value)
+        private boolean __toBool(Object object)
         {
-            Long lValue = (Long) value;
-            return lValue != null ? lValue.intValue() : null;
+            if (object instanceof Boolean)
+            {
+                return BooleanUtils.toBoolean((Boolean) object);
+            }
+            else if (object instanceof Number)
+            {
+                Number i = (Number) object;
+                return i != null && i.intValue() != 0;
+            }
+
+            throw new IllegalArgumentException("Not able to convert object to bool : unexpected object type.");
         }
         
+        private int __toInt(Object object)
+        {
+            if (object instanceof Number)
+            {
+                Number n = (Number) object;
+                return n == null ? 0 : n.intValue();
+            }
+
+            throw new IllegalArgumentException("Not able to convert object to int : unexpected object type.");
+        }
+
+        /**
+         * Returns the formatted context name
+         * @return context name
+         */
         public String getContext()
         {
             return _renderingContext + '-' + _workspaceJCR;
@@ -514,33 +541,59 @@
     /**
      * Object model representing an entry of stats for a PageElement
      */
-    @SuppressWarnings("javadoc")
     protected class PageElementStatsEntry
     {
+        /** page element id */
         protected final String _pageElementID;
+        /** rendering context */
         protected final String _renderingContext;
+        /** workspace JCR */
         protected final String _workspaceJCR;
-        protected final Boolean _cacheable;
-        protected final Integer _hits;
-        protected final Integer _cacheHits;
+        /** is cacheable */
+        protected final boolean _cacheable;
+        /** hits */
+        protected final int _hits;
+        /** cache hits */
+        protected final int _cacheHits;
         
         /**
          * Ctor
+         * @param data map of raw data object.
          */
         protected PageElementStatsEntry(Map<String, Object> data)
         {
-            _pageElementID = (String) data.get("Page_Element_Id");
-            _renderingContext = (String) data.get("Rendering_Context");
-            _workspaceJCR = (String) data.get("Workspace_JCR");
-            _cacheable = (Boolean) data.get("PE_Cacheable");
-            _hits = __toInteger(data.get("PE_Hits"));
-            _cacheHits = __toInteger(data.get("PE_Cache_Hits"));
+            _pageElementID = (String) data.get("PAGE_ELEMENT_ID");
+            _renderingContext = (String) data.get("RENDERING_CONTEXT");
+            _workspaceJCR = (String) data.get("WORKSPACE_JCR");
+            _cacheable = __toBool(data.get("PE_CACHEABLE"));
+            _hits = __toInt(data.get("PE_HITS"));
+            _cacheHits = __toInt(data.get("PE_CACHE_HITS"));
+        }
+        
+        private boolean __toBool(Object object)
+        {
+            if (object instanceof Boolean)
+            {
+                return BooleanUtils.toBoolean((Boolean) object);
+            }
+            else if (object instanceof Number)
+            {
+                Number i = (Number) object;
+                return i != null && i.intValue() != 0;
+            }
+
+            throw new IllegalArgumentException("Not able to convert object to bool : unexpected object type.");
         }
         
-        private Integer __toInteger(Object value)
+        private int __toInt(Object object)
         {
-            Long lValue = (Long) value;
-            return lValue != null ? lValue.intValue() : null;
+            if (object instanceof Number)
+            {
+                Number n = (Number) object;
+                return n == null ? 0 : n.intValue();
+            }
+
+            throw new IllegalArgumentException("Not able to convert object to int : unexpected object type.");
         }
     }
 }
Index: main/plugin-web/src/org/ametys/web/cache/monitoring/ui/ServersCacheStatsGenerator.java
===================================================================
--- main/plugin-web/src/org/ametys/web/cache/monitoring/ui/ServersCacheStatsGenerator.java	(revision 20673)
+++ main/plugin-web/src/org/ametys/web/cache/monitoring/ui/ServersCacheStatsGenerator.java	(working copy)
@@ -39,6 +39,7 @@
 import org.apache.cocoon.generation.ServiceableGenerator;
 import org.apache.cocoon.xml.AttributesImpl;
 import org.apache.cocoon.xml.XMLUtils;
+import org.apache.commons.lang.BooleanUtils;
 import org.apache.commons.lang.StringUtils;
 import org.joda.time.Duration;
 import org.joda.time.format.PeriodFormat;
@@ -63,7 +64,7 @@
 public class ServersCacheStatsGenerator extends ServiceableGenerator
 {
     /** List of paths used to during the sanitize process of the server path */
-    protected static final String[] _SPECIAL_PATH_PREFIXS = new String[]{"/skins/", "/plugins/", "/kernel", "/_external/"};
+    protected static final String[] _SPECIAL_PATH_PREFIXS = new String[]{"/skins/", "/plugins/", "/kernel/", "/_external/"};
     
     /**
      * This multimap associates site names to a list of prefix. This is needed
@@ -131,7 +132,7 @@
         // Populate and organize stats maps.
         _initializeStats(rawStats);
         
-        Long start = null;
+        long start = 0;
         if (getLogger().isDebugEnabled())
         {
             start = System.currentTimeMillis();
@@ -154,12 +155,9 @@
         
         if (getLogger().isDebugEnabled())
         {
-            if (start != null)
-            {
-                long end = System.currentTimeMillis();
-                String duration = PeriodFormat.getDefault().print(new Duration(end - start).toPeriod());
-                getLogger().debug(String.format("The SAX process of the Apache and Front-office cache statistics took %s", duration));
-            }
+            long end = System.currentTimeMillis();
+            String duration = PeriodFormat.getDefault().print(new Duration(end - start).toPeriod());
+            getLogger().debug(String.format("The SAX process of the Apache and Front-office cache statistics took %s", duration));
         }
     }
     
@@ -222,11 +220,10 @@
         sb.append(" SELECT F.Server_Site, F.Server_Path, F.Server_Hits, F.Server_Cache_Hits,");
         sb.append("     F.Front_Site, F.Front_Path, F.Front_Cacheable, F.Front_Hits, F.Front_Cache_Hits_1, F.Front_Cache_Hits_2,");
         sb.append("     B.Page_Id, B.Page_Path, B.Cacheable, B.Hits");
-        sb.append(" FROM CACHE_FRONT_STATS F");
-        sb.append(" LEFT OUTER JOIN CACHE_BACK_STATS B");
-        sb.append("     ON F.Front_Path = B.Page_Path AND F.Front_Path is not NULL AND B.Rendering_Context = 'front'");
-        sb.append(" WHERE F.Server_Site = ? OR F.Server_Site = '' OR F.Server_Site is NULL");
-        sb.append("     OR F.Front_Site = ? OR F.Front_Site = '' OR F.Front_Site is NULL");
+        sb.append(" FROM ").append(Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS).append(" F");
+        sb.append(" LEFT OUTER JOIN ").append(Constants.__SQL_TABLE_NAME_PAGE_STATISTICS).append(" B");
+        sb.append("     ON F.Front_Path = B.Page_Path AND B.Rendering_Context = 'front'");
+        sb.append(" WHERE (F.Server_Site = ? OR F.Server_Site = '-' OR F.Front_Site = ? OR F.Front_Site = '-')");
         
         return sb.toString();
     }
@@ -238,7 +235,7 @@
         
         for (int i = 0; i < cols.length; i++)
         {
-            cols[i] = meta.getColumnLabel(i + 1);
+            cols[i] = meta.getColumnLabel(i + 1).toUpperCase();
         }
         
         List<RawStatsEntry> entries = new ArrayList<RawStatsEntry>();
@@ -291,7 +288,6 @@
     
     private void _addToApacheStats(FrontFromApacheStatsEntry apacheEntry)
     {
-        // could be null in case of a resource. That's ok, we will handle this case later when SAX'ing.
         String siteName = apacheEntry._serverSite;
         
         Map<String, FrontFromApacheStatsEntry> siteMap = _fromApacheStats.get(siteName);
@@ -322,8 +318,7 @@
     
     private void _addToFrontOnlyStats(FrontFromFrontStatsEntry frontEntry)
     {
-        // could be null in case of a resource. That's ok, we will handle this case later when SAX'ing.
-        String siteName = StringUtils.defaultIfEmpty(frontEntry._frontSite, null);
+        String siteName = frontEntry._frontSite;
         
         Map<String, FrontFromFrontStatsEntry> siteMap = _fromFrontOnlyStats.get(siteName);
         if (siteMap == null)
@@ -543,7 +538,7 @@
     
     private void _saxStatsOrphanEntries() throws SAXException
     {
-        Multimap<String, String> pathMap = _pathMaps.get(null);
+        Multimap<String, String> pathMap = _pathMaps.get("-");
         if (pathMap == null || pathMap.isEmpty())
         {
             return;
@@ -555,13 +550,13 @@
             return;
         }
         
-        Map<String, FrontFromApacheStatsEntry> apacheStats = _fromApacheStats.get(null);
+        Map<String, FrontFromApacheStatsEntry> apacheStats = _fromApacheStats.get("-");
         if (apacheStats == null)
         {
             apacheStats = Collections.EMPTY_MAP;
         }
         
-        Map<String, FrontFromFrontStatsEntry> frontOnlyStats = _fromFrontOnlyStats.get(null);
+        Map<String, FrontFromFrontStatsEntry> frontOnlyStats = _fromFrontOnlyStats.get("-");
         if (frontOnlyStats == null)
         {
             frontOnlyStats = Collections.EMPTY_MAP;
@@ -596,27 +591,38 @@
     /**
      * Object model representing a raw entry of stats retrieved through the DB.
      */
-    @SuppressWarnings("javadoc")
     protected class RawStatsEntry
     {
+        /** The map of raw data objects */
         protected final Map<String, Object> _data;
         
         /**
          * Ctor
+         * @param data map of raw data object.
          */
         protected RawStatsEntry(Map<String, Object> data)
         {
             _data = data;
         }
         
+        /**
+         * Indicates if this instance has apache information.
+         * @return a boolean
+         */
         protected boolean hasApacheInfo()
         {
-            return _data.get("Server_Path") != null;
+            String serverPath = (String) _data.get("SERVER_PATH");
+            return serverPath != null && !"-".equals(serverPath);
         }
         
+        /**
+         * Indicates if this instance has back(-office) information.
+         * @return a boolean
+         */
         protected boolean hasBackInfo()
         {
-            return _data.get("Page_Id") != null;
+            String pageId = (String) _data.get("PAGE_ID");
+            return pageId != null && !"-".equals(pageId);
         }
     }
     
@@ -624,28 +630,36 @@
      * Object model representing an entry of stats for a front resource, coming
      * from Apache
      */
-    @SuppressWarnings("javadoc")
     protected class FrontFromApacheStatsEntry extends FrontFromFrontStatsEntry
     {
-        
+        /** Server site name */
         protected final String _serverSite;
+        /** Server path */
         protected final String _serverPath;
-        protected Integer _serverHits;
-        protected Integer _serverCacheHits;
+        /** server hits */
+        protected int _serverHits;
+        /** server cache hits */
+        protected int _serverCacheHits;
         
         /**
          * Ctor
+         * @param data map of raw data object.
          */
         protected FrontFromApacheStatsEntry(Map<String, Object> data)
         {
             super(data);
             
-            _serverSite = (String) data.get("Server_Site");
-            _serverPath = (String) data.get("Server_Path");
-            _serverHits = __toInteger(data.get("Server_Hits"));
-            _serverCacheHits = __toInteger(data.get("Server_Cache_Hits"));
+            _serverSite = (String) data.get("SERVER_SITE");
+            _serverPath = (String) data.get("SERVER_PATH");
+            _serverHits = __toInt(data.get("SERVER_HITS"));
+            _serverCacheHits = __toInt(data.get("SERVER_CACHE_HITS"));
         }
         
+        /**
+         * Merge this instance of <code>FrontFromApacheStatsEntry</code> with
+         * another instance of <code>FrontFromApacheStatsEntry</code>
+         * @param that
+         */
         protected void merge(FrontFromApacheStatsEntry that)
         {
             if (that == null)
@@ -668,6 +682,11 @@
             }
         }
         
+        /**
+         * Returns a sanitized path given the different path properties of this
+         * instance.
+         * @return The sanitized path
+         */
         protected String getSanitizedPath()
         {
             if (hasFrontInfo())
@@ -727,9 +746,13 @@
             return sanitizedPath;
         }
         
+        /**
+         * Indicates if this instance has front(-office) information.
+         * @return a boolean
+         */
         protected boolean hasFrontInfo()
         {
-            return _frontPath != null;
+            return _frontPath != null && !"-".equals(_frontPath);
         }
     }
     
@@ -737,33 +760,70 @@
      * Object model representing an entry of stats for a front resource, coming
      * from the Front (direct request to tomcat, bypassing any Apache HTTP server if any).
      */
-    @SuppressWarnings("javadoc")
     protected class FrontFromFrontStatsEntry
     {
+        /** front site name */
         protected String _frontSite;
+        /** front path */
         protected String _frontPath;
-        protected Boolean _frontCacheable;
-        protected Integer _frontHits;
-        protected Integer _frontCacheHits1;
-        protected Integer _frontCacheHits2;
+        /** is front cacheable */
+        protected boolean _frontCacheable;
+        /** front hits */
+        protected int _frontHits;
+        /** front cache hits 1 */
+        protected int _frontCacheHits1;
+        /** front cache hits 2 */
+        protected int _frontCacheHits2;
         
         /**
          * Ctor
+         * @param data map of raw data object.
          */
         protected FrontFromFrontStatsEntry(Map<String, Object> data)
         {
-            _frontSite = (String) data.get("Front_Site");
-            _frontPath = (String) data.get("Front_Path");
-            _frontCacheable = (Boolean) data.get("Front_Cacheable");
-            _frontHits = __toInteger(data.get("Front_Hits"));
-            _frontCacheHits1 = __toInteger(data.get("Front_Cache_Hits_1"));
-            _frontCacheHits2 = __toInteger(data.get("Front_Cache_Hits_2"));
+            _frontSite = (String) data.get("FRONT_SITE");
+            _frontPath = (String) data.get("FRONT_PATH");
+            _frontCacheable = __toBool(data.get("FRONT_CACHEABLE"));
+            _frontHits = __toInt(data.get("FRONT_HITS"));
+            _frontCacheHits1 = __toInt(data.get("FRONT_CACHE_HITS_1"));
+            _frontCacheHits2 = __toInt(data.get("FRONT_CACHE_HITS_2"));
+        }
+        
+        
+        /**
+         * Object to boolean
+         * @param object
+         * @return the boolean
+         */
+        protected boolean __toBool(Object object)
+        {
+            if (object instanceof Boolean)
+            {
+                return BooleanUtils.toBoolean((Boolean) object);
+            }
+            else if (object instanceof Number)
+            {
+                Number i = (Number) object;
+                return i != null && i.intValue() != 0;
+            }
+
+            throw new IllegalArgumentException("Not able to convert object to bool : unexpected object type.");
         }
         
-        protected Integer __toInteger(Object value)
+        /**
+         * Object to int
+         * @param object
+         * @return the int
+         */
+        protected int __toInt(Object object)
         {
-            Long lValue = (Long) value;
-            return lValue != null ? lValue.intValue() : null;
+            if (object instanceof Number)
+            {
+                Number n = (Number) object;
+                return n == null ? 0 : n.intValue();
+            }
+
+            throw new IllegalArgumentException("Not able to convert object to int : unexpected object type.");
         }
     }
     
@@ -771,29 +831,63 @@
      * Object model representing an entry of stats for a back resource (ie. a
      * page).
      */
-    @SuppressWarnings("javadoc")
     protected class BackStatsEntry
     {
+        /** page id */
         protected final String _pageId;
+        /** page path */
         protected final String _pagePath;
+        /** cacheable */
         protected final boolean _cacheable;
+        /** hits */
         protected final int _hits;
         
         /**
          * Ctor
+         * @param data map of raw data object.
          */
         protected BackStatsEntry(Map<String, Object> data)
         {
-            _pageId = (String) data.get("Page_Id");
-            _pagePath = (String) data.get("Page_Path");
-            _cacheable = (Boolean) data.get("Cacheable");
-            _hits = __toInteger(data.get("Hits"));
+            _pageId = (String) data.get("PAGE_ID");
+            _pagePath = (String) data.get("PAGE_PATH");
+            _cacheable = __toBool(data.get("CACHEABLE"));
+            _hits = __toInt(data.get("HITS"));
+        }
+        
+        /**
+         * Object to boolean
+         * @param object
+         * @return the boolean
+         */
+        protected boolean __toBool(Object object)
+        {
+            if (object instanceof Boolean)
+            {
+                return BooleanUtils.toBoolean((Boolean) object);
+            }
+            else if (object instanceof Number)
+            {
+                Number i = (Number) object;
+                return i != null && i.intValue() != 0;
+            }
+
+            throw new IllegalArgumentException("Not able to convert object to bool : unexpected object type.");
         }
         
-        private Integer __toInteger(Object value)
+        /**
+         * Object to int
+         * @param object
+         * @return the int
+         */
+        protected int __toInt(Object object)
         {
-            Long lValue = (Long) value;
-            return lValue != null ? lValue.intValue() : null;
+            if (object instanceof Number)
+            {
+                Number n = (Number) object;
+                return n == null ? 0 : n.intValue();
+            }
+
+            throw new IllegalArgumentException("Not able to convert object to int : unexpected object type.");
         }
     }
 }
Index: main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/FrontFromHTTPServerResourceStatistics.java
===================================================================
--- main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/FrontFromHTTPServerResourceStatistics.java	(revision 20673)
+++ main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/FrontFromHTTPServerResourceStatistics.java	(working copy)
@@ -19,6 +19,9 @@
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
+import java.sql.Timestamp;
+
+import org.apache.commons.lang.BooleanUtils;
 
 import org.ametys.web.cache.monitoring.Constants;
 import org.ametys.web.cache.monitoring.process.statistics.ResourceStatistics;
@@ -38,7 +41,7 @@
     private final boolean _frontCacheHit1;
     private final boolean _frontCacheHit2;
     
-    private final long _newHits;
+    private final int _newHits;
     
     /**
      * Creates a statistic
@@ -52,7 +55,7 @@
      * @param frontCacheHit2 The front cache hit 2 status
      * @param newHits The hits
      */
-    public FrontFromHTTPServerResourceStatistics(String httpserverSite, String httpserverPath, boolean httpserverCacheHit, String frontSite, String frontPath, boolean frontCacheable, boolean frontCacheHit1, boolean frontCacheHit2, long newHits)
+    public FrontFromHTTPServerResourceStatistics(String httpserverSite, String httpserverPath, boolean httpserverCacheHit, String frontSite, String frontPath, boolean frontCacheable, boolean frontCacheHit1, boolean frontCacheHit2, int newHits)
     {
         _httpserverSite = httpserverSite;
         _httpserverPath = httpserverPath;
@@ -70,7 +73,7 @@
     @Override
     public PreparedStatement getFindStatement(Connection connection) throws SQLException
     {
-        PreparedStatement stmt = connection.prepareStatement("SELECT count(1) " + Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS + " WHERE Server_Site = ? AND Server_Path = ?");
+        PreparedStatement stmt = connection.prepareStatement("SELECT count(1) FROM " + Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS + " WHERE Server_Site = ? AND Server_Path = ?");
         
         stmt.setString(1, _httpserverSite);
         stmt.setString(2, _httpserverPath);
@@ -81,19 +84,23 @@
     @Override
     public PreparedStatement getInsertStatement(Connection connection) throws SQLException
     {
-        PreparedStatement stmt = connection.prepareStatement("INSERT INTO " + Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS + " (Server_Site, Server_Path, Server_Hits, Server_Cache_Hits, Front_Site, Front_Path, Front_Cacheable, Front_Hits, Front_Cache_Hits_1, Front_Cache_Hits_2) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
+        PreparedStatement stmt = connection.prepareStatement("INSERT INTO " + Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS + " (Server_Site, Server_Path, Server_Hits, Server_Cache_Hits, Front_Site, Front_Path, Front_Cacheable, Front_Hits, Front_Cache_Hits_1, Front_Cache_Hits_2, Created_At, Updated_At) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
         
         stmt.setString(1, _httpserverSite);
         stmt.setString(2, _httpserverPath);
-        stmt.setLong(3, _newHits);
-        stmt.setLong(4, _getServerCacheHits());
+        stmt.setInt(3, _newHits);
+        stmt.setInt(4, _getServerCacheHits());
         
         stmt.setString(5, _frontSite);
         stmt.setString(6, _frontPath);
-        stmt.setBoolean(7, _frontCacheable);
-        stmt.setLong(8, _newHits);
-        stmt.setLong(9, _getFrontCacheHits1());
-        stmt.setLong(10, _getFrontCacheHits2());
+        stmt.setInt(7, BooleanUtils.toInteger(_frontCacheable));
+        stmt.setInt(8, _newHits);
+        stmt.setInt(9, _getFrontCacheHits1());
+        stmt.setInt(10, _getFrontCacheHits2());
+        
+        Timestamp now = new Timestamp(System.currentTimeMillis());
+        stmt.setTimestamp(11, now);
+        stmt.setTimestamp(12, now);
         
         return stmt;
     }
@@ -101,40 +108,41 @@
     @Override
     public PreparedStatement getUpdateStatement(Connection connection) throws SQLException
     {
-        PreparedStatement stmt = connection.prepareStatement("UPDATE " + Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS + " SET Server_Hits = Server_Hits + ?, Server_Cache_Hits = Server_Cache_Hits + ?, Front_Site = ?, Front_Path = ?, Front_Cacheable = ?, Front_Hits = Front_Hits + ?, Front_Cache_Hits_1 = Front_Cache_Hits_1 + ?, Front_Cache_Hits_2 = Front_Cache_Hits_2 + ? WHERE Server_Site = ? AND Server_Path = ?");
+        PreparedStatement stmt = connection.prepareStatement("UPDATE " + Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS + " SET Server_Hits = Server_Hits + ?, Server_Cache_Hits = Server_Cache_Hits + ?, Front_Site = ?, Front_Path = ?, Front_Cacheable = ?, Front_Hits = Front_Hits + ?, Front_Cache_Hits_1 = Front_Cache_Hits_1 + ?, Front_Cache_Hits_2 = Front_Cache_Hits_2 + ?, Updated_At = ? WHERE Server_Site = ? AND Server_Path = ?");
 
-        stmt.setLong(1, _newHits);
-        stmt.setLong(2, _getServerCacheHits());
+        stmt.setInt(1, _newHits);
+        stmt.setInt(2, _getServerCacheHits());
         stmt.setString(3, _frontSite);
         stmt.setString(4, _frontPath);
-        stmt.setBoolean(5, _frontCacheable);
-        stmt.setLong(6, _newHits);
-        stmt.setLong(7, _getFrontCacheHits1());
-        stmt.setLong(8, _getFrontCacheHits2());
+        stmt.setInt(5, BooleanUtils.toInteger(_frontCacheable));
+        stmt.setInt(6, _newHits);
+        stmt.setInt(7, _getFrontCacheHits1());
+        stmt.setInt(8, _getFrontCacheHits2());
+        stmt.setTimestamp(9, new Timestamp(System.currentTimeMillis()));
         
-        stmt.setString(9, _httpserverSite);
-        stmt.setString(10, _httpserverPath);
+        stmt.setString(10, _httpserverSite);
+        stmt.setString(11, _httpserverPath);
         
         return stmt;
     }
     
     @Override
-    public long getHits()
+    public int getHits()
     {
         return _newHits;
     }
     
-    private long _getServerCacheHits()
+    private int _getServerCacheHits()
     {
         return _httpserverCacheHit ? _newHits : 0;
     }
     
-    private long _getFrontCacheHits1()
+    private int _getFrontCacheHits1()
     {
         return _frontCacheHit1 ? _newHits : 0;
     }
     
-    private long _getFrontCacheHits2()
+    private int _getFrontCacheHits2()
     {
         return _frontCacheHit2 ? _newHits : 0;
     }
Index: main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/HTTPServerOnlyResourceStatistics.java
===================================================================
--- main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/HTTPServerOnlyResourceStatistics.java	(revision 20673)
+++ main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/HTTPServerOnlyResourceStatistics.java	(working copy)
@@ -19,6 +19,7 @@
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
+import java.sql.Timestamp;
 
 import org.ametys.web.cache.monitoring.Constants;
 import org.ametys.web.cache.monitoring.process.statistics.ResourceStatistics;
@@ -32,7 +33,7 @@
     private final String _site;
     private final String _path;
     private final boolean _cacheHit;
-    private final long _newHits;
+    private final int _newHits;
     
     /**
      * Creates a statistics
@@ -41,7 +42,7 @@
      * @param cacheHit The cache hit status
      * @param newHits The number of hits
      */
-    public HTTPServerOnlyResourceStatistics(String site, String path, boolean cacheHit, long newHits)
+    public HTTPServerOnlyResourceStatistics(String site, String path, boolean cacheHit, int newHits)
     {
         _site = site;
         _path = path;
@@ -52,7 +53,7 @@
     @Override
     public PreparedStatement getFindStatement(Connection connection) throws SQLException
     {
-        PreparedStatement stmt = connection.prepareStatement("SELECT count(1) " + Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS + " WHERE Server_Site = ? AND Server_Path = ?");
+        PreparedStatement stmt = connection.prepareStatement("SELECT count(1) FROM " + Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS + " WHERE Server_Site = ? AND Server_Path = ?");
         
         stmt.setString(1, _site);
         stmt.setString(2, _path);
@@ -63,12 +64,16 @@
     @Override
     public PreparedStatement getInsertStatement(Connection connection) throws SQLException
     {
-        PreparedStatement stmt = connection.prepareStatement("INSERT INTO " + Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS + " (Server_Site, Server_Path, Server_Hits, Server_Cache_Hits) values (?, ?, ?, ?)");
+        PreparedStatement stmt = connection.prepareStatement("INSERT INTO " + Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS + " (Server_Site, Server_Path, Server_Hits, Server_Cache_Hits, Created_At, Updated_At) values (?, ?, ?, ?, ?, ?)");
         
         stmt.setString(1, _site);
         stmt.setString(2, _path);
-        stmt.setLong(3, _newHits);
-        stmt.setLong(4, _getCacheHits());
+        stmt.setInt(3, _newHits);
+        stmt.setInt(4, _getCacheHits());
+        
+        Timestamp now = new Timestamp(System.currentTimeMillis());
+        stmt.setTimestamp(5, now);
+        stmt.setTimestamp(6, now);
         
         return stmt;
     }
@@ -76,24 +81,25 @@
     @Override
     public PreparedStatement getUpdateStatement(Connection connection) throws SQLException
     {
-        PreparedStatement stmt = connection.prepareStatement("UPDATE " + Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS + " SET Server_Hits = Server_Hits + ?, Server_Cache_Hits = Server_Cache_Hits + ? WHERE Server_Site = ? AND Server_Path = ?");
+        PreparedStatement stmt = connection.prepareStatement("UPDATE " + Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS + " SET Server_Hits = Server_Hits + ?, Server_Cache_Hits = Server_Cache_Hits + ?, Updated_At = ? WHERE Server_Site = ? AND Server_Path = ?");
 
-        stmt.setLong(1, _newHits);
-        stmt.setLong(2, _getCacheHits());
+        stmt.setInt(1, _newHits);
+        stmt.setInt(2, _getCacheHits());
+        stmt.setTimestamp(3, new Timestamp(System.currentTimeMillis()));
         
-        stmt.setString(3, _site);
-        stmt.setString(4, _path);
+        stmt.setString(4, _site);
+        stmt.setString(5, _path);
         
         return stmt;
     }
     
     @Override
-    public long getHits()
+    public int getHits()
     {
         return _newHits;
     }
     
-    private long _getCacheHits()
+    private int _getCacheHits()
     {
         return _cacheHit ? _newHits : 0;
     }
Index: main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/HTTPServerOnlyResourceStatisticsFactory.java
===================================================================
--- main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/HTTPServerOnlyResourceStatisticsFactory.java	(revision 20673)
+++ main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/HTTPServerOnlyResourceStatisticsFactory.java	(working copy)
@@ -63,15 +63,15 @@
         try
         {
             connection = ConnectionHelper.getConnection(Constants.MONITORING_DATASOURCE_POOLNAME);
-            stmt = connection.prepareStatement("SELECT count(*) AS increment, Site, Path, Cache_Hit FROM " + Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS + " T WHERE PROCESSED = false AND Cache_Hit = true AND (Ori_Status_Code = 200 OR Ori_Status_Code = 304) GROUP BY Site, Path, Cache_Hit ORDER BY max(T.Id)");
+            stmt = connection.prepareStatement("SELECT count(*) AS \"increment\", Site, Path, Cache_Hit FROM " + Constants.__SQL_TABLE_NAME_HTTPSERVER_ACCESS + " WHERE PROCESSED = 0 AND Cache_Hit = 1 AND (Ori_Status_Code = '200' OR Ori_Status_Code = '304') GROUP BY Site, Path, Cache_Hit");
             resultSet = stmt.executeQuery();
             
             while (resultSet.next())
             {
                 String site = resultSet.getString("Site");
                 String path = resultSet.getString("Path");
-                boolean cacheHit = BooleanUtils.toBoolean(resultSet.getBoolean("Cache_Hit")); // converts null to false, avoiding NPE while unboxing.
-                long newHits = resultSet.getLong("increment");
+                boolean cacheHit = BooleanUtils.toBoolean(resultSet.getInt("Cache_Hit"));
+                int newHits = resultSet.getInt("increment");
 
                 resourceStatisticsList.add(new HTTPServerOnlyResourceStatistics(site, path, cacheHit, newHits));
             }
@@ -87,43 +87,33 @@
     }
     
     @Override
-    public long getMaxIdToProcess() throws SQLException
+    public int markResourcesAsProcessed() throws SQLException
     {
         Connection connection = null;
         Statement stmt = null;
-        ResultSet resultSet = null;
         try
         {
             connection = ConnectionHelper.getConnection(Constants.MONITORING_DATASOURCE_POOLNAME);
             stmt = connection.createStatement();
-            resultSet = stmt.executeQuery("SELECT max(Id) FROM " + Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS + " WHERE PROCESSED = false AND (Ori_Status_Code = 200 OR Ori_Status_Code = 304)");
-            
-            if (resultSet.next())
-            {
-                return resultSet.getLong(1);
-            }
-            return -1;
+            return stmt.executeUpdate("UPDATE " + Constants.__SQL_TABLE_NAME_HTTPSERVER_ACCESS + " SET Processed = 1 WHERE Processed = 0 AND Cache_Hit = 1 AND (Ori_Status_Code = '200' OR Ori_Status_Code = '304')");
         }
         finally
         {
-            ConnectionHelper.cleanup(resultSet);
             ConnectionHelper.cleanup(stmt);
             ConnectionHelper.cleanup(connection);
         }
     }
     
     @Override
-    public int markResourcesAsProcessed(long id) throws SQLException
+    public int purgeRawData() throws SQLException
     {
         Connection connection = null;
-        PreparedStatement stmt = null;
+        Statement stmt = null;
         try
         {
             connection = ConnectionHelper.getConnection(Constants.MONITORING_DATASOURCE_POOLNAME);
-            stmt = connection.prepareStatement("UPDATE " + Constants.__SQL_TABLE_NAME_HTTPSERVER_ACCESS + " AS S LEFT OUTER JOIN " + Constants.__SQL_TABLE_NAME_FRONT_ACCESS + " F ON S.Unique_Id = F.Unique_Id SET S.Processed = true WHERE S.Id <= ? AND F.Unique_Id is NULL AND S.Processed = false AND (S.Ori_Status_Code = 200 OR S.Ori_Status_Code = 304)");
-            stmt.setLong(1, id);
-            
-            return stmt.executeUpdate();
+            stmt = connection.createStatement();
+            return stmt.executeUpdate("DELETE FROM " + Constants.__SQL_TABLE_NAME_HTTPSERVER_ACCESS + " WHERE PROCESSED = 1");
         }
         finally
         {
Index: main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/PageElementResourceStatisticsFactory.java
===================================================================
--- main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/PageElementResourceStatisticsFactory.java	(revision 20673)
+++ main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/PageElementResourceStatisticsFactory.java	(working copy)
@@ -63,7 +63,7 @@
         try
         {
             connection = ConnectionHelper.getConnection(Constants.MONITORING_DATASOURCE_POOLNAME);
-            stmt = connection.prepareStatement("SELECT count(*) AS increment, Page_Element_Id, Page_Id, Rendering_Context, Workspace_JCR, Cacheable, Cache_Hit FROM " + Constants.__SQL_TABLE_NAME_PAGE_ELEMENTS_STATISTICS + " T WHERE PROCESSED = false GROUP BY Page_Element_Id, Page_Id, Rendering_Context, Workspace_JCR, Cacheable, Cache_Hit ORDER BY max(T.Id)");
+            stmt = connection.prepareStatement("SELECT count(*) AS \"increment\", Page_Element_Id, Page_Id, Rendering_Context, Workspace_JCR, Cacheable, Cache_Hit FROM " + Constants.__SQL_TABLE_NAME_PAGE_ELEMENTS_ACCESS + " WHERE PROCESSED = 0 GROUP BY Page_Element_Id, Page_Id, Rendering_Context, Workspace_JCR, Cacheable, Cache_Hit");
             resultSet = stmt.executeQuery();
             
             while (resultSet.next())
@@ -72,9 +72,9 @@
                 String pageId = resultSet.getString("Page_Id");
                 String renderingContext = resultSet.getString("Rendering_Context");
                 String jcrWorkspace = resultSet.getString("Workspace_JCR");
-                boolean cacheable = resultSet.getBoolean("Cacheable");
-                boolean cacheHit = BooleanUtils.toBoolean(resultSet.getBoolean("Cache_Hit")); // converts null to false, avoiding NPE while unboxing.
-                long newHits = resultSet.getLong("increment");
+                boolean cacheable = BooleanUtils.toBoolean(resultSet.getInt("Cacheable"));
+                boolean cacheHit = BooleanUtils.toBoolean(resultSet.getInt("Cache_Hit"));
+                int newHits = resultSet.getInt("increment");
 
                 resourceStatisticsList.add(new PageElementResourceStatistics(pageElementId, pageId, renderingContext, jcrWorkspace, cacheable, cacheHit, newHits));
             }
@@ -90,43 +90,33 @@
     }
     
     @Override
-    public long getMaxIdToProcess() throws SQLException
+    public int markResourcesAsProcessed() throws SQLException
     {
         Connection connection = null;
         Statement stmt = null;
-        ResultSet resultSet = null;
         try
         {
             connection = ConnectionHelper.getConnection(Constants.MONITORING_DATASOURCE_POOLNAME);
             stmt = connection.createStatement();
-            resultSet = stmt.executeQuery("SELECT max(Id) FROM " + Constants.__SQL_TABLE_NAME_PAGE_ELEMENTS_STATISTICS + " WHERE PROCESSED = false");
-            
-            if (resultSet.next())
-            {
-                return resultSet.getLong(1);
-            }
-            return -1;
+            return stmt.executeUpdate("UPDATE " + Constants.__SQL_TABLE_NAME_PAGE_ELEMENTS_ACCESS + " SET PROCESSED = 1 WHERE Processed = 0");
         }
         finally
         {
-            ConnectionHelper.cleanup(resultSet);
             ConnectionHelper.cleanup(stmt);
             ConnectionHelper.cleanup(connection);
         }
     }
     
     @Override
-    public int markResourcesAsProcessed(long id) throws SQLException
+    public int purgeRawData() throws SQLException
     {
         Connection connection = null;
-        PreparedStatement stmt = null;
+        Statement stmt = null;
         try
         {
             connection = ConnectionHelper.getConnection(Constants.MONITORING_DATASOURCE_POOLNAME);
-            stmt = connection.prepareStatement("UPDATE " + Constants.__SQL_TABLE_NAME_PAGE_ELEMENTS_STATISTICS + " SET PROCESSED = true WHERE Id <= ? AND Processed = false");
-            stmt.setLong(1, id);
-            
-            return stmt.executeUpdate();
+            stmt = connection.createStatement();
+            return stmt.executeUpdate("DELETE FROM " + Constants.__SQL_TABLE_NAME_PAGE_ELEMENTS_ACCESS + " WHERE PROCESSED = 1");
         }
         finally
         {
Index: main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/PageElementResourceStatistics.java
===================================================================
--- main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/PageElementResourceStatistics.java	(revision 20673)
+++ main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/PageElementResourceStatistics.java	(working copy)
@@ -19,6 +19,9 @@
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
+import java.sql.Timestamp;
+
+import org.apache.commons.lang.BooleanUtils;
 
 import org.ametys.web.cache.monitoring.Constants;
 import org.ametys.web.cache.monitoring.process.statistics.ResourceStatistics;
@@ -35,7 +38,7 @@
     private final String _workspaceJCR;
     private final boolean _cacheable;
     private final boolean _cacheHit;
-    private final long _newHits;
+    private final int _newHits;
     
     /**
      * Creates a statistics
@@ -47,7 +50,7 @@
      * @param cacheHit The cache hit status
      * @param increment The number of increment
      */
-    public PageElementResourceStatistics(String pageElementId, String pageId, String renderingContext, String jcrWorkspace, boolean cacheable, boolean cacheHit, long increment)
+    public PageElementResourceStatistics(String pageElementId, String pageId, String renderingContext, String jcrWorkspace, boolean cacheable, boolean cacheHit, int increment)
     {
         _pageElementId = pageElementId;
         _pageId = pageId;
@@ -61,7 +64,7 @@
     @Override
     public PreparedStatement getFindStatement(Connection connection) throws SQLException
     {
-        PreparedStatement stmt = connection.prepareStatement("SELECT count(1) " + Constants.__SQL_TABLE_NAME_PAGE_ELEMENTS_STATISTICS + " WHERE Page_Element_Id = ? AND Page_Id = ? AND Rendering_Context = ? AND Workspace_JCR = ?");
+        PreparedStatement stmt = connection.prepareStatement("SELECT count(1) FROM " + Constants.__SQL_TABLE_NAME_PAGE_ELEMENTS_STATISTICS + " WHERE Page_Element_Id = ? AND Page_Id = ? AND Rendering_Context = ? AND Workspace_JCR = ?");
         
         stmt.setString(1, _pageElementId);
         stmt.setString(2, _pageId);
@@ -74,15 +77,19 @@
     @Override
     public PreparedStatement getInsertStatement(Connection connection) throws SQLException
     {
-        PreparedStatement stmt = connection.prepareStatement("INSERT INTO " + Constants.__SQL_TABLE_NAME_PAGE_ELEMENTS_STATISTICS + " (Page_Element_Id, Page_Id, Rendering_Context, Workspace_JCR, Cacheable, Hits, Cache_Hits) values (?, ?, ?, ?, ?, ?, ?)");
+        PreparedStatement stmt = connection.prepareStatement("INSERT INTO " + Constants.__SQL_TABLE_NAME_PAGE_ELEMENTS_STATISTICS + " (Page_Element_Id, Page_Id, Rendering_Context, Workspace_JCR, Cacheable, Hits, Cache_Hits, Created_At, Updated_At) values (?, ?, ?, ?, ?, ?, ?, ?, ?)");
         
         stmt.setString(1, _pageElementId);
         stmt.setString(2, _pageId);
         stmt.setString(3, _renderingContext);
         stmt.setString(4, _workspaceJCR);
-        stmt.setBoolean(5, _cacheable);
-        stmt.setLong(6, _newHits);
-        stmt.setLong(7, _getCacheHits());
+        stmt.setInt(5, BooleanUtils.toInteger(_cacheable));
+        stmt.setInt(6, _newHits);
+        stmt.setInt(7, _getCacheHits());
+        
+        Timestamp now = new Timestamp(System.currentTimeMillis());
+        stmt.setTimestamp(8, now);
+        stmt.setTimestamp(9, now);
         
         return stmt;
     }
@@ -90,27 +97,28 @@
     @Override
     public PreparedStatement getUpdateStatement(Connection connection) throws SQLException
     {
-        PreparedStatement stmt = connection.prepareStatement("UPDATE " + Constants.__SQL_TABLE_NAME_PAGE_ELEMENTS_STATISTICS + " SET Cacheable = ?, Hits = Hits + ?, Cache_Hits = Cache_Hits + ? WHERE Page_Element_Id = ? AND Page_Id = ? AND Rendering_Context = ? AND Workspace_JCR = ?");
+        PreparedStatement stmt = connection.prepareStatement("UPDATE " + Constants.__SQL_TABLE_NAME_PAGE_ELEMENTS_STATISTICS + " SET Cacheable = ?, Hits = Hits + ?, Cache_Hits = Cache_Hits + ?, Updated_At = ? WHERE Page_Element_Id = ? AND Page_Id = ? AND Rendering_Context = ? AND Workspace_JCR = ?");
 
-        stmt.setBoolean(1, _cacheable);
-        stmt.setLong(2, _newHits);
-        stmt.setLong(3, _getCacheHits());
+        stmt.setInt(1, BooleanUtils.toInteger(_cacheable));
+        stmt.setInt(2, _newHits);
+        stmt.setInt(3, _getCacheHits());
+        stmt.setTimestamp(4, new Timestamp(System.currentTimeMillis()));
         
-        stmt.setString(4, _pageElementId);
-        stmt.setString(5, _pageId);
-        stmt.setString(6, _renderingContext);
-        stmt.setString(7, _workspaceJCR);
+        stmt.setString(5, _pageElementId);
+        stmt.setString(6, _pageId);
+        stmt.setString(7, _renderingContext);
+        stmt.setString(8, _workspaceJCR);
         
         return stmt;
     }
     
     @Override
-    public long getHits()
+    public int getHits()
     {
         return _newHits;
     }
     
-    private long _getCacheHits()
+    private int _getCacheHits()
     {
         return _cacheHit ? _newHits : 0;
     }
Index: main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/PageResourceStatisticsFactory.java
===================================================================
--- main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/PageResourceStatisticsFactory.java	(revision 20673)
+++ main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/PageResourceStatisticsFactory.java	(working copy)
@@ -24,6 +24,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.commons.lang.BooleanUtils;
+
 import org.ametys.runtime.datasource.ConnectionHelper;
 import org.ametys.web.cache.monitoring.Constants;
 import org.ametys.web.cache.monitoring.process.statistics.ResourceStatistics;
@@ -61,7 +63,7 @@
         try
         {
             connection = ConnectionHelper.getConnection(Constants.MONITORING_DATASOURCE_POOLNAME);
-            stmt = connection.prepareStatement("SELECT count(*) AS increment, Page_Id, Page_Path, Rendering_Context, Workspace_JCR, Cacheable FROM " + Constants.__SQL_TABLE_NAME_PAGE_STATISTICS + " T WHERE PROCESSED = false GROUP BY Page_Id, Page_Path, Rendering_Context, Workspace_JCR, Cacheable ORDER BY max(T.Id)");
+            stmt = connection.prepareStatement("SELECT count(*) AS \"increment\", Page_Id, Page_Path, Rendering_Context, Workspace_JCR, Cacheable FROM " + Constants.__SQL_TABLE_NAME_PAGE_ACCESS + " WHERE PROCESSED = 0 GROUP BY Page_Id, Page_Path, Rendering_Context, Workspace_JCR, Cacheable");
             resultSet = stmt.executeQuery();
             
             while (resultSet.next())
@@ -70,8 +72,8 @@
                 String path = resultSet.getString("Page_Path");
                 String renderingContext = resultSet.getString("Rendering_Context");
                 String workspaceJCR = resultSet.getString("Workspace_JCR");
-                boolean cacheable = resultSet.getBoolean("Cacheable");
-                long increment = resultSet.getLong("increment");
+                boolean cacheable = BooleanUtils.toBoolean(resultSet.getInt("Cacheable"));
+                int increment = resultSet.getInt("increment");
                 
                 resourceStatisticsList.add(new PageResourceStatistics(pageId, path, renderingContext, workspaceJCR, cacheable, increment));
             }
@@ -87,43 +89,33 @@
     }
     
     @Override
-    public long getMaxIdToProcess() throws SQLException
+    public int markResourcesAsProcessed() throws SQLException
     {
         Connection connection = null;
         Statement stmt = null;
-        ResultSet resultSet = null;
         try
         {
             connection = ConnectionHelper.getConnection(Constants.MONITORING_DATASOURCE_POOLNAME);
             stmt = connection.createStatement();
-            resultSet = stmt.executeQuery("SELECT max(Id) FROM " + Constants.__SQL_TABLE_NAME_PAGE_STATISTICS + " WHERE PROCESSED = false");
-            
-            if (resultSet.next())
-            {
-                return resultSet.getLong(1);
-            }
-            return -1;
+            return stmt.executeUpdate("UPDATE " + Constants.__SQL_TABLE_NAME_PAGE_ACCESS + " SET PROCESSED = 1 WHERE Processed = 0");
         }
         finally
         {
-            ConnectionHelper.cleanup(resultSet);
             ConnectionHelper.cleanup(stmt);
             ConnectionHelper.cleanup(connection);
         }
     }
     
     @Override
-    public int markResourcesAsProcessed(long id) throws SQLException
+    public int purgeRawData() throws SQLException
     {
         Connection connection = null;
-        PreparedStatement stmt = null;
+        Statement stmt = null;
         try
         {
             connection = ConnectionHelper.getConnection(Constants.MONITORING_DATASOURCE_POOLNAME);
-            stmt = connection.prepareStatement("UPDATE " + Constants.__SQL_TABLE_NAME_PAGE_STATISTICS + " SET PROCESSED = true WHERE Id <= ? AND Processed = false");
-            stmt.setLong(1, id);
-            
-            return stmt.executeUpdate();
+            stmt = connection.createStatement();
+            return stmt.executeUpdate("DELETE FROM " + Constants.__SQL_TABLE_NAME_PAGE_ACCESS + " WHERE PROCESSED = 1");
         }
         finally
         {
Index: main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/FrontFromHTTPServerResourceStatisticsFactory.java
===================================================================
--- main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/FrontFromHTTPServerResourceStatisticsFactory.java	(revision 20673)
+++ main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/FrontFromHTTPServerResourceStatisticsFactory.java	(working copy)
@@ -67,20 +67,24 @@
         try
         {
             connection = ConnectionHelper.getConnection(Constants.MONITORING_DATASOURCE_POOLNAME);
-            stmt = connection.prepareStatement("SELECT count(*) AS increment, S.Site AS S_Site, S.Path AS S_Path, S.Cache_Hit AS S_Cache_Hit, T.Site AS F_Site, T.Ametys_Path AS F_Ametys_Path, T.Cacheable AS F_Cacheable, T.Cache_Hit_1 AS F_Cache_Hit_1, T.Cache_Hit_2 AS F_Cache_Hit_2 FROM " + Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS + " T INNER JOIN " + Constants.__SQL_TABLE_NAME_HTTPSERVER_ACCESS + " S ON T.Unique_Id = S.Unique_Id AND T.Processed = false AND T.Unique_Id is not NULL AND (S.Ori_Status_Code = 200 OR S.Ori_Status_Code = 304) GROUP BY S.Site, S.Path, S.Cache_Hit, T.Site, T.Ametys_Path, T.Cacheable, T.Cache_Hit_1, T.Cache_Hit_2 ORDER BY max(T.Id)");
+            stmt = connection.prepareStatement("SELECT count(*) AS \"increment\", S.Site AS \"S_Site\", S.Path AS \"S_Path\", S.Cache_Hit AS \"S_Cache_Hit\","
+                    + " F.Site AS \"F_Site\", F.Ametys_Path AS \"F_Ametys_Path\", F.Cacheable AS \"F_Cacheable\", F.Cache_Hit_1 AS \"F_Cache_Hit_1\", F.Cache_Hit_2 AS \"F_Cache_Hit_2\""
+                    + " FROM " + Constants.__SQL_TABLE_NAME_FRONT_ACCESS + " F"
+                    + " INNER JOIN " + Constants.__SQL_TABLE_NAME_HTTPSERVER_ACCESS + " S ON F.Unique_Id = S.Unique_Id AND F.Processed = 0 AND (S.Ori_Status_Code = '200' OR S.Ori_Status_Code = '304')"
+                    + " GROUP BY S.Site, S.Path, S.Cache_Hit, F.Site, F.Ametys_Path, F.Cacheable, F.Cache_Hit_1, F.Cache_Hit_2");
             resultSet = stmt.executeQuery();
             
             while (resultSet.next())
             {
                 String httpserverSite = resultSet.getString("S_Site");
                 String httpserverPath = resultSet.getString("S_Path");
-                boolean httpserverCacheHit = BooleanUtils.toBoolean(resultSet.getBoolean("S_Cache_Hit")); // converts null to false, avoiding NPE while unboxing.
+                boolean httpserverCacheHit = BooleanUtils.toBoolean(resultSet.getInt("S_Cache_Hit"));
                 String frontSite = resultSet.getString("F_Site");
                 String frontPath = resultSet.getString("F_Ametys_Path");
-                boolean frontCacheable = resultSet.getBoolean("F_Cacheable");
-                boolean frontCacheHit1 = BooleanUtils.toBoolean(resultSet.getBoolean("F_Cache_Hit_1")); // converts null to false, avoiding NPE while unboxing.
-                boolean frontCacheHit2 = BooleanUtils.toBoolean(resultSet.getBoolean("F_Cache_Hit_2")); // converts null to false, avoiding NPE while unboxing.
-                long newHits = resultSet.getLong("increment");
+                boolean frontCacheable = BooleanUtils.toBoolean(resultSet.getInt("F_Cacheable"));
+                boolean frontCacheHit1 = BooleanUtils.toBoolean(resultSet.getInt("F_Cache_Hit_1"));
+                boolean frontCacheHit2 = BooleanUtils.toBoolean(resultSet.getInt("F_Cache_Hit_2"));
+                int newHits = resultSet.getInt("increment");
 
                 resourceStatisticsList.add(new FrontFromHTTPServerResourceStatistics(httpserverSite, httpserverPath, httpserverCacheHit, frontSite, frontPath, frontCacheable, frontCacheHit1, frontCacheHit2, newHits));
             }
@@ -96,51 +100,38 @@
     }
     
     @Override
-    public long getMaxIdToProcess() throws SQLException
+    public int markResourcesAsProcessed() throws SQLException
     {
         Connection connection = null;
         Statement stmt = null;
-        ResultSet resultSet = null;
+        Statement stmt2 = null;
         try
         {
             connection = ConnectionHelper.getConnection(Constants.MONITORING_DATASOURCE_POOLNAME);
+            
+            StringBuilder sql = new StringBuilder();
+            sql.append("UPDATE CACHE_RA_FRONT ");
+            sql.append("SET Processed = 1 ");
+            sql.append("WHERE Processed = 0 ");
+            sql.append("AND Unique_Id IN ");
+            sql.append("    (SELECT Unique_Id FROM CACHE_RA_HTTPSERVER WHERE (Ori_Status_Code = '200' OR Ori_Status_Code = '304'))");
             stmt = connection.createStatement();
-            resultSet = stmt.executeQuery("SELECT max(F.Id) FROM $tbl_name$ AS F INNER JOIN " + Constants.__SQL_TABLE_NAME_HTTPSERVER_ACCESS + " S ON F.Unique_Id = S.Unique_Id AND F.Processed = false AND F.Unique_Id is not NULL AND (S.Ori_Status_Code = 200 OR S.Ori_Status_Code = 304)");
-
-            if (resultSet.next())
-            {
-                return resultSet.getLong(1);
-            }
-            return -1;
-        }
-        finally
-        {
-            ConnectionHelper.cleanup(resultSet);
-            ConnectionHelper.cleanup(stmt);
-            ConnectionHelper.cleanup(connection);
-        }
-    }
-    
-    @Override
-    public int markResourcesAsProcessed(long id) throws SQLException
-    {
-        Connection connection = null;
-        PreparedStatement stmt = null;
-        PreparedStatement stmt2 = null;
-        try
-        {
-            connection = ConnectionHelper.getConnection(Constants.MONITORING_DATASOURCE_POOLNAME);
-            stmt = connection.prepareStatement("UPDATE " + Constants.__SQL_TABLE_NAME_FRONT_ACCESS + " AS F INNER JOIN " + Constants.__SQL_TABLE_NAME_HTTPSERVER_ACCESS + " S ON F.Unique_Id = S.Unique_Id AND F.Processed = false AND F.Unique_Id is not NULL AND (S.Ori_Status_Code = 200 OR S.Ori_Status_Code = 304) SET F.Processed = true WHERE F.Id <= ?");
-            stmt.setLong(1, id);
+            int processed = stmt.executeUpdate(sql.toString());
             
-            int processed = stmt.executeUpdate();
             
-            stmt2 = connection.prepareStatement("UPDATE " + Constants.__SQL_TABLE_NAME_HTTPSERVER_ACCESS + " AS S INNER JOIN " + Constants.__SQL_TABLE_NAME_FRONT_ACCESS + " F ON S.Unique_Id = F.Unique_Id AND S.Processed = false AND F.Processed = true SET S.Processed = true");
-            int processed2 = stmt2.executeUpdate();
+            StringBuilder sql2 = new StringBuilder();
+            sql2.append("UPDATE CACHE_RA_HTTPSERVER ");
+            sql2.append("SET Processed = 1 ");
+            sql2.append("WHERE Processed = 0 ");
+            sql2.append("AND (Ori_Status_Code = '200' OR Ori_Status_Code = '304') ");
+            sql2.append("AND Unique_Id IN ");
+            sql2.append("    (SELECT DISTINCT Unique_Id FROM CACHE_RA_FRONT)");
+            stmt2 = connection.createStatement();
+            int processed2 = stmt2.executeUpdate(sql2.toString());
             
-            if (__LOGGER.isWarnEnabled())
+            if (__LOGGER.isDebugEnabled())
             {
-                __LOGGER.warn(String.format("Comparing processed and apacheProcessed for type 'FRONT_FROM_APACHE': %s-%s . These values should be equals.", processed, processed2));
+                __LOGGER.debug(String.format("Comparing processed and apacheProcessed for type 'FRONT_FROM_APACHE': %s-%s . These values should be equals.", processed, processed2));
             }
             
             return processed;
@@ -152,4 +143,11 @@
             ConnectionHelper.cleanup(connection);
         }
     }
+
+    @Override
+    public int purgeRawData() throws SQLException
+    {
+        // Nothing to do here (as it is already done is FrontOnly & HTTPServerOnly factories)
+        return 0;
+    }
 }
Index: main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/FrontOnlyResourceStatistics.java
===================================================================
--- main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/FrontOnlyResourceStatistics.java	(revision 20673)
+++ main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/FrontOnlyResourceStatistics.java	(working copy)
@@ -19,6 +19,9 @@
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
+import java.sql.Timestamp;
+
+import org.apache.commons.lang.BooleanUtils;
 
 import org.ametys.web.cache.monitoring.Constants;
 import org.ametys.web.cache.monitoring.process.statistics.ResourceStatistics;
@@ -33,7 +36,7 @@
     private final boolean _cacheable;
     private final boolean _cacheHit1;
     private final boolean _cacheHit2;
-    private final long _newHits;
+    private final int _newHits;
     
     /**
      * Creates a statistics
@@ -44,7 +47,7 @@
      * @param cacheHit2 The cache hit 2 status
      * @param newHits The number of hits
      */
-    public FrontOnlyResourceStatistics(String site, String path, boolean cacheable, boolean cacheHit1, boolean cacheHit2, long newHits)
+    public FrontOnlyResourceStatistics(String site, String path, boolean cacheable, boolean cacheHit1, boolean cacheHit2, int newHits)
     {
         _site = site;
         _path = path;
@@ -57,7 +60,7 @@
     @Override
     public PreparedStatement getFindStatement(Connection connection) throws SQLException
     {
-        PreparedStatement stmt = connection.prepareStatement("SELECT count(1) " + Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS + " WHERE Front_Site = ? AND Front_Path = ? AND Server_Path is NULL");
+        PreparedStatement stmt = connection.prepareStatement("SELECT count(1) FROM " + Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS + " WHERE Front_Site = ? AND Front_Path = ? AND Server_Path = '-'");
         
         stmt.setString(1, _site);
         stmt.setString(2, _path);
@@ -68,14 +71,18 @@
     @Override
     public PreparedStatement getInsertStatement(Connection connection) throws SQLException
     {
-        PreparedStatement stmt = connection.prepareStatement("INSERT INTO " + Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS + " (Front_Site, Front_Path, Front_Cacheable, Front_Hits, Front_Cache_Hits_1, Front_Cache_Hits_2) values (?, ?, ?, ?, ?, ?)");
+        PreparedStatement stmt = connection.prepareStatement("INSERT INTO " + Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS + " (Front_Site, Front_Path, Front_Cacheable, Front_Hits, Front_Cache_Hits_1, Front_Cache_Hits_2, Created_At, Updated_At) values (?, ?, ?, ?, ?, ?, ?, ?)");
         
         stmt.setString(1, _site);
         stmt.setString(2, _path);
-        stmt.setBoolean(3, _cacheable);
-        stmt.setLong(4, _newHits);
-        stmt.setLong(5, _getCacheHits1());
-        stmt.setLong(6, _getCacheHits2());
+        stmt.setInt(3, BooleanUtils.toInteger(_cacheable));
+        stmt.setInt(4, _newHits);
+        stmt.setInt(5, _getCacheHits1());
+        stmt.setInt(6, _getCacheHits2());
+        
+        Timestamp now = new Timestamp(System.currentTimeMillis());
+        stmt.setTimestamp(7, now);
+        stmt.setTimestamp(8, now);
         
         return stmt;
     }
@@ -83,31 +90,32 @@
     @Override
     public PreparedStatement getUpdateStatement(Connection connection) throws SQLException
     {
-        PreparedStatement stmt = connection.prepareStatement("UPDATE " + Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS + " SET Front_Cacheable = ?, Front_Hits = Front_Hits + ?, Front_Cache_Hits_1 = Front_Cache_Hits_1 + ?, Front_Cache_Hits_2 = Front_Cache_Hits_2 + ? WHERE Front_Site = ? AND Front_Path = ? AND Server_Path is NULL");
+        PreparedStatement stmt = connection.prepareStatement("UPDATE " + Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS + " SET Front_Cacheable = ?, Front_Hits = Front_Hits + ?, Front_Cache_Hits_1 = Front_Cache_Hits_1 + ?, Front_Cache_Hits_2 = Front_Cache_Hits_2 + ?, Updated_At = ? WHERE Front_Site = ? AND Front_Path = ? AND Server_Path = '-'");
 
-        stmt.setBoolean(1, _cacheable);
-        stmt.setLong(2, _newHits);
-        stmt.setLong(3, _getCacheHits1());
-        stmt.setLong(4, _getCacheHits2());
+        stmt.setInt(1, BooleanUtils.toInteger(_cacheable));
+        stmt.setInt(2, _newHits);
+        stmt.setInt(3, _getCacheHits1());
+        stmt.setInt(4, _getCacheHits2());
+        stmt.setTimestamp(5, new Timestamp(System.currentTimeMillis()));
         
-        stmt.setString(5, _site);
-        stmt.setString(6, _path);
+        stmt.setString(6, _site);
+        stmt.setString(7, _path);
         
         return stmt;
     }
     
     @Override
-    public long getHits()
+    public int getHits()
     {
         return _newHits;
     }
     
-    private long _getCacheHits1()
+    private int _getCacheHits1()
     {
         return _cacheHit1 ? _newHits : 0;
     }
     
-    private long _getCacheHits2()
+    private int _getCacheHits2()
     {
         return _cacheHit2 ? _newHits : 0;
     }
Index: main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/FrontOnlyResourceStatisticsFactory.java
===================================================================
--- main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/FrontOnlyResourceStatisticsFactory.java	(revision 20673)
+++ main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/FrontOnlyResourceStatisticsFactory.java	(working copy)
@@ -63,17 +63,17 @@
         try
         {
             connection = ConnectionHelper.getConnection(Constants.MONITORING_DATASOURCE_POOLNAME);
-            stmt = connection.prepareStatement("SELECT count(*) AS increment, Site, Ametys_Path, Cacheable, Cache_Hit_1, Cache_Hit_2 FROM " + Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS + " T WHERE PROCESSED = false AND Unique_Id is NULL GROUP BY Site, Ametys_Path, Cacheable, Cache_Hit_1, Cache_Hit_2 ORDER BY max(T.Id)");
+            stmt = connection.prepareStatement("SELECT count(*) AS \"increment\", Site, Ametys_Path, Cacheable, Cache_Hit_1, Cache_Hit_2 FROM " + Constants.__SQL_TABLE_NAME_FRONT_ACCESS + " WHERE PROCESSED = 0 AND Unique_Id = '-' GROUP BY Site, Ametys_Path, Cacheable, Cache_Hit_1, Cache_Hit_2");
             resultSet = stmt.executeQuery();
             
             while (resultSet.next())
             {
                 String site = resultSet.getString("Site");
                 String path = resultSet.getString("Ametys_Path");
-                boolean cacheable = resultSet.getBoolean("Cacheable");
-                boolean cacheHit1 = BooleanUtils.toBoolean(resultSet.getBoolean("Cache_Hit_1")); // converts null to false, avoiding NPE while unboxing.
-                boolean cacheHit2 = BooleanUtils.toBoolean(resultSet.getBoolean("Cache_Hit_2")); // converts null to false, avoiding NPE while unboxing.
-                long newHits = resultSet.getLong("increment");
+                boolean cacheable = BooleanUtils.toBoolean(resultSet.getInt("Cacheable"));
+                boolean cacheHit1 = BooleanUtils.toBoolean(resultSet.getInt("Cache_Hit_1"));
+                boolean cacheHit2 = BooleanUtils.toBoolean(resultSet.getInt("Cache_Hit_2"));
+                int newHits = resultSet.getInt("increment");
 
                 resourceStatisticsList.add(new FrontOnlyResourceStatistics(site, path, cacheable, cacheHit1, cacheHit2, newHits));
             }
@@ -89,43 +89,33 @@
     }
     
     @Override
-    public long getMaxIdToProcess() throws SQLException
+    public int markResourcesAsProcessed() throws SQLException
     {
         Connection connection = null;
         Statement stmt = null;
-        ResultSet resultSet = null;
         try
         {
             connection = ConnectionHelper.getConnection(Constants.MONITORING_DATASOURCE_POOLNAME);
             stmt = connection.createStatement();
-            resultSet = stmt.executeQuery("SELECT max(Id) FROM " + Constants.__SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS + " WHERE PROCESSED = false AND Unique_Id is NULL");
-            
-            if (resultSet.next())
-            {
-                return resultSet.getLong(1);
-            }
-            return -1;
+            return stmt.executeUpdate("UPDATE " + Constants.__SQL_TABLE_NAME_FRONT_ACCESS + " SET PROCESSED = 1 WHERE Processed = 0 AND Unique_Id = '-'");
         }
         finally
         {
-            ConnectionHelper.cleanup(resultSet);
             ConnectionHelper.cleanup(stmt);
             ConnectionHelper.cleanup(connection);
         }
     }
     
     @Override
-    public int markResourcesAsProcessed(long id) throws SQLException
+    public int purgeRawData() throws SQLException
     {
         Connection connection = null;
-        PreparedStatement stmt = null;
+        Statement stmt = null;
         try
         {
             connection = ConnectionHelper.getConnection(Constants.MONITORING_DATASOURCE_POOLNAME);
-            stmt = connection.prepareStatement("UPDATE " + Constants.__SQL_TABLE_NAME_HTTPSERVER_ACCESS + " SET PROCESSED = true WHERE Id <= ? AND Processed = false AND Unique_Id is NULL");
-            stmt.setLong(1, id);
-            
-            return stmt.executeUpdate();
+            stmt = connection.createStatement();
+            return stmt.executeUpdate("DELETE FROM " + Constants.__SQL_TABLE_NAME_FRONT_ACCESS + " WHERE PROCESSED = 1");
         }
         finally
         {
Index: main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/PageResourceStatistics.java
===================================================================
--- main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/PageResourceStatistics.java	(revision 20673)
+++ main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/impl/PageResourceStatistics.java	(working copy)
@@ -19,6 +19,9 @@
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
+import java.sql.Timestamp;
+
+import org.apache.commons.lang.BooleanUtils;
 
 import org.ametys.web.cache.monitoring.Constants;
 import org.ametys.web.cache.monitoring.process.statistics.ResourceStatistics;
@@ -34,7 +37,7 @@
     private final String _renderingContext;
     private final String _workspaceJCR;
     private final boolean _cacheable;
-    private final long _newHits;
+    private final int _newHits;
     
     /**
      * Creates a page resource statistics
@@ -45,7 +48,7 @@
      * @param cacheable Is the page cacheable ?
      * @param increment Number of associated hits
      */
-    public PageResourceStatistics(String pageId, String path, String renderingContext, String jcrWorkspace, boolean cacheable, long increment)
+    public PageResourceStatistics(String pageId, String path, String renderingContext, String jcrWorkspace, boolean cacheable, int increment)
     {
         _pageId = pageId;
         _path = path;
@@ -58,7 +61,7 @@
     @Override
     public PreparedStatement getFindStatement(Connection connection) throws SQLException
     {
-        PreparedStatement stmt = connection.prepareStatement("SELECT count(1) " + Constants.__SQL_TABLE_NAME_PAGE_STATISTICS + " WHERE Page_Id = ? AND Rendering_Context = ? AND Workspace_JCR = ?");
+        PreparedStatement stmt = connection.prepareStatement("SELECT count(1) FROM " + Constants.__SQL_TABLE_NAME_PAGE_STATISTICS + " WHERE Page_Id = ? AND Rendering_Context = ? AND Workspace_JCR = ?");
         
         stmt.setString(1, _pageId);
         stmt.setString(2, _renderingContext);
@@ -70,14 +73,18 @@
     @Override
     public PreparedStatement getInsertStatement(Connection connection) throws SQLException
     {
-        PreparedStatement stmt = connection.prepareStatement("INSERT INTO " + Constants.__SQL_TABLE_NAME_PAGE_STATISTICS + " (Page_Id, Page_Path, Rendering_Context, Workspace_JCR, Cacheable, Hits) values (?, ?, ?, ?, ?, ?)");
+        PreparedStatement stmt = connection.prepareStatement("INSERT INTO " + Constants.__SQL_TABLE_NAME_PAGE_STATISTICS + " (Page_Id, Page_Path, Rendering_Context, Workspace_JCR, Cacheable, Hits, Created_At, Updated_At) values (?, ?, ?, ?, ?, ?, ?, ?)");
         
         stmt.setString(1, _pageId);
         stmt.setString(2, _path);
         stmt.setString(3, _renderingContext);
         stmt.setString(4, _workspaceJCR);
-        stmt.setBoolean(5, _cacheable);
-        stmt.setLong(6, _newHits);
+        stmt.setInt(5, BooleanUtils.toInteger(_cacheable));
+        stmt.setInt(6, _newHits);
+        
+        Timestamp now = new Timestamp(System.currentTimeMillis());
+        stmt.setTimestamp(7, now);
+        stmt.setTimestamp(8, now);
         
         return stmt;
     }
@@ -85,21 +92,22 @@
     @Override
     public PreparedStatement getUpdateStatement(Connection connection) throws SQLException
     {
-        PreparedStatement stmt = connection.prepareStatement("UPDATE " + Constants.__SQL_TABLE_NAME_PAGE_STATISTICS + " SET Page_Path = ?, Cacheable = ?, Hits = Hits + ? WHERE Page_Id = ? AND Rendering_Context = ? AND Workspace_JCR = ?");
+        PreparedStatement stmt = connection.prepareStatement("UPDATE " + Constants.__SQL_TABLE_NAME_PAGE_STATISTICS + " SET Page_Path = ?, Cacheable = ?, Hits = Hits + ?, Updated_At = ? WHERE Page_Id = ? AND Rendering_Context = ? AND Workspace_JCR = ?");
 
         stmt.setString(1, _path);
-        stmt.setBoolean(2, _cacheable);
-        stmt.setLong(3, _newHits);
+        stmt.setInt(2, BooleanUtils.toInteger(_cacheable));
+        stmt.setInt(3, _newHits);
+        stmt.setTimestamp(4, new Timestamp(System.currentTimeMillis()));
         
-        stmt.setString(4, _pageId);
-        stmt.setString(5, _renderingContext);
-        stmt.setString(6, _workspaceJCR);
+        stmt.setString(5, _pageId);
+        stmt.setString(6, _renderingContext);
+        stmt.setString(7, _workspaceJCR);
 
         return stmt;
     }
     
     @Override
-    public long getHits()
+    public int getHits()
     {
         return _newHits;
     }
Index: main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/ResourceStatistics.java
===================================================================
--- main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/ResourceStatistics.java	(revision 20673)
+++ main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/ResourceStatistics.java	(working copy)
@@ -54,5 +54,5 @@
      * Returns the number of hits
      * @return int the hits
      */
-    public long getHits();
+    public int getHits();
 }
Index: main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/ResourceStatisticsComponent.java
===================================================================
--- main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/ResourceStatisticsComponent.java	(revision 20673)
+++ main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/ResourceStatisticsComponent.java	(working copy)
@@ -29,8 +29,6 @@
 
 import org.ametys.runtime.datasource.ConnectionHelper;
 import org.ametys.web.cache.monitoring.Constants;
-import org.ametys.web.cache.monitoring.process.access.impl.PageElementResourceAccess;
-import org.ametys.web.cache.monitoring.process.access.impl.PageResourceAccess;
 import org.ametys.web.cache.monitoring.process.statistics.impl.FrontFromHTTPServerResourceStatisticsFactory;
 import org.ametys.web.cache.monitoring.process.statistics.impl.FrontOnlyResourceStatisticsFactory;
 import org.ametys.web.cache.monitoring.process.statistics.impl.HTTPServerOnlyResourceStatisticsFactory;
@@ -50,7 +48,10 @@
      */
     public void updateStatistics()
     {
-        getLogger().debug("Updating cache stats tables...");
+        if (getLogger().isDebugEnabled())
+        {
+            getLogger().debug("Updating cache stats tables...");
+        }
         
         long start = System.currentTimeMillis();
         int totalUpdated = 0;
@@ -86,34 +87,19 @@
     
     private int _update(Connection connection, String logName, ResourceStatisticsFactory factory) throws SQLException
     {
-        ResultSet rs = null;
+        // Retrieves resources to process + update cache stats
+        List<ResourceStatistics> resourceStatisticsList = factory.getResourceAccessToProcess();
+        int hits = _updateCacheStats(connection, resourceStatisticsList);
         
-        try
-        {
-            long id = factory.getMaxIdToProcess();
-            if (id <= 0)
-            {
-                // nothing to do.
-                return 0;
-            }
-            
-            // Retrieves resources to process + update cache stats
-            List<ResourceStatistics> resourceStatisticsList = factory.getResourceAccessToProcess();
-            int hits = _updateCacheStats(connection, resourceStatisticsList);
-            
-            // Mark handled resource access as processed
-            int processed = factory.markResourcesAsProcessed(id);
-            if (getLogger().isDebugEnabled())
-            {
-                getLogger().debug(String.format("It appears to be %s new hits for the ResourceStatistics '%s'. Also, %s access logs have been marked has processed.", hits, logName, processed));
-            }
-            
-            return processed;
-        }
-        finally
+        // Mark handled resource access as processed
+        int processed = factory.markResourcesAsProcessed();
+        
+        if (getLogger().isDebugEnabled())
         {
-            ConnectionHelper.cleanup(rs);
+            getLogger().debug(String.format("It appears to be %s new hits for the ResourceStatistics '%s'. Also, %s access logs have been marked has processed.", hits, logName, processed));
         }
+        
+        return processed;
     }
     
     private int _updateCacheStats(Connection connection, List<ResourceStatistics> resourceStatisticsList) throws SQLException
@@ -121,7 +107,6 @@
         int hits = 0;
         
         PreparedStatement stmt = null;
-        ResultSet resultSet = null;
         try
         {
             for (ResourceStatistics resourceStatistics : resourceStatisticsList)
@@ -141,7 +126,6 @@
         }
         finally
         {
-            ConnectionHelper.cleanup(resultSet);
             ConnectionHelper.cleanup(stmt);
         }
         
@@ -173,33 +157,25 @@
      */
     public void purgeRawData()
     {
-        getLogger().debug("Purging raw monitoring data...");
-        long start = System.currentTimeMillis();
+        long start = 0;
+        if (getLogger().isDebugEnabled())
+        {
+            getLogger().debug("Purging raw monitoring data...");
+            start = System.currentTimeMillis();
+        }
         
         int totalPurged = 0;
-        
-        Connection connection = null;
-        PreparedStatement stmt = null;
-        PreparedStatement stmt2 = null;
         try
         {
-            connection = ConnectionHelper.getConnection(Constants.MONITORING_DATASOURCE_POOLNAME);
-            
-            stmt = PageResourceAccess.getPurgeStatement(connection);
-            totalPurged += stmt.executeUpdate();
-
-            stmt2 = PageElementResourceAccess.getPurgeStatement(connection);
-            totalPurged += stmt2.executeUpdate();
+            totalPurged += PageResourceStatisticsFactory.getInstance().purgeRawData();
+            totalPurged += PageElementResourceStatisticsFactory.getInstance().purgeRawData();
+            totalPurged += FrontOnlyResourceStatisticsFactory.getInstance().purgeRawData();
+            totalPurged += HTTPServerOnlyResourceStatisticsFactory.getInstance().purgeRawData();
+            totalPurged += FrontFromHTTPServerResourceStatisticsFactory.getInstance().purgeRawData();
         }
         catch (SQLException e)
         {
-            getLogger().error("An error occured whil purging raw monitoring data", e);
-        }
-        finally
-        {
-            ConnectionHelper.cleanup(stmt);
-            ConnectionHelper.cleanup(stmt2);
-            ConnectionHelper.cleanup(connection);
+            getLogger().error("An error occured while purging raw monitoring data", e);
         }
 
         if (getLogger().isDebugEnabled())
Index: main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/ResourceStatisticsFactory.java
===================================================================
--- main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/ResourceStatisticsFactory.java	(revision 20673)
+++ main/plugin-web/src/org/ametys/web/cache/monitoring/process/statistics/ResourceStatisticsFactory.java	(working copy)
@@ -32,17 +32,16 @@
     public List<ResourceStatistics> getResourceAccessToProcess() throws SQLException;
     
     /**
-     * Get the max id of this kind of statistics
-     * @return The id
+     * Mark the statistics of this kind as processed
+     * @return The number of resources processed
      * @throws SQLException If an error occured
      */
-    public long getMaxIdToProcess() throws SQLException;
+    public int markResourcesAsProcessed() throws SQLException;
     
     /**
-     * Mark the statistics of this kind as processed
-     * @param id The max id to process
-     * @return The number of resources processed
-     * @throws SQLException If an error occured
+     * Purge the processed raw data related to this kind of statistics.
+     * @return The number of purged rows.
+     * @throws SQLException
      */
-    public int markResourcesAsProcessed(long id) throws SQLException;
+    public int purgeRawData() throws SQLException;
 }
Index: main/plugin-web/src/org/ametys/web/cache/monitoring/process/CacheMonitoringScheduler.java
===================================================================
--- main/plugin-web/src/org/ametys/web/cache/monitoring/process/CacheMonitoringScheduler.java	(revision 20673)
+++ main/plugin-web/src/org/ametys/web/cache/monitoring/process/CacheMonitoringScheduler.java	(working copy)
@@ -74,29 +74,33 @@
             return;
         }
         
-        if (_logger.isDebugEnabled())
-        {
-            _logger.debug("Scheduling the CacheMonitoringScheduler component to run its task each hours");
-        }
-        
         // Daemon thread
         _timer = new Timer("CacheMonitoringScheduler", true);
         
-        // The task is each hour, starting at h5m if not too late.
+        // The task is each hour, starting at h15m if not too late.
         // It is a quarter after the execution of the task of the FrontCacheMonitoringScheduler
         GregorianCalendar calendar = new GregorianCalendar();
         int minute = calendar.get(Calendar.MINUTE);
         
-        if (minute > 0)
+        // If 3h10, will starts at 3h15.
+        // If 3h11, will starts at 4h15
+        if (minute > 10)
         {
             calendar.add(Calendar.HOUR_OF_DAY, 1);
         }
         
-        calendar.set(Calendar.MINUTE, 5);
+        calendar.set(Calendar.MINUTE, 15);
         calendar.set(Calendar.SECOND, 0);
         calendar.set(Calendar.MILLISECOND, 0);
         
-        _timer.scheduleAtFixedRate(this, calendar.getTime(), 60 * 60 * 1000);
+        // TODO uncomment after testing
+//        _timer.scheduleAtFixedRate(this, calendar.getTime(), 60 * 60 * 1000);
+        _timer.scheduleAtFixedRate(this, 30 * 1000, 60 * 1000);
+        
+        if (_logger.isInfoEnabled())
+        {
+            _logger.info("Cache monitoring scheduler : The process will run each hour, starting " + calendar.getTime());
+        }
     }
     
     @Override
Index: main/plugin-web/src/org/ametys/web/cache/monitoring/process/access/ResourceAccessComponent.java
===================================================================
--- main/plugin-web/src/org/ametys/web/cache/monitoring/process/access/ResourceAccessComponent.java	(revision 20673)
+++ main/plugin-web/src/org/ametys/web/cache/monitoring/process/access/ResourceAccessComponent.java	(working copy)
@@ -16,6 +16,7 @@
 
 package org.ametys.web.cache.monitoring.process.access;
 
+import java.sql.BatchUpdateException;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
@@ -155,10 +156,15 @@
             
             return 0;
         }
-        catch (SQLException e)
+        catch (BatchUpdateException e)
         {
-            // more detailed treatment is possible through e.getUpdateCounts()
             getLogger().error("Batch exception while inserting new records to the database", e);
+            // more detailed treatment is possible through e.getUpdateCounts()
+            return 0;
+        }
+        catch (SQLException e)
+        {
+            getLogger().error("SQLException exception while inserting new records to the database", e);
             return 0;
         }
         finally
Index: main/plugin-web/src/org/ametys/web/cache/monitoring/process/access/impl/PageResourceAccess.java
===================================================================
--- main/plugin-web/src/org/ametys/web/cache/monitoring/process/access/impl/PageResourceAccess.java	(revision 20673)
+++ main/plugin-web/src/org/ametys/web/cache/monitoring/process/access/impl/PageResourceAccess.java	(working copy)
@@ -19,8 +19,9 @@
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
-import java.sql.Statement;
+import java.sql.Timestamp;
 
+import org.apache.commons.lang.BooleanUtils;
 import org.apache.commons.lang.StringUtils;
 
 import org.ametys.web.cache.monitoring.Constants;
@@ -49,7 +50,7 @@
      */
     public PageResourceAccess(String internalUuid, String pageID, String path)
     {
-        _internalUuid = internalUuid;
+        _internalUuid = StringUtils.defaultIfEmpty(internalUuid, "-");
         _pageID = pageID;
         _path = StringUtils.substringBefore(path, "?");
     }
@@ -58,7 +59,7 @@
     @Override
     public PreparedStatement getInsertStatement(Connection connection) throws SQLException
     {
-        return connection.prepareStatement("INSERT IGNORE INTO " + Constants.__SQL_TABLE_NAME_PAGE_ACCESS + " (Internal_Uuid, Page_Id, Page_Path, Rendering_Context, Workspace_JCR, Cacheable) values (?, ?, ?, ?, ?, ?)", Statement.NO_GENERATED_KEYS);
+        return connection.prepareStatement("INSERT INTO " + Constants.__SQL_TABLE_NAME_PAGE_ACCESS + " (Internal_Uuid, Page_Id, Page_Path, Rendering_Context, Workspace_JCR, Cacheable, Created_At) values (?, ?, ?, ?, ?, ?, ?)");
     }
     
     @Override
@@ -69,23 +70,10 @@
         stmt.setString(3, _path);
         stmt.setString(4, _renderingContext.toString());
         stmt.setString(5, _workspaceJCR);
-        stmt.setBoolean(6, _cacheable);
-    }
-    
-    /**
-     * Creates the purge statement used when doing the SQL purge
-     * @param connection
-     * @return The prepares statement ready to execute
-     * @throws SQLException
-     */
-    public static PreparedStatement getPurgeStatement(Connection connection) throws SQLException
-    {
-        return connection.prepareStatement("DELETE FROM " + Constants.__SQL_TABLE_NAME_PAGE_ACCESS + " WHERE PROCESSED = true");
+        stmt.setInt(6, BooleanUtils.toInteger(_cacheable));
+        stmt.setTimestamp(7, new Timestamp(System.currentTimeMillis()));
     }
     
-    
-    
-    
     /**
      * Create a page element resource access for this page resource access.
      * @param pageElementID
Index: main/plugin-web/src/org/ametys/web/cache/monitoring/process/access/impl/PageElementResourceAccess.java
===================================================================
--- main/plugin-web/src/org/ametys/web/cache/monitoring/process/access/impl/PageElementResourceAccess.java	(revision 20673)
+++ main/plugin-web/src/org/ametys/web/cache/monitoring/process/access/impl/PageElementResourceAccess.java	(working copy)
@@ -19,8 +19,10 @@
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
-import java.sql.Statement;
-import java.sql.Types;
+import java.sql.Timestamp;
+
+import org.apache.commons.lang.BooleanUtils;
+import org.apache.commons.lang.StringUtils;
 
 import org.ametys.web.cache.monitoring.Constants;
 import org.ametys.web.cache.monitoring.process.access.ResourceAccess;
@@ -50,31 +52,31 @@
         
         /**
          * Utility method the get the PageElementType corresponding to a ZoneType
-         * @param ziType
+         * @param zoneItemType
          * @return the PageElementType
          */
-        public static PageElementType fromZoneItemType(ZoneType ziType)
+        public static PageElementType fromZoneItemType(ZoneType zoneItemType)
         {
-            switch (ziType)
+            switch (zoneItemType)
             {
                 case CONTENT:
-                    return CONTENT;
+                    return PageElementType.CONTENT;
                 case SERVICE:
-                    return SERVICE;
+                    return PageElementType.SERVICE;
                 default:
-                    throw new IllegalArgumentException("Unknown ZoneType : " + ziType);
+                    throw new IllegalArgumentException("Unknown ZoneType : " + zoneItemType);
             }
         }
     }
     
     private final String _internalUuid;
+    private final String _pageID;
     private final String _pageElementID;
     private final PageElementType _pageElementType;
-    private final String _pageID;
     private final RenderingContext _renderingContext;
     private final String _workspaceJCR;
     private boolean _cacheable;
-    private Boolean _cacheHit;
+    private boolean _cacheHit;
     
     /**
      * Ctor
@@ -85,12 +87,12 @@
      * @param rc
      * @param ws
      */
-    public PageElementResourceAccess(String uuid, String peid, String pageID, PageElementType pet, RenderingContext rc, String ws)
+    public PageElementResourceAccess(String uuid, String pageID, String peid, PageElementType pet, RenderingContext rc, String ws)
     {
-        _internalUuid = uuid;
+        _internalUuid = StringUtils.defaultIfEmpty(uuid, "-");
+        _pageID = pageID;
         _pageElementID = peid;
         _pageElementType = pet;
-        _pageID = pageID;
         _renderingContext = rc;
         _workspaceJCR = ws;
     }
@@ -98,7 +100,7 @@
     @Override
     public PreparedStatement getInsertStatement(Connection connection) throws SQLException
     {
-        return connection.prepareStatement("INSERT IGNORE INTO " + Constants.__SQL_TABLE_NAME_PAGE_ELEMENTS_ACCESS + " (Internal_Uuid, Page_Element_Id, Page_Element_Type, Page_Id, Rendering_Context, Workspace_JCR, Cacheable, Cache_Hit) values (?, ?, ?, ?, ?, ?, ?, ?)", Statement.NO_GENERATED_KEYS);
+        return connection.prepareStatement("INSERT INTO " + Constants.__SQL_TABLE_NAME_PAGE_ELEMENTS_ACCESS + " (Internal_Uuid, Page_Element_Id, Page_Element_Type, Page_Id, Rendering_Context, Workspace_JCR, Cacheable, Cache_Hit, Created_At) values (?, ?, ?, ?, ?, ?, ?, ?, ?)");
     }
     
     @Override
@@ -110,20 +112,9 @@
         stmt.setString(4, _pageID);
         stmt.setString(5, _renderingContext.toString());
         stmt.setString(6, _workspaceJCR);
-        stmt.setBoolean(7, _cacheable);
-        // Handle null cases, avoid NPE and set NULL into the db in thoses cases.
-        stmt.setObject(8, _cacheHit, Types.BOOLEAN);
-    }
-    
-    /**
-     * Creates the purge statement used when doing the SQL purge
-     * @param connection
-     * @return The prepares statement ready to execute
-     * @throws SQLException
-     */
-    public static PreparedStatement getPurgeStatement(Connection connection) throws SQLException
-    {
-        return connection.prepareStatement("DELETE FROM " + Constants.__SQL_TABLE_NAME_PAGE_ELEMENTS_ACCESS + " WHERE PROCESSED = true");
+        stmt.setInt(7, BooleanUtils.toInteger(_cacheable));
+        stmt.setInt(8, BooleanUtils.toInteger(_cacheHit));
+        stmt.setTimestamp(9, new Timestamp(System.currentTimeMillis()));
     }
     
     /**
Index: main/plugin-web/src/org/ametys/web/cache/monitoring/Constants.java
===================================================================
--- main/plugin-web/src/org/ametys/web/cache/monitoring/Constants.java	(revision 20673)
+++ main/plugin-web/src/org/ametys/web/cache/monitoring/Constants.java	(working copy)
@@ -25,18 +25,18 @@
     public static final String MONITORING_DATASOURCE_POOLNAME = "cache.monitoring.datasource";
 
     /** The name of the table for page resource access */
-    public static final String __SQL_TABLE_NAME_PAGE_ACCESS = "Back_Requests";
+    public static final String __SQL_TABLE_NAME_PAGE_ACCESS = "Cache_RA_Back";
     /** The name of the table for page elements resource access */
-    public static final String __SQL_TABLE_NAME_PAGE_ELEMENTS_ACCESS = "Back_Page_Element_Requests";
+    public static final String __SQL_TABLE_NAME_PAGE_ELEMENTS_ACCESS = "Cache_RA_Back_Page_Element";
     /** The name of the table for front resource access */
-    public static final String __SQL_TABLE_NAME_FRONT_ACCESS = "Front_Requests";
+    public static final String __SQL_TABLE_NAME_FRONT_ACCESS = "Cache_RA_Front";
     /** The name of the table for httpserver resource access */
-    public static final String __SQL_TABLE_NAME_HTTPSERVER_ACCESS = "Server_Requests";
+    public static final String __SQL_TABLE_NAME_HTTPSERVER_ACCESS = "Cache_RA_HTTPServer";
     
     /** The name of the table for back statictics */
-    public static final String __SQL_TABLE_NAME_PAGE_STATISTICS = "Cache_Back_Stats";
+    public static final String __SQL_TABLE_NAME_PAGE_STATISTICS = "Cache_Stats_Back";
     /** The name of the table for back statictics for page elements*/
-    public static final String __SQL_TABLE_NAME_PAGE_ELEMENTS_STATISTICS = "Cache_Back_Page_Element_Stats";
+    public static final String __SQL_TABLE_NAME_PAGE_ELEMENTS_STATISTICS = "Cache_Stats_Back_Page_Element";
     /** The name of the table for front statictics */
-    public static final String __SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS = "Cache_Front_Stats";
+    public static final String __SQL_TABLE_NAME_HTTPSERVER_AND_FRONT_STATISTICS = "Cache_Stats_Front";
 }
Index: main/plugin-web/src/org/ametys/web/repository/site/SiteGenerator.java
===================================================================
--- main/plugin-web/src/org/ametys/web/repository/site/SiteGenerator.java	(revision 20673)
+++ main/plugin-web/src/org/ametys/web/repository/site/SiteGenerator.java	(working copy)
@@ -74,6 +74,7 @@
         attr.addAttribute("", "id", "id", "CDATA", site.getId());
         attr.addAttribute("", "name", "name", "CDATA", site.getName());
         attr.addAttribute("", "title", "title", "CDATA", StringUtils.defaultString(site.getTitle()));
+        attr.addAttribute("", "path", "path", "CDATA", site.getSitePath());
         XMLUtils.startElement(contentHandler, "site", attr);
         _saxSite (site);
         XMLUtils.endElement(contentHandler, "site");
@@ -84,7 +85,7 @@
     private void _saxSite (Site site) throws SAXException
     {
         CompositeMetadata metaHolder = site.getMetadataHolder();
-
+        
         XMLUtils.startElement(contentHandler, "metadata");
         String[] metadataNames = metaHolder.getMetadataNames();
         for (int i = 0; i < metadataNames.length; i++)
@@ -100,5 +101,5 @@
         
         XMLUtils.endElement(contentHandler, "metadata");
     }
-
+    
 }
Index: main/plugin-web/pages/administrator/sites/cache-statistics-back-tree.xsl
===================================================================
--- main/plugin-web/pages/administrator/sites/cache-statistics-back-tree.xsl	(revision 0)
+++ main/plugin-web/pages/administrator/sites/cache-statistics-back-tree.xsl	(revision 0)
@@ -0,0 +1,232 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Copyright 2012 Anyware Services
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+   -->
+    
+<xsl:stylesheet version="1.0"
+                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:i18n="http://apache.org/cocoon/i18n/2.1"
+                xmlns:text="http://ametys.org/text/3.0"
+                extension-element-prefixes="text"> 
+    
+    <xsl:import href="plugin:core://stylesheets/helper/text.xsl"/>
+    
+    <xsl:param name="contextPath"/>
+    <xsl:param name="pluginName"/>
+    
+    
+    <xsl:template match="/stats">
+    	<root>
+			<!-- filters site that contains at least a page with a context (ie. some statistics) -->
+			<xsl:apply-templates select="site" />
+		</root>
+    </xsl:template>
+    
+    <xsl:template match="site">
+    	<site id="{@id}" label="{@name}" qtip="{@id}" leaf="true" expanded="true"
+    	icon="{$contextPath}/plugins/{$pluginName}/resources/img/administrator/stats/sitemap_16.png" cls="site-node">
+			<xsl:variable name="hits"><xsl:call-template name="get-hits-sum" /></xsl:variable>
+			<xsl:variable name="cacheHits"><xsl:call-template name="get-cachehits-sum" /></xsl:variable>
+			
+			<xsl:attribute name="pageHits"><xsl:call-template name="get-pagehits-sum" /></xsl:attribute>
+			<xsl:attribute name="cacheable"><xsl:call-template name="get-weighted-cacheable-mean" /></xsl:attribute>
+			<xsl:attribute name="hits"><xsl:value-of select="$hits" /></xsl:attribute>
+			<xsl:attribute name="cacheHits"><xsl:value-of select="$cacheHits" /></xsl:attribute>
+			<xsl:attribute name="eff"><xsl:value-of select="round($cacheHits*100 div $hits)" /><xsl:text> %</xsl:text></xsl:attribute>
+    	
+    		<xsl:apply-templates select="sitemap[descendant::context[1]]">
+    			<xsl:sort select="@name" />
+    		</xsl:apply-templates>
+    	</site>
+    </xsl:template>
+    
+    <xsl:template match="sitemap">
+    	<sitemap 	id="{@id}" label="{@name}" qtip="{@id}" leaf="true" expanded="true"
+    				icon="{$contextPath}/plugins/{$pluginName}/resources/img/administrator/stats/sitemap_16.png" cls="sitemap-node">
+			<xsl:variable name="hits"><xsl:call-template name="get-hits-sum" /></xsl:variable>
+			<xsl:variable name="cacheHits"><xsl:call-template name="get-cachehits-sum" /></xsl:variable>
+			
+			<xsl:attribute name="pageHits"><xsl:call-template name="get-pagehits-sum" /></xsl:attribute>
+			<xsl:attribute name="cacheable"><xsl:call-template name="get-weighted-cacheable-mean" /></xsl:attribute>
+			<xsl:attribute name="hits"><xsl:value-of select="$hits" /></xsl:attribute>
+			<xsl:attribute name="cacheHits"><xsl:value-of select="$cacheHits" /></xsl:attribute>
+			<xsl:attribute name="eff"><xsl:value-of select="round($cacheHits*100 div $hits)" /><xsl:text> %</xsl:text></xsl:attribute>
+    	
+    		<xsl:apply-templates select="page[descendant::context[1]]">
+    			<xsl:sort select="@name" />
+    		</xsl:apply-templates>
+    	</sitemap>
+    </xsl:template>
+    
+    <xsl:template match="page">
+    	<page 	id="{@id}" label="{@name}.html" qtip="{@id}" leaf="true"
+    			icon="{$contextPath}/plugins/{$pluginName}/resources/img/administrator/stats/content_16.png" cls="page-node">
+			<xsl:variable name="hits"><xsl:call-template name="get-hits-sum" /></xsl:variable>
+			<xsl:variable name="cacheHits"><xsl:call-template name="get-cachehits-sum" /></xsl:variable>
+			
+			<xsl:attribute name="pageHits"><xsl:call-template name="get-pagehits-sum" /></xsl:attribute>
+			<xsl:attribute name="cacheable"><xsl:call-template name="get-weighted-cacheable-mean" /></xsl:attribute>
+			<xsl:attribute name="hits"><xsl:value-of select="$hits" /></xsl:attribute>
+			<xsl:attribute name="cacheHits"><xsl:value-of select="$cacheHits" /></xsl:attribute>
+			<xsl:attribute name="eff"><xsl:value-of select="round($cacheHits*100 div $hits)" /><xsl:text> %</xsl:text></xsl:attribute>
+    	
+    		<xsl:apply-templates select="self::page[context[1]]" mode="alone" />
+			<xsl:apply-templates select="page[descendant::context[1]]">
+				<xsl:sort select="@name" />
+			</xsl:apply-templates>
+    	</page>
+    </xsl:template>
+    
+    <xsl:template match="page" mode="alone">
+    	<context 	id="{@id}_alone" label="détails" qtip="Détails des statistiques pour la page {@name}.html" leaf="true"
+    				iconCls="x-tree-node-inline-icon" cls="context-node">
+			<xsl:variable name="hits"><xsl:call-template name="get-hits-sum-details" /></xsl:variable>
+			<xsl:variable name="cacheHits"><xsl:call-template name="get-cachehits-sum-details" /></xsl:variable>
+			
+			<xsl:attribute name="pageHits"><xsl:call-template name="get-pagehits-sum-details" /></xsl:attribute>
+			<xsl:attribute name="cacheable"><xsl:call-template name="get-weighted-cacheable-mean-details" /></xsl:attribute>
+			<xsl:attribute name="hits"><xsl:value-of select="$hits" /></xsl:attribute>
+			<xsl:attribute name="cacheHits"><xsl:value-of select="$cacheHits" /></xsl:attribute>
+			<xsl:attribute name="eff"><xsl:value-of select="round($cacheHits*100 div $hits)" /><xsl:text> %</xsl:text></xsl:attribute>
+    	
+    		<xsl:apply-templates select="context">
+    			<xsl:sort select="@renderingContext" />
+    			<xsl:sort select="@workspaceJCR" />
+    		</xsl:apply-templates>
+    	</context>
+    </xsl:template>
+    
+    <xsl:template match="context">
+   		<context 	id="{../@id}_{@renderingContext}_{@workspaceJCR}" leaf="true" icon="" iconCls="x-tree-node-inline-icon" cls="context-node"
+   					label="{@renderingContext}/{@workspaceJCR}" pageHits="{hits}">
+			<xsl:variable name="hits"><xsl:call-template name="get-hits-sum" /></xsl:variable>
+			<xsl:variable name="cacheHits"><xsl:call-template name="get-cachehits-sum" /></xsl:variable>
+			
+			<xsl:attribute name="cacheable"><xsl:call-template name="get-weighted-cacheable-mean" /></xsl:attribute>
+			<xsl:attribute name="hits"><xsl:value-of select="$hits" /></xsl:attribute>
+			<xsl:attribute name="cacheHits"><xsl:value-of select="$cacheHits" /></xsl:attribute>
+			<xsl:attribute name="eff"><xsl:value-of select="round($cacheHits*100 div $hits)" /><xsl:text> %</xsl:text></xsl:attribute>
+			
+    		<xsl:apply-templates select="zone|inputdata" />
+    	</context>
+    </xsl:template>
+    
+    <xsl:template match="zone">
+    	<zone 	id="{@id}_{../@renderingContext}_{../@workspaceJCR}" label="{@name}" qtip="{@id}" leaf="true" icon="" iconCls="x-tree-node-inline-icon" cls="zone-node">
+			<xsl:variable name="hits"><xsl:call-template name="get-hits-sum" /></xsl:variable>
+			<xsl:variable name="cacheHits"><xsl:call-template name="get-cachehits-sum" /></xsl:variable>
+			
+			<xsl:attribute name="cacheable"><xsl:call-template name="get-weighted-cacheable-mean" /></xsl:attribute>
+			<xsl:attribute name="hits"><xsl:value-of select="$hits" /></xsl:attribute>
+			<xsl:attribute name="cacheHits"><xsl:value-of select="$cacheHits" /></xsl:attribute>
+			<xsl:attribute name="eff"><xsl:value-of select="round($cacheHits*100 div $hits)" /><xsl:text> %</xsl:text></xsl:attribute>
+			
+    		<xsl:apply-templates select="zoneitem" />
+    	</zone>
+    </xsl:template>
+    
+    <xsl:template match="zoneitem">
+    	<zoneitem 	id="{@id}_{../../@renderingContext}_{../../@workspaceJCR}" leaf="true" icon="" iconCls="x-tree-node-inline-icon"
+					label="#{@index} ({@type})" cacheable="{@cacheable}" hits="{hits}" cacheHits="{cacheHits}" eff="{round(cacheHits*100 div hits)} %">
+					
+			<xsl:attribute name="qtip">
+				<xsl:value-of select="concat('id : ', @id, '&lt;br/&gt;')" />
+				<xsl:value-of select="concat('type : ', @type, '&lt;br/&gt;')" />
+				<xsl:choose>
+					<xsl:when test="@type = 'content'">
+						<xsl:value-of select="concat('content type : ', @contentType, '&lt;br/&gt;')" />
+						<xsl:value-of select="concat('content id : ', @contentId)" />
+					</xsl:when>
+					<xsl:when test="@type = 'service'">
+						<xsl:value-of select="concat('service id : ', @serviceId)" />
+					</xsl:when>
+				</xsl:choose>
+			</xsl:attribute>
+    	</zoneitem>
+    </xsl:template>
+    
+    <xsl:template match="inputdata">
+    	<inputdata 	id="{../../@id}_{../@renderingContext}_{../@workspaceJCR}_inputdata" label="InputData" leaf="true" icon="" iconCls="x-tree-node-inline-icon" cls="inputdata-node">
+			<xsl:variable name="hits"><xsl:call-template name="get-hits-sum" /></xsl:variable>
+			<xsl:variable name="cacheHits"><xsl:call-template name="get-cachehits-sum" /></xsl:variable>
+			
+			<xsl:attribute name="cacheable"><xsl:call-template name="get-weighted-cacheable-mean" /></xsl:attribute>
+			<xsl:attribute name="hits"><xsl:value-of select="$hits" /></xsl:attribute>
+			<xsl:attribute name="cacheHits"><xsl:value-of select="$cacheHits" /></xsl:attribute>
+			<xsl:attribute name="eff"><xsl:value-of select="round($cacheHits*100 div $hits)" /><xsl:text> %</xsl:text></xsl:attribute>
+			
+    		<xsl:apply-templates select="inputdataitem" />
+    	</inputdata>
+    </xsl:template>
+    
+    <xsl:template match="inputdataitem">
+    	<inputdataitem 	id="{../../../@id}_{../../@renderingContext}_{../../@workspaceJCR}_{@id}" qtip="{@id}" leaf="true" icon="" iconCls="x-tree-node-inline-icon"
+						label="{@title}" cacheable="{@cacheable}" hits="{hits}" cacheHits="{cacheHits}" eff="{round(cacheHits*100 div hits)} %">
+    	</inputdataitem>
+    </xsl:template>
+    
+    <xsl:template name="get-pagehits-sum">
+    	<xsl:value-of select="sum(.//context/hits)" />
+    </xsl:template>
+    
+    <xsl:template name="get-cachehits-sum">
+    	<xsl:value-of select="sum(.//zoneitem/cacheHits|.//inputdataitem/cacheHits)" />
+    </xsl:template>
+    
+    <xsl:template name="get-hits-sum">
+    	<xsl:value-of select="sum(.//zoneitem/hits|.//inputdataitem/hits)" />
+    </xsl:template>
+    
+    <xsl:template name="get-pagehits-sum-details">
+    	<xsl:value-of select="sum(context/hits)" />
+    </xsl:template>
+    
+    <!-- moyenne du nombre de page element cacheables -->
+    <xsl:template name="get-cacheable-mean">
+    	<xsl:variable name="cacheables" select="count(.//zoneitem[@cacheable='true']|.//inputdataitem[@cacheable='true'])" />
+    	<xsl:variable name="total" select="count(.//zoneitem|.//inputdataitem)" />
+    	<xsl:value-of select="round($cacheables*100 div $total)" /><xsl:text> %</xsl:text>
+    </xsl:template>
+    
+    <!-- moyenne du nombre de pages element cacheables ponderée par le nombre de hits -->
+    <xsl:template name="get-weighted-cacheable-mean">
+    	<xsl:variable name="cacheables" select="sum(.//zoneitem[@cacheable='true']/hits|.//inputdataitem[@cacheable='true']/hits)" />
+    	<xsl:variable name="total" select="sum(.//zoneitem/hits|.//inputdataitem/hits)" />
+    	<xsl:value-of select="round($cacheables*100 div $total)" /><xsl:text> %</xsl:text>
+    </xsl:template>
+    
+	<!-- moyenne du nombre de page element cacheables pour la page courante -->
+    <xsl:template name="get-cacheable-mean-details">
+    	<xsl:variable name="cacheables" select="count(context/zone/zoneitem[@cacheable='true']|context/inputdata/inputdataitem[@cacheable='true'])" />
+    	<xsl:variable name="total" select="count(context/zone/zoneitem|context/inputdata/inputdataitem)" />
+    	<xsl:value-of select="round($cacheables*100 div $total)" /><xsl:text> %</xsl:text>
+    </xsl:template>
+    
+    <!-- moyenne du nombre de pages element cacheables ponderée par le nombre de hits pour la page courante -->
+    <xsl:template name="get-weighted-cacheable-mean-details">
+    	<xsl:variable name="cacheables" select="sum(context/zone/zoneitem[@cacheable='true']/hits|context/inputdata/inputdataitem[@cacheable='true']/hits)" />
+    	<xsl:variable name="total" select="sum(context/zone/zoneitem/hits|context/inputdata/inputdataitem/hits)" />
+    	<xsl:value-of select="round($cacheables*100 div $total)" /><xsl:text> %</xsl:text>
+    </xsl:template>
+    
+    <xsl:template name="get-cachehits-sum-details">
+    	<xsl:value-of select="sum(context/zone/zoneitem/cacheHits|context/inputdata/inputdataitem/cacheHits)" />
+    </xsl:template>
+    
+    <xsl:template name="get-hits-sum-details">
+    	<xsl:value-of select="sum(context/zone/zoneitem/hits|context/inputdata/inputdataitem/hits)" />
+    </xsl:template>
+    
+</xsl:stylesheet>
Index: main/plugin-web/pages/administrator/sites/cache-statistics-back.xsl
===================================================================
--- main/plugin-web/pages/administrator/sites/cache-statistics-back.xsl	(revision 0)
+++ main/plugin-web/pages/administrator/sites/cache-statistics-back.xsl	(revision 0)
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Copyright 2012 Anyware Services
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+   -->
+<xsl:stylesheet version="1.0" 
+                xmlns:i18n="http://apache.org/cocoon/i18n/2.1" 
+                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:ametys="org.ametys.web.transformation.xslt.AmetysXSLTHelper"
+                exclude-result-prefixes="ametys">
+    
+    <xsl:param name="contextPath"/>
+    <xsl:param name="pluginName"/>
+    
+    <xsl:template match="/">
+        <html>
+            <head>
+                <title>
+                    <i18n:translate>
+                        <i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_BACK_STATISTICS_TITLE"/>
+                        <i18n:param name="name"><xsl:value-of select="site/@name"/></i18n:param>
+                    </i18n:translate>
+                </title>
+				<link rel="stylesheet" href="{ametys:pluginResourceURL('extjs', 'ux/js/treegrid/treegrid.css')}" type="text/css"/>
+				<style>
+					.custom-hd-row { background-image: url("<xsl:value-of select="ametys:pluginResourceURL('extjs', 'images/default/grid/grid3-hrow.gif')" />"); }
+				</style>
+            </head>
+            
+            <script>
+                <script type="text/javascript" src="{ametys:pluginResourceURL('extjs', 'ux/js/treegrid/TreeGrid.js')}"></script>
+                <script type="text/javascript" src="{ametys:pluginResourceURL('extjs', 'ux/js/treegrid/TreeGridColumnResizer.js')}"></script>
+                <script type="text/javascript" src="{ametys:pluginResourceURL('extjs', 'ux/js/treegrid/TreeGridColumns.js')}"></script>
+                <script type="text/javascript" src="{ametys:pluginResourceURL('extjs', 'ux/js/treegrid/TreeGridLoader.js')}"></script>
+                <script type="text/javascript" src="{ametys:pluginResourceURL('extjs', 'ux/js/treegrid/TreeGridNodeUI.js')}"></script>
+                <script type="text/javascript" src="{ametys:pluginResourceURL('extjs', 'ux/js/treegrid/TreeGridSorter.js')}"></script>
+                
+				<script type="text/javascript" src="{ametys:pluginResourceURL($pluginName, 'js/org/ametys/web/administration/CacheStatistics.i18n.js')}"></script>
+				<script type="text/javascript" src="{ametys:pluginResourceURL($pluginName, 'js/org/ametys/web/administration/CacheStatisticsBack.i18n.js')}"></script>
+                
+                <script type="text/javascript">
+            		org.ametys.web.administration.CacheStatisticsBack.init("<xsl:value-of select="$pluginName"/>", "<xsl:value-of select="site/@name"/>", "<xsl:value-of select="site/@path"/>");
+            		
+                   	org.ametys.runtime.administrator.Panel.createPanel = function () 
+					{
+						return new Ext.Panel({
+							region: 'center',
+							
+							baseCls: 'transparent-panel',
+							border: false,
+							layout: 'border',
+							autoScroll: true,
+							
+							items : [org.ametys.web.administration.CacheStatisticsBack._centerPanel,
+									 org.ametys.web.administration.CacheStatisticsBack._rightPanel
+							]
+						});
+					}
+                </script>
+            </script>
+            
+            <body>
+            </body>
+        </html>
+    </xsl:template>
+    
+</xsl:stylesheet>
Index: main/plugin-web/pages/administrator/sites/cache-statistics-servers-tree.xsl
===================================================================
--- main/plugin-web/pages/administrator/sites/cache-statistics-servers-tree.xsl	(revision 0)
+++ main/plugin-web/pages/administrator/sites/cache-statistics-servers-tree.xsl	(revision 0)
@@ -0,0 +1,435 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Copyright 2012 Anyware Services
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+   -->
+    
+<xsl:stylesheet version="1.0"
+                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:i18n="http://apache.org/cocoon/i18n/2.1"
+                xmlns:text="http://ametys.org/text/3.0"
+                extension-element-prefixes="text"> 
+    
+    <xsl:import href="plugin:core://stylesheets/helper/text.xsl"/>
+    
+    <xsl:param name="contextPath"/>
+    <xsl:param name="pluginName"/>
+    
+    <xsl:template match="/stats">
+    	<root>
+			<xsl:apply-templates select="site" />
+			
+			<!-- Displays orphans if it contains at least some statistics -->
+			<xsl:apply-templates select="orphans[descendant::resource[1]]" />
+		</root>
+    </xsl:template>
+    
+    <xsl:template match="site">
+    	<site>
+    		<xsl:call-template name="entry-attributes">
+    			<xsl:with-param name="label" select="concat('Site : ', @name)" />
+    			<xsl:with-param name="desc" select="@id" />
+    			<xsl:with-param name="expanded" select="'true'" />
+    			<xsl:with-param name="icon" select="concat($contextPath, '/plugins/', $pluginName, '/resources/img/administrator/stats/sitemap_16.png')" />
+    		</xsl:call-template>
+    		
+    		<xsl:apply-templates select="resource">
+    			<xsl:sort select="@name" />
+    		</xsl:apply-templates>
+    	</site>
+   		<total>
+   			<!-- Total for pages only -->
+   			<xsl:call-template name="entry-attributes">
+    			<xsl:with-param name="label" select="concat('Site : ', @name, ' (pages)')" />
+    			<xsl:with-param name="desc" select="concat('Total des statistiques pour les pages du site ', @name)" />
+    			<xsl:with-param name="icon" select="concat($contextPath, '/plugins/', $pluginName, '/resources/img/administrator/stats/sitemap_16.png')" />
+				
+				<xsl:with-param name="cacheable"><xsl:call-template name="get-weighted-cacheable-mean-total-page" /></xsl:with-param>
+				<xsl:with-param name="apacheHits"><xsl:call-template name="get-apacheHits-sum-total-page" /></xsl:with-param>
+				<xsl:with-param name="apacheCacheHits"><xsl:call-template name="get-apacheCachehits-sum-total-page" /></xsl:with-param>
+				<xsl:with-param name="frontHits"><xsl:call-template name="get-frontHits-sum-total-page" /></xsl:with-param>
+				<xsl:with-param name="frontCacheHits"><xsl:call-template name="get-frontCachehits-sum-total-page" /></xsl:with-param>
+				<xsl:with-param name="backHits"><xsl:call-template name="get-backHits-sum-total-page" /></xsl:with-param>
+			</xsl:call-template>
+  			</total>
+    	
+		<spacer>
+			<xsl:call-template name="node-attributes" />
+		</spacer>
+    </xsl:template>
+    
+    <xsl:template match="orphans">
+    	<orphans>
+    		<xsl:call-template name="entry-attributes">
+    			<xsl:with-param name="label" select="'Orphelins'" />
+    			<xsl:with-param name="desc" select="'Statistiques non rattachées à un site.'" />
+    			<xsl:with-param name="expanded" select="'true'" />
+				<xsl:with-param name="icon" select="concat($contextPath, '/plugins/', $pluginName, '/resources/img/administrator/stats/sitemap_16.png')" />
+    		</xsl:call-template>
+    		
+    		<xsl:apply-templates select="resource">
+    			<xsl:sort select="@name" />
+    		</xsl:apply-templates>
+    	</orphans>
+    </xsl:template>
+    
+    <xsl:template match="resource">
+    	<xsl:choose>
+    		<xsl:when test="@type='folder'"><xsl:call-template name="folder" /></xsl:when>
+			<xsl:otherwise><xsl:call-template name="file" /></xsl:otherwise>
+    	</xsl:choose>
+   	</xsl:template>
+   	
+   	<xsl:template name="folder">
+    	<resource>
+    		<xsl:call-template name="entry-attributes">
+    			<xsl:with-param name="label" select="@name" />
+    		</xsl:call-template>
+    		
+    		<xsl:apply-templates select="resource">
+    			<xsl:sort select="@name" />
+    		</xsl:apply-templates>
+    	</resource>
+    </xsl:template>
+    
+   	<xsl:template name="file">
+    	<xsl:variable name="isApacheEntry" select="boolean(entry[@type='apache'])" />
+    	<xsl:variable name="isFrontEntry" select="boolean(entry[@type='front'])" />
+    	<xsl:variable name="isBackEntry" select="boolean(entry[@type='back'])" />
+    	
+    	<resource>
+    		<xsl:variable name="apachePath">
+    			<xsl:if test="$isApacheEntry"><xsl:value-of select="concat('Apache : ', entry[@type='apache']/@apachePath, '&lt;br/&gt;')" /></xsl:if>
+    		</xsl:variable>
+    		<xsl:variable name="frontPath">
+    			<xsl:choose>
+    				<xsl:when test="$isFrontEntry"><xsl:value-of select="concat('Front : ', entry[@type='front']/@path, '&lt;br/&gt;')" /></xsl:when>
+    				<xsl:when test="entry[@type='apache']/@frontPath"><xsl:value-of select="concat('Front : ', entry[@type='apache']/@frontPath, '&lt;br/&gt;')" /></xsl:when>
+   				</xsl:choose>
+    		</xsl:variable>
+    		<xsl:variable name="backId">
+    			<xsl:if test="$isBackEntry"><xsl:value-of select="concat('Id : ', entry[@type='back']/@id)" /></xsl:if>
+    		</xsl:variable>
+    		
+			<xsl:variable name="cacheable">
+				<xsl:call-template name="get-weighted-cacheable-mean-page" />
+			</xsl:variable>
+			<xsl:variable name="apacheHits">
+				<xsl:variable name="child"><xsl:call-template name="get-apacheHits-sum" /></xsl:variable>
+				<xsl:value-of select="$child + sum(entry[@type='apache']/apacheHits)" />
+			</xsl:variable>
+			<xsl:variable name="apacheCacheHits">
+				<xsl:variable name="child"><xsl:call-template name="get-apacheCachehits-sum" /></xsl:variable>
+				<xsl:value-of select="$child + sum(entry[@type='apache']/apacheCacheHits)" />
+			</xsl:variable>
+			<xsl:variable name="frontHits">
+				<xsl:variable name="child"><xsl:call-template name="get-frontHits-sum" /></xsl:variable>
+				<xsl:value-of select="$child + sum(entry[@type='apache' or @type='front']/*[local-name()='frontHits' or local-name()='hits'])" />
+			</xsl:variable>
+			<xsl:variable name="frontCacheHits">
+				<xsl:variable name="child"><xsl:call-template name="get-frontCachehits-sum" /></xsl:variable>
+				<xsl:value-of select="$child + sum(entry[@type='apache' or @type='front']/*[local-name()='frontCacheHits1' or local-name()='frontCacheHits2' or local-name()='cacheHits1' or local-name()='cacheHits2'])" />
+			</xsl:variable>
+			<xsl:variable name="backHits">
+				<xsl:choose>
+					<xsl:when test="@type = 'page'">
+						<xsl:variable name="child"><xsl:call-template name="get-backHits-sum" /></xsl:variable>
+						<xsl:value-of select="$child + sum(entry[@type='back']/hits)" />
+					</xsl:when>
+					<xsl:otherwise><xsl:text>N/A</xsl:text></xsl:otherwise>
+				</xsl:choose>
+			</xsl:variable>
+    		
+    		<xsl:call-template name="entry-attributes">
+    			<xsl:with-param name="label" select="@name" />
+    			<xsl:with-param name="desc" select="concat($apachePath, $frontPath, $backId)" />
+    			
+    			<xsl:with-param name="cacheable" select="$cacheable" />
+    			<xsl:with-param name="apacheHits" select="$apacheHits" />
+    			<xsl:with-param name="apacheCacheHits" select="$apacheCacheHits" />
+    			<xsl:with-param name="frontHits" select="$frontHits" />
+    			<xsl:with-param name="frontCacheHits" select="$frontCacheHits" />
+    			<xsl:with-param name="backHits" select="$backHits" />
+    		</xsl:call-template>
+    		
+    		<xsl:apply-templates select="self::resource[resource]" mode="alone" />
+    		
+    		<xsl:apply-templates select="resource">
+    			<xsl:sort select="@name" />
+    		</xsl:apply-templates>
+    	</resource>
+    </xsl:template>
+    
+    <xsl:template match="resource" mode="alone">
+    	<xsl:if test="@type='page'">
+    		<xsl:call-template name="file-alone" />
+    	</xsl:if>
+   	</xsl:template>
+    
+   	<xsl:template name="file-alone">
+    	<resource>
+    		<xsl:call-template name="entry-attributes">
+    			<xsl:with-param name="label" select="'détails'" />
+    			<xsl:with-param name="desc" select="concat('Détails des statistiques pour la page ', @name)" />
+    			<xsl:with-param name="icon" select="''" />
+    			<xsl:with-param name="iconCls" select="'x-tree-node-inline-icon'" />
+    			
+    			<xsl:with-param name="cacheable" select="@cacheable" />
+    			<xsl:with-param name="apacheHits" select="sum(entry[@type='apache']/apacheHits)" />
+    			<xsl:with-param name="apacheCacheHits" select="sum(entry[@type='apache']/apacheCacheHits)" />
+    			<xsl:with-param name="frontHits" select="sum(entry[@type='apache' or @type='front']/*[local-name()='frontHits' or local-name()='hits'])" />
+    			<xsl:with-param name="frontCacheHits" select="sum(entry[@type='apache' or @type='front']/*[local-name()='frontCacheHits1' or local-name()='frontCacheHits2' or local-name()='cacheHits1' or local-name()='cacheHits2'])" />
+    			<xsl:with-param name="backHits" select="sum(entry[@type='back']/hits)" />
+    		</xsl:call-template>
+    	</resource>
+    </xsl:template>
+    
+	<xsl:template name="node-attributes">
+		<xsl:param name="label" />
+		<xsl:param name="id" />
+		<xsl:param name="desc" />
+		<xsl:param name="leaf" select="'true'" />
+		<xsl:param name="expanded" />
+		<xsl:param name="icon" />
+		<xsl:param name="iconCls" select="'x-tree-node-inline-icon'" />
+		<xsl:param name="cls" />
+		
+		<xsl:param name="cacheable" />
+		<xsl:param name="hits" />
+		<xsl:param name="hitsA" />
+		<xsl:param name="hitsF" />
+		<xsl:param name="hitsB" />
+		<xsl:param name="cacheHits" />
+		<xsl:param name="cacheHitsA" />
+		<xsl:param name="cacheHitsF" />
+		<xsl:param name="eff" />
+		<xsl:param name="effA" />
+		<xsl:param name="effF" />
+		
+		<xsl:call-template name="if-param-attr"><xsl:with-param name="name" select="'label'" /><xsl:with-param name="value" select="$label" /></xsl:call-template>
+		<xsl:call-template name="if-param-attr"><xsl:with-param name="name" select="'id'" /><xsl:with-param name="value" select="$id" /></xsl:call-template>
+		<xsl:call-template name="if-param-attr"><xsl:with-param name="name" select="'qtip'" /><xsl:with-param name="value" select="$desc" /></xsl:call-template><!-- desc -> qtip -->
+		<xsl:call-template name="if-param-attr"><xsl:with-param name="name" select="'leaf'" /><xsl:with-param name="value" select="$leaf" /></xsl:call-template>
+		<xsl:call-template name="if-param-attr"><xsl:with-param name="name" select="'expanded'" /><xsl:with-param name="value" select="$expanded" /></xsl:call-template>
+		<xsl:call-template name="if-param-attr"><xsl:with-param name="name" select="'icon'" /><xsl:with-param name="value" select="$icon" /></xsl:call-template>
+		<xsl:call-template name="if-param-attr"><xsl:with-param name="name" select="'iconCls'" /><xsl:with-param name="value" select="$iconCls" /></xsl:call-template>
+		<xsl:call-template name="if-param-attr"><xsl:with-param name="name" select="'cls'" /><xsl:with-param name="value" select="$cls" /></xsl:call-template>
+	
+		<xsl:call-template name="if-param-attr"><xsl:with-param name="name" select="'cacheable'" /><xsl:with-param name="value" select="$cacheable" /></xsl:call-template>
+		<xsl:call-template name="if-param-attr"><xsl:with-param name="name" select="'hits'" /><xsl:with-param name="value" select="$hits" /></xsl:call-template>
+		<xsl:call-template name="if-param-attr"><xsl:with-param name="name" select="'hitsA'" /><xsl:with-param name="value" select="$hitsA" /></xsl:call-template>
+		<xsl:call-template name="if-param-attr"><xsl:with-param name="name" select="'hitsF'" /><xsl:with-param name="value" select="$hitsF" /></xsl:call-template>
+		<xsl:call-template name="if-param-attr"><xsl:with-param name="name" select="'hitsB'" /><xsl:with-param name="value" select="$hitsB" /></xsl:call-template>
+		<xsl:call-template name="if-param-attr"><xsl:with-param name="name" select="'cacheHits'" /><xsl:with-param name="value" select="$cacheHits" /></xsl:call-template>
+		<xsl:call-template name="if-param-attr"><xsl:with-param name="name" select="'cacheHitsA'" /><xsl:with-param name="value" select="$cacheHitsA" /></xsl:call-template>
+		<xsl:call-template name="if-param-attr"><xsl:with-param name="name" select="'cacheHitsF'" /><xsl:with-param name="value" select="$cacheHitsF" /></xsl:call-template>
+		<xsl:call-template name="if-param-attr"><xsl:with-param name="name" select="'eff'" /><xsl:with-param name="value" select="$eff" /></xsl:call-template>
+		<xsl:call-template name="if-param-attr"><xsl:with-param name="name" select="'effA'" /><xsl:with-param name="value" select="$effA" /></xsl:call-template>
+		<xsl:call-template name="if-param-attr"><xsl:with-param name="name" select="'effF'" /><xsl:with-param name="value" select="$effF" /></xsl:call-template>
+	</xsl:template>
+	
+	<xsl:template name="if-param-attr">
+		<xsl:param name="name" />
+		<xsl:param name="value" />
+		
+		<xsl:if test="$value != ''">
+			<xsl:attribute name="{$name}"><xsl:value-of select="$value" /></xsl:attribute>
+		</xsl:if>
+	</xsl:template>
+	
+	<xsl:template name="entry-attributes">
+		<xsl:param name="label" />
+		<xsl:param name="id" />
+		<xsl:param name="desc" />
+		<xsl:param name="leaf" select="'true'" />
+		<xsl:param name="expanded" />
+		<xsl:param name="icon"><xsl:call-template name="get-entry-icon" /></xsl:param>
+		<xsl:param name="iconCls"><xsl:call-template name="get-entry-iconCls" /></xsl:param>
+		<xsl:param name="cls" />
+		
+		<xsl:param name="cacheable"><xsl:call-template name="get-weighted-cacheable-mean" /></xsl:param>
+		<xsl:param name="apacheHits"><xsl:call-template name="get-apacheHits-sum" /></xsl:param>
+		<xsl:param name="apacheCacheHits"><xsl:call-template name="get-apacheCachehits-sum" /></xsl:param>
+		<xsl:param name="frontHits"><xsl:call-template name="get-frontHits-sum" /></xsl:param>
+		<xsl:param name="frontCacheHits"><xsl:call-template name="get-frontCachehits-sum" /></xsl:param>
+		<xsl:param name="backHits"><xsl:call-template name="get-backHits-sum" /></xsl:param>
+		
+		<xsl:variable name="hits" select="$frontHits + $apacheCacheHits" />
+		<xsl:variable name="hitsA" select="$apacheHits" />
+		<xsl:variable name="hitsF" select="$frontHits - ($apacheHits - $apacheCacheHits)" />
+		<xsl:variable name="hitsB">
+			<xsl:choose>
+				<xsl:when test="string(number($backHits)) != 'NaN'"><xsl:value-of select="$backHits" /></xsl:when>
+				<xsl:otherwise><xsl:text>-</xsl:text></xsl:otherwise>
+			</xsl:choose>
+		</xsl:variable>
+		
+		<xsl:variable name="cacheHits" select="$apacheCacheHits + $frontCacheHits" />
+		<xsl:variable name="cacheHitsA" select="$apacheCacheHits" />
+		<xsl:variable name="cacheHitsF" select="$frontCacheHits" />
+		
+		<xsl:variable name="eff"><xsl:call-template name="get-percent"><xsl:with-param name="value" select="round(100*$cacheHits div $hits)" /></xsl:call-template></xsl:variable>
+		<xsl:variable name="effA"><xsl:call-template name="get-percent"><xsl:with-param name="value" select="round(100*$cacheHitsA div $hits)" /></xsl:call-template></xsl:variable>
+		<xsl:variable name="effF"><xsl:call-template name="get-percent"><xsl:with-param name="value" select="round(100*$cacheHitsF div $hits)" /></xsl:call-template></xsl:variable>
+		
+		<xsl:call-template name="node-attributes">
+			<xsl:with-param name="label" select="$label" />
+			<xsl:with-param name="id" select="$id" />
+			<xsl:with-param name="desc" select="$desc" />
+			<xsl:with-param name="leaf" select="$leaf" />
+			<xsl:with-param name="expanded" select="$expanded" />
+			<xsl:with-param name="icon" select="$icon" />
+			<xsl:with-param name="iconCls" select="$iconCls" />
+			<xsl:with-param name="cls" select="$cls" />
+			
+			<xsl:with-param name="cacheable" select="$cacheable" />
+			<xsl:with-param name="hits" select="$hits" />
+			<xsl:with-param name="hitsA" select="$hitsA" />
+			<xsl:with-param name="hitsF" select="$hitsF" />
+			<xsl:with-param name="hitsB" select="$hitsB" />
+			<xsl:with-param name="cacheHits" select="$cacheHits" />
+			<xsl:with-param name="cacheHitsA" select="$cacheHitsA" />
+			<xsl:with-param name="cacheHitsF" select="$cacheHitsF" />
+			<xsl:with-param name="eff" select="$eff" />
+			<xsl:with-param name="effA" select="$effA" />
+			<xsl:with-param name="effF" select="$effF" />
+		</xsl:call-template>
+	</xsl:template>
+	
+	<xsl:template name="get-percent">
+		<xsl:param name="value" />
+		<xsl:variable name="svalue" select="string(number($value))" />
+		<xsl:if test="$svalue != 'NaN' and $svalue != 'Infinity'"><xsl:value-of select="concat($value, ' %')" /></xsl:if>
+	</xsl:template>
+	
+    <xsl:template name="get-apacheHits-sum">
+    	<xsl:value-of select="sum(.//resource/entry[@type='apache']/apacheHits)" />
+    </xsl:template>
+    
+    <xsl:template name="get-apacheCachehits-sum">
+    	<xsl:value-of select="sum(.//resource/entry[@type='apache']/apacheCacheHits)" />
+    </xsl:template>
+	
+    <xsl:template name="get-frontHits-sum">
+    	<xsl:value-of select="sum(.//resource/entry[@type='apache' or @type='front']/*[local-name()='frontHits' or local-name()='hits'])" />
+    </xsl:template>
+    
+    <xsl:template name="get-frontCachehits-sum">
+    	<xsl:value-of select="sum(.//resource/entry[@type='apache' or @type='front']/*[local-name()='frontCacheHits1' or local-name()='frontCacheHits2' or local-name()='cacheHits1' or local-name()='cacheHits2'])" />
+    </xsl:template>
+    
+    <!-- Currently, only applicable to pages --> 
+    <xsl:template name="get-backHits-sum">
+		<xsl:choose>
+			<xsl:when test="@type = 'page'">
+				<xsl:value-of select="sum(.//resource[@type='page']/entry[@type='back']/hits)" />
+			</xsl:when>
+			<xsl:otherwise><xsl:text>N/A</xsl:text></xsl:otherwise>
+		</xsl:choose>
+    </xsl:template>
+    
+	<!-- moyenne du nombre de pages cacheables -->
+    <xsl:template name="get-cacheable-mean">
+    	<xsl:variable name="cacheables" select="count(.//resource[@type != 'folder' and @cacheable='true'])" />
+    	<xsl:variable name="total" select="count(.//resource[@type != 'folder'])" />
+    	<xsl:call-template name="get-percent"><xsl:with-param name="value" select="round($cacheables*100 div $total)" /></xsl:call-template>
+    </xsl:template>
+    
+	<!-- moyenne du nombre de pages cacheables ponderée par le nombre de hits -->
+    <xsl:template name="get-weighted-cacheable-mean">
+    	<!-- sum apacheCacheHits + frontHits to get the total hits for a resource. -->
+    	<xsl:variable name="cacheables" select="sum(.//resource[@type != 'folder' and @cacheable='true']/entry[@type='apache' or @type='front']/*[local-name()='apacheCacheHits' or local-name()='frontHits' or local-name()='hits'])" />
+    	<xsl:variable name="total" select="sum(.//resource[@type != 'folder']/entry[@type='apache' or @type='front']/*[local-name()='apacheCacheHits' or local-name()='frontHits' or local-name()='hits'])" />
+    	<xsl:call-template name="get-percent"><xsl:with-param name="value" select="round($cacheables*100 div $total)" /></xsl:call-template>
+    </xsl:template>
+    
+    <!-- moyenne du nombre de sous ressources cacheables (incluant la ressource courante) -->
+    <xsl:template name="get-cacheable-mean-page">
+    	<xsl:choose>
+    		<!-- cas où la page courante n'as pas de sous-ressources -->
+    		<xsl:when test="not(resource)"><xsl:value-of select="@cacheable" /></xsl:when>
+    		<xsl:otherwise>
+		    	<xsl:variable name="cacheables" select="count(.//resource[@type != 'folder' and @cacheable='true']) + count(self::resource[@type != 'folder' and @cacheable='true'])" />
+		    	<xsl:variable name="total" select="count(.//resource[@type != 'folder']) + count(self::resource[@type != 'folder'])" />
+		    	<xsl:call-template name="get-percent"><xsl:with-param name="value" select="round($cacheables*100 div $total)" /></xsl:call-template>
+    		</xsl:otherwise>
+    	</xsl:choose>
+    </xsl:template>
+    
+    <!-- moyenne du nombre de sous ressources cacheables (incluant la ressource courante) ponderée par le nombre de hits -->
+    <xsl:template name="get-weighted-cacheable-mean-page">
+    	<xsl:choose>
+    		<!-- cas où la page courante n'as pas de sous-ressources -->
+    		<xsl:when test="not(resource)"><xsl:value-of select="@cacheable" /></xsl:when>
+    		<xsl:otherwise>
+    			<!-- sum apacheCacheHits + frontHits to get the total hits for a resource. -->
+		    	<xsl:variable name="cacheables" select="sum(.//resource[@type != 'folder' and @cacheable='true']/entry[@type='apache' or @type='front']/*[local-name()='apacheCacheHits' or local-name()='frontHits' or local-name()='hits']) + sum(self::resource[@type != 'folder' and @cacheable='true']/entry[@type='apache' or @type='front']/*[local-name()='apacheCacheHits' or local-name()='frontHits' or local-name()='hits'])" />
+		    	<xsl:variable name="total" select="sum(.//resource[@type != 'folder']/entry[@type='apache' or @type='front']/*[local-name()='apacheCacheHits' or local-name()='frontHits' or local-name()='hits']) + sum(self::resource[@type != 'folder']/entry[@type='apache' or @type='front']/*[local-name()='apacheCacheHits' or local-name()='frontHits' or local-name()='hits'])" />
+		    	<xsl:call-template name="get-percent"><xsl:with-param name="value" select="round($cacheables*100 div $total)" /></xsl:call-template>
+    		</xsl:otherwise>
+    	</xsl:choose>
+    </xsl:template>
+    
+	<!-- moyenne du nombre de pages cacheables -->
+    <xsl:template name="get-cacheable-mean-total-page">
+    	<xsl:variable name="cacheables" select="count(.//resource[@type = 'page' and @cacheable='true'])" />
+    	<xsl:variable name="total" select="count(.//resource[@type = 'page'])" />
+    	<xsl:call-template name="get-percent"><xsl:with-param name="value" select="round($cacheables*100 div $total)" /></xsl:call-template>
+    </xsl:template>
+    
+	<!-- moyenne du nombre de pages cacheables ponderée par le nombre de hits -->
+    <xsl:template name="get-weighted-cacheable-mean-total-page">
+    	<!-- sum apacheCacheHits + frontHits to get the total hits for a resource. -->
+    	<xsl:variable name="cacheables" select="sum(.//resource[@type = 'page' and @cacheable='true']/entry[@type='apache' or @type='front']/*[local-name()='apacheCacheHits' or local-name()='frontHits' or local-name()='hits'])" />
+    	<xsl:variable name="total" select="sum(.//resource[@type = 'page']/entry[@type='apache' or @type='front']/*[local-name()='apacheCacheHits' or local-name()='frontHits' or local-name()='hits'])" />
+    	<xsl:call-template name="get-percent"><xsl:with-param name="value" select="round($cacheables*100 div $total)" /></xsl:call-template>
+    </xsl:template>
+    
+    <xsl:template name="get-apacheHits-sum-total-page">
+    	<xsl:value-of select="sum(.//resource[@type='page']/entry[@type='apache']/apacheHits)" />
+    </xsl:template>
+    
+    <xsl:template name="get-apacheCachehits-sum-total-page">
+    	<xsl:value-of select="sum(.//resource[@type='page']/entry[@type='apache']/apacheCacheHits)" />
+    </xsl:template>
+	
+    <xsl:template name="get-frontHits-sum-total-page">
+    	<xsl:value-of select="sum(.//resource[@type='page']/entry[@type='apache' or @type='front']/*[local-name()='frontHits' or local-name()='hits'])" />
+    </xsl:template>
+    
+    <xsl:template name="get-frontCachehits-sum-total-page">
+    	<xsl:value-of select="sum(.//resource[@type='page']/entry[@type='apache' or @type='front']/*[local-name()='frontCacheHits1' or local-name()='frontCacheHits2' or local-name()='cacheHits1' or local-name()='cacheHits2'])" />
+    </xsl:template>
+    
+    <xsl:template name="get-backHits-sum-total-page">
+    	<xsl:value-of select="sum(.//resource[@type='page']/entry[@type='back']/hits)" />
+    </xsl:template>
+    
+    <xsl:template name="get-entry-icon">
+    	<xsl:choose>
+    		<xsl:when test="@type = 'folder'">
+    			<xsl:value-of select="concat($contextPath, '/plugins/', $pluginName, '/resources/img/administrator/stats/resources_16.png')" />
+    		</xsl:when>
+    		<xsl:when test="@type = 'page'">
+    			<xsl:value-of select="concat($contextPath, '/plugins/', $pluginName, '/resources/img/administrator/stats/content_16.png')" />
+    		</xsl:when>
+    	</xsl:choose>
+    </xsl:template>
+    
+    <xsl:template name="get-entry-iconCls">
+    		<xsl:if test="@type = 'asset'">
+    			<xsl:value-of select="'x-tree-node-inline-icon'" />
+    		</xsl:if>
+    </xsl:template>
+</xsl:stylesheet>
Index: main/plugin-web/pages/administrator/sites/cache-statistics-servers.xsl
===================================================================
--- main/plugin-web/pages/administrator/sites/cache-statistics-servers.xsl	(revision 0)
+++ main/plugin-web/pages/administrator/sites/cache-statistics-servers.xsl	(revision 0)
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Copyright 2012 Anyware Services
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+   -->
+<xsl:stylesheet version="1.0" 
+                xmlns:i18n="http://apache.org/cocoon/i18n/2.1" 
+                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:ametys="org.ametys.web.transformation.xslt.AmetysXSLTHelper"
+                exclude-result-prefixes="ametys">
+    
+    <xsl:param name="contextPath"/>
+    <xsl:param name="pluginName"/>
+    
+    <xsl:template match="/">
+        <html>
+            <head>
+                <title>
+                    <i18n:translate>
+                        <i18n:text i18n:key="PLUGINS_WEB_ADMINISTRATOR_CACHE_SERVERS_STATISTICS_TITLE"/>
+                        <i18n:param name="name"><xsl:value-of select="site/@name"/></i18n:param>
+                    </i18n:translate>
+                </title>
+				<link rel="stylesheet" href="{ametys:pluginResourceURL('extjs', 'ux/js/treegrid/treegrid.css')}" type="text/css"/>
+				<style>
+					.custom-hd-row { background-image: url("<xsl:value-of select="ametys:pluginResourceURL('extjs', 'images/default/grid/grid3-hrow.gif')" />"); }
+					/* Fixing chrome custom header issue */
+					td.x-treegrid-hd-hidden { border: 0; }
+					td.x-treegrid-hd-hidden div.x-treegrid-hd-inner { display: none; }
+				</style>
+            </head>
+            
+            <script>
+                <script type="text/javascript" src="{ametys:pluginResourceURL('extjs', 'ux/js/treegrid/TreeGrid.js')}"></script>
+                <script type="text/javascript" src="{ametys:pluginResourceURL('extjs', 'ux/js/treegrid/TreeGridColumnResizer.js')}"></script>
+                <script type="text/javascript" src="{ametys:pluginResourceURL('extjs', 'ux/js/treegrid/TreeGridColumns.js')}"></script>
+                <script type="text/javascript" src="{ametys:pluginResourceURL('extjs', 'ux/js/treegrid/TreeGridLoader.js')}"></script>
+                <script type="text/javascript" src="{ametys:pluginResourceURL('extjs', 'ux/js/treegrid/TreeGridNodeUI.js')}"></script>
+                <script type="text/javascript" src="{ametys:pluginResourceURL('extjs', 'ux/js/treegrid/TreeGridSorter.js')}"></script>
+                
+				<script type="text/javascript" src="{ametys:pluginResourceURL($pluginName, 'js/org/ametys/web/administration/CacheStatistics.i18n.js')}"></script>
+				<script type="text/javascript" src="{ametys:pluginResourceURL($pluginName, 'js/org/ametys/web/administration/CacheStatisticsServers.i18n.js')}"></script>
+				
+                <script type="text/javascript">
+					org.ametys.web.administration.CacheStatisticsServers.init("<xsl:value-of select="$pluginName"/>", "<xsl:value-of select="site/@name"/>", "<xsl:value-of select="site/@path"/>");
+					
+                    org.ametys.runtime.administrator.Panel.createPanel = function() 
+                    {
+						return new Ext.Panel({
+							region: 'center',
+							
+							baseCls: 'transparent-panel',
+							border: false,
+							layout: 'border',
+							autoScroll: true,
+							
+							items : [org.ametys.web.administration.CacheStatisticsServers._centerPanel,
+									 org.ametys.web.administration.CacheStatisticsServers._rightPanel
+							]
+						});
+                    }
+                </script>
+            </script>
+            
+            <body>
+            </body>
+        </html>
+    </xsl:template>
+    
+</xsl:stylesheet>
Index: main/plugin-web/sitemap-back.xmap
===================================================================
--- main/plugin-web/sitemap-back.xmap	(revision 20673)
+++ main/plugin-web/sitemap-back.xmap	(working copy)
@@ -28,6 +28,8 @@
             <map:generator name="convert-pagepath-to-id" src="org.ametys.web.repository.page.generators.ConvertPagePathToIdGenerator" label="xml" pool-grow="2" pool-max="16" pool-min="0"/>
             <map:generator name="child-pages" src="org.ametys.web.repository.page.generators.ChildrenPagesIdGenerator" label="xml" pool-grow="2" pool-max="16" pool-min="0"/>
             <map:generator name="global-statistics" src="org.ametys.web.site.GlobalStatisticsGenerator" logger="org.ametys.web.site.GlobalStatisticsGenerator"/>
+			<map:generator name="cache-stats-back" src="org.ametys.web.cache.monitoring.ui.PageElementCacheStatsGenerator" logger="org.ametys.web.cachemonitoring.generators.PageElementCacheStatsGenerator" label="xml"/>
+			<map:generator name="cache-stats-servers" src="org.ametys.web.cache.monitoring.ui.ServersCacheStatsGenerator" logger="org.ametys.web.cachemonitoring.generators.ServersCacheStatsGenerator" label="xml"/>
             <map:generator name="site-statistics" src="org.ametys.web.site.SiteStatisticsGenerator" logger="org.ametys.web.site.SiteStatisticsGenerator" label="xml" pool-grow="2" pool-max="16" pool-min="0"/>
             <map:generator name="site-parameters" src="org.ametys.web.site.SiteParametersGenerator" logger="org.ametys.web.site.SiteParametersGenerator" label="xml"/>
 			<map:generator name="page-info" src="org.ametys.web.repository.page.generators.PageInformationGenerator" label="xml" pool-grow="2" pool-max="16" pool-min="0"/>
@@ -300,6 +302,67 @@
                 <map:serialize type="xml"/>
 			</map:match>
 			
+			<map:match pattern="administrator/sites/*/cache-statistics-back.html">
+				<map:generate type="site-configuration" label="xml">
+                    <map:parameter name="name" value="{1}"/>
+                </map:generate>
+                <map:transform src="pages/administrator/sites/cache-statistics-back.xsl">
+                    <map:parameter name="contextPath" value="{request:contextPath}"/>
+                    <map:parameter name="pluginName" value="{request-attr:pluginName}"/>
+                </map:transform>
+                <map:transform type="i18n">
+                    <map:parameter name="locale" value="{locale:locale}"/>
+                    <map:parameter name="plugin" value="{request-attr:pluginName}"/>
+                </map:transform>
+                <map:serialize type="xml"/>
+			</map:match>
+			
+            <map:match pattern="administrator/sites/*/cache-statistics-back-tree.xml">
+                <map:generate type="cache-stats-back" label="xml">
+                	<map:parameter name="siteName" value="{1}"/>
+                	<map:parameter name="contexts" value="{request-param:contexts}"/>
+                </map:generate>
+                <map:transform src="pages/administrator/sites/cache-statistics-back-tree.xsl">
+                    <map:parameter name="contextPath" value="{request:contextPath}"/>
+                    <map:parameter name="pluginName" value="{request-attr:pluginName}"/>
+                </map:transform>
+                <map:transform type="i18n">
+                    <map:parameter name="locale" value="{locale:locale}"/>
+                    <map:parameter name="plugin" value="{request-attr:pluginName}"/>
+                </map:transform>
+                <map:serialize type="xml"/>
+            </map:match>
+            
+			<map:match pattern="administrator/sites/*/cache-statistics-servers.html">
+				<map:generate type="site-configuration" label="xml">
+                    <map:parameter name="name" value="{1}"/>
+                </map:generate>
+                <map:transform src="pages/administrator/sites/cache-statistics-servers.xsl">
+                    <map:parameter name="contextPath" value="{request:contextPath}"/>
+                    <map:parameter name="pluginName" value="{request-attr:pluginName}"/>
+                </map:transform>
+                <map:transform type="i18n">
+                    <map:parameter name="locale" value="{locale:locale}"/>
+                    <map:parameter name="plugin" value="{request-attr:pluginName}"/>
+                </map:transform>
+                <map:serialize type="xml"/>
+			</map:match>
+			
+            <map:match pattern="administrator/sites/*/cache-statistics-servers-tree.xml">
+                <map:generate type="cache-stats-servers">
+                	<map:parameter name="siteName" value="{1}"/>
+                </map:generate>
+                <map:transform src="pages/administrator/sites/cache-statistics-servers-tree.xsl">
+                    <map:parameter name="contextPath" value="{request:contextPath}"/>
+                    <map:parameter name="pluginName" value="{request-attr:pluginName}"/>
+                </map:transform>
+                <map:transform type="i18n">
+                    <map:parameter name="locale" value="{locale:locale}"/>
+                    <map:parameter name="plugin" value="{request-attr:pluginName}"/>
+                </map:transform>
+                <map:serialize type="xml"/>
+            </map:match>
+			
 			<map:match pattern="administrator/skins/view.html">
 				<map:generate type="admin-skin-actions" label="content"/>
 				<map:transform type="i18n">
Index: main/workspace-web/src/org/ametys/web/repository/IsPageCacheableAction.java
===================================================================
--- main/workspace-web/src/org/ametys/web/repository/IsPageCacheableAction.java	(revision 20673)
+++ main/workspace-web/src/org/ametys/web/repository/IsPageCacheableAction.java	(working copy)
@@ -32,14 +32,15 @@
 import org.apache.cocoon.environment.SourceResolver;
 
 import org.ametys.plugins.repository.AmetysObjectIterable;
+import org.ametys.web.cache.monitoring.process.access.impl.PageResourceAccess;
 import org.ametys.web.inputdata.InputData;
 import org.ametys.web.inputdata.InputDataExtensionPoint;
 import org.ametys.web.pageaccess.PageAccessInfo;
 import org.ametys.web.pageaccess.PageAccessManager;
 import org.ametys.web.repository.page.Page;
+import org.ametys.web.repository.page.Page.PageType;
 import org.ametys.web.repository.page.Zone;
 import org.ametys.web.repository.page.ZoneItem;
-import org.ametys.web.repository.page.Page.PageType;
 import org.ametys.web.repository.page.ZoneItem.ZoneType;
 import org.ametys.web.service.Service;
 import org.ametys.web.service.ServiceExtensionPoint;
@@ -66,15 +67,21 @@
     public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
     {
         Request request = ObjectModelHelper.getRequest(objectModel);
-
         Page page = (Page) request.getAttribute(Page.class.getName());
         
-        if (_isCacheable(page))
+        boolean isCacheable = _isCacheable(page);
+        if (isCacheable)
         {
             Response response = ObjectModelHelper.getResponse(objectModel);
             response.addHeader("X-Ametys-Cacheable", "true");
         }
-
+        
+        // Page access monitoring.
+        String uuid = request.getHeader("X-Ametys-FO-UUID");
+        PageResourceAccess pageAccess = new PageResourceAccess(uuid, page.getId(), request.getRequestURI());
+        pageAccess.setCacheable(isCacheable);
+        request.setAttribute("PAGE_ACCESS", pageAccess);
+        
         return EMPTY_MAP;
     }
     
Index: main/workspace-web/src/org/ametys/web/repository/PageGenerator.java
===================================================================
--- main/workspace-web/src/org/ametys/web/repository/PageGenerator.java	(revision 20673)
+++ main/workspace-web/src/org/ametys/web/repository/PageGenerator.java	(working copy)
@@ -51,6 +51,10 @@
 import org.ametys.runtime.authentication.AccessDeniedException;
 import org.ametys.runtime.authentication.AuthorizationRequiredException;
 import org.ametys.runtime.util.IgnoreRootHandler;
+import org.ametys.web.cache.monitoring.process.access.ResourceAccessComponent;
+import org.ametys.web.cache.monitoring.process.access.impl.PageElementResourceAccess;
+import org.ametys.web.cache.monitoring.process.access.impl.PageElementResourceAccess.PageElementType;
+import org.ametys.web.cache.monitoring.process.access.impl.PageResourceAccess;
 import org.ametys.web.cache.pageelement.PageElementCache;
 import org.ametys.web.renderingcontext.RenderingContext;
 import org.ametys.web.renderingcontext.RenderingContextHandler;
@@ -105,11 +109,17 @@
     /** The service assignment handler. */
     private ServicesAssignmentHandler _serviceAssignmentHandler;
     
+    /** The resource access monitoring component */
+    private ResourceAccessComponent _resourceAccessComponent;
+    
+    /** The monitored resource access */
+    private PageResourceAccess _pageAccess;
+    
     private int _zoneItemsInCache;
     private int _zoneItemsSaxed;
     private int _zonesSaxed;
     
-
+    
     @Override
     public void service(ServiceManager serviceManager) throws ServiceException
     {
@@ -124,6 +134,7 @@
         _renderingContextHandler = (RenderingContextHandler) serviceManager.lookup(RenderingContextHandler.ROLE);
         _cTypeAssignmentHandler = (ContentTypesAssignmentHandler) serviceManager.lookup(ContentTypesAssignmentHandler.ROLE);
         _serviceAssignmentHandler = (ServicesAssignmentHandler) serviceManager.lookup(ServicesAssignmentHandler.ROLE);
+        _resourceAccessComponent = (ResourceAccessComponent) serviceManager.lookup(ResourceAccessComponent.ROLE);
     }
     
     @Override
@@ -131,12 +142,12 @@
     {
         long t0 = System.currentTimeMillis();
         
+        Request request = ObjectModelHelper.getRequest(objectModel);
+        
         _zoneItemsInCache = 0;
         _zoneItemsSaxed = 0;
         _zonesSaxed = 0;
-
-        Request request = ObjectModelHelper.getRequest(objectModel);
-
+        
         Page page = (Page) request.getAttribute(Page.class.getName());
         String title = page.getTitle();
         
@@ -149,13 +160,19 @@
             throw new IllegalStateException("Cannot invoke the PageGenerator on a Page without a PageContent");
         }
         
+        // Monitor the access to this page.
+        _pageAccess = (PageResourceAccess) request.getAttribute("PAGE_ACCESS");
+        _pageAccess.setRenderingContext(renderingContext);
+        _pageAccess.setWorkspaceJCR(workspace);
+        _resourceAccessComponent.addAccessRecord(_pageAccess);
+        
         contentHandler.startDocument();
         AttributesImpl attrs = new AttributesImpl();
         attrs.addCDATAAttribute("title", title);
         attrs.addCDATAAttribute("long-title", page.getLongTitle());
         attrs.addCDATAAttribute("id", page.getId());
         XMLUtils.startElement(contentHandler, "page", attrs);
-
+        
         try
         {
             XMLUtils.startElement(contentHandler, "metadata");
@@ -187,16 +204,17 @@
         }
         catch (AmetysRepositoryException e)
         {
+            _pageAccess = null;
             throw new ProcessingException("Unable to SAX page metadata", e);
         }
-
-        AttributesImpl pcattrs = new AttributesImpl(); 
+        
+        AttributesImpl pcattrs = new AttributesImpl();
         pcattrs.addCDATAAttribute("modifiable", Boolean.toString(page instanceof ModifiablePage));
         pcattrs.addCDATAAttribute("moveable", Boolean.toString(page instanceof MoveablePage));
         XMLUtils.startElement(contentHandler, "pageContents", pcattrs);
         
         long t1 = System.currentTimeMillis();
-
+        
         try
         {
             // Iterate on existing zones
@@ -204,7 +222,7 @@
             {
                 String zoneName = zone.getName();
                 AmetysObjectIterable<? extends ZoneItem> zoneItems = zone.getZoneItems();
-
+                
                 _saxZone(page, zoneName, zoneItems, workspace, siteName, renderingContext);
             }
             
@@ -223,6 +241,7 @@
         }
         catch (AmetysRepositoryException ex)
         {
+            _pageAccess = null;
             throw new ProcessingException("Unable to get Content", ex);
         }
         
@@ -239,8 +258,10 @@
         XMLUtils.endElement(contentHandler, "pageContents");
         XMLUtils.endElement(contentHandler, "page");
         contentHandler.endDocument();
+        
+        _pageAccess = null;
     }
-
+    
     /**
      * Sax a zone
      * @param page The page
@@ -259,7 +280,7 @@
         
         AttributesImpl zoneAttrs = new AttributesImpl();
         zoneAttrs.addCDATAAttribute("name", zoneName);
-
+        
         if (localZoneItems == null || !localZoneItems.hasNext())
         {
             // zone is empty => try to inherit
@@ -271,7 +292,7 @@
                 localZoneItems = parentPageZone.getZoneItems();
             }
         }
-
+        
         Request request = ObjectModelHelper.getRequest(objectModel);
         request.setAttribute(Zone.class.getName(), zoneName);
         
@@ -281,10 +302,10 @@
         _saxAvailableServices(page, zoneName);
         
         _saxZoneItems(page, localZoneItems, workspace, site, renderingContext);
-
+        
         XMLUtils.endElement(contentHandler, "zone");
         request.setAttribute(Zone.class.getName(), null);
-
+        
     }
     
     /**
@@ -331,7 +352,7 @@
     
     /**
      * Sax zone items
-     * @param page 
+     * @param page
      * @param zoneItems The zone items to sax
      * @throws SAXException
      * @throws MalformedURLException
@@ -355,18 +376,23 @@
             
             String id = zoneItem.getId();
             ZoneType type = zoneItem.getType();
-
+            
             request.setAttribute(ZoneItem.class.getName(), zoneItem);
             
             AttributesImpl zoneItemAttrs = new AttributesImpl();
             zoneItemAttrs.addCDATAAttribute("id", id);
             
+            PageElementResourceAccess zoneAccess = _pageAccess.createPageElementAccess(id, PageElementType.fromZoneItemType(type));
+            
             // try to get content from cache
             SaxBuffer cachedContent = _zoneItemCache.getPageElement(workspace, site, _getType(zoneItem), id, page.getId(), renderingContext);
-
+            
             if (cachedContent != null)
             {
                 _zoneItemsInCache++;
+                zoneAccess.setCacheable(true);
+                zoneAccess.setCacheHit(true);
+                
                 cachedContent.toSAX(contentHandler);
             }
             else
@@ -381,14 +407,17 @@
                 {
                     String serviceId = zoneItem.getServiceId();
                     Service service = _serviceExtPt.getExtension(serviceId);
-
+                    
                     if (service != null)
-                    {   
+                    {
                         isCacheable = service.isCacheable(zoneItem);
                     }
                     // if service is null, an exception will be thrown later
                 }
                 
+                zoneAccess.setCacheable(isCacheable);
+                zoneAccess.setCacheHit(false);
+                
                 SaxBuffer buffer = null;
                 ContentHandler handler; // the actual ContentHandler, either the real one, or a buffer
                 if (isCacheable)
@@ -402,10 +431,10 @@
                 }
                 
                 XMLUtils.startElement(handler, "zoneItem", zoneItemAttrs);
-
+                
                 XMLUtils.startElement(handler, "information");
                 XMLUtils.createElement(handler, "type", type.toString());
-
+                
                 Source src = null;
                 Exception ex = null;
                 if (type == ZoneType.CONTENT)
@@ -414,7 +443,7 @@
                     {
                         Content content = zoneItem.getContent();
                         String metadataSetName = StringUtils.defaultString(zoneItem.getMetadataSetName(), "main");
-
+                        
                         XMLUtils.createElement(handler, "contentId", content.getId());
                         XMLUtils.createElement(handler, "contentName", content.getName());
                         XMLUtils.createElement(handler, "metadataSetName", metadataSetName);
@@ -462,7 +491,7 @@
                 {
                     String serviceId = zoneItem.getServiceId();
                     Service service = _serviceExtPt.getExtension(serviceId);
-       
+                    
                     if (service == null)
                     {
                         ex =  new ProcessingException("Unable to get service for name '" + serviceId + "'");
@@ -472,20 +501,20 @@
                         AttributesImpl serviceAttrs = new AttributesImpl();
                         serviceAttrs.addCDATAAttribute("id", service.getId());
                         XMLUtils.startElement(handler, "type-information", serviceAttrs);
-                    
+                        
                         service.getLabel().toSAX(handler, "label");
                         service.getDescription().toSAX(handler, "description");
                         XMLUtils.createElement(handler, "smallIcon", service.getSmallIcon());
                         XMLUtils.createElement(handler, "mediumIcon", service.getMediumIcon());
-                    
+                        
                         XMLUtils.endElement(handler, "type-information");
-        
+                        
                         src = resolver.resolveURI(service.getURL(), null, _getParameters(service, zoneItem));
                     }
                 }
-
+                
                 XMLUtils.endElement(handler, "information");
-
+                
                 if (src == null)
                 {
                     getLogger().error("Unable to display zone item", ex);
@@ -515,7 +544,7 @@
                         resolver.release(src);
                     }
                 }
-
+                
                 XMLUtils.endElement(handler, "zoneItem");
                 
                 // finally store the buffered data in the cache and SAX it to the pipeline
@@ -526,6 +555,9 @@
                 }
             }
             
+            // Monitor the access to this zone item.
+            _resourceAccessComponent.addAccessRecord(zoneAccess);
+            
             // Empty content request attributes
             request.setAttribute(Content.class.getName(), null);
             // Empty zone item request attribute
@@ -619,7 +651,7 @@
             getLogger().error("The page '" + childPage.getId() + "' cannot inherit a zone '" + zoneName + "' of template '" + templateName + "' in skin '" + skinId + "' as asked for page '" + page.getId() + "' in site '" + site.getName() + "'", e);
             return null;
         }
-
+        
         // This zone is not defined for the template
         if (zoneDef == null)
         {
@@ -632,7 +664,7 @@
         {
             return null;
         }
-
+        
         // Get the parent page (that is a container page)
         Page parentPage = page;
         do
@@ -656,8 +688,8 @@
             // No inheritance for this template
             return null;
         }
-    
-        // Finally we will inherit from the parentPage and the zone inheritanceSrc 
+        
+        // Finally we will inherit from the parentPage and the zone inheritanceSrc
         return _inherit(childPage, parentPage, inheritanceSrc);
     }
     
@@ -689,7 +721,7 @@
     {
         CompositeMetadata serviceParams = zoneItem.getServiceParameters();
         Map<String, Object> params = new HashMap<String, Object>();
-
+        
         for (ServiceParameterOrRepeater serviceParameter : service.getParameters().values())
         {
             if (serviceParameter instanceof ServiceParameter)
@@ -716,7 +748,7 @@
         
         return params;
     }
-
+    
     /**
      * Get the values of a repeater in a service instance.
      * @param repeater the repeater definition.
Index: main/workspace-web/src/org/ametys/web/inputdata/InputDataGenerator.java
===================================================================
--- main/workspace-web/src/org/ametys/web/inputdata/InputDataGenerator.java	(revision 20673)
+++ main/workspace-web/src/org/ametys/web/inputdata/InputDataGenerator.java	(working copy)
@@ -27,6 +27,10 @@
 import org.xml.sax.SAXException;
 
 import org.ametys.plugins.repository.provider.WorkspaceSelector;
+import org.ametys.web.cache.monitoring.process.access.ResourceAccessComponent;
+import org.ametys.web.cache.monitoring.process.access.impl.PageElementResourceAccess;
+import org.ametys.web.cache.monitoring.process.access.impl.PageElementResourceAccess.PageElementType;
+import org.ametys.web.cache.monitoring.process.access.impl.PageResourceAccess;
 import org.ametys.web.cache.pageelement.PageElementCache;
 import org.ametys.web.renderingcontext.RenderingContext;
 import org.ametys.web.renderingcontext.RenderingContextHandler;
@@ -45,6 +49,9 @@
     private RenderingContextHandler _renderingconContextHandler;
     private SiteManager _sitesManager;
     
+    /** The resource access monitoring component */
+    private ResourceAccessComponent _resourceAccessComponent;
+    
     @Override
     public void service(ServiceManager sManager) throws ServiceException
     {
@@ -54,8 +61,9 @@
         _renderingconContextHandler = (RenderingContextHandler) sManager.lookup(RenderingContextHandler.ROLE);
         _workspaceSelector = (WorkspaceSelector) sManager.lookup(WorkspaceSelector.ROLE);
         _sitesManager = (SiteManager) sManager.lookup(SiteManager.ROLE);
+        _resourceAccessComponent = (ResourceAccessComponent) sManager.lookup(ResourceAccessComponent.ROLE);
     }
-
+    
     @Override
     public void generate() throws SAXException, ProcessingException
     {
@@ -66,7 +74,7 @@
         String siteName;
         Site site;
         String pageId = null;
-
+        
         Page page = (Page) request.getAttribute(Page.class.getName());
         if (page != null)
         {
@@ -83,6 +91,9 @@
         String workspace = _workspaceSelector.getWorkspace();
         RenderingContext renderingContext = _renderingconContextHandler.getRenderingContext();
         
+        // Access monitoring
+        PageResourceAccess pageAccess = (PageResourceAccess) request.getAttribute("PAGE_ACCESS");
+        
         contentHandler.startDocument();
         XMLUtils.startElement(contentHandler, "inputData");
         
@@ -90,17 +101,25 @@
         {
             InputData inputData = _inputDataExtensionPoint.getExtension(id);
             
+            PageElementResourceAccess inputDataAccess = pageAccess.createPageElementAccess(id, PageElementType.INPUTDATA);
+            
             // lookup cached content
             SaxBuffer cachedContent = _inputDataCache.getPageElement(workspace, siteName, id, pageId, renderingContext);
             
             if (cachedContent != null)
             {
+                inputDataAccess.setCacheable(true);
+                inputDataAccess.setCacheHit(true);
+                
                 cachedContent.toSAX(contentHandler);
             }
             else
             {
                 boolean isCacheable = inputData.isCacheable(site, page);
                 
+                inputDataAccess.setCacheable(isCacheable);
+                inputDataAccess.setCacheHit(false);
+                
                 SaxBuffer buffer = null;
                 ContentHandler handler; // the actual ContentHandler, either the real one, or a buffer
                 if (isCacheable)
@@ -122,6 +141,9 @@
                     buffer.toSAX(contentHandler);
                 }
             }
+            
+            // Monitor the access to this zone item.
+            _resourceAccessComponent.addAccessRecord(inputDataAccess);
         }
         
         XMLUtils.endElement(contentHandler, "inputData");