diff --git a/commons-exo-extension/src/main/webapp/WEB-INF/conf/commons-exo/cache-configuration.xml b/commons-exo-extension/src/main/webapp/WEB-INF/conf/commons-exo/cache-configuration.xml
new file mode 100644
index 00000000..44590f11
--- /dev/null
+++ b/commons-exo-extension/src/main/webapp/WEB-INF/conf/commons-exo/cache-configuration.xml
@@ -0,0 +1,1354 @@
+
+
+
+
+
+ org.infinispan.transaction.lookup.TransactionManagerLookup
+ org.exoplatform.services.transaction.infinispan.JBossStandaloneJTAManagerLookup
+
+
+
+ org.exoplatform.services.transaction.TransactionService
+ org.exoplatform.services.transaction.infinispan.JBossTransactionsService
+
+
+ timeout
+ ${gatein.jcr.transaction.timeout:420}
+
+
+
+
+
+ org.exoplatform.services.cache.ExoCacheFactory
+ org.exoplatform.services.cache.impl.infinispan.ExoCacheFactoryImpl
+
+
+ cache.config.template
+ ${exo.cache.config.template:jar:/conf/cache/infinispan/local/cache-config.xml}
+
+
+ cache.config.template
+ ${exo.cache.config.template:jar:/conf/cache/infinispan/cluster/cache-config.xml}
+
+
+ cache.async.config.template
+ ${exo.cache.async.config.template:jar:/conf/cache/infinispan/cluster/cache-async-config.xml}
+
+
+
+
+
+ org.exoplatform.services.cache.ExoCacheFactory
+
+ addCreator
+ addCreator
+ org.exoplatform.services.cache.impl.infinispan.ExoCacheCreatorPlugin
+ add Exo Cache Creator
+
+
+ Generic-insp-cacheCreator
+ The generic cache creator
+
+
+
+
+ NONE
+
+
+ LRU
+
+
+ UNORDERED
+
+
+ MANUAL
+
+
+ LIRS
+
+
+
+
+ ${exo.cache.eviction.defaultStrategy:LIRS}
+
+
+ ${exo.cache.expiration.defaultMaxIdle:-1}
+
+
+ ${exo.cache.expiration.defaultWakeUpInterval:5000}
+
+
+
+
+
+
+
+
+ org.exoplatform.services.cache.CacheService
+
+ addExoCacheConfig
+ addExoCacheConfig
+ org.exoplatform.services.cache.ExoCacheConfigPlugin
+ Configures the cache for analytics queue which must remain a local cache
+
+
+ analytics.queue
+
+
+
+ analytics.queue
+
+
+ ${analytics.queue.MaxNodes:2000}
+
+
+ ${analytics.queue.TimeToLive:-1}
+
+
+
+
+
+ commons.WebNotificationCache
+ The Cache configuration for the Web Notification Cache
+
+
+ commons.WebNotificationCache
+
+
+ ${exo.cache.commons.WebNotificationCache.strategy:LIRS}
+
+
+ ${exo.cache.commons.WebNotificationCache.TimeToLive:86400}
+
+
+ ${exo.cache.commons.WebNotificationCache.MaxNodes:100000}
+
+
+ ${exo.cache.commons.WebNotificationCache.cacheMode:replication}
+
+
+
+
+
+ commons.WebNotificationsCache
+ The Cache configuration for the Web Notification List Cache
+
+
+ commons.WebNotificationsCache
+
+
+ ${exo.cache.commons.WebNotificationsCache.strategy:LIRS}
+
+
+ ${exo.cache.commons.WebNotificationsCache.TimeToLive:86400}
+
+
+ ${exo.cache.commons.WebNotificationsCache.MaxNodes:1000}
+
+
+ ${exo.cache.commons.WebNotificationsCache.cacheMode:replication}
+
+
+
+
+
+ commons.WebNotificationCountCache
+ The Cache configuration for the Web Notification Count Cache
+
+
+ commons.WebNotificationCountCache
+
+
+ ${exo.cache.commons.WebNotificationCountCache.strategy:LIRS}
+
+
+ ${exo.cache.commons.WebNotificationCountCache.TimeToLive:86400}
+
+
+ ${exo.cache.commons.WebNotificationCountCache.MaxNodes:1000}
+
+
+ ${exo.cache.commons.WebNotificationCountCache.cacheMode:replication}
+
+
+
+
+
+ commons.UserSettingService
+ The Cache configuration for the UserSettingService
+
+
+ commons.UserSettingService
+
+
+ ${exo.cache.commons.UserSettingService.strategy:LIRS}
+
+
+ ${exo.cache.commons.UserSettingService.MaxNodes:500}
+
+
+ ${exo.cache.commons.UserSettingService.TimeToLive:86400}
+
+
+ ${exo.cache.commons.UserSettingService.cacheMode:asyncInvalidation}
+
+
+
+
+
+ commons.UserStateService
+ The Cache configuration for the UserStateService
+
+
+ commons.UserStateService
+
+
+ ${exo.cache.commons.UserStateService.strategy:LIRS}
+
+
+ ${exo.cache.commons.UserStateService.MaxNodes:1000}
+
+
+ ${exo.cache.commons.UserStateService.TimeToLive:86400}
+
+
+ ${exo.cache.commons.UserStateService.cacheMode:replication}
+
+
+
+
+ gamification.domain
+
+
+ gamification.domain
+
+
+ ${exo.cache.gamification.domain.MaxNodes:1000}
+
+
+ ${exo.cache.gamification.domain.TimeToLive:-1}
+
+
+
+
+ gamification.rule
+
+
+ gamification.rule
+
+
+ ${exo.cache.gamification.rule.MaxNodes:2000}
+
+
+ ${exo.cache.gamification.rule.TimeToLive:-1}
+
+
+
+
+ gamification.realization
+
+
+ gamification.realization
+
+
+ ${exo.cache.gamification.realization.MaxNodes:5000}
+
+
+ ${exo.cache.gamification.realization.TimeToLive:-1}
+
+
+
+
+ wiki.PageRenderingCache
+ The wiki markup cache configuration
+
+
+ wiki.PageRenderingCache
+
+
+ ${exo.cache.wiki.PageRenderingCache.strategy:LIRS}
+
+
+ ${exo.cache.wiki.PageRenderingCache.MaxNodes:1000}
+
+
+ ${exo.cache.wiki.PageRenderingCache.TimeToLive:86400}
+
+
+ ${exo.cache.wiki.PageRenderingCache.cacheMode:replication}
+
+
+
+
+ wiki.PageAttachmentCache
+ The Cache configuration for wiki page attachment count
+
+
+ wiki.PageAttachmentCache
+
+
+ ${exo.cache.wiki.PageAttachmentCache.strategy:LIRS}
+
+
+ ${exo.cache.wiki.PageAttachmentCache.MaxNodes:1000}
+
+
+ ${exo.cache.wiki.PageAttachmentCache.TimeToLive:86400}
+
+
+ ${exo.cache.wiki.PageAttachmentCache.cacheMode:replication}
+
+
+
+
+ perkstore.product
+
+
+ perkstore.product
+
+
+ ${exo.cache.perkstore.product.MaxNodes:1000}
+
+
+ ${exo.cache.perkstore.product.TimeToLive:-1}
+
+
+
+
+ perkstore.order
+
+
+ perkstore.order
+
+
+ ${exo.cache.perkstore.order.MaxNodes:2000}
+
+
+ ${exo.cache.perkstore.order.TimeToLive:-1}
+
+
+
+
+ portal.User
+ Exo Cache cluster configuration for IDM User entity
+
+
+ portal.User
+
+
+ ${exo.cache.portal.user.strategy:LIRS}
+
+
+ ${exo.cache.portal.user.MaxNodes:5000}
+
+
+ ${exo.cache.portal.user.TimeToLive:3600}
+
+
+ ${exo.cache.portal.user.cacheMode:replication}
+
+
+
+
+ portal.Profile
+ Exo Cache cluster configuration for IDM User Profile entity
+
+
+ portal.Profile
+
+
+ ${exo.cache.portal.profile.strategy:LIRS}
+
+
+ ${exo.cache.portal.profile.MaxNodes:5000}
+
+
+ ${exo.cache.portal.profile.TimeToLive:3600}
+
+
+ ${exo.cache.portal.profile.cacheMode:replication}
+
+
+
+
+ portal.Membership
+ Exo Cache cluster configuration for IDM Membership entity
+
+
+ portal.Membership
+
+
+ ${exo.cache.portal.membership:LIRS}
+
+
+ ${exo.cache.portal.membership.MaxNodes:5000}
+
+
+ ${exo.cache.portal.membership.TimeToLive:86400}
+
+
+ ${exo.cache.portal.membership.cacheMode:replication}
+
+
+
+
+
+ portal.Role
+ Exo Cache cluster configuration for IDM Membership Type entity
+
+
+ portal.Role
+
+
+ ${exo.cache.portal.role.strategy:LIRS}
+
+
+ ${exo.cache.portal.role.MaxNodes:5000}
+
+
+ ${exo.cache.portal.role.TimeToLive:-1}
+
+
+ ${exo.cache.portal.role.cacheMode:replication}
+
+
+
+
+
+ portal.Group
+ Exo Cache cluster configuration for IDM Group entity
+
+
+ portal.Group
+
+
+ ${exo.cache.portal.group.strategy:LIRS}
+
+
+ ${exo.cache.portal.group.MaxNodes:5000}
+
+
+ ${exo.cache.portal.group.TimeToLive:-1}
+
+
+ ${exo.cache.portal.group.cacheMode:replication}
+
+
+
+
+
+ commons.SettingService
+ The Cache configuration for the setting service
+
+
+ commons.SettingService
+
+
+ ${exo.cache.commons.SettingService.MaxNodes:100000}
+
+
+ ${exo.cache.commons.SettingService.TimeToLive:86400}
+
+
+ ${exo.cache.commons.SettingService:replication}
+
+
+ ${exo.cache.commons.SettingService.strategy:LIRS}
+
+
+
+
+
+ portal.PortletPreferences
+ The cache configuration for Portlet Preferences
+
+
+ portal.PortletPreferences
+
+
+ ${exo.cache.portal.preferences.strategy:LIRS}
+
+
+ ${exo.cache.portal.preferences.MaxNodes:10000}
+
+
+ ${exo.cache.portal.preferences.TimeToLive:86400}
+
+
+ ${exo.cache.portal.preferences.cacheMode:invalidation}
+
+
+
+
+ portal.NavigationNode
+ The Cache configuration for the MOP session Manager
+
+
+ portal.NavigationNode
+
+
+ ${exo.cache.portal.mop.strategy:LIRS}
+
+
+ ${exo.cache.portal.mop.MaxNodes:5000}
+
+
+ ${exo.cache.portal.mop.TimeToLive:86400}
+
+
+ ${exo.cache.portal.mop.cacheMode:invalidation}
+
+
+
+
+ portal.NavigationService
+ The cache configuration for the navigation Trees service
+
+
+ portal.NavigationService
+
+
+ ${exo.cache.portal.navigation.strategy:LIRS}
+
+
+ ${exo.cache.portal.navigation.MaxNodes:1000}
+
+
+ ${exo.cache.portal.navigation.TimeToLive:86400}
+
+
+ ${exo.cache.portal.navigation.cacheMode:invalidation}
+
+
+
+
+ portal.SiteService
+ The cache configuration for Site layout service
+
+
+ portal.SiteService
+
+
+ ${exo.cache.portal.site.strategy:LIRS}
+
+
+ ${exo.cache.portal.site.MaxNodes:1000}
+
+
+ ${exo.cache.portal.site.TimeToLive:86400}
+
+
+ ${exo.cache.portal.site.cacheMode:invalidation}
+
+
+
+
+ portal.SiteKeysByFilterService
+ The cache configuration for Site layout service
+
+
+ portal.SiteKeysByFilterService
+
+
+ ${exo.cache.portal.site.strategy:LIRS}
+
+
+ ${exo.cache.portal.site.MaxNodes:1000}
+
+
+ ${exo.cache.portal.site.TimeToLive:86400}
+
+
+ ${exo.cache.portal.site.cacheMode:invalidation}
+
+
+
+
+ portal.DescriptionService
+ The Cache configuration for the description service
+
+
+ portal.DescriptionService
+
+
+ ${exo.cache.portal.description.strategy:LIRS}
+
+
+ ${exo.cache.portal.description.MaxNodes:10000}
+
+
+ ${exo.cache.portal.description.TimeToLive:86400}
+
+
+ ${exo.cache.portal.description.cacheMode:invalidation}
+
+
+
+
+ portal.PageService
+ The Cache configuration for the page service
+
+
+ portal.PageService
+
+
+ ${exo.cache.portal.page.strategy:LIRS}
+
+
+ ${exo.cache.portal.page.MaxNodes:1000}
+
+
+ ${exo.cache.portal.page.TimeToLive:86400}
+
+
+ ${exo.cache.portal.page.cacheMode:invalidation}
+
+
+
+
+
+ portal.TemplateService
+ The Cache configuration for the template service
+
+
+ portal.TemplateService
+
+
+ ${exo.cache.portal.template.strategy:LIRS}
+
+
+ ${exo.cache.portal.template.MaxNodes:5000}
+
+
+ ${exo.cache.portal.template.TimeToLive:-1}
+
+
+ ${exo.cache.portal.template.cacheMode:invalidation}
+
+
+
+
+ portal.ResourceBundleData
+
+
+
+ portal.ResourceBundleData
+
+
+ ${exo.cache.portal.ResourceBundleData.MaxNodes:1000}
+
+
+ ${exo.cache.portal.ResourceBundleData.TimeToLive:-1}
+
+
+
+
+
+ social.IdentityCache
+ The Cache configuration for the IdentityCache
+
+
+ social.IdentityCache
+
+
+ ${exo.cache.social.IdentityCache.strategy:LIRS}
+
+
+ ${exo.cache.social.IdentityCache.MaxNodes:1100}
+
+
+ ${exo.cache.social.IdentityCache.TimeToLive:86400}
+
+
+ ${exo.cache.social.IdentityCache.cacheMode:replication}
+
+
+
+
+ social.IdentityIndexCache
+ The Cache configuration for the IdentityIndexCache
+
+
+ social.IdentityIndexCache
+
+
+ ${exo.cache.social.IdentityIndexCache.strategy:LIRS}
+
+
+ ${exo.cache.social.IdentityIndexCache.MaxNodes:1100}
+
+
+ ${exo.cache.social.IdentityIndexCache.TimeToLive:86400}
+
+
+ ${exo.cache.social.IdentityIndexCache.cacheMode:replication}
+
+
+
+
+ social.ProfileCache
+ The Cache configuration for the ProfileCache
+
+
+ social.ProfileCache
+
+
+ ${exo.cache.social.ProfileCache.strategy:LIRS}
+
+
+ ${exo.cache.social.ProfileCache.MaxNodes:1100}
+
+
+ ${exo.cache.social.ProfileCache.TimeToLive:86400}
+
+
+ ${exo.cache.social.ProfileCache.cacheMode:replication}
+
+
+
+
+ social.IdentitiesCountCache
+ The Cache configuration for the IdentitiesCountCache
+
+
+ social.IdentitiesCountCache
+
+
+ ${exo.cache.social.IdentitiesCountCache.strategy:LIRS}
+
+
+ ${exo.cache.social.IdentitiesCountCache.MaxNodes:1100}
+
+
+ ${exo.cache.social.IdentitiesCountCache.TimeToLive:86400}
+
+
+ ${exo.cache.social.IdentitiesCountCache.cacheMode:replication}
+
+
+
+
+ social.IdentitiesCache
+ The Cache configuration for the IdentitiesCache
+
+
+ social.IdentitiesCache
+
+
+ ${exo.cache.social.IdentitiesCache.strategy:LIRS}
+
+
+ ${exo.cache.social.IdentitiesCache.MaxNodes:1100}
+
+
+ ${exo.cache.social.IdentitiesCache.TimeToLive:86400}
+
+
+ ${exo.cache.social.IdentitiesCache.cacheMode:replication}
+
+
+
+
+
+
+ social.RelationshipCache
+ The Cache configuration for the RelationshipCache
+
+
+ social.RelationshipCache
+
+
+ ${exo.cache.social.RelationshipCache.strategy:LIRS}
+
+
+ ${exo.cache.social.RelationshipCache.MaxNodes:100000}
+
+
+ ${exo.cache.social.RelationshipCache.TimeToLive:86400}
+
+
+ ${exo.cache.social.RelationshipCache.cacheMode:replication}
+
+
+
+
+ social.RelationshipFromIdentityCache
+ The Cache configuration for the RelationshipFromIdentityCache
+
+
+ social.RelationshipFromIdentityCache
+
+
+ ${exo.cache.social.RelationshipFromIdentityCache.strategy:LIRS}
+
+
+ ${exo.cache.social.RelationshipFromIdentityCache.MaxNodes:100000}
+
+
+ ${exo.cache.social.RelationshipFromIdentityCache.TimeToLive:86400}
+
+
+ ${exo.cache.social.RelationshipFromIdentityCache.cacheMode:replication}
+
+
+
+
+ social.RelationshipsCountCache
+ The Cache configuration for the RelationshipsCountCache
+
+
+ social.RelationshipsCountCache
+
+
+ ${exo.cache.social.RelationshipsCountCache.strategy:LIRS}
+
+
+ ${exo.cache.social.RelationshipsCountCache.MaxNodes:10000}
+
+
+ ${exo.cache.social.RelationshipsCountCache.TimeToLive:86400}
+
+
+ ${exo.cache.social.RelationshipsCountCache.cacheMode:replication}
+
+
+
+
+ social.RelationshipsCache
+ The Cache configuration for the RelationshipsCache
+
+
+ social.RelationshipsCache
+
+
+ ${exo.cache.social.RelationshipsCache.strategy:LIRS}
+
+
+ ${exo.cache.social.RelationshipsCache.MaxNodes:10000}
+
+
+ ${exo.cache.social.RelationshipsCache.TimeToLive:86400}
+
+
+ ${exo.cache.social.RelationshipsCache.cacheMode:replication}
+
+
+
+
+ social.SuggestionsCache
+ The Cache configuration for the SuggestionsCache
+
+
+ social.SuggestionsCache
+
+
+ ${exo.cache.social.SuggestionsCache.strategy:LIRS}
+
+
+ ${exo.cache.social.SuggestionsCache.MaxNodes:1000}
+
+
+ ${exo.cache.social.SuggestionsCache.TimeToLive:86400}
+
+
+ ${exo.cache.social.SuggestionsCache.cacheMode:replication}
+
+
+
+
+
+
+ social.ActivityCache
+ The Cache configuration for the ActivityCache
+
+
+ social.ActivityCache
+
+
+ ${exo.cache.social.ActivityCache.strategy:LIRS}
+
+
+ ${exo.cache.social.ActivityCache.MaxNodes:20000}
+
+
+ ${exo.cache.social.ActivityCache.TimeToLive:86400}
+
+
+ ${exo.cache.social.ActivityCache.cacheMode:replication}
+
+
+
+
+ social.ActivitiesCountCache
+
+
+
+ ${exo.cache.social.ActivitiesCountCache.strategy:LIRS}
+
+
+ social.ActivitiesCountCache
+
+
+ ${exo.cache.social.ActivitiesCountCache.MaxNodes:20000}
+
+
+ ${exo.cache.social.ActivitiesCountCache.TimeToLive:86400}
+
+
+ ${exo.cache.social.ActivitiesCountCache.cacheMode:replication}
+
+
+
+
+ social.ActivitiesCache
+
+
+
+ ${exo.cache.social.ActivitiesCache.strategy:LIRS}
+
+
+ social.ActivitiesCache
+
+
+ ${exo.cache.social.ActivitiesCache.MaxNodes:20000}
+
+
+ ${exo.cache.social.ActivitiesCache.TimeToLive:86400}
+
+
+ ${exo.cache.social.ActivitiesCache.cacheMode:replication}
+
+
+
+
+
+
+ social.SpaceCache
+ The Cache configuration for the SpaceCache
+
+
+ social.SpaceCache
+
+
+ ${exo.cache.social.SpaceCache.strategy:LIRS}
+
+
+ ${exo.cache.social.SpaceCache.MaxNodes:100}
+
+
+ ${exo.cache.social.SpaceCache.TimeToLive:86400}
+
+
+ ${exo.cache.social.SpaceCache.cacheMode:replication}
+
+
+
+
+ social.SpaceSimpleCache
+
+
+
+ social.SpaceSimpleCache
+
+
+ ${exo.cache.social.SpaceSimpleCache.MaxNodes:500}
+
+
+ ${exo.cache.social.SpaceSimpleCache.TimeToLive:86400}
+
+
+
+
+ social.SpaceRefCache
+ The Cache configuration for the SpaceRefCache
+
+
+ social.SpaceRefCache
+
+
+ ${exo.cache.social.SpaceRefCache.strategy:LIRS}
+
+
+ ${exo.cache.social.SpaceRefCache.MaxNodes:100}
+
+
+ ${exo.cache.social.SpaceRefCache.TimeToLive:86400}
+
+
+ ${exo.cache.social.SpaceRefCache.cacheMode:replication}
+
+
+
+
+ social.SpacesCountCache
+ The Cache configuration for the SpacesCountCache
+
+
+ social.SpacesCountCache
+
+
+ ${exo.cache.social.SpacesCountCache.strategy:LIRS}
+
+
+ ${exo.cache.social.SpacesCountCache.MaxNodes:4000}
+
+
+ ${exo.cache.social.SpacesCountCache.TimeToLive:86400}
+
+
+ ${exo.cache.social.SpacesCountCache.cacheMode:replication}
+
+
+
+
+ social.SpacesCache
+ The Cache configuration for the SpacesCache
+
+
+ social.SpacesCache
+
+
+ ${exo.cache.social.SpacesCache.strategy:LIRS}
+
+
+ ${exo.cache.social.SpacesCache.MaxNodes:4000}
+
+
+ ${exo.cache.social.SpacesCache.TimeToLive:86400}
+
+
+ ${exo.cache.social.SpacesCache.cacheMode:replication}
+
+
+
+
+ social.translation
+ The Cache configuration for the TranslationStorage
+
+
+ social.translation
+
+
+ ${exo.cache.social.TranslationCache.strategy:LIRS}
+
+
+ ${exo.cache.social.TranslationCache.MaxNodes:5000}
+
+
+ ${exo.cache.social.TranslationCache.TimeToLive:86400}
+
+
+ ${exo.cache.social.TranslationCache.cacheMode:replication}
+
+
+
+
+ social.linkSettings
+ The Cache configuration for the LinkStorage
+
+
+ social.linkSettings
+
+
+ ${exo.cache.social.LinkSettingsCache.strategy:LIRS}
+
+
+ ${exo.cache.social.LinkSettingsCache.MaxNodes:5000}
+
+
+ ${exo.cache.social.LinkSettingsCache.TimeToLive:86400}
+
+
+ ${exo.cache.social.TranslationCache.cacheMode:replication}
+
+
+
+
+ social.cmsSetting
+ The Cache configuration for the CMSStorage
+
+
+ social.cmsSetting
+
+
+ ${exo.cache.social.cmsSettingCache.strategy:LIRS}
+
+
+ ${exo.cache.social.cmsSettingCache.MaxNodes:5000}
+
+
+ ${exo.cache.social.cmsSettingCache.TimeToLive:86400}
+
+
+ ${exo.cache.social.TranslationCache.cacheMode:replication}
+
+
+
+
+
+ social.ProfileAvatar
+ The Cache configuration for the ProfileAvatar
+
+
+ social.ProfileAvatar
+
+
+ ${exo.cache.social.ProfileAvatar.strategy:LIRS}
+
+
+ ${exo.cache.social.ProfileAvatar.MaxNodes:300}
+
+
+ ${exo.cache.social.ProfileAvatar.TimeToLive:600}
+
+
+ ${exo.cache.social.TranslationCache.cacheMode:replication}
+
+
+
+
+ wallet.transactions
+ Wallet application transactions cache
+
+
+ wallet.transactions
+
+
+ ${exo.cache.wallet.transactions.MaxNodes:2000}
+
+
+ ${exo.cache.wallet.transactions.TimeToLive:-1}
+
+
+ ${exo.cache.wallet.transactions.strategy:LIRS}
+
+
+ ${exo.cache.wallet.transactions.cacheMode:asyncInvalidation}
+
+
+
+
+ wallet.account
+
+
+
+ wallet.account
+
+
+ ${exo.cache.wallet.account.MaxNodes:2000}
+
+
+ ${exo.cache.wallet.account.TimeToLive:-1}
+
+
+ ${exo.cache.wallet.account.strategy:LIRS}
+
+
+ ${exo.cache.wallet.account.cacheMode:asyncInvalidation}
+
+
+
+
+
+
+
+
diff --git a/commons-exo-extension/src/main/webapp/WEB-INF/conf/configuration.xml b/commons-exo-extension/src/main/webapp/WEB-INF/conf/configuration.xml
new file mode 100644
index 00000000..8adc015f
--- /dev/null
+++ b/commons-exo-extension/src/main/webapp/WEB-INF/conf/configuration.xml
@@ -0,0 +1,23 @@
+
+
+
+ war:/conf/commons-exo/cache-configuration.xml
+
diff --git a/commons-exo-extension/src/main/webapp/WEB-INF/conf/uiconf/portal/webui/container/ContainerConfigOption.groovy b/commons-exo-extension/src/main/webapp/WEB-INF/conf/uiconf/portal/webui/container/ContainerConfigOption.groovy
deleted file mode 100644
index 1822acb2..00000000
--- a/commons-exo-extension/src/main/webapp/WEB-INF/conf/uiconf/portal/webui/container/ContainerConfigOption.groovy
+++ /dev/null
@@ -1,89 +0,0 @@
-/**
- * Copyright (C) 2023 eXo Platform SAS.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-
-import org.exoplatform.webui.core.model.SelectItemCategory;
-import org.exoplatform.webui.core.model.SelectItemOption;
-
- List templates = new ArrayList();
-
- SelectItemCategory table = new SelectItemCategory("table");
- table.addSelectItemOption(new SelectItemOption("simpleTable",
- " ",
- "SimpleTableContainerLayout"));
- table.addSelectItemOption(new SelectItemOption("siteTopBar",
- "\n" +
- " Everyone \n" +
- " \n" +
- " Everyone \n" +
- " \n" +
- " \n" +
- " social \n" +
- " TopBarLogo \n" +
- " \n" +
- " Company Logo \n" +
- " Everyone \n" +
- " false \n" +
- " false \n" +
- " \n" +
- " \n" +
- " \n" +
- " layout-management \n" +
- " SiteNavigation \n" +
- " \n" +
- " site navigation \n" +
- " Everyone \n" +
- " false \n" +
- " false \n" +
- " \n" +
- " \n" +
- " \n" +
- " \n" +
- " \n" +
- " social \n" +
- " TopBarMenu \n" +
- " \n" +
- " Top Bar Menu \n" +
- " Everyone \n" +
- " false \n" +
- " false \n" +
- " \n" +
- " \n" +
- " \n" +
- " \n" +
- " \n",
- "SiteTopBarContainerLayout"));
- templates.add(table);
-
- SelectItemCategory row = new SelectItemCategory("row");
- row.addSelectItemOption(new SelectItemOption("simpleRow",
- " ",
- "SimpleRowContainerLayout"));
- templates.add(row);
-
- SelectItemCategory column = new SelectItemCategory("column");
- column.addSelectItemOption(new SelectItemOption("simpleColumn",
- "" +
- " " +
- " SimpleColumnContainer " +
- " " +
- " ",
- "SimpleColumnContainerLayout"));
- templates.add(column);
-
- return templates;
diff --git a/exo.core.component.database/pom.xml b/exo.core.component.database/pom.xml
new file mode 100644
index 00000000..e23e6c8a
--- /dev/null
+++ b/exo.core.component.database/pom.xml
@@ -0,0 +1,187 @@
+
+
+
+
+
+ 4.0.0
+
+
+ org.exoplatform.commons-exo
+ commons-exo
+ 7.0.x-SNAPSHOT
+
+
+ exo.core.component.database
+
+ Meeds:: PLF Core :: Component :: Database Service
+ Implementation of Database Service of Exoplatform SAS eXo Core' project.
+
+
+ 0.18
+
+
+
+
+ io.meeds.kernel
+ exo.kernel.component.common
+
+
+ io.meeds.kernel
+ exo.kernel.commons
+
+
+ io.meeds.kernel
+ exo.kernel.container
+
+
+ io.meeds.kernel
+ exo.kernel.component.cache
+
+
+ io.meeds.kernel
+ exo.kernel.commons.test
+ test
+
+
+ javax.resource
+ javax.resource-api
+ test
+
+
+ org.hsqldb
+ hsqldb
+ test
+
+
+ com.experlog
+ xapool
+ true
+
+
+ com.atomikos
+ transactions-jta
+ provided
+
+
+ org.mockito
+ mockito-all
+
+
+
+
+ org.jboss.logging
+ jboss-logging
+
+
+ javax.transaction
+ javax.transaction-api
+
+
+ org.hibernate.orm
+ hibernate-core
+
+
+ org.slf4j
+ slf4j-api
+
+
+ org.jboss.spec.javax.transaction
+ jboss-transaction-api_1.1_spec
+
+
+ org.jboss.logging
+ jboss-logging
+
+
+ org.javassist
+ javassist
+
+
+
+
+ commons-dbcp
+ commons-dbcp
+ runtime
+
+
+ xerces
+ xercesImpl
+
+
+ commons-pool
+ commons-pool
+
+
+
+
+ commons-pool
+ commons-pool
+ runtime
+
+
+ com.atomikos
+ transactions-jta
+ provided
+
+
+ org.mockito
+ mockito-all
+
+
+
+
+
+
+
+
+ maven-antrun-plugin
+
+
+ prepare-test-policy
+ process-test-resources
+
+
+ Creating Access Policy for tests
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ run
+
+
+
+
+
+
+
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/DAO.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/DAO.java
new file mode 100644
index 00000000..f45a459f
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/DAO.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import org.exoplatform.commons.utils.PageList;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.List;
+
+/**
+ * Created by The eXo Platform SAS Author : Tuan Nguyen
+ * tuan08@users.sourceforge.net Apr 4, 2006
+ */
+public abstract class DAO
+{
+
+ /**
+ * Logger.
+ */
+ private static final Log LOG = ExoLogger.getLogger("exo.core.component.database.DAO");
+
+ protected ExoDatasource eXoDS_;
+
+ protected DBObjectMapper mapper_;
+
+ static int totalQueryTime = 0;
+
+ static int totalBathTime = 0;
+
+ static int totalCloseConnect = 0;
+
+ public DAO(ExoDatasource datasource)
+ {
+ eXoDS_ = datasource;
+ mapper_ = new ReflectionMapper();
+ }
+
+ public DAO(ExoDatasource datasource, DBObjectMapper mapper)
+ {
+ eXoDS_ = datasource;
+ mapper_ = mapper;
+ }
+
+ public ExoDatasource getExoDatasource()
+ {
+ return eXoDS_;
+ }
+
+ abstract public T load(long id) throws Exception;
+
+ abstract public PageList loadAll() throws Exception;
+
+ abstract public void update(T bean) throws Exception;
+
+ abstract public void update(List beans) throws Exception;
+
+ abstract public void save(T bean) throws Exception;
+
+ abstract public void save(List beans) throws Exception;
+
+ abstract public void remove(T bean) throws Exception;
+
+ abstract public T remove(long id) throws Exception;
+
+ abstract public T createInstance() throws Exception;
+
+ protected T loadUnique(String query) throws Exception
+ {
+ Connection connection = eXoDS_.getConnection();
+ try
+ {
+ return loadUnique(connection, query);
+ }
+ finally
+ {
+ eXoDS_.closeConnection(connection);
+ }
+ }
+
+ protected T loadUnique(Connection connection, String query) throws Exception
+ {
+ Statement statement = null;
+ try
+ {
+ statement = connection.createStatement();
+ ResultSet resultSet = statement.executeQuery(query);
+ if (!resultSet.next())
+ {
+ return null;
+ }
+ T bean = createInstance();
+ mapper_.mapResultSet(resultSet, bean);
+ resultSet.close();
+ return bean;
+ }
+ finally
+ {
+ if (statement != null)
+ statement.close();
+ }
+ }
+
+ protected void loadInstances(String loadQuery, List list) throws Exception
+ {
+ Connection connection = eXoDS_.getConnection();
+ try
+ {
+ loadInstances(connection, loadQuery, list);
+ }
+ finally
+ {
+ eXoDS_.closeConnection(connection);
+ }
+ }
+
+ protected void loadInstances(Connection connection, String loadQuery, List list) throws Exception
+ {
+ Statement statement = connection.createStatement();
+ ResultSet resultSet = null;
+ try
+ {
+ resultSet = statement.executeQuery(loadQuery);
+ while (resultSet.next())
+ {
+ T bean = createInstance();
+ mapper_.mapResultSet(resultSet, bean);
+ list.add(bean);
+ }
+ }
+ finally
+ {
+ if (resultSet != null)
+ {
+ try
+ {
+ resultSet.close();
+ }
+ catch (Exception e)
+ {
+ LOG.debug("Could not close the result set");
+ }
+ }
+ try
+ {
+ statement.close();
+ }
+ catch (Exception e)
+ {
+ LOG.debug("Could not close the statement");
+ }
+ }
+ }
+
+ protected void execute(String query, T bean) throws Exception
+ {
+ Connection connection = eXoDS_.getConnection();
+ try
+ {
+ execute(connection, query, bean);
+ }
+ finally
+ {
+ eXoDS_.closeConnection(connection);
+ }
+ }
+
+ protected void execute(Connection connection, String query, T bean) throws Exception
+ {
+ PreparedStatement statement = connection.prepareStatement(query);
+ if (bean != null)
+ mapper_.mapUpdate(bean, statement);
+ statement.executeUpdate();
+ eXoDS_.commit(connection);
+ statement.close();
+ }
+
+ public E loadDBField(String query) throws Exception
+ {
+ Connection connection = eXoDS_.getConnection();
+ try
+ {
+ return this. loadDBField(connection, query);
+ }
+ finally
+ {
+ eXoDS_.closeConnection(connection);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ protected E loadDBField(Connection connection, String query) throws Exception
+ {
+ Statement statement = connection.createStatement();
+ long startGet = System.currentTimeMillis();
+ ResultSet resultSet = statement.executeQuery(query);
+ totalQueryTime += System.currentTimeMillis() - startGet;
+ if (!resultSet.next())
+ return null;
+ E value = (E)resultSet.getObject(1);
+ resultSet.close();
+ statement.close();
+ return value;
+ }
+
+ protected void execute(String template, List beans) throws Exception
+ {
+ Connection connection = eXoDS_.getConnection();
+ try
+ {
+ execute(connection, template, beans);
+ }
+ finally
+ {
+ eXoDS_.closeConnection(connection);
+ }
+ }
+
+ protected void execute(Connection connection, String template, List beans) throws Exception
+ {
+ PreparedStatement statement = connection.prepareStatement(template);
+ QueryBuilder builder = eXoDS_.getQueryBuilder();
+ for (T bean : beans)
+ {
+ String query = builder.mapDataToSql(template, mapper_.toParameters(bean));
+ statement.addBatch(query);
+ LOG.info(" addBatch " + query);
+ }
+ statement.executeBatch();
+ statement.close();
+ eXoDS_.commit(connection);
+ }
+
+ public DBObjectMapper getDBObjectMapper()
+ {
+ return mapper_;
+ }
+
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/DBObject.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/DBObject.java
new file mode 100644
index 00000000..cbda6af9
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/DBObject.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+/**
+ * Created by The eXo Platform SAS
+ * Author : Tuan Nguyen tuan.nguyen@exoplatform.com Mar 15, 2007
+ */
+abstract public class DBObject
+{
+
+ protected long dbObjectId_ = -1;
+
+ public long getDBObjectId()
+ {
+ return dbObjectId_;
+ }
+
+ public void setDBObjectId(long id)
+ {
+ dbObjectId_ = id;
+ }
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/DBObjectEvent.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/DBObjectEvent.java
new file mode 100644
index 00000000..0a4a6a14
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/DBObjectEvent.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import org.exoplatform.services.listener.Event;
+
+/**
+ * Created by The eXo Platform SAS
+ * Author : Nhu Dinh Thuan nhudinhthuan@exoplatform.com Apr 6, 2007
+ */
+public class DBObjectEvent, T extends DBObject> extends Event
+{
+
+ public DBObjectEvent(String name, E e, T t)
+ {
+ super(name, e, t);
+ }
+
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/DBObjectMapper.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/DBObjectMapper.java
new file mode 100644
index 00000000..f371fa9f
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/DBObjectMapper.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+
+/**
+ * Created by The eXo Platform SAS
+ * Author : Nhu Dinh Thuan nhudinhthuan@exoplatform.com Mar 29, 2007
+ */
+public interface DBObjectMapper
+{
+
+ public void mapUpdate(T bean, PreparedStatement statement) throws Exception;
+
+ public String[][] toParameters(T bean) throws Exception;
+
+ public void mapResultSet(ResultSet res, T bean) throws Exception;
+
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/DBObjectPageList.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/DBObjectPageList.java
new file mode 100644
index 00000000..90ed43c5
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/DBObjectPageList.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.hibernate.Session;
+import org.hibernate.query.Query;
+
+import org.exoplatform.commons.utils.PageList;
+
+/**
+ * @author Tuan Nguyen (tuan08@users.sourceforge.net)
+ * @since Oct 21, 2004
+ * @version $Id: DBObjectPageList.java 5332 2006-04-29 18:32:44Z geaz $
+ */
+public class DBObjectPageList extends PageList
+{
+
+ private String findQuery_;
+
+ private String countQuery_;
+
+ private HibernateService service_;
+
+ private Map binding = new HashMap();
+
+ public DBObjectPageList(HibernateService service, Class> objectType) throws Exception
+ {
+ super(20);
+ service_ = service;
+ findQuery_ = "from o in class " + objectType.getName();
+ countQuery_ = "select count(o) from " + objectType.getName() + " o";
+ Session session = service_.openSession();
+ List> l = session.createQuery(countQuery_).list();
+ Number count = (Number)l.get(0);
+ setAvailablePage(count.intValue());
+ }
+
+ public DBObjectPageList(HibernateService service, ObjectQuery oq) throws Exception
+ {
+ super(20);
+ service_ = service;
+ findQuery_ = oq.getHibernateQueryWithBinding();
+ countQuery_ = oq.getHibernateCountQueryWithBinding();
+ binding = oq.getBindingFields();
+
+ Session session = service_.openSession();
+
+ Query countQuery = session.createQuery(countQuery_);
+ bindFields(countQuery);
+
+ List> l = countQuery.list();
+
+ Number count = (Number)l.get(0);
+ setAvailablePage(count.intValue());
+ }
+
+ public DBObjectPageList(HibernateService service, int pageSize, String query, String countQuery) throws Exception
+ {
+ super(pageSize);
+ service_ = service;
+ findQuery_ = query;
+ countQuery_ = countQuery;
+ Session session = service_.openSession();
+ List> l = session.createQuery(countQuery_).list();
+ Number count = (Number)l.get(0);
+ setAvailablePage(count.intValue());
+ }
+
+ @Override
+ protected void populateCurrentPage(int page) throws Exception
+ {
+ Session session = service_.openSession();
+ Query query = session.createQuery(findQuery_);
+ bindFields(query);
+
+ int from = getFrom();
+ query.setFirstResult(from);
+ query.setMaxResults(getTo() - from);
+ currentListPage_ = query.list();
+ }
+
+ @Override
+ public List getAll() throws Exception
+ {
+ Session session = service_.openSession();
+
+ Query query = session.createQuery(findQuery_);
+ bindFields(query);
+
+ return query.list();
+ }
+
+ /**
+ * Bind a value to a named query parameter.
+ *
+ * @param query
+ */
+ private void bindFields(Query query)
+ {
+ for (Entry entry : binding.entrySet())
+ {
+ query.setParameter(entry.getKey(), entry.getValue());
+ }
+ }
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/DBObjectQuery.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/DBObjectQuery.java
new file mode 100644
index 00000000..9c33c5ee
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/DBObjectQuery.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import org.exoplatform.services.database.annotation.Table;
+
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author Tuan Nguyen (tuan08@users.sourceforge.net)
+ * @since Nov 25, 2004
+ * @version $Id: ObjectQuery.java 6006 2006-06-06 10:01:27Z thangvn $
+ */
+public class DBObjectQuery
+{
+
+ private static DateTimeFormatter ft_ = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
+
+ private Class extends DBObject> type_;
+
+ private String orderBy_;
+
+ private String groupBy_;
+
+ private List parameters_;
+
+ private List selectParameter_;
+
+ public DBObjectQuery(Class type)
+ {
+ type_ = type;
+ parameters_ = new ArrayList(3);
+ selectParameter_ = new ArrayList(10);
+ }
+
+ public DBObjectQuery addEQ(String field, Object value)
+ {
+ if (value == null)
+ return this;
+ parameters_.add(new Parameter(field, " = ", value));
+ return this;
+ }
+
+ public DBObjectQuery addGT(String field, Object value)
+ {
+ if (value == null)
+ return this;
+ parameters_.add(new Parameter(field, " > ", value));
+ return this;
+ }
+
+ public DBObjectQuery addLT(String field, Object value)
+ {
+ if (value == null)
+ return this;
+ parameters_.add(new Parameter(field, " < ", value));
+ return this;
+ }
+
+ public DBObjectQuery addLIKE(String field, String value)
+ {
+ if (value == null || value.length() < 1)
+ return this;
+ parameters_.add(new Parameter(field, " LIKE ", optimizeInputString(value)));
+ return this;
+ }
+
+ public DBObjectQuery addSUM(String field)
+ {
+ selectParameter_.add(new Parameter("SUM", field));
+ return this;
+ }
+
+ public DBObjectQuery addSelect(String field, String value)
+ {
+ selectParameter_.add(new Parameter(field, " AS ", value));
+ return this;
+ }
+
+ public DBObjectQuery addSelect(String... fields)
+ {
+ for (String field : fields)
+ {
+ selectParameter_.add(new Parameter(field, null, null));
+ }
+ return this;
+ }
+
+ public DBObjectQuery addSelect(String field)
+ {
+ selectParameter_.add(new Parameter(field, null, null));
+ return this;
+ }
+
+ public DBObjectQuery addSelectCount(String type)
+ {
+ selectParameter_.add(new Parameter("countselect", type));
+ return this;
+ }
+
+ public DBObjectQuery addSelectMaxMin(String op, String field)
+ {
+ selectParameter_.add(new Parameter(op, field));
+ return this;
+ }
+
+ public DBObjectQuery setAscOrderBy(String field)
+ {
+ orderBy_ = " ORDER BY " + field + " ASC";
+ return this;
+ }
+
+ public DBObjectQuery setDescOrderBy(String field)
+ {
+ orderBy_ = " ORDER BY " + field + " DESC";
+ return this;
+ }
+
+ public DBObjectQuery setGroupBy(String field)
+ {
+ groupBy_ = " GROUP BY " + field;
+ return this;
+ }
+
+ public String toQuery()
+ {
+ return constuctQuery(false);
+ }
+
+ public String toQueryUseOR()
+ {
+ return constuctQuery(true);
+ }
+
+ private String constuctQuery(boolean useOR)
+ {
+ StringBuilder builder = new StringBuilder("SELECT ");
+ if (selectParameter_.size() > 0)
+ {
+ for (int i = 0; i < selectParameter_.size(); i++)
+ {
+ if (i > 0)
+ builder.append(", ");
+ parameters_.get(i).build(builder);
+ }
+ }
+ else
+ {
+ builder.append(" * ");
+ }
+
+ Table table = type_.getAnnotation(Table.class);
+ builder.append(" FROM ").append(table.name());
+ if (parameters_.size() > 0)
+ {
+ builder.append(" WHERE ");
+ for (int i = 0; i < parameters_.size(); i++)
+ {
+ if (i > 0)
+ builder.append(useOR ? " OR " : " AND ");
+ parameters_.get(i).build(builder);
+ }
+ }
+ if (orderBy_ != null)
+ builder.append(orderBy_);
+ return builder.toString();
+ }
+
+ public String toCountQuery()
+ {
+ return consturctCountQuery(false);
+ }
+
+ public String toCountQueryUseOR()
+ {
+ return consturctCountQuery(true);
+ }
+
+ private String consturctCountQuery(boolean useOR)
+ {
+ StringBuilder builder = new StringBuilder();
+ Table table = type_.getAnnotation(Table.class);
+ builder.append("SELECT COUNT(*) FROM ").append(table.name());
+ if (parameters_.size() > 0)
+ {
+ builder.append(" WHERE ");
+ for (int i = 0; i < parameters_.size(); i++)
+ {
+ if (i > 0)
+ builder.append(useOR ? " OR " : " AND ");
+ parameters_.get(i).build(builder);
+ }
+ }
+ return builder.toString();
+ }
+
+ /*
+ * public String getHibernateGroupByQuery() { StringBuilder b = new
+ * StringBuilder("SELECT ") ; if(selectParameter_.size() > 0){ for(int i = 0;
+ * i < selectParameter_.size(); i++){ Parameter p = selectParameter_.get(i) ;
+ * if(p.op_.equals("fieldselect")){ b.append(p.field_) ; }else
+ * if(p.op_.equals("countselect")){ b.append("COUNT"); if (p.field_ != "" ||
+ * p.field_.length() > 0){ b.append("(").append(p.field_).append(" )"); }else{
+ * b.append("(*)"); } }else {
+ * b.append(p.op_).append("(").append(p.field_).append(") "); } if(i <
+ * selectParameter_.size() - 1 ) b.append(" , ") ; } } Table table =
+ * type_.getAnnotation(Table.class) ; b.append(" FROM ").append(table.name())
+ * ; if(parameters_.size() > 0) { b.append(" WHERE ") ; for(int i = 0; i <
+ * parameters_.size(); i ++) { if(i > 0) b.append(" AND ") ; Parameter p =
+ * parameters_.get(i) ; if(p.value_ instanceof String) {
+ * b.append(p.field_).append(p.op_).append("'").append(p.value_).append("'") ;
+ * } else if(p.value_ instanceof Date) { String value = ft_.format((Date)
+ * p.value_) ;
+ * b.append(' ').append(p.field_).append(p.op_).append("'").append(
+ * value).append("'") ; } else if(p.op_.equals("max") || p.op_.equals("min")){
+ * b.append(p.op_).append("(").append(p.field_).append(") "); } else{
+ * b.append(' ').append(p.field_).append(p.op_).append(p.value_); } } }
+ * if(groupBy_ != null ) b.append(groupBy_ ); if(orderBy_ != null )
+ * b.append(orderBy_ ); return b.toString() ; }
+ */
+
+ public String optimizeInputString(String value)
+ {
+ value = value.replace('*', '%');
+ value = value.replaceAll("'", "'");
+ value = value.replaceAll("<", "<");
+ value = value.replaceAll(">", ">");
+ return value;
+ }
+
+ public List getParameters()
+ {
+ return parameters_;
+ }
+
+ static public class Parameter
+ {
+
+ String op_;
+
+ String field_;
+
+ String label_;
+
+ Object value_;
+
+ public Parameter(String field, String op, Object value)
+ {
+ op_ = op;
+ field_ = field;
+ value_ = value;
+ }
+
+ public Parameter(String op, String field)
+ {
+ op_ = op;
+ field_ = field;
+ }
+
+ void build(StringBuilder builder)
+ {
+ builder.append(' ').append(field_).append(op_);
+ if (op_ == null || op_.trim().length() < 1 || value_ == null)
+ return;
+ builder.append(' ');
+ if (CharSequence.class.isInstance(value_))
+ {
+ builder.append('\'').append(value_).append('\'');
+ }
+ else if (value_ instanceof Date)
+ {
+ LocalDateTime ldt = LocalDateTime.ofInstant(((Date)value_).toInstant(), ZoneId.systemDefault());
+ String value = ldt.format(ft_);
+ builder.append("'").append(value).append("'");
+ }
+ else
+ {
+ builder.append(value_);
+ }
+ }
+ }
+
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/DBQueryParameter.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/DBQueryParameter.java
new file mode 100644
index 00000000..2ac81b6f
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/DBQueryParameter.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import java.util.Comparator;
+
+/**
+ * Created by The eXo Platform SAS
+ * Author : Nhu Dinh Thuan nhudinhthuan@exoplatform.com Apr 2, 2007
+ */
+public class DBQueryParameter
+{
+
+ protected String name;
+
+ protected String value;
+
+ protected Operator operator;
+
+ protected int order = WHERE;
+
+ public final static int SELECT = 1, WHERE = 3, GROUP = 4, HAVING = 5, ORDER = 6;
+
+ protected DBQueryParameter()
+ {
+ }
+
+ public DBQueryParameter(String value)
+ {
+ this.value = value;
+ }
+
+ public DBQueryParameter(String name, String value)
+ {
+ this.name = name;
+ this.value = value;
+ }
+
+ public DBQueryParameter(String name, String value, Operator operator)
+ {
+ this.name = name;
+ this.value = value;
+ this.operator = operator;
+ }
+
+ public void build(StringBuilder builder)
+ {
+ if (order == WHERE && builder.indexOf(" WHERE ") < 0)
+ builder.append(" WHERE ");
+ builder.append(' ').append(name).append(operator.toString()).append(value);
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public Operator getOperator()
+ {
+ return operator;
+ }
+
+ public void setOperator(Operator operator)
+ {
+ this.operator = operator;
+ }
+
+ public String getValue()
+ {
+ return value;
+ }
+
+ public void setValue(String value)
+ {
+ this.value = value;
+ }
+
+ public final static Comparator PARAMETER_SORT = new Comparator()
+ {
+ public int compare(DBQueryParameter param1, DBQueryParameter param2)
+ {
+ return param1.order - param2.order;
+ }
+ };
+
+ public static class Operator
+ {
+
+ public final static Operator AND = new Operator(" AND ");
+
+ public final static Operator OR = new Operator(" OR ");
+
+ public final static Operator LESS_THAN = new Operator(" < ");
+
+ public final static Operator LESS_THAN_AND_EQUALS = new Operator(" <= ");
+
+ public final static Operator GREATER_THAN = new Operator(" > ");
+
+ public final static Operator GREATER_THAN_AND_EQUALS = new Operator(" >= ");
+
+ public final static Operator LIKE = new Operator(" LIKE ");
+
+ public final static Operator IN = new Operator(" IN ");
+
+ public final static Operator IS = new Operator(" IS ");
+
+ public final static Operator EQUALS = new Operator(" = ");
+
+ private String value;
+
+ public Operator(String value)
+ {
+ this.value = value;
+ }
+
+ public String toString()
+ {
+ return value;
+ }
+
+ public String getValue()
+ {
+ return value;
+ }
+
+ }
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/DBTableManager.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/DBTableManager.java
new file mode 100644
index 00000000..53e2f3be
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/DBTableManager.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+/**
+ * Created by The eXo Platform SAS
+ * Author : Tuan Nguyen tuan08@users.sourceforge.net Apr 4, 2006
+ * The DBTableManager is an interface
+ * to help the developer to check if a table is existed or not and create/drop a
+ * table. We can implement more one more DBTableManager according to the
+ * database type and version.
+ */
+abstract public class DBTableManager
+{
+ /**
+ * This method should: 1. Extract the table information such table name and
+ * table fields from the class T, the information are annotated in the class T
+ * 2. Generate the SQL statement and create the table
+ *
+ * @param
+ * @param type
+ * @param dropIfExist
+ * @throws Exception
+ */
+ abstract public void createTable(Class type, boolean dropIfExist) throws Exception;
+
+ /**
+ * This method should: 1. Extract the table information from the class T, the
+ * information are annotated in the class T 2. Generate the SQL statement and
+ * drop the table
+ *
+ * @param
+ * @param type
+ * @throws Exception
+ */
+ abstract public void dropTable(Class type) throws Exception;
+
+ /**
+ * This method should: 1. Extract the table information from the class T, the
+ * information are annotated in the class T 2. Check to see if the table is
+ * existed in the database system
+ *
+ * @param
+ * @param type
+ * @return
+ * @throws Exception
+ */
+ abstract public boolean hasTable(Class type) throws Exception;
+
+ /**
+ * This method should check the database type and version and create a
+ * corresponded DBTableManager
+ *
+ * @param datasource
+ * @return
+ */
+ final static public DBTableManager createDBTableManager(ExoDatasource datasource)
+ {
+ if (datasource.getDatabaseType() == ExoDatasource.HSQL_DB_TYPE)
+ {
+ return new StandardSQLTableManager(datasource);
+ }
+ else if (ExoDatasource.ORACLE_DB_TYPE == datasource.getDatabaseType())
+ {
+ return new OracleTableManager(datasource);
+ }
+ else if (ExoDatasource.SQL_SERVER_TYPE == datasource.getDatabaseType())
+ {
+ return new MSSQLServerTableManager(datasource);
+ }
+ return new StandardSQLTableManager(datasource);
+ }
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/DatabaseService.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/DatabaseService.java
new file mode 100644
index 00000000..cae0c27c
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/DatabaseService.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import org.exoplatform.services.transaction.TransactionService;
+
+import java.sql.Connection;
+
+/**
+ * Created by The eXo Platform SAS
+ * Author : Tuan Nguyen tuan08@users.sourceforge.net Apr 4, 2006
+ * This service should provide a single
+ * interface to access the different datasource.
+ */
+public interface DatabaseService
+{
+
+ /**
+ * This method should return the default datasource of the application
+ *
+ * @return
+ * @throws Exception
+ */
+ public ExoDatasource getDatasource() throws Exception;
+
+ /**
+ * This method should look up the datasouce by the datasource name and return.
+ * If the datasource is not found then the method should return null
+ *
+ * @param dsname
+ * @return
+ * @throws Exception
+ */
+ public ExoDatasource getDatasource(String dsname) throws Exception;
+
+ public Connection getConnection() throws Exception;
+
+ public Connection getConnection(String dsName) throws Exception;
+
+ public void closeConnection(Connection conn) throws Exception;
+
+ /**
+ * This method should return the transaction service
+ *
+ * @return
+ * @throws Exception
+ */
+ public TransactionService getTransactionService() throws Exception;
+
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/ExoDatasource.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/ExoDatasource.java
new file mode 100644
index 00000000..36e60ed8
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/ExoDatasource.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import org.exoplatform.services.database.table.IDGenerator;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+
+import javax.sql.DataSource;
+
+/**
+ * Created by The eXo Platform SAS
+ * Author : Tuan Nguyen tuan08@users.sourceforge.net Apr 4, 2006
+ * This class is a wrapper class for the java.sql.Datasource class.
+ * In additional to the java.sql.Datasourcemethod such getConnection().
+ * The ExoDatasource provides 2 other methods:
+ * DBTableManager getDBTableManager and IDGenerator getIDGenerator()
+ */
+public class ExoDatasource
+{
+
+ /**
+ * Logger.
+ */
+ private static final Log LOG = ExoLogger.getLogger("exo.core.component.organization.database.ExoDatasource");
+
+ final public static int STANDARD_DB_TYPE = 0;
+
+ final public static int HSQL_DB_TYPE = 1;
+
+ final public static int MYSQL_DB_TYPE = 2;
+
+ final public static int DB2_DB_TYPE = 3;
+
+ final public static int DERBY_DB_TYPE = 4;
+
+ final public static int ORACLE_DB_TYPE = 5;
+
+ final public static int SQL_SERVER_TYPE = 6;
+
+ static int totalGetConnect = 0;
+
+ final public static int MSSQL_DB_TYPE = 6;
+
+ final public static int SYSBASE_DB_TYPE = 7;
+
+ final public static int POSTGRES_DB_TYPE = 8;
+
+ private DataSource xaDatasource_;
+
+ private DBTableManager tableManager_;
+
+ private IDGenerator idGenerator_;
+
+ private QueryBuilder queryManager_;
+
+ private String databaseName_;
+
+ private String databaseVersion_;
+
+ private int dbType_ = STANDARD_DB_TYPE;
+
+ Connection conn;
+
+ /**
+ * The constructor should:
+ * 1. Keep track of the datasource object
+ * 2. Create the DBTableManager object base on the datasource information such database type, version
+ * 3. Create an IDGenerator for the datasource
+ *
+ * @param ds
+ * @throws Exception
+ */
+ public ExoDatasource(final DataSource ds) throws Exception
+ {
+ xaDatasource_ = ds;
+ DatabaseMetaData metaData = ds.getConnection().getMetaData();
+
+ databaseName_ = metaData.getDatabaseProductName();
+ databaseVersion_ = metaData.getDatabaseProductVersion();
+
+ String dbname = databaseName_.toLowerCase();
+ LOG.debug("DB Name: " + dbname);
+ if (dbname.indexOf("oracle") >= 0)
+ {
+ dbType_ = ORACLE_DB_TYPE;
+ }
+ else if (dbname.indexOf("hsql") >= 0)
+ {
+ dbType_ = HSQL_DB_TYPE;
+ }
+ else if (dbname.indexOf("mysql") >= 0)
+ {
+ dbType_ = MYSQL_DB_TYPE;
+ }
+ else if (dbname.indexOf("derby") >= 0)
+ {
+ dbType_ = DERBY_DB_TYPE;
+ }
+ else if (dbname.indexOf("db2") >= 0)
+ {
+ dbType_ = DB2_DB_TYPE;
+ }
+ else if (dbname.indexOf("server") >= 0)
+ {
+ dbType_ = SQL_SERVER_TYPE;
+ }
+ else
+ {
+ dbType_ = STANDARD_DB_TYPE;
+ }
+
+ tableManager_ = DBTableManager.createDBTableManager(this);
+ idGenerator_ = new IDGenerator(this);
+ queryManager_ = new QueryBuilder(dbType_);
+ }
+
+ /**
+ * This method should return the real Datasource object
+ *
+ * @return
+ */
+ public DataSource getDatasource()
+ {
+ return xaDatasource_;
+ }
+
+ /**
+ * This method should call the datasource getConnection method and return the
+ * Connection object. The developer can add some debug code or broadcast an
+ * event here.
+ *
+ * @return
+ * @throws Exception
+ */
+ public Connection getConnection() throws Exception
+ {
+ return xaDatasource_.getConnection();
+ }
+
+ /**
+ * This method should delegate to the method close of the Connection object.
+ * The developer can add debug or broadcast an event here.
+ *
+ * @param conn
+ * @throws Exception
+ */
+ public void closeConnection(Connection conn) throws Exception
+ {
+ conn.close();
+ }
+
+ /**
+ * This method should delegate to the commit() method of the Connection
+ * object. The developer can add the debug code here
+ *
+ * @param conn
+ * @throws Exception
+ */
+ public void commit(Connection conn) throws Exception
+ {
+ conn.setAutoCommit(false);
+ conn.commit();
+ }
+
+ /**
+ * This method should return the DBTableManager object. The DBTableManager
+ * object should be initialized in the constructor according to the database
+ * type and version
+ *
+ * @return
+ */
+ public DBTableManager getDBTableManager()
+ {
+ return tableManager_;
+ }
+
+ /**
+ * This method should return the IDGenerator object, the developer can use the
+ * id generator to generate an unique long id for an db object
+ *
+ * @return
+ */
+ public IDGenerator getIDGenerator()
+ {
+ return idGenerator_;
+ }
+
+ public int getDatabaseType()
+ {
+ return dbType_;
+ }
+
+ public String getDatabaseName()
+ {
+ return databaseName_;
+ }
+
+ public String getDatabaseVersion()
+ {
+ return databaseVersion_;
+ }
+
+ public QueryBuilder getQueryBuilder()
+ {
+ return queryManager_;
+ }
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/HibernateService.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/HibernateService.java
new file mode 100644
index 00000000..bd188a59
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/HibernateService.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.cfg.Configuration;
+
+import java.io.Serializable;
+import java.util.Collection;
+
+/**
+ * Created by The eXo Platform SAS
+ * Author : Tuan Nguyen tuan08@users.sourceforge.net
+ * Date: Jun 14, 2003 Time: 1:12:22 PM
+ */
+public interface HibernateService
+{
+ public Configuration getHibernateConfiguration();
+
+ public Session openSession();
+
+ public Session openNewSession();
+
+ public void closeSession(Session session);
+
+ /** Close the session that assign to the current thread */
+ public void closeSession();
+
+ SessionFactory getSessionFactory();
+
+ public Object findOne(Session session, String query, String id) throws Exception;
+
+ public Collection> findAll(Session session, String query) throws Exception;
+
+ public Object findExactOne(Session session, String query, String id) throws Exception;
+
+ public Object findOne(Class> clazz, java.io.Serializable id) throws Exception;
+
+ public Object findOne(ObjectQuery q) throws Exception;
+
+ public Object create(Object obj) throws Exception;
+
+ public Object update(Object obj) throws Exception;
+
+ public Object save(Object obj) throws Exception;
+
+ public Object remove(Object obj) throws Exception;
+
+ public Object remove(Class> clazz, Serializable id) throws Exception;
+
+ public Object remove(Session session, Class> clazz, Serializable id) throws Exception;
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/MSSQLServerTableManager.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/MSSQLServerTableManager.java
new file mode 100644
index 00000000..9862b984
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/MSSQLServerTableManager.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import org.exoplatform.services.database.annotation.TableField;
+
+/**
+ * Created by The eXo Platform SAS
+ * Author : Le Bien Thuy lebienthuy@exoplatform.com Apr 4, 2006
+ */
+public class MSSQLServerTableManager extends StandardSQLTableManager
+{
+
+ public MSSQLServerTableManager(ExoDatasource datasource)
+ {
+ super(datasource);
+ }
+
+ protected void appendDateField(TableField field, StringBuilder builder)
+ {
+ builder.append(field.name()).append(" DATETIME");
+ }
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/ObjectQuery.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/ObjectQuery.java
new file mode 100644
index 00000000..c2f6bbd4
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/ObjectQuery.java
@@ -0,0 +1,429 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Tuan Nguyen (tuan08@users.sourceforge.net)
+ * @since Nov 25, 2004
+ * @version $Id: ObjectQuery.java 6006 2006-06-06 10:01:27Z thangvn $
+ */
+public class ObjectQuery
+{
+
+ private Class> type_;
+
+ private String orderBy_;
+
+ private String groupBy_;
+
+ private List parameters_;
+
+ private List selectParameter_;
+
+ public ObjectQuery(Class> type)
+ {
+ type_ = type;
+ parameters_ = new ArrayList(3);
+ selectParameter_ = new ArrayList(10);
+ }
+
+ public ObjectQuery addEQ(String field, Object value)
+ {
+ if (value != null)
+ {
+ parameters_.add(new Parameter(" = ", field, value));
+ }
+ return this;
+ }
+
+ public ObjectQuery addGT(String field, Object value)
+ {
+ if (value != null)
+ {
+ parameters_.add(new Parameter(" > ", field, value));
+ }
+ return this;
+ }
+
+ public ObjectQuery addLT(String field, Object value)
+ {
+ if (value != null)
+ {
+ parameters_.add(new Parameter(" < ", field, value));
+ }
+ return this;
+ }
+
+ public ObjectQuery addLIKE(String field, String value)
+ {
+ if (value != null && value.length() > 0)
+ {
+ parameters_.add(new Parameter(" LIKE ", field, optimizeInputString(value)));
+ }
+ return this;
+ }
+
+ public String optimizeInputString(String value)
+ {
+ value = value.replace('*', '%');
+ return value;
+ }
+
+ public ObjectQuery addSUM(String field)
+ {
+ selectParameter_.add(new Parameter("SUM", field));
+ return this;
+ }
+
+ public ObjectQuery addSelect(String field)
+ {
+ selectParameter_.add(new Parameter("FIELDSELECT", field));
+ return this;
+ }
+
+ public ObjectQuery addSelectCount(String type)
+ {
+ selectParameter_.add(new Parameter("COUNTSELECT", type));
+ return this;
+ }
+
+ public ObjectQuery addSelectMaxMin(String op, String field)
+ {
+ selectParameter_.add(new Parameter(op, field));
+ return this;
+ }
+
+ public ObjectQuery setGroupBy(String field)
+ {
+ groupBy_ = " GROUP BY o." + field;
+ return this;
+ }
+
+ public ObjectQuery setAscOrderBy(String field)
+ {
+ orderBy_ = " ORDER BY o." + field + " asc";
+ return this;
+ }
+
+ public ObjectQuery setDescOrderBy(String field)
+ {
+ orderBy_ = " ORDER BY o." + field + " desc";
+ return this;
+ }
+
+ public String getHibernateQuery()
+ {
+ StringBuffer b = new StringBuffer();
+ b.append("from o in class ").append(type_.getName());
+ if (parameters_.size() > 0)
+ {
+ b.append(" WHERE ");
+ for (int i = 0; i < parameters_.size(); i++)
+ {
+ if (i > 0)
+ b.append(" AND ");
+ Parameter p = parameters_.get(i);
+ if (p.value_ instanceof String)
+ {
+ if (p.field_.startsWith("UPPER") || p.field_.startsWith("LOWER"))
+ {
+ b.append(p.field_).append(p.op_).append("'").append(p.value_).append("'");
+ }
+ else
+ {
+ b.append(" o.").append(p.field_).append(p.op_).append("'").append(p.value_).append("'");
+ }
+ }
+ else if (p.value_ instanceof Date)
+ {
+ SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+ String value = ft.format((Date)p.value_);
+ b.append(" o.").append(p.field_).append(p.op_).append("'").append(value).append("'");
+ }
+ else
+ {
+ b.append(" o.").append(p.field_).append(p.op_).append(p.value_);
+ }
+ }
+ }
+ if (orderBy_ != null)
+ b.append(orderBy_);
+ return b.toString();
+ }
+
+ /**
+ *
+ * @return
+ */
+ public String getHibernateQueryWithBinding()
+ {
+ StringBuffer b = new StringBuffer();
+ b.append("from o in class ").append(type_.getName());
+ if (parameters_.size() > 0)
+ {
+ b.append(" WHERE ");
+ for (int i = 0; i < parameters_.size(); i++)
+ {
+ if (i > 0)
+ b.append(" AND ");
+ Parameter p = parameters_.get(i);
+ if (p.value_ instanceof String)
+ {
+ if (p.field_.startsWith("UPPER") || p.field_.startsWith("LOWER"))
+ {
+ b.append(p.field_).append(p.op_).append(":").append(p.field_.substring(6, p.field_.length() - 1))
+ .append(i);
+ }
+ else
+ {
+ b.append(" o.").append(p.field_).append(p.op_).append(":").append(p.field_).append(i);
+ }
+ }
+ else if (p.value_ instanceof Date)
+ {
+ b.append(" o.").append(p.field_).append(p.op_).append(":").append(p.field_).append(i);
+ }
+ else
+ {
+ b.append(" o.").append(p.field_).append(p.op_).append(p.value_);
+ }
+ }
+ }
+
+ if (orderBy_ != null)
+ {
+ b.append(orderBy_);
+ }
+
+ return b.toString();
+ }
+
+ /**
+ *
+ * @return
+ */
+ public Map getBindingFields()
+ {
+ Map binding = new HashMap();
+
+ if (parameters_.size() > 0)
+ {
+ for (int i = 0; i < parameters_.size(); i++)
+ {
+ Parameter p = parameters_.get(i);
+ if (p.value_ instanceof String)
+ {
+ if (p.field_.startsWith("UPPER") || p.field_.startsWith("LOWER"))
+ {
+ binding.put(p.field_.substring(6, p.field_.length() - 1) + i, p.value_);
+ }
+ else
+ {
+ binding.put(p.field_ + i, p.value_);
+ }
+ }
+ else if (p.value_ instanceof Date)
+ {
+ binding.put(p.field_ + i, p.value_);
+ }
+ }
+ }
+
+ return binding;
+ }
+
+ public String getHibernateGroupByQuery()
+ {
+ StringBuffer b = new StringBuffer();
+ b.append("select ");
+ if (selectParameter_.size() > 0)
+ {
+ for (int i = 0; i < selectParameter_.size(); i++)
+ {
+ Parameter p = selectParameter_.get(i);
+ if (p.op_.equals("fieldselect"))
+ {
+ b.append("o.").append(p.field_);
+ }
+ else if (p.op_.equals("countselect"))
+ {
+ b.append("COUNT");
+ if (!(p.field_.equals("")) || p.field_.length() > 0)
+ {
+ b.append("(").append(p.field_).append(" o)");
+ }
+ else
+ {
+ b.append("(o)");
+ }
+ }
+ else
+ {
+ b.append(p.op_).append("(").append("o.").append(p.field_).append(") ");
+ }
+ if (i < selectParameter_.size() - 1)
+ b.append(" , ");
+ }
+ }
+ b.append(" from o in class ").append(type_.getName());
+ if (parameters_.size() > 0)
+ {
+ b.append(" where ");
+ for (int i = 0; i < parameters_.size(); i++)
+ {
+ if (i > 0)
+ b.append(" and ");
+ Parameter p = parameters_.get(i);
+ if (p.value_ instanceof String)
+ {
+ b.append(" o.").append(p.field_).append(p.op_).append("'").append(p.value_).append("'");
+ }
+ else if (p.value_ instanceof Date)
+ {
+ SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+ String value = ft.format((Date)p.value_);
+ b.append(" o.").append(p.field_).append(p.op_).append("'").append(value).append("'");
+ }
+ else if (p.op_.equals("MAX") || p.op_.equals("MIN"))
+ {
+ b.append(p.op_).append("(").append("o.").append(p.field_).append(") ");
+ }
+ else
+ {
+ b.append(" o.").append(p.field_).append(p.op_).append(p.value_);
+ }
+ }
+ }
+ if (groupBy_ != null)
+ b.append(groupBy_);
+ if (orderBy_ != null)
+ b.append(orderBy_);
+ return b.toString();
+ }
+
+ public String getHibernateCountQuery()
+ {
+ StringBuffer b = new StringBuffer();
+ b.append("SELECT COUNT(o) FROM o IN CLASS ").append(type_.getName());
+ if (parameters_.size() > 0)
+ {
+ b.append(" WHERE ");
+ for (int i = 0; i < parameters_.size(); i++)
+ {
+ if (i > 0)
+ b.append(" AND ");
+ Parameter p = parameters_.get(i);
+ if (p.value_ instanceof String)
+ {
+ if (p.field_.startsWith("UPPER") || p.field_.startsWith("LOWER"))
+ {
+ b.append(p.field_).append(p.op_).append("'").append(p.value_).append("'");
+ }
+ else
+ {
+ b.append(" o.").append(p.field_).append(p.op_).append("'").append(p.value_).append("'");
+ }
+ }
+ else if (p.value_ instanceof Date)
+ {
+ SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+ String value = ft.format((Date)p.value_);
+ b.append(" o.").append(p.field_).append(p.op_).append("'").append(value).append("'");
+ }
+ else
+ {
+ b.append(" o.").append(p.field_).append(p.op_).append(p.value_);
+ }
+ }
+ }
+ return b.toString();
+ }
+
+ /**
+ *
+ * @return
+ */
+ public String getHibernateCountQueryWithBinding()
+ {
+ StringBuffer b = new StringBuffer();
+ b.append("SELECT COUNT(o) FROM o IN CLASS ").append(type_.getName());
+ if (parameters_.size() > 0)
+ {
+ b.append(" WHERE ");
+ for (int i = 0; i < parameters_.size(); i++)
+ {
+ if (i > 0)
+ b.append(" AND ");
+ Parameter p = parameters_.get(i);
+ if (p.value_ instanceof String)
+ {
+ if (p.field_.startsWith("UPPER") || p.field_.startsWith("LOWER"))
+ {
+ b.append(p.field_).append(p.op_).append(":").append(p.field_.substring(6, p.field_.length() - 1))
+ .append(i);
+ }
+ else
+ {
+ b.append(" o.").append(p.field_).append(p.op_).append(":").append(p.field_).append(i);
+ }
+ }
+ else if (p.value_ instanceof Date)
+ {
+ b.append(" o.").append(p.field_).append(p.op_).append(":").append(p.field_).append(i);
+ }
+ else
+ {
+ b.append(" o.").append(p.field_).append(p.op_).append(p.value_);
+ }
+ }
+ }
+ return b.toString();
+ }
+
+ static class Parameter
+ {
+ String op_;
+
+ String field_;
+
+ String label_;
+
+ Object value_;
+
+ Parameter(String op, String field, Object value)
+ {
+ op_ = op;
+ field_ = field;
+ value_ = value;
+ }
+
+ Parameter(String op, String field)
+ {
+ op_ = op;
+ field_ = field;
+ }
+ }
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/OracleTableManager.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/OracleTableManager.java
new file mode 100644
index 00000000..8c62a940
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/OracleTableManager.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import org.exoplatform.services.database.annotation.TableField;
+
+/**
+ * Created by The eXo Platform SAS
+ * Author : Le Bien Thuy lebienthuy@exoplatform.com Apr 4, 2006
+ */
+public class OracleTableManager extends StandardSQLTableManager
+{
+
+ public OracleTableManager(ExoDatasource datasource)
+ {
+ super(datasource);
+ }
+
+ @Override
+ protected void appendId(StringBuilder builder)
+ {
+ builder.append("ID INT NOT NULL PRIMARY KEY, ");
+ }
+
+ @Override
+ protected void appendLongField(TableField field, StringBuilder builder)
+ {
+ builder.append(field.name()).append(" NUMBER");
+ }
+
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/QueryBuilder.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/QueryBuilder.java
new file mode 100644
index 00000000..f527d1e1
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/QueryBuilder.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import org.exoplatform.services.database.annotation.Query;
+import org.exoplatform.services.database.annotation.Table;
+import org.exoplatform.services.database.annotation.TableField;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+/**
+ * Created by The eXo Platform SAS
+ * Author : Nhu Dinh Thuan nhudinhthuan@exoplatform.com Mar 30, 2007
+ */
+public class QueryBuilder
+{
+
+ private int databaseType = ExoDatasource.STANDARD_DB_TYPE;
+
+ public QueryBuilder()
+ {
+ }
+
+ public QueryBuilder(int dbType)
+ {
+ databaseType = dbType;
+ }
+
+ public String createSelectQuery(Class type, long id) throws Exception
+ {
+ Table table = type.getAnnotation(Table.class);
+ TableField[] fields = table.field();
+
+ StringBuilder query = new StringBuilder("SELECT ");
+ for (int i = 0; i < fields.length; i++)
+ {
+ TableField field = fields[i];
+ query.append(field.name());
+ if (i != fields.length - 1)
+ query.append(", ");
+ }
+ query.append(" FROM ").append(table.name());
+ if (id > -1)
+ query.append(" WHERE ID = ").append(id);
+ return query.toString();
+ }
+
+ public String createUpdateQuery(Class type) throws Exception
+ {
+ Table table = type.getAnnotation(Table.class);
+ TableField[] fields = table.field();
+
+ StringBuilder query = new StringBuilder("UPDATE ").append(table.name()).append(" SET ");
+ for (int i = 0; i < fields.length; i++)
+ {
+ TableField field = fields[i];
+ query.append(field.name()).append(" = '$").append(field.name()).append('\'');
+ if (i != fields.length - 1)
+ query.append(", ");
+ else
+ query.append(" WHERE ID = $id");
+ }
+ return query.toString();
+ }
+
+ public String createInsertQuery(Class type) throws Exception
+ {
+ Table table = type.getAnnotation(Table.class);
+ TableField[] fields = table.field();
+
+ StringBuilder query = new StringBuilder("INSERT INTO ").append(table.name()).append("(ID, ");
+ for (int i = 0; i < fields.length; i++)
+ {
+ TableField field = fields[i];
+ query.append(field.name());
+ if (i != fields.length - 1)
+ query.append(", ");
+ else
+ query.append(") VALUES($id, ");
+ }
+
+ for (int i = 0; i < fields.length; i++)
+ {
+ query.append("'$").append(fields[i].name()).append('\'');
+ if (i != fields.length - 1)
+ query.append(", ");
+ else
+ query.append(")");
+ }
+ return query.toString();
+ }
+
+ public String createUpdateQuery(Class type, long id) throws Exception
+ {
+ Table table = type.getAnnotation(Table.class);
+ TableField[] fields = table.field();
+
+ StringBuilder query = new StringBuilder("UPDATE ").append(table.name()).append(" SET ");
+ for (int i = 0; i < fields.length; i++)
+ {
+ TableField field = fields[i];
+ query.append(field.name()).append(" = ?");
+ if (i != fields.length - 1)
+ query.append(", ");
+ else
+ query.append(" WHERE ID = ").append(id);
+ }
+
+ return query.toString();
+ }
+
+ public String createInsertQuery(Class clazz, long id) throws Exception
+ {
+ Table table = clazz.getAnnotation(Table.class);
+ TableField[] fields = table.field();
+
+ StringBuilder query = new StringBuilder("INSERT INTO ").append(table.name()).append("(ID, ");
+ for (int i = 0; i < fields.length; i++)
+ {
+ TableField field = fields[i];
+ query.append(field.name());
+ if (i != fields.length - 1)
+ query.append(", ");
+ }
+ query.append(") VALUES(").append(id).append(", ");
+
+ for (int i = 0; i < fields.length; i++)
+ {
+ query.append("?");
+ if (i != fields.length - 1)
+ query.append(", ");
+ else
+ query.append(")");
+ }
+ return query.toString();
+ }
+
+ public String createRemoveQuery(Class type, long id) throws Exception
+ {
+ Table table = type.getAnnotation(Table.class);
+ StringBuilder builder = new StringBuilder("DELETE FROM ");
+ builder.append(table.name()).append(" WHERE ID = ").append(id).toString();
+ return builder.toString();
+ }
+
+ public > String getQuery(Class clazz, String name) throws Exception
+ {
+ Query query = clazz.getAnnotation(Query.class);
+ String value = null;
+ if (query != null && query.name().equals(name))
+ value = getQuery(query);
+ if (value != null)
+ return value;
+ List list = ReflectionUtil.getMethod(clazz, name);
+ for (Method method : list)
+ {
+ query = method.getAnnotation(Query.class);
+ if (query != null && query.name().equals(name))
+ value = getQuery(query);
+ if (value != null)
+ return value;
+ }
+ return null;
+ }
+
+ private String getQuery(Query query)
+ {
+ switch (databaseType)
+ {
+ case ExoDatasource.STANDARD_DB_TYPE :
+ return query.standardSQL();
+ case ExoDatasource.HSQL_DB_TYPE :
+ if (query.hsqlSQL().length() > 0)
+ return query.hsqlSQL();
+ case ExoDatasource.MYSQL_DB_TYPE :
+ if (query.mysqlSQL().length() > 0)
+ return query.mysqlSQL();
+ case ExoDatasource.MSSQL_DB_TYPE :
+ if (query.mssqlSQL().length() > 0)
+ return query.mssqlSQL();
+ case ExoDatasource.ORACLE_DB_TYPE :
+ if (query.oracleSQL().length() > 0)
+ return query.oracleSQL();
+ case ExoDatasource.DB2_DB_TYPE :
+ if (query.db2SQL().length() > 0)
+ return query.db2SQL();
+ case ExoDatasource.DERBY_DB_TYPE :
+ if (query.derbySQL().length() > 0)
+ return query.derbySQL();
+ case ExoDatasource.POSTGRES_DB_TYPE :
+ if (query.postgresSQL().length() > 0)
+ return query.postgresSQL();
+ case ExoDatasource.SYSBASE_DB_TYPE :
+ if (query.sysbaseSQL().length() > 0)
+ return query.sysbaseSQL();
+ default :
+ return query.standardSQL();
+ }
+ }
+
+ public String mapDataToSql(String template, String[][] parameters) throws Exception
+ {
+ StringBuilder builder = new StringBuilder();
+ int i = 0;
+ int start = 0;
+ while (i < template.length())
+ {
+ if (template.charAt(i) != '$')
+ {
+ i++;
+ continue;
+ }
+
+ if (i > 0 && template.charAt(i - 1) == '\\')
+ {
+ builder.append(template.subSequence(start, i - 1));
+ start = i;
+ i++;
+ continue;
+ }
+
+ if (i == template.length() - 1)
+ break;
+
+ int j = i + 1;
+ while (j < template.length())
+ {
+ if (Character.isWhitespace(template.charAt(j)))
+ break;
+ if (template.charAt(j) == '\'' && template.charAt(j - 1) != '\\')
+ break;
+ if (template.charAt(j) == ',' && template.charAt(j - 1) != '\\')
+ break;
+ j++;
+ }
+ String name = template.substring(i + 1, j);
+ start = replace(template, builder, parameters, name, start, i);
+ i++;
+ }
+ if (start > 0 && start < template.length())
+ {
+ builder.append(template.subSequence(start, template.length()));
+ }
+ if (builder.length() < 1)
+ return template.toString();
+ return builder.toString();
+ }
+
+ private int replace(String template, StringBuilder builder, String[][] parameters, String name, int start,
+ int current) throws Exception
+ {
+ for (int k = 0; k < parameters.length; k++)
+ {
+ if (!parameters[k][0].equals(name))
+ continue;
+ builder.append(template.subSequence(start, current)).append(parameters[k][1]);
+ return current + 1 + name.length();
+ }
+ return start;
+ }
+
+ public String encode(CharSequence seq)
+ {
+ if (seq.length() < 1)
+ return seq.toString();
+ StringBuilder builder = new StringBuilder();
+ int i = 0;
+ int start = 0;
+ while (i < seq.length())
+ {
+ if (seq.charAt(i) == '\'')
+ {
+ builder.append(seq.subSequence(start, i)).append("''");
+ start = i + 1;
+ }
+ i++;
+ }
+ if (start > 0 && start < seq.length())
+ {
+ builder.append(seq.subSequence(start, seq.length()));
+ }
+ if (builder.length() < 1)
+ return seq.toString();
+ return builder.toString();
+ }
+
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/ReflectionMapper.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/ReflectionMapper.java
new file mode 100644
index 00000000..f78517ef
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/ReflectionMapper.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import org.exoplatform.services.database.annotation.Table;
+import org.exoplatform.services.database.annotation.TableField;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.LineNumberReader;
+import java.io.Reader;
+import java.lang.reflect.Field;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.Types;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Created by The eXo Platform SAS
+ * Author: Nhu Dinh Thuan nhudinhthuan@exoplatform.com Apr 2, 2007
+ */
+public class ReflectionMapper implements DBObjectMapper
+{
+
+ public String[][] toParameters(T bean) throws Exception
+ {
+ Map map = new HashMap();
+ getParameters(bean, bean.getClass(), map);
+
+ String[][] parameters = new String[map.size()][2];
+ Iterator iter = map.keySet().iterator();
+ int i = 0;
+ while (iter.hasNext())
+ {
+ parameters[i][0] = iter.next();
+ parameters[i][1] = map.get(parameters[i][0]);
+ i++;
+ }
+ return parameters;
+ }
+
+ private void getParameters(Object bean, Class> clazz, Map map) throws Exception
+ {
+ Field[] fields = clazz.getDeclaredFields();
+ for (int i = 0; i < fields.length; i++)
+ {
+ Object value = ReflectionUtil.getValue(bean, fields[i]);
+ if (value == null)
+ value = new String();
+ if (value instanceof Calendar)
+ {
+ value = new java.sql.Date(((Calendar)value).getTimeInMillis());
+ }
+ else if (value instanceof Date)
+ {
+ value = new java.sql.Date(((Date)value).getTime());
+ }
+ map.put(fields[i].getName(), value.toString());
+ }
+ if (clazz == DBObject.class)
+ return;
+ Class> superClazz = clazz.getSuperclass();
+ getParameters(superClazz.cast(bean), superClazz, map);
+ }
+
+ public void mapResultSet(ResultSet resultSet, T bean) throws Exception
+ {
+ Class extends DBObject> clazz = bean.getClass();
+ Table table = clazz.getAnnotation(Table.class);
+ TableField[] tableFields = table.field();
+
+ ResultSetMetaData rsmd = resultSet.getMetaData();
+ int numberOfColumns = rsmd.getColumnCount();
+ for (int i = 1; i <= numberOfColumns; i++)
+ {
+ String name = rsmd.getColumnName(i);
+ TableField tableField = searchTableField(tableFields, name);
+ if (tableField == null)
+ continue;
+ String fieldName = tableField.field().length() == 0 ? tableField.name() : tableField.field();
+ Field field = getField(clazz, fieldName);
+ if (field == null)
+ continue;
+ ReflectionUtil.setValue(bean, field, getValue(rsmd.getColumnType(i), resultSet, name));
+ }
+ }
+
+ public void mapUpdate(T bean, PreparedStatement statement) throws Exception
+ {
+ Class extends DBObject> clazz = bean.getClass();
+ Table table = clazz.getAnnotation(Table.class);
+ TableField[] tableFields = table.field();
+
+ int i = 1;
+ for (TableField tableField : tableFields)
+ {
+ String fieldName = tableField.field().length() == 0 ? tableField.name() : tableField.field();
+ Field field = getField(clazz, fieldName);
+ if (field == null)
+ continue;
+ statement.setObject(i, ReflectionUtil.getValue(bean, field));
+ i++;
+ }
+ }
+
+ private Field getField(Class> clazz, String name) throws Exception
+ {
+ Field field = clazz.getDeclaredField(name);
+ if (field != null)
+ return field;
+ if (clazz == DBObject.class)
+ return null;
+ return getField(clazz.getSuperclass(), name);
+ }
+
+ private Object getValue(int type, ResultSet resultSet, String name) throws Exception
+ {
+ switch (type)
+ {
+ case Types.CLOB :
+ return loadClob(resultSet, name);
+ case Types.BLOB :
+ return loadBlob(resultSet, name);
+ case Types.BINARY :
+ return loadBinary(resultSet, name);
+ default :
+ return resultSet.getObject(name.toUpperCase());
+ }
+ }
+
+ private synchronized byte[] loadBinary(ResultSet resultSet, String name) throws Exception
+ {
+ InputStream input = resultSet.getBinaryStream(name);
+ if (input == null)
+ return null;
+ ByteArrayOutputStream output = loadInputStream(input);
+ return output.toByteArray();
+ }
+
+ private synchronized byte[] loadBlob(ResultSet resultSet, String name) throws Exception
+ {
+ Blob clob = resultSet.getBlob(name);
+ if (clob == null)
+ return null;
+ ByteArrayOutputStream output = loadInputStream(clob.getBinaryStream());
+ return output.toByteArray();
+ }
+
+ private synchronized String loadClob(ResultSet resultSet, String name) throws Exception
+ {
+ Clob clob = resultSet.getClob(name);
+ if (clob == null)
+ return null;
+ Reader input = clob.getCharacterStream();
+ if (input == null)
+ return null;
+ LineNumberReader lineReader = new LineNumberReader(input);
+ StringBuilder builder = new StringBuilder();
+ String line;
+ while ((line = lineReader.readLine()) != null)
+ {
+ builder.append(line);
+ }
+ return builder.toString();
+ }
+
+ private ByteArrayOutputStream loadInputStream(InputStream input) throws Exception
+ {
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ byte[] data = new byte[1024];
+ int available = -1;
+ while ((available = input.read(data)) > -1)
+ {
+ output.write(data, 0, available);
+ }
+ return output;
+ }
+
+ private TableField searchTableField(TableField[] tableFields, String name)
+ {
+ for (TableField tableField : tableFields)
+ {
+ if (tableField.name().equals(name) && tableField.field().length() > 0)
+ return tableField;
+ }
+ for (TableField field : tableFields)
+ {
+ if (field.name().equals(name) && field.field().length() < 1)
+ return field;
+ }
+ return null;
+ }
+
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/ReflectionUtil.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/ReflectionUtil.java
new file mode 100644
index 00000000..5b4c8a44
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/ReflectionUtil.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by The eXo Platform SAS
+ * Author : Nhu Dinh Thuan nhudinhthuan@exoplatform.com Mar 29, 2007
+ */
+public class ReflectionUtil
+{
+
+ private static final Log LOG = ExoLogger.getLogger("exo.core.component.database.ReflectionUtil");
+
+ public final static void setValue(Object bean, Field field, Object value) throws Exception
+ {
+ Class extends Object> clazz = bean.getClass();
+ Method method = getMethod("set", field, clazz);
+ if (method != null)
+ method.invoke(bean, new Object[]{value});
+ method = getMethod("put", field, clazz);
+ if (method != null)
+ method.invoke(bean, new Object[]{value});
+ field.setAccessible(true);
+ field.set(bean, value);
+ }
+
+ public final static Object getValue(Object bean, Field field) throws Exception
+ {
+ Class extends Object> clazz = bean.getClass();
+ Method method = getMethod("get", field, clazz);
+ if (method != null)
+ return method.invoke(bean, new Object[]{});
+ method = getMethod("is", field, clazz);
+ if (method != null)
+ return method.invoke(bean, new Object[]{});
+ field.setAccessible(true);
+ return field.get(bean);
+ }
+
+ public final static Method getMethod(String prefix, Field field, Class extends Object> clazz) throws Exception
+ {
+ StringBuilder name = new StringBuilder(field.getName());
+ name.setCharAt(0, Character.toUpperCase(name.charAt(0)));
+ name.insert(0, prefix);
+ try
+ {
+ Method method = clazz.getDeclaredMethod(name.toString(), new Class[]{});
+ return method;
+ }
+ catch (Exception e)
+ {
+ if (LOG.isTraceEnabled())
+ {
+ LOG.trace("An exception occurred: " + e.getMessage());
+ }
+ }
+ return null;
+ }
+
+ public final static List getMethod(Class> clazz, String name) throws Exception
+ {
+ Method[] methods = clazz.getDeclaredMethods();
+ List list = new ArrayList();
+ for (Method method : methods)
+ {
+ if (method.getName().equals(name))
+ list.add(method);
+ }
+ return list;
+ }
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/StandardSQLTableManager.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/StandardSQLTableManager.java
new file mode 100644
index 00000000..1f4360ce
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/StandardSQLTableManager.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import org.exoplatform.services.database.annotation.Table;
+import org.exoplatform.services.database.annotation.TableField;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+/**
+ * Created by The eXo Platform SAS
+ * Author : Tuan Nguyen tuan08@users.sourceforge.net Apr 4, 2006
+ */
+public class StandardSQLTableManager extends DBTableManager
+{
+
+ /**
+ * Logger.
+ */
+ private static final Log LOG = ExoLogger
+ .getLogger("exo.core.component.organization.database.StandardSQLTableManager");
+
+ private ExoDatasource exoDatasource;
+
+ public StandardSQLTableManager(ExoDatasource datasource)
+ {
+ exoDatasource = datasource;
+ }
+
+ public void createTable(Class type, boolean dropIfExist) throws Exception
+ {
+ Table table = type.getAnnotation(Table.class);
+ if (table == null)
+ {
+ throw new Exception("Cannot find the annotation for class " + type.getClass().getName());
+ }
+ StringBuilder builder = new StringBuilder(1000);
+ builder.append("CREATE TABLE ").append(table.name()).append(" (");
+ appendId(builder);
+ TableField[] fields = table.field();
+ for (int i = 0; i < fields.length; i++)
+ {
+ TableField field = fields[i];
+ String fieldType = field.type();
+ if ("string".equals(fieldType))
+ {
+ appendStringField(field, builder);
+ }
+ else if ("int".equals(fieldType))
+ {
+ appendIntegerField(field, builder);
+ }
+ else if ("long".equals(fieldType))
+ {
+ appendLongField(field, builder);
+ }
+ else if ("float".equals(fieldType))
+ {
+ appendFloatField(field, builder);
+ }
+ else if ("double".equals(fieldType))
+ {
+ appendDoubleField(field, builder);
+ }
+ else if ("boolean".equals(fieldType))
+ {
+ appendBooleanField(field, builder);
+ }
+ else if ("date".equals(fieldType))
+ {
+ appendDateField(field, builder);
+ }
+ else if ("binary".equals(fieldType))
+ {
+ appendBinaryField(field, builder);
+ }
+ if (i != fields.length - 1)
+ builder.append(", ");
+ }
+ builder.append(")");
+
+ // print out the sql string
+ Connection conn = exoDatasource.getConnection();
+ conn.setAutoCommit(false);
+ Statement statement = conn.createStatement();
+ LOG.debug("QUERY: \n " + builder + "\n");
+ if (dropIfExist && hasTable(type))
+ statement.execute("DROP TABLE IF EXISTS " + table.name());
+ statement.execute(builder.toString());
+ statement.close();
+ conn.commit();
+ exoDatasource.closeConnection(conn);
+ }
+
+ public void dropTable(Class type) throws Exception
+ {
+ Table table = type.getAnnotation(Table.class);
+ if (table == null)
+ {
+ throw new Exception("Can not find the annotation for class " + type.getClass().getName());
+ }
+ Connection conn = exoDatasource.getConnection();
+ Statement s = conn.createStatement();
+ s.execute("DROP TABLE " + table.name());
+ s.close();
+ conn.commit();
+ exoDatasource.closeConnection(conn);
+ }
+
+ public boolean hasTable(Class type) throws Exception
+ {
+ Table table = type.getAnnotation(Table.class);
+ if (table == null)
+ {
+ throw new Exception("Can not find the annotation for class " + type.getClass().getName());
+ }
+ Connection connection = exoDatasource.getConnection();
+ Statement statement = connection.createStatement();
+ try
+ {
+ if (statement.execute("SELECT 1 FROM " + table.name()) == true)
+ return true;
+ }
+ catch (SQLException ex)
+ {
+ return false;
+ }
+ finally
+ {
+ statement.close();
+ exoDatasource.closeConnection(connection);
+ }
+ return false;
+ }
+
+ protected void appendId(StringBuilder builder)
+ {
+ builder.append("ID BIGINT NOT NULL PRIMARY KEY, ");
+ }
+
+ protected void appendStringField(TableField field, StringBuilder builder) throws Exception
+ {
+ if (field.length() < 1)
+ {
+ throw new Exception("You forget to specify the length for field " + field.name() + " , type " + field.type());
+ }
+ builder.append(field.name()).append(" ").append("VARCHAR(" + field.length() + ")");
+ if (!field.nullable())
+ builder.append(" NOT NULL ");
+ }
+
+ protected void appendIntegerField(TableField field, StringBuilder builder)
+ {
+ builder.append(field.name()).append(" INTEGER");
+ }
+
+ protected void appendLongField(TableField field, StringBuilder builder)
+ {
+ builder.append(field.name()).append(" BIGINT");
+ }
+
+ protected void appendFloatField(TableField field, StringBuilder builder)
+ {
+ builder.append(field.name()).append(" REAL");
+ }
+
+ protected void appendDoubleField(TableField field, StringBuilder builder)
+ {
+ builder.append(field.name()).append(" DOUBLE");
+ }
+
+ protected void appendBooleanField(TableField field, StringBuilder builder)
+ {
+ builder.append(field.name()).append(" BIT");
+ }
+
+ protected void appendDateField(TableField field, StringBuilder builder)
+ {
+ builder.append(field.name()).append(" DATE");
+ }
+
+ protected void appendDateTimeField(TableField field, StringBuilder builder)
+ {
+ builder.append(field.name()).append(" DATETIME");
+ }
+
+ protected void appendBinaryField(TableField field, StringBuilder builder)
+ {
+ builder.append(field.name()).append(" VARBINARY");
+ }
+
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/XResources.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/XResources.java
new file mode 100644
index 00000000..5c5da958
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/XResources.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import java.util.HashMap;
+
+/**
+ * @author Tuan Nguyen (tuan08@users.sourceforge.net)
+ * @since Oct 22, 2004
+ * @version $Id: XResources.java 5332 2006-04-29 18:32:44Z geaz $
+ */
+public class XResources extends HashMap
+{
+
+ public Object getResource(Class> cl)
+ {
+ return get(cl);
+ }
+
+ public XResources addResource(Class> cl, Object resource)
+ {
+ put(cl, resource);
+ return this;
+ }
+
+ public Object removeResource(Class> cl)
+ {
+ return remove(cl);
+ }
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/annotation/Query.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/annotation/Query.java
new file mode 100644
index 00000000..c5ff23c4
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/annotation/Query.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Created by The eXo Platform SAS Author : Nhu Dinh Thuan
+ * nhudinhthuan@exoplatform.com Mar 30, 2007
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface Query {
+ String name();
+
+ String standardSQL();
+
+ String mysqlSQL() default "";
+
+ String mssqlSQL() default "";
+
+ String oracleSQL() default "";
+
+ String postgresSQL() default "";
+
+ String hsqlSQL() default "";
+
+ String derbySQL() default "";
+
+ String sysbaseSQL() default "";
+
+ String db2SQL() default "";
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/annotation/Table.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/annotation/Table.java
new file mode 100644
index 00000000..66716404
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/annotation/Table.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Author : Nhu Dinh Thuan nhudinhthuan@exoplatform.com Jul 5, 2006
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface Table {
+ String name();
+
+ TableField[] field();
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/annotation/TableField.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/annotation/TableField.java
new file mode 100644
index 00000000..ab0ae931
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/annotation/TableField.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Author : Nhu Dinh Thuan nhudinhthuan@exoplatform.com Jul 5, 2006
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface TableField {
+ String name();
+
+ String field() default "";
+
+ String type();
+
+ int length() default -1;
+
+ boolean unique() default false;
+
+ boolean nullable() default true;
+
+ String defaultValue() default "";
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/creator/DBConnectionInfo.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/creator/DBConnectionInfo.java
new file mode 100644
index 00000000..b7fb814f
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/creator/DBConnectionInfo.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database.creator;
+
+import java.util.Map;
+
+/**
+ * Class contains needed database connection information.
+ *
+ * @author Anatoliy Bazko
+ * @version $Id$
+ */
+public class DBConnectionInfo
+{
+ private final Map connectionProperties;
+
+ private final String dbName;
+
+ /**
+ * DBConnectionInfo constructor.
+ * @param connectionProperties
+ * connection properties
+ */
+ public DBConnectionInfo(String dbName, Map connectionProperties)
+ {
+ this.dbName = dbName;
+ this.connectionProperties = connectionProperties;
+ }
+
+ public Map getProperties()
+ {
+ return connectionProperties;
+ }
+
+ public String getDBName()
+ {
+ return dbName;
+ }
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/creator/DBCreator.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/creator/DBCreator.java
new file mode 100644
index 00000000..d6c3aaf4
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/creator/DBCreator.java
@@ -0,0 +1,461 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database.creator;
+
+import org.exoplatform.commons.utils.ClassLoading;
+import org.exoplatform.commons.utils.IOUtil;
+import org.exoplatform.container.configuration.ConfigurationException;
+import org.exoplatform.container.configuration.ConfigurationManager;
+import org.exoplatform.container.xml.InitParams;
+import org.exoplatform.container.xml.PropertiesParam;
+import org.exoplatform.container.xml.Property;
+import org.exoplatform.services.database.utils.DialectConstants;
+import org.exoplatform.services.database.utils.DialectDetecter;
+import org.exoplatform.services.database.utils.JDBCUtils;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * @author Anatoliy Bazko
+ * @version $Id$
+ */
+public class DBCreator
+{
+
+ private final static String CONNECTION_PROPERTIES = "db-connection";
+
+ private final static String DRIVER_NAME = "driverClassName";
+
+ private final static String SERVER_URL = "url";
+
+ private final static String USERNAME = "username";
+
+ private final static String PASSWORD = "password";
+
+ private final static String DB_CREATION_PROPERTIES = "db-creation";
+
+ private final static String DB_SCRIPT_PATH = "scriptPath";
+
+ private final static String DB_USERNAME = "username";
+
+ private final static String DB_PASSWORD = "password";
+
+ /**
+ * Database template.
+ */
+ public static final String DATABASE_TEMPLATE = "${database}";
+
+ /**
+ * User name template.
+ */
+ public static final String USERNAME_TEMPLATE = "${username}";
+
+ /**
+ * Password template.
+ */
+ public static final String PASSWORD_TEMPLATE = "${password}";
+
+ /**
+ * Server url.
+ */
+ protected final String serverUrl;
+
+ /**
+ * Connection properties.
+ */
+ protected final Map connectionProperties;
+
+ /**
+ * DDL script database creation.
+ */
+ protected final String dbScript;
+
+ /**
+ * User name for new database.
+ */
+ protected final String dbUserName;
+
+ /**
+ * User's password.
+ */
+ protected final String dbPassword;
+
+ /**
+ * DBCreator constructor.
+ *
+ * @param serverUrl Server URL
+ * @param connectionProperties Connection properties
+ * @param scriptPath Script path
+ * @param dbUserName DB username
+ * @param dbPassword DB password
+ * @param cm configuration manager instance
+ */
+ public DBCreator(String serverUrl, Map connectionProperties, String scriptPath, String dbUserName,
+ String dbPassword, ConfigurationManager cm) throws ConfigurationException
+ {
+ this.serverUrl = serverUrl;
+ this.connectionProperties = connectionProperties;
+ this.dbUserName = dbUserName;
+ this.dbPassword = dbPassword;
+ this.dbScript = readScript(scriptPath, cm);
+ }
+
+ /**
+ * DBCreator constructor.
+ *
+ * @param params
+ * Initializations parameters
+ * @param cm
+ * configuration manager instance
+ */
+ public DBCreator(InitParams params, ConfigurationManager cm) throws ConfigurationException
+ {
+ if (params == null)
+ {
+ throw new ConfigurationException("Initializations parameters expected");
+ }
+
+ PropertiesParam prop = params.getPropertiesParam(CONNECTION_PROPERTIES);
+
+ if (prop != null)
+ {
+ if (prop.getProperty(DRIVER_NAME) == null)
+ {
+ throw new ConfigurationException("driverClassName expected in db-connection properties section");
+ }
+
+ serverUrl = prop.getProperty(SERVER_URL);
+ if (serverUrl == null)
+ {
+ throw new ConfigurationException("url expected in db-connection properties section");
+ }
+
+ if (prop.getProperty(USERNAME) == null)
+ {
+ throw new ConfigurationException("username expected in db-connection properties section");
+ }
+
+ if (prop.getProperty(PASSWORD) == null)
+ {
+ throw new ConfigurationException("password expected in db-connection properties section");
+ }
+
+ // Store all connection properties into single map
+ Iterator pit = prop.getPropertyIterator();
+ connectionProperties = new HashMap();
+ while (pit.hasNext())
+ {
+ Property p = pit.next();
+ if (!p.getName().equalsIgnoreCase(SERVER_URL))
+ {
+ connectionProperties.put(p.getName(), p.getValue());
+ }
+ }
+ }
+ else
+ {
+ throw new ConfigurationException("db-connection properties expected in initializations parameters");
+ }
+
+ prop = params.getPropertiesParam(DB_CREATION_PROPERTIES);
+ if (prop != null)
+ {
+ String scriptPath = prop.getProperty(DB_SCRIPT_PATH);
+ if (scriptPath != null)
+ {
+ this.dbScript = readScript(scriptPath, cm);
+ }
+ else
+ {
+ throw new ConfigurationException("scriptPath expected in db-creation properties section");
+ }
+
+ this.dbUserName = prop.getProperty(DB_USERNAME);
+ if (dbUserName == null)
+ {
+ throw new ConfigurationException("username expected in db-creation properties section");
+ }
+
+ this.dbPassword = prop.getProperty(DB_PASSWORD);
+ if (dbPassword == null)
+ {
+ throw new ConfigurationException("password expected in db-creation properties section");
+ }
+ }
+ else
+ {
+ throw new ConfigurationException("db-creation properties expected in initializations parameters");
+ }
+ }
+
+ /**
+ * Execute DDL script for new database creation. Database name are passed as parameter,
+ * user name and password are passed via configuration. In script database name, user name
+ * and password defined via templates as ${database}, ${username} and ${password} respectively.
+ * At execution time method replaces templates by real values.
+ *
+ * @param dbName
+ * new database name
+ * @throws DBCreatorException
+ * if any error occurs
+ */
+ public DBConnectionInfo createDatabase(final String dbName) throws DBCreatorException
+ {
+ Connection conn = openConnection();
+ try
+ {
+ String dialect = DialectDetecter.detect(conn.getMetaData());
+
+ if (dialect.equalsIgnoreCase(DialectConstants.DB_DIALECT_MSSQL)
+ || dialect.equalsIgnoreCase(DialectConstants.DB_DIALECT_SYBASE))
+ {
+ executeInAutoCommitMode(conn, dbName);
+ }
+ else
+ {
+ executeInBatchMode(conn, dbName);
+ }
+
+ return constructDBConnectionInfo(dbName, dialect);
+ }
+ catch (SQLException e)
+ {
+ throw new DBCreatorException("Can't execute SQL script : " + JDBCUtils.getFullMessage(e), e);
+ }
+ finally
+ {
+ try
+ {
+ conn.close();
+ }
+ catch (SQLException e)
+ {
+ throw new DBCreatorException("Can't close connection", e);
+ }
+ }
+ }
+
+ /**
+ * Get database connection info.
+ *
+ * @param dbName
+ * new database name
+ * @throws DBCreatorException
+ * if any error occurs or database is not available
+ */
+ public DBConnectionInfo getDBConnectionInfo(String dbName) throws DBCreatorException
+ {
+ Connection conn = openConnection();
+ try
+ {
+ return constructDBConnectionInfo(dbName, DialectDetecter.detect(conn.getMetaData()));
+ }
+ catch (SQLException e)
+ {
+ throw new DBCreatorException("Can not get database connection information", e);
+ }
+ finally
+ {
+ try
+ {
+ conn.close();
+ }
+ catch (SQLException e)
+ {
+ throw new DBCreatorException("Can't close connection", e);
+ }
+ }
+ }
+
+ /**
+ * Executes DDL script in generic batch mode.
+ *
+ * @param conn
+ * connection to server
+ * @param dbName
+ * database name
+ * @throws SQLException
+ * if any errors occurs
+ */
+ private void executeInBatchMode(Connection conn, String dbName) throws SQLException
+ {
+ Statement statement = conn.createStatement();
+ for (String scr : dbScript.split(";"))
+ {
+ scr = scr.replace(DATABASE_TEMPLATE, dbName);
+ scr = scr.replace(USERNAME_TEMPLATE, dbUserName);
+ scr = scr.replace(PASSWORD_TEMPLATE, dbPassword);
+
+ String s = JDBCUtils.cleanWhitespaces(scr.trim());
+ if (s.length() > 0)
+ {
+ statement.addBatch(s);
+ }
+ }
+ statement.executeBatch();
+ }
+
+ /**
+ * Construct database url connection depending on specific database.
+ *
+ * @param dbName
+ * database name
+ * @param dialect
+ * dialect
+ * @param serverUrl
+ * url to DB server
+ * @param connectionProperties
+ * connection properties
+ * @return DBConnectionInfo
+ */
+ private DBConnectionInfo constructDBConnectionInfo(String dbName, String dialect)
+ {
+ StringBuilder dbUrl = new StringBuilder(serverUrl);
+
+ if (dialect.equalsIgnoreCase(DialectConstants.DB_DIALECT_MSSQL))
+ {
+ dbUrl.append(serverUrl.endsWith(";") ? "" : ";");
+ dbUrl.append("databaseName=");
+ dbUrl.append(dbName);
+ dbUrl.append(";");
+ }
+ else if (dialect.equalsIgnoreCase(DialectConstants.DB_DIALECT_ORACLE)
+ || dialect.equalsIgnoreCase(DialectConstants.DB_DIALECT_ORACLEOCI))
+ {
+ // do nothing
+ }
+ else
+ {
+ dbUrl.append(serverUrl.endsWith("/") ? "" : "/");
+ dbUrl.append(dbName);
+ }
+
+ // clone connection properties
+ Map connProperties = new HashMap();
+
+ for (Entry entry : connectionProperties.entrySet())
+ {
+ connProperties.put(entry.getKey(), entry.getValue());
+ }
+
+ // add url to database
+ connProperties.put(SERVER_URL, dbUrl.toString());
+
+ return new DBConnectionInfo(dbName, connProperties);
+ }
+
+ /**
+ * Executes DDL script with autocommit mode set true. Actually need for MSSQL and Sybase database servers.
+ * After execution "create database" command newly created database not available for "use" command and
+ * therefore you can't create user inside.
+ *
+ * @param conn
+ * connection to server
+ * @param dbName
+ * database name
+ * @throws SQLException
+ * if any errors occurs
+ */
+ private void executeInAutoCommitMode(Connection conn, String dbName) throws SQLException
+ {
+ conn.setAutoCommit(true);
+ for (String scr : dbScript.split(";"))
+ {
+ scr = scr.replace(DATABASE_TEMPLATE, dbName);
+ scr = scr.replace(USERNAME_TEMPLATE, dbUserName);
+ scr = scr.replace(PASSWORD_TEMPLATE, dbPassword);
+
+ String s = JDBCUtils.cleanWhitespaces(scr.trim());
+ if (s.length() > 0)
+ {
+ conn.createStatement().executeUpdate(s);
+ }
+ }
+ }
+
+ /**
+ * Read script resource.
+ *
+ * @param scriptPath
+ * path to the script
+ * @param cm
+ * the configuration manager will help to find script in jars
+ * @return
+ * script content
+ * @throws ConfigurationException
+ * if script not found
+ */
+ private String readScript(String scriptPath, ConfigurationManager cm) throws ConfigurationException
+ {
+ try
+ {
+ return IOUtil.getStreamContentAsString(cm.getInputStream(scriptPath));
+ }
+ catch (Exception e)
+ {
+ try
+ {
+ return IOUtil.getFileContentAsString(scriptPath);
+ }
+ catch (IOException ioe)
+ {
+ throw new ConfigurationException("Can't read script at " + scriptPath, e);
+ }
+ }
+ }
+
+ /**
+ * Open connection to the DB.
+ *
+ * @param connectionProperties
+ * connection properties
+ * @return connection
+ * @throws DBCreatorException
+ * if can't establish connection to DB
+ */
+ private Connection openConnection() throws DBCreatorException
+ {
+ Connection conn = null;
+ try
+ {
+ ClassLoading.forName(connectionProperties.get(DRIVER_NAME), this);
+
+ conn = DriverManager.getConnection(serverUrl, connectionProperties.get(USERNAME),
+ connectionProperties.get(PASSWORD));
+
+ return conn;
+ }
+ catch (SQLException e)
+ {
+ throw new DBCreatorException("Can't establish the JDBC connection to database " + serverUrl, e);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new DBCreatorException("Can't load the JDBC driver " + connectionProperties.get(DRIVER_NAME), e);
+ }
+ }
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/creator/DBCreatorException.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/creator/DBCreatorException.java
new file mode 100644
index 00000000..ab4484ed
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/creator/DBCreatorException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database.creator;
+
+/**
+ * @author Anatoliy Bazko
+ * @version $Id$
+ */
+public class DBCreatorException extends Exception
+{
+
+ /**
+ * DBCreationException constructor.
+ */
+ public DBCreatorException(Throwable e)
+ {
+ super(e);
+ }
+
+ /**
+ * DBCreationException constructor.
+ */
+ public DBCreatorException(String message, Throwable e)
+ {
+ super(message, e);
+ }
+
+ /**
+ * DBCreationException constructor.
+ */
+ public DBCreatorException(String message)
+ {
+ super(message);
+ }
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/impl/HibernateConfigurationImpl.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/impl/HibernateConfigurationImpl.java
new file mode 100644
index 00000000..c1a8284b
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/impl/HibernateConfigurationImpl.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database.impl;
+
+import org.hibernate.SessionFactory;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.service.ServiceRegistry;
+
+/**
+ * Created by The eXo Platform SAS .
+ *
+ * @author Gennady Azarenkov
+ * @version $Id: HibernateConfigurationImpl.java 5332 2006-04-29 18:32:44Z geaz
+ * $ Hibernate's Configuration. One per 'properties-param' entry in
+ * container configuration
+ */
+public class HibernateConfigurationImpl extends Configuration {
+ public SessionFactory buildSessionFactory() {
+ ServiceRegistry servReg = getStandardServiceRegistryBuilder().applySettings(getProperties())
+ .build();
+ return super.buildSessionFactory(servReg);
+ }
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/impl/HibernateServiceImpl.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/impl/HibernateServiceImpl.java
new file mode 100644
index 00000000..073f7b8e
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/impl/HibernateServiceImpl.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database.impl;
+
+import java.io.Serializable;
+import java.security.PrivilegedAction;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.cfg.Configuration;
+
+import org.exoplatform.commons.exception.ObjectNotFoundException;
+import org.exoplatform.container.ExoContainer;
+import org.exoplatform.container.component.ComponentRequestLifecycle;
+import org.exoplatform.container.xml.InitParams;
+import org.exoplatform.container.xml.PropertiesParam;
+import org.exoplatform.container.xml.Property;
+import org.exoplatform.services.database.HibernateService;
+import org.exoplatform.services.database.ObjectQuery;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+
+/**
+ * Created by The eXo Platform SAS .
+ *
+ * @author Tuan Nguyen tuan08@users.sourceforge.net Date: Jun 14, 2003
+ * @author dhodnett $Id: HibernateServiceImpl.java,v 1.3 2004/10/30 02:27:52
+ * tuan08 Exp $
+ */
+public class HibernateServiceImpl implements HibernateService, ComponentRequestLifecycle {
+
+ public static final String AUTO_DIALECT = "AUTO";
+
+ private ThreadLocal threadLocal_;
+
+ private static final Log LOG = ExoLogger.getLogger("exo.core.component.database.HibernateServiceImpl");
+
+ private HibernateConfigurationImpl conf_;
+
+ private SessionFactory sessionFactory_;
+
+ public HibernateServiceImpl(InitParams initParams) {
+ threadLocal_ = new ThreadLocal();
+ PropertiesParam param = initParams.getPropertiesParam("hibernate.properties");
+ conf_ = new HibernateConfigurationImpl();
+ Iterator> properties = param.getPropertyIterator();
+ while (properties.hasNext()) {
+ Property p = (Property) properties.next();
+ conf_.setProperty(p.getName(), p.getValue());
+ }
+
+ // Replace the potential "java.io.tmpdir" variable in the connection URL
+ String connectionURL = conf_.getProperty("hibernate.connection.url");
+ if (connectionURL != null) {
+ connectionURL =
+ connectionURL.replace("${java.io.tmpdir}", System.getProperty("java.io.tmpdir"));
+ conf_.setProperty("hibernate.connection.url", connectionURL);
+ }
+ }
+
+ public Configuration getHibernateConfiguration() {
+ return conf_;
+ }
+
+ /**
+ * @return the SessionFactory
+ */
+ public SessionFactory getSessionFactory() {
+ if (sessionFactory_ == null) {
+ sessionFactory_ = conf_.buildSessionFactory();
+ }
+
+ return sessionFactory_;
+ }
+
+ public Session openSession() {
+ Session currentSession = threadLocal_.get();
+ if (currentSession == null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("open new hibernate session in openSession()");
+ }
+ currentSession = getSessionFactory().openSession();
+ threadLocal_.set(currentSession);
+ }
+ return currentSession;
+ }
+
+ public Session openNewSession() {
+ Session currentSession = threadLocal_.get();
+ if (currentSession != null) {
+ closeSession(currentSession);
+ }
+ currentSession = getSessionFactory().openSession();
+ threadLocal_.set(currentSession);
+ return currentSession;
+ }
+
+ public void closeSession(Session session) {
+ if (session == null) {
+ return;
+ }
+ try {
+ session.close();
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("close hibernate session in openSession(Session session)");
+ }
+ } catch (HibernateException t) {
+ LOG.error("Error closing hibernate session : " + t.getMessage(), t);
+ }
+ threadLocal_.set(null);
+ }
+
+ final public void closeSession() {
+ Session s = threadLocal_.get();
+ if (s != null) {
+ s.close();
+ }
+ threadLocal_.set(null);
+ }
+
+ public Object findExactOne(Session session, String query, String id) throws Exception {
+ Object res = session.createQuery(query).setParameter("id", id).uniqueResult();
+ if (res == null) {
+ throw new ObjectNotFoundException("Cannot find the object with id: " + id);
+ }
+ return res;
+ }
+
+ public Object findOne(Session session, String query, String id) throws Exception {
+ List> l = session.createQuery(query).setParameter("id", id).list();
+ if (l.size() == 0) {
+ return null;
+ } else if (l.size() > 1) {
+ throw new Exception("Expect only one object but found" + l.size());
+ } else {
+ return l.get(0);
+ }
+ }
+
+ public Collection> findAll(Session session, String query) throws Exception {
+ List> l = session.createQuery(query).list();
+ if (l.size() == 0) {
+ return null;
+ } else {
+ return l;
+ }
+ }
+
+ @SuppressWarnings("rawtypes")
+ public Object findOne(Class clazz, Serializable id) throws Exception {
+ Session session = openSession();
+ Object obj = session.get(clazz, id);
+ return obj;
+ }
+
+ public Object findOne(ObjectQuery q) throws Exception {
+ Session session = openSession();
+ List> l = session.createQuery(q.getHibernateQuery()).list();
+ if (l.size() == 0) {
+ return null;
+ } else if (l.size() > 1) {
+ throw new Exception("Expect only one object but found" + l.size());
+ } else {
+ return l.get(0);
+ }
+ }
+
+ public Object create(Object obj) throws Exception {
+ Session session = openSession();
+ session.save(obj);
+ session.flush();
+ return obj;
+ }
+
+ public Object update(Object obj) throws Exception {
+ Session session = openSession();
+ session.update(obj);
+ session.flush();
+ return obj;
+ }
+
+ public Object save(Object obj) throws Exception {
+ Session session = openSession();
+ session.merge(obj);
+ session.flush();
+ return obj;
+ }
+
+ public Object remove(Object obj) throws Exception {
+ Session session = openSession();
+ session.delete(obj);
+ session.flush();
+ return obj;
+ }
+
+ @SuppressWarnings("rawtypes")
+ public Object remove(Class clazz, Serializable id) throws Exception {
+ Session session = openSession();
+ Object obj = session.get(clazz, id);
+ session.delete(obj);
+ session.flush();
+ return obj;
+ }
+
+ @SuppressWarnings("rawtypes")
+ public Object remove(Session session, Class clazz, Serializable id) throws Exception {
+ Object obj = session.get(clazz, id);
+ session.delete(obj);
+ return obj;
+ }
+
+ public void startRequest(ExoContainer container) {
+
+ }
+
+ public void endRequest(ExoContainer container) {
+ closeSession();
+ }
+
+ @Override
+ public boolean isStarted(ExoContainer container) {
+ Session s = threadLocal_.get();
+ return s != null && s.isOpen();
+ }
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/impl/XAPoolTxSupportDatabaseService.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/impl/XAPoolTxSupportDatabaseService.java
new file mode 100644
index 00000000..9be06cf3
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/impl/XAPoolTxSupportDatabaseService.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database.impl;
+
+import org.enhydra.jdbc.pool.StandardXAPoolDataSource;
+import org.enhydra.jdbc.standard.StandardXADataSource;
+import org.exoplatform.container.xml.InitParams;
+import org.exoplatform.container.xml.PropertiesParam;
+import org.exoplatform.services.database.DatabaseService;
+import org.exoplatform.services.database.ExoDatasource;
+import org.exoplatform.services.transaction.TransactionService;
+
+import java.sql.Connection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.sql.DataSource;
+
+/**
+ * Created by The eXo Platform SAS
+ * Author : Tuan Nguyen tuan08@users.sourceforge.net Apr 4, 2006
+ */
+public class XAPoolTxSupportDatabaseService implements DatabaseService
+{
+ private HashMap datasources_;
+
+ private ExoDatasource defaultDS_;
+
+ private TransactionService txService_;
+
+ public XAPoolTxSupportDatabaseService(InitParams params, TransactionService txService) throws Exception
+ {
+ datasources_ = new HashMap(5);
+ txService_ = txService;
+ Iterator> i = params.getPropertiesParamIterator();
+ while (i.hasNext())
+ {
+ PropertiesParam param = (PropertiesParam)i.next();
+ String name = param.getName();
+ ExoDatasource ds = new ExoDatasource(createDatasource(param.getProperties()));
+ datasources_.put(name, ds);
+ if (defaultDS_ == null)
+ defaultDS_ = ds;
+ }
+ }
+
+ public ExoDatasource getDatasource() throws Exception
+ {
+ return defaultDS_;
+ }
+
+ public ExoDatasource getDatasource(String dsName) throws Exception
+ {
+ return datasources_.get(dsName);
+ }
+
+ public Connection getConnection() throws Exception
+ {
+ return defaultDS_.getConnection();
+ }
+
+ public Connection getConnection(String dsName) throws Exception
+ {
+ ExoDatasource ds = datasources_.get(dsName);
+ return ds.getConnection();
+ }
+
+ public void closeConnection(Connection conn) throws Exception
+ {
+ defaultDS_.closeConnection(conn);
+ }
+
+ public TransactionService getTransactionService() throws Exception
+ {
+ return txService_;
+ }
+
+ private DataSource createDatasource(Map props) throws Exception
+ {
+ StandardXADataSource ds = new StandardXADataSource();
+
+ ds.setDriverName(props.get("connection.driver"));
+ ds.setUrl(props.get("connection.url"));
+ ds.setUser(props.get("connection.login"));
+ ds.setPassword(props.get("connection.password"));
+ ds.setTransactionManager(txService_.getTransactionManager());
+
+ StandardXAPoolDataSource pool = new StandardXAPoolDataSource(3);
+ pool.setMinSize(Integer.parseInt(props.get("connection.min-size")));
+ pool.setMaxSize(Integer.parseInt(props.get("connection.max-size")));
+ pool.setUser(props.get("connection.login"));
+ pool.setPassword(props.get("connection.password"));
+ pool.setDataSource(ds);
+ return pool;
+ }
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/jdbc/CreateDBSchemaPlugin.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/jdbc/CreateDBSchemaPlugin.java
new file mode 100644
index 00000000..2e0de838
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/jdbc/CreateDBSchemaPlugin.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database.jdbc;
+
+import org.exoplatform.container.component.BaseComponentPlugin;
+import org.exoplatform.container.configuration.ConfigurationException;
+import org.exoplatform.container.xml.InitParams;
+import org.exoplatform.container.xml.ValueParam;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+/**
+ * Created by The eXo Platform SAS .
+ *
+ * @author Gennady
+ * Azarenkov
+ * @version $Id: CreateDBSchemaPlugin.java 8017 2006-08-16 15:12:00Z peterit $
+ */
+public class CreateDBSchemaPlugin extends BaseComponentPlugin
+{
+
+ protected static final Log LOG = ExoLogger.getLogger("exo.core.component.database.CreateDBSchemaPlugin");
+
+ private String dataSource;
+
+ private String script;
+
+ public CreateDBSchemaPlugin(InitParams params) throws ConfigurationException
+ {
+ ValueParam dsParam = params.getValueParam("data-source");
+ ValueParam scriptFileParam = params.getValueParam("script-file");
+ ValueParam scriptParam = params.getValueParam("script");
+
+ if (dsParam == null)
+ return;
+ dataSource = dsParam.getValue();
+ if (scriptParam != null)
+ {
+ script = scriptParam.getValue();
+ return;
+ }
+ // ClassLoader cl = this.getClass().getClassLoader();
+ // //Thread.currentThread().getContextClassLoader();
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ InputStream is = cl.getResourceAsStream(scriptFileParam.getValue());
+
+ if (is == null)
+ is = ClassLoader.getSystemResourceAsStream(scriptFileParam.getValue());
+
+ if (is == null)
+ {
+ try
+ {
+ LOG.warn("Db script not found as system resource... Trying to search as file by path: "
+ + scriptFileParam.getValue());
+ is = new FileInputStream(scriptFileParam.getValue());
+ LOG.info("Db script found as file by path: " + scriptFileParam.getValue());
+ }
+ catch (IOException e)
+ {
+ LOG.warn("Db script not found as file by path: " + scriptFileParam.getValue() + ". " + e.getMessage());
+ }
+ }
+
+ if (is == null)
+ {
+ try
+ {
+ LOG.warn("Db script not found as system resource... Trying to search as file by url: "
+ + scriptFileParam.getValue());
+ is = new URL(scriptFileParam.getValue()).openStream();
+ LOG.info("Db script found as file by url: " + scriptFileParam.getValue());
+ }
+ catch (IOException e)
+ {
+ LOG.warn("Db script not found as file by url: " + scriptFileParam.getValue() + ". " + e.getMessage());
+ }
+ }
+
+ if (is == null)
+ {
+ throw new ConfigurationException("Could not open input stream for db script "
+ + cl.getResource(scriptFileParam.getValue()));
+ }
+
+ try
+ {
+ byte[] buf = new byte[is.available()];
+ is.read(buf);
+ script = new String(buf);
+ }
+ catch (IOException e)
+ {
+ LOG.error(e.getLocalizedMessage(), e);
+ }
+ finally
+ {
+ try
+ {
+ is.close();
+ }
+ catch (IOException e)
+ {
+ if (LOG.isTraceEnabled())
+ {
+ LOG.trace("An exception occurred: " + e.getMessage());
+ }
+ }
+ }
+ }
+
+ public String getDataSource()
+ {
+ return dataSource;
+ }
+
+ public String getScript()
+ {
+ return script;
+ }
+
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/jdbc/DBSchemaCreator.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/jdbc/DBSchemaCreator.java
new file mode 100644
index 00000000..81110605
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/jdbc/DBSchemaCreator.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database.jdbc;
+
+import org.exoplatform.container.component.ComponentPlugin;
+import org.exoplatform.services.database.utils.JDBCUtils;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+import org.exoplatform.services.naming.InitialContextInitializer;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.sql.DataSource;
+
+/**
+ * Created by The eXo Platform SAS .
+ *
+ * @author Gennady Azarenkov
+ * @version $Id: DBSchemaCreator.java 13053 2007-03-01 06:44:00Z tuan08 $
+ */
+
+public class DBSchemaCreator
+{
+ static private String SQL_ALREADYEXISTS = ".*((already exist)|(duplicate key)| (already used)|(ORA-00955))+.*";
+
+ private final Pattern pattern;
+
+ private static final Log LOG = ExoLogger.getLogger("exo.core.component.database.DBSchemaCreator");
+
+ private List createDBSchemaPlugins = new ArrayList();
+
+ public DBSchemaCreator(InitialContextInitializer contextInit)
+ {
+ pattern = Pattern.compile(SQL_ALREADYEXISTS, Pattern.CASE_INSENSITIVE);
+ }
+
+ // for testing only
+ private DBSchemaCreator(String dsName, String script) throws SQLException, NamingException
+ {
+ pattern = Pattern.compile(SQL_ALREADYEXISTS, Pattern.CASE_INSENSITIVE);
+ createTables(dsName, script);
+ }
+
+ public void createTables(String dsName, String script) throws NamingException, SQLException
+ {
+ InitialContext context = new InitialContext();
+ DataSource ds = (DataSource)context.lookup(dsName);
+ Connection conn = ds.getConnection();
+ String sql = "";
+ try
+ {
+ String[] scripts = JDBCUtils.splitWithSQLDelimiter(script);
+
+ for (String scr : scripts)
+ {
+ String s = JDBCUtils.cleanWhitespaces(scr.trim());
+
+ if (s.length() < 1)
+ continue;
+ sql = s;
+ if (LOG.isDebugEnabled())
+ LOG.debug("Execute script: \n[" + sql + "]");
+
+ try
+ {
+ conn.setAutoCommit(false);
+ conn.createStatement().executeUpdate(sql);
+ conn.commit();
+ }
+ catch (SQLException e)
+ {
+ conn.rollback();
+ // already exists check
+ Matcher aeMatcher = pattern.matcher(e.getMessage().trim());
+ if (!aeMatcher.matches())
+ throw e;
+ if (LOG.isDebugEnabled())
+ LOG.debug(e.getMessage());
+ }
+
+ }
+ LOG.info("DB schema of DataSource: '" + dsName + "' created succesfully. context " + context);
+ }
+ catch (SQLException e)
+ {
+ LOG.error("Could not create db schema of DataSource: '" + dsName + "'. Reason: " + e.getMessage() + "; "
+ + JDBCUtils.getFullMessage(e) + ". Last command: " + sql, e);
+ }
+ finally
+ {
+ conn.close();
+ }
+
+ }
+
+ public void addPlugin(ComponentPlugin plugin)
+ {
+ if (plugin instanceof CreateDBSchemaPlugin)
+ {
+ CreateDBSchemaPlugin csplugin = (CreateDBSchemaPlugin)plugin;
+ try
+ {
+ createTables(csplugin.getDataSource(), csplugin.getScript());
+ createDBSchemaPlugins.add(csplugin);
+ }
+ catch (NamingException e)
+ {
+ LOG.error(e.getLocalizedMessage(), e);
+ }
+ catch (SQLException e)
+ {
+ LOG.error(e.getLocalizedMessage(), e);
+ }
+ }
+ }
+
+ public ComponentPlugin removePlugin(String name)
+ {
+ return null;
+ }
+
+ public Collection getPlugins()
+ {
+ return createDBSchemaPlugins;
+ }
+
+ // for testing
+ public static DBSchemaCreator initialize(String dsName, String script) throws SQLException, NamingException
+ {
+ return new DBSchemaCreator(dsName, script);
+ }
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/table/ExoLongID.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/table/ExoLongID.java
new file mode 100644
index 00000000..ee6a8b1a
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/table/ExoLongID.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database.table;
+
+import org.exoplatform.services.database.DBObject;
+import org.exoplatform.services.database.annotation.Table;
+import org.exoplatform.services.database.annotation.TableField;
+
+/**
+ * Created by The eXo Platform SAS Mar 16, 2007
+ */
+@Table(name = "EXO_LONG_ID", field = {
+ @TableField(name = "EXO_NAME", type = "string", length = 500, unique = true, nullable = false),
+ @TableField(name = "EXO_START", type = "long")})
+public class ExoLongID extends DBObject
+{
+
+ final static public long BLOCK_SIZE = 3;
+
+ private String name;
+
+ private long currentBlockId;
+
+ public ExoLongID()
+ {
+ }
+
+ public ExoLongID(String name, long start)
+ {
+ this.name = name;
+ this.currentBlockId = start;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public long getCurrentBlockId()
+ {
+ return currentBlockId;
+ }
+
+ public void setCurrentBlockId(long start)
+ {
+ this.currentBlockId = start;
+ }
+
+ public void setNextBlock()
+ {
+ this.currentBlockId = this.currentBlockId + BLOCK_SIZE;
+ }
+
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/table/IDGenerator.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/table/IDGenerator.java
new file mode 100644
index 00000000..9aabfcdc
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/table/IDGenerator.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database.table;
+
+import org.exoplatform.commons.utils.PageList;
+import org.exoplatform.services.database.DAO;
+import org.exoplatform.services.database.DBObject;
+import org.exoplatform.services.database.DBObjectMapper;
+import org.exoplatform.services.database.DBTableManager;
+import org.exoplatform.services.database.ExoDatasource;
+import org.exoplatform.services.database.annotation.Table;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Created by The eXo Platform SAS
+ * Author : Tuan Nguyen tuan08@users.sourceforge.net Apr 4, 2006
+ */
+public class IDGenerator extends DAO
+{
+
+ private HashMap idTrackers_;
+
+ public IDGenerator(ExoDatasource datasource) throws Exception
+ {
+ super(datasource, new ExoLongIDMapper());
+ idTrackers_ = new HashMap();
+
+ DBTableManager tableManager = datasource.getDBTableManager();
+ if (tableManager.hasTable(ExoLongID.class))
+ return;
+ tableManager.createTable(ExoLongID.class, true);
+ }
+
+ public ExoLongID loadObjectByName(String name) throws Exception
+ {
+ Table table = ExoLongID.class.getAnnotation(Table.class);
+ StringBuilder builder = new StringBuilder("SELECT EXO_NAME, EXO_START FROM ");
+ builder.append(table.name()).append(" WHERE EXO_NAME = '").append(name).append('\'');
+ return loadUnique(builder.toString());
+ }
+
+ public long generateLongId(T bean) throws Exception
+ {
+ return generateLongId(bean.getClass());
+ }
+
+ // Lazy loading
+ synchronized public long generateLongId(Class type) throws Exception
+ {
+ IDTracker idTracker = idTrackers_.get(type);
+
+ if (idTracker == null)
+ {
+ ExoLongID instanceID = loadObjectByName(type.getName());
+ long currentId = 0;
+
+ if (instanceID == null)
+ {
+ instanceID = new ExoLongID(type.getName(), ExoLongID.BLOCK_SIZE);
+ save(instanceID);
+ }
+ else
+ {
+ currentId = instanceID.getCurrentBlockId();
+ instanceID.setNextBlock();
+ update(instanceID);
+ }
+ idTracker = new IDTracker(instanceID, currentId);
+ idTrackers_.put(type, idTracker);
+ }
+
+ // System.out.println("+++>>" + load(1)) ;
+
+ long generatedId = ++idTracker.currentId;
+ if (generatedId > idTracker.blockTracker.getCurrentBlockId() + ExoLongID.BLOCK_SIZE)
+ {
+ idTracker.blockTracker.setNextBlock();
+ update(idTracker.blockTracker);
+ }
+ return generatedId;
+ }
+
+ public void restartTracker()
+ {
+ idTrackers_.clear();
+ } // for testing
+
+ static private class IDTracker
+ {
+
+ private ExoLongID blockTracker;
+
+ private long currentId;
+
+ private IDTracker(ExoLongID dbobject, long id)
+ {
+ blockTracker = dbobject;
+ currentId = id;
+ }
+ }
+
+ static public class ExoLongIDMapper implements DBObjectMapper
+ {
+
+ public String[][] toParameters(ExoLongID bean) throws Exception
+ {
+ return null;
+ }
+
+ public void mapUpdate(ExoLongID bean, PreparedStatement pstm) throws Exception
+ {
+ pstm.setString(1, bean.getName());
+ pstm.setLong(2, bean.getCurrentBlockId());
+ }
+
+ public void mapResultSet(ResultSet res, ExoLongID bean) throws Exception
+ {
+ bean.setName(res.getString(1));
+ bean.setCurrentBlockId(res.getLong(2));
+ }
+ }
+
+ public ExoLongID createInstance() throws Exception
+ {
+ return new ExoLongID();
+ }
+
+ public ExoLongID load(long id) throws Exception
+ {
+ return null;
+ }
+
+ public PageList loadAll() throws Exception
+ {
+ return null;
+ }
+
+ public ExoLongID remove(long id) throws Exception
+ {
+ return null;
+ }
+
+ public void remove(ExoLongID bean) throws Exception
+ {
+ }
+
+ public void save(ExoLongID bean) throws Exception
+ {
+ }
+
+ public void save(List beans) throws Exception
+ {
+ }
+
+ public void update(ExoLongID bean) throws Exception
+ {
+ }
+
+ public void update(List beans) throws Exception
+ {
+ }
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/utils/DialectConstants.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/utils/DialectConstants.java
new file mode 100644
index 00000000..4340d972
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/utils/DialectConstants.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2012 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database.utils;
+
+/**
+ * @author Anatoliy Bazko
+ * @version $Id: DialectConstants.java 34360 2009-07-22 23:58:59Z tolusha $
+ */
+public class DialectConstants
+{
+ /**
+ * DB_DIALECT_AUTO.
+ */
+ public final static String DB_DIALECT_AUTO = "AUTO";
+
+ /**
+ * DB_DIALECT_GENERIC.
+ */
+ public final static String DB_DIALECT_GENERIC = "GENERIC";
+
+ /**
+ * DB_DIALECT_ORACLE.
+ */
+ public final static String DB_DIALECT_ORACLE = "ORACLE";
+
+ /**
+ * DB_DIALECT_ORACLEOCI.
+ */
+ public final static String DB_DIALECT_ORACLEOCI = "ORACLE-OCI";
+
+ /**
+ * DB_DIALECT_PGSQL.
+ */
+ public final static String DB_DIALECT_PGSQL = "PGSQL";
+
+ /**
+ * DB_DIALECT_PGSQL_SCS.
+ */
+ public final static String DB_DIALECT_PGSQL_SCS = "PGSQL-SCS";
+
+ /**
+ * DB_DIALECT_MYSQL.
+ */
+ public final static String DB_DIALECT_MYSQL = "MYSQL";
+
+ /**
+ * DB_DIALECT_MYSQL_UTF8.
+ */
+ public final static String DB_DIALECT_MYSQL_UTF8 = "MYSQL-UTF8";
+
+ /**
+ * DB_DIALECT_MYSQL_NDB.
+ */
+ public final static String DB_DIALECT_MYSQL_NDB = "MYSQL-NDB";
+
+ /**
+ * DB_DIALECT_MYSQL_NDB_UTF8.
+ */
+ public final static String DB_DIALECT_MYSQL_NDB_UTF8 = "MYSQL-NDB-UTF8";
+
+ /**
+ * DB_DIALECT_MYSQL_MYISAM.
+ */
+ public final static String DB_DIALECT_MYSQL_MYISAM = "MYSQL-MyISAM";
+
+ /**
+ * DB_DIALECT_MYSQL_MYISAM_UTF8.
+ */
+ public final static String DB_DIALECT_MYSQL_MYISAM_UTF8 = "MYSQL-MyISAM-UTF8";
+
+ /**
+ * DB_DIALECT_HSQLDB.
+ */
+ public final static String DB_DIALECT_HSQLDB = "HSQLDB";
+
+ /**
+ * DB_DIALECT_DB2.
+ */
+ public final static String DB_DIALECT_DB2 = "DB2";
+
+
+ /**
+ * DB_DIALECT_DB2V8.
+ */
+ public final static String DB_DIALECT_DB2V8 = "DB2V8";
+
+ /**
+ * DB_DIALECT_MSSQL.
+ */
+ public final static String DB_DIALECT_MSSQL = "MSSQL";
+
+ /**
+ * DB_DIALECT_SYBASE.
+ */
+ public final static String DB_DIALECT_SYBASE = "SYBASE";
+
+ /**
+ * DB_DIALECT_DERBY.
+ */
+ public final static String DB_DIALECT_DERBY = "DERBY";
+
+ /**
+ * DB_DIALECT_INGRES.
+ */
+ public final static String DB_DIALECT_INGRES = "INGRES";
+
+ /**
+ * DB_DIALECT_H2.
+ */
+ public final static String DB_DIALECT_H2 = "H2";
+
+ /**
+ * DB_DIALECTS.
+ */
+ public final static String[] DB_DIALECTS = {DB_DIALECT_GENERIC, DB_DIALECT_ORACLE, DB_DIALECT_ORACLEOCI,
+ DB_DIALECT_PGSQL, DB_DIALECT_PGSQL_SCS, DB_DIALECT_MYSQL, DB_DIALECT_MYSQL_NDB, DB_DIALECT_MYSQL_NDB_UTF8,
+ DB_DIALECT_HSQLDB, DB_DIALECT_DB2, DB_DIALECT_DB2V8, DB_DIALECT_MSSQL, DB_DIALECT_SYBASE,
+ DB_DIALECT_DERBY, DB_DIALECT_MYSQL_UTF8, DB_DIALECT_INGRES, DB_DIALECT_H2, DB_DIALECT_MYSQL_MYISAM,
+ DB_DIALECT_MYSQL_MYISAM_UTF8};
+
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/utils/DialectDetecter.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/utils/DialectDetecter.java
new file mode 100644
index 00000000..d005fc64
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/utils/DialectDetecter.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database.utils;
+
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+
+import java.sql.DatabaseMetaData;
+import java.sql.SQLException;
+
+/**
+ * JDBC dialect detecter based on database metadata and vendor product name.
+ *
+ * @author Peter Nedonosko
+ * @version $Id:DialectDetecter.java 1111 2010-01-01 00:00:01Z pnedonosko $
+ */
+public class DialectDetecter
+{
+
+ /**
+ * Logger.
+ */
+ private final static Log LOG = ExoLogger.getLogger("exo.core.component.database.DialectDetecter");
+
+ /**
+ * Detect databse dialect using JDBC metadata. Based on code of
+ * http://svn.jboss.org/repos/hibernate/core/trunk/core/src/main/java/org/hibernate/
+ * dialect/resolver/StandardDialectResolver.java
+ *
+ * @param metaData {@link DatabaseMetaData}
+ * @return String
+ * @throws SQLException if error occurs
+ */
+ public static String detect(final DatabaseMetaData metaData) throws SQLException
+ {
+ final String databaseName = metaData.getDatabaseProductName();
+
+ if ("HSQL Database Engine".equals(databaseName))
+ {
+ return DialectConstants.DB_DIALECT_HSQLDB;
+ }
+
+ if ("H2".equals(databaseName))
+ {
+ return DialectConstants.DB_DIALECT_H2;
+ }
+
+ if ("MySQL".equals(databaseName))
+ {
+ return DialectConstants.DB_DIALECT_MYSQL;
+ }
+
+ if ("PostgreSQL".equals(databaseName))
+ {
+ int majorVersion = metaData.getDatabaseMajorVersion();
+ int minorVersion = metaData.getDatabaseMinorVersion();
+
+ return (majorVersion > 9 || (majorVersion == 9 && minorVersion >= 1)) ? DialectConstants.DB_DIALECT_PGSQL_SCS
+ : DialectConstants.DB_DIALECT_PGSQL;
+ }
+
+ if ("EnterpriseDB".equals(databaseName))
+ {
+ return DialectConstants.DB_DIALECT_PGSQL_SCS;
+ }
+
+ if ("Apache Derby".equals(databaseName))
+ {
+ return DialectConstants.DB_DIALECT_DERBY;
+ }
+
+ if ("ingres".equalsIgnoreCase(databaseName))
+ {
+ return DialectConstants.DB_DIALECT_INGRES;
+ }
+
+ if (databaseName.startsWith("Microsoft SQL Server"))
+ {
+ return DialectConstants.DB_DIALECT_MSSQL;
+ }
+
+ if ("Sybase SQL Server".equals(databaseName) || "Adaptive Server Enterprise".equals(databaseName))
+ {
+ return DialectConstants.DB_DIALECT_SYBASE;
+ }
+
+ if (databaseName.startsWith("Adaptive Server Anywhere"))
+ {
+ return DialectConstants.DB_DIALECT_SYBASE;
+ }
+
+ if (databaseName.startsWith("DB2/"))
+ {
+ return detectDB2Dialect(metaData);
+ }
+
+ if ("Oracle".equals(databaseName))
+ {
+ return DialectConstants.DB_DIALECT_ORACLE;
+ }
+
+ return DialectConstants.DB_DIALECT_GENERIC;
+ }
+
+ /**
+ * Detects DB2 dialect.
+ */
+ private static String detectDB2Dialect(final DatabaseMetaData metaData) throws SQLException
+ {
+ if (LOG.isDebugEnabled())
+ {
+ LOG.debug("DB Major version = " + metaData.getDatabaseMajorVersion() + ", DB Minor version = "
+ + metaData.getDatabaseMinorVersion() + ", DB Product version = " + metaData.getDatabaseProductVersion());
+ }
+
+ int majorVersion = metaData.getDatabaseMajorVersion();
+ if (majorVersion < 9)
+ {
+ if (LOG.isDebugEnabled())
+ {
+ LOG.debug("The dialect " + DialectConstants.DB_DIALECT_DB2V8
+ + " will be used as the major version is lower than 9.");
+ }
+
+ return DialectConstants.DB_DIALECT_DB2V8;
+ }
+ else
+ {
+ if (LOG.isDebugEnabled())
+ {
+ LOG.debug("The dialect " + DialectConstants.DB_DIALECT_DB2
+ + " will be used as the major version is greater or equal to 9");
+ }
+
+ return DialectConstants.DB_DIALECT_DB2;
+ }
+ }
+
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/database/utils/JDBCUtils.java b/exo.core.component.database/src/main/java/org/exoplatform/services/database/utils/JDBCUtils.java
new file mode 100644
index 00000000..acc54b13
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/database/utils/JDBCUtils.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database.utils;
+
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import javax.sql.DataSource;
+
+/**
+ * This class provides JDBC tools
+ *
+ * @author Nicolas Filotto
+ * @version $Id$
+ */
+/**
+ * @author Anatoliy Bazko
+ * @version $Id: JDBCUtils.java 34360 2009-07-22 23:58:59Z tolusha $
+ *
+ */
+public class JDBCUtils
+{
+ private static final Log LOG = ExoLogger.getLogger("exo.core.component.database.JDBCUtils");
+
+ /**
+ * Default SQL delimiter.
+ */
+ public static final String SQL_DELIMITER = ";";
+
+ /**
+ * SQL delimiter comment prefix.
+ */
+ public static final String SQL_DELIMITER_COMMENT_PREFIX = "/*$DELIMITER:";
+
+ public static final String SQL_DELIMITER_COMMENT_SUFFIX = "*/";
+
+ private JDBCUtils()
+ {
+ }
+
+ /**
+ * Indicates whether or not a given table exists
+ *
+ * @param tableName
+ * the name of the table to check
+ * @param con
+ * the connection to use
+ * @return true
if it exists, false
otherwise
+ */
+ public static boolean tableExists(String tableName, Connection con)
+ {
+ Statement stmt = null;
+ ResultSet trs = null;
+ try
+ {
+ String dialect = DialectDetecter.detect(con.getMetaData());
+ String query;
+ if (dialect.startsWith(DialectConstants.DB_DIALECT_MYSQL) || dialect.startsWith(DialectConstants.DB_DIALECT_PGSQL))
+ {
+ query = "SELECT count(*) from (SELECT 1 FROM " + tableName + " LIMIT 1) T";
+ }
+ else if (dialect.startsWith(DialectConstants.DB_DIALECT_ORACLE))
+ {
+ query = "SELECT count(*) from (SELECT 1 FROM " + tableName + " WHERE ROWNUM = 1) T";
+ }
+ else if (dialect.startsWith(DialectConstants.DB_DIALECT_DB2) || dialect.startsWith(DialectConstants.DB_DIALECT_DERBY)
+ || dialect.startsWith(DialectConstants.DB_DIALECT_INGRES))
+ {
+ query = "SELECT count(*) from (SELECT 1 FROM " + tableName + " FETCH FIRST 1 ROWS ONLY) T";
+ }
+ else if (dialect.startsWith(DialectConstants.DB_DIALECT_MSSQL))
+ {
+ query = "SELECT count(*) from (SELECT TOP (1) 1 as C FROM " + tableName + ") T";
+ }
+ else if (dialect.startsWith(DialectConstants.DB_DIALECT_SYBASE))
+ {
+ query = "SELECT count(*) from (SELECT TOP 1 1 FROM " + tableName + ") T";
+ }
+ else
+ {
+ query = "SELECT count(*) FROM " + tableName;
+ }
+ stmt = con.createStatement();
+ trs = stmt.executeQuery(query);
+ return trs.next();
+ }
+ catch (SQLException e)
+ {
+ if (LOG.isDebugEnabled())
+ {
+ LOG.debug("SQLException occurs while checking the table " + tableName, e);
+ }
+ return false;
+ }
+ finally
+ {
+ freeResources(trs, stmt, null);
+ }
+ }
+
+ /**
+ * Retrieves the full message from SQLException.
+ *
+ * @param exception
+ * SQLException which will be parsed
+ */
+ public static String getFullMessage(SQLException exception)
+ {
+ StringBuilder errorTrace = new StringBuilder(exception.getMessage());
+
+ SQLException next = exception;
+ while (next != null)
+ {
+ errorTrace.append("; ");
+ errorTrace.append(next.getMessage());
+
+ next = next.getNextException();
+ }
+
+ Throwable cause = exception.getCause();
+
+ return errorTrace + (cause != null ? " (Cause: " + cause.getMessage() + ")" : "");
+ }
+
+ /**
+ * Replace whitespace characters with space character.
+ */
+ public static String cleanWhitespaces(String string)
+ {
+ if (string != null)
+ {
+ char[] cc = string.toCharArray();
+ for (int ci = cc.length - 1; ci > 0; ci--)
+ {
+ if (Character.isWhitespace(cc[ci]))
+ {
+ cc[ci] = ' ';
+ }
+ }
+ return new String(cc);
+ }
+ return string;
+ }
+
+ /**
+ * Split string resource with SQL Delimiter. Delimiter can be taken from resource
+ * at the begining of the first line. It surrounded with {@link #SQL_DELIMITER_COMMENT_PREFIX}
+ * and {@link #SQL_DELIMITER_COMMENT_SUFFIX}. Otherwise the default delimiter will
+ * be used {@link #SQL_DELIMITER}.
+ */
+ public static String[] splitWithSQLDelimiter(String resource)
+ {
+ if (resource.startsWith(SQL_DELIMITER_COMMENT_PREFIX))
+ {
+ try
+ {
+ String scripts = resource.substring(SQL_DELIMITER_COMMENT_PREFIX.length());
+
+ int endOfDelimIndex = scripts.indexOf(SQL_DELIMITER_COMMENT_SUFFIX);
+ String delim = scripts.substring(0, endOfDelimIndex).trim();
+
+ scripts = scripts.substring(endOfDelimIndex + 2).trim();
+ return scripts.split(delim);
+ }
+ catch (IndexOutOfBoundsException e)
+ {
+ LOG.warn("Error of parse SQL-script file. Invalid DELIMITER configuration. Valid format is '"
+ + SQL_DELIMITER_COMMENT_PREFIX + "XXX*/' at begin of the SQL-script file, where XXX - DELIMITER string."
+ + " Spaces will be trimed. ", e);
+ LOG.info("Using DELIMITER:[" + SQL_DELIMITER + "]");
+
+ return resource.split(SQL_DELIMITER);
+ }
+ }
+ else
+ {
+ return resource.split(SQL_DELIMITER);
+ }
+ }
+
+ /**
+ * Returns appropriate blob type field for specific database.
+ */
+ public static String getAppropriateBlobType(DataSource dataSource) throws SQLException
+ {
+ String dialect = resolveDialect(dataSource);
+
+ if (dialect.startsWith(DialectConstants.DB_DIALECT_HSQLDB))
+ {
+ return "VARBINARY(65535)";
+ }
+ else if (dialect.startsWith(DialectConstants.DB_DIALECT_MYSQL))
+ {
+ return "LONGBLOB";
+ }
+ else if (dialect.startsWith(DialectConstants.DB_DIALECT_PGSQL))
+ {
+ return "bytea";
+ }
+ else if (dialect.startsWith(DialectConstants.DB_DIALECT_MSSQL))
+ {
+ return "VARBINARY(MAX)";
+ }
+ else if (dialect.startsWith(DialectConstants.DB_DIALECT_SYBASE))
+ {
+ return "IMAGE";
+ }
+ else if (dialect.startsWith(DialectConstants.DB_DIALECT_INGRES))
+ {
+ return "long byte";
+ }
+
+ return "BLOB";
+ }
+
+ /**
+ * Returns appropriate timestamp type field for specific database.
+ */
+ public static String getAppropriateTimestamp(DataSource dataSource) throws SQLException
+ {
+ String dialect = resolveDialect(dataSource);
+
+ if (dialect.startsWith(DialectConstants.DB_DIALECT_ORACLE))
+ {
+ return "NUMBER(19, 0)";
+ }
+
+ return "BIGINT";
+ }
+
+ /**
+ * Returns appropriate char type field for specific database.
+ */
+ public static String getAppropriateCharType(DataSource dataSource) throws SQLException
+ {
+ String dialect = resolveDialect(dataSource);
+
+ if (dialect.startsWith(DialectConstants.DB_DIALECT_ORACLE))
+ {
+ // Oracle suggests the use VARCHAR2 instead of VARCHAR while declaring data type.
+ return "VARCHAR2(512)";
+ }
+
+ return "VARCHAR(512)";
+ }
+
+ /**
+ * Returns dialect one of dialect {@link DialectConstants} based on {@link DataSource} name.
+ */
+ public static String resolveDialect(final DataSource dataSource) throws SQLException
+ {
+ Connection jdbcConn = dataSource.getConnection();
+
+ try
+ {
+ return DialectDetecter.detect(jdbcConn.getMetaData());
+ }
+ finally
+ {
+ freeResources(null, null, jdbcConn);
+ }
+ }
+
+ /**
+ * Closes database related resources.
+ */
+ public static void freeResources(ResultSet resultSet, Statement statement, Connection conn)
+ {
+ if (resultSet != null)
+ {
+ try
+ {
+ resultSet.close();
+ }
+ catch (SQLException e)
+ {
+ LOG.error(e.getMessage(), e);
+ }
+ }
+
+ if (statement != null)
+ {
+ try
+ {
+ statement.close();
+ }
+ catch (SQLException e)
+ {
+ LOG.error(e.getMessage(), e);
+ }
+ }
+
+ if (conn != null)
+ {
+ try
+ {
+ conn.close();
+ }
+ catch (SQLException e)
+ {
+ LOG.error(e.getMessage(), e);
+ }
+ }
+ }
+
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/transaction/TransactionService.java b/exo.core.component.database/src/main/java/org/exoplatform/services/transaction/TransactionService.java
new file mode 100644
index 00000000..bc95d1b5
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/transaction/TransactionService.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.transaction;
+
+import javax.transaction.RollbackException;
+import javax.transaction.SystemException;
+import javax.transaction.TransactionManager;
+import javax.transaction.UserTransaction;
+import javax.transaction.xa.XAResource;
+
+/**
+ * Created by The eXo Platform SAS. The transaction service
+ *
+ * @author Gennady
+ * Azarenkov
+ * @version $Id: $
+ */
+
+public interface TransactionService
+{
+
+ /**
+ * @return TransactionManager
+ */
+ TransactionManager getTransactionManager();
+
+ /**
+ * @return UserTransaction
+ */
+ UserTransaction getUserTransaction();
+
+ /**
+ * @return default timeout in seconds
+ */
+ int getDefaultTimeout();
+
+ /**
+ * Sets timeout in seconds,
+ *
+ * @param seconds int
+ * @throws SystemException
+ */
+ void setTransactionTimeout(int seconds) throws SystemException;
+
+ /**
+ * Enlists XA resource in transaction manager.
+ *
+ * @param xares XAResource
+ * @return true if the resource was enlisted successfully; otherwise
+ * false .
+ *
+ * @exception RollbackException Thrown to indicate that
+ * the transaction has been marked for rollback only.
+ *
+ * @exception IllegalStateException Thrown if the transaction in the
+ * target object is in the prepared state or the transaction is
+ * inactive.
+ *
+ * @exception SystemException Thrown if the transaction manager
+ * encounters an unexpected error condition.
+ */
+ boolean enlistResource(XAResource xares) throws RollbackException, SystemException, IllegalStateException;
+
+ /**
+ * Delists XA resource from transaction manager.
+ *
+ * @param xares XAResource
+ * @exception IllegalStateException Thrown if the transaction in the
+ * target object is inactive.
+ *
+ * @exception SystemException Thrown if the transaction manager
+ * encounters an unexpected error condition.
+ *
+ * @return true if the resource was delisted successfully; otherwise
+ * false .
+ */
+ boolean delistResource(XAResource xares) throws RollbackException, SystemException, IllegalStateException;
+
+}
diff --git a/exo.core.component.database/src/main/java/org/exoplatform/services/transaction/impl/AbstractTransactionService.java b/exo.core.component.database/src/main/java/org/exoplatform/services/transaction/impl/AbstractTransactionService.java
new file mode 100644
index 00000000..f9d02f45
--- /dev/null
+++ b/exo.core.component.database/src/main/java/org/exoplatform/services/transaction/impl/AbstractTransactionService.java
@@ -0,0 +1,446 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.transaction.impl;
+
+import org.exoplatform.container.xml.InitParams;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+import org.exoplatform.services.transaction.TransactionService;
+
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.InvalidTransactionException;
+import javax.transaction.NotSupportedException;
+import javax.transaction.RollbackException;
+import javax.transaction.Status;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import javax.transaction.UserTransaction;
+import javax.transaction.xa.XAResource;
+
+/**
+ * This abstract class implements the main logic of all the methods expected for a
+ * {@link TransactionService}. If you intend to use a {@link TransactionManager} in
+ * standalone mode (not manager by your Application Server), you can set the
+ * transaction timeout thanks to the value-param
called timeout
+ * the value of this parameter is expressed in seconds.
+ *
+ * @author Nicolas Filotto
+ * @version $Id$
+ *
+ */
+public abstract class AbstractTransactionService implements TransactionService
+{
+ /**
+ * The logger
+ */
+ private static final Log LOG = ExoLogger.getLogger("exo.kernel.component.common.AbstractTransactionService");
+
+ /**
+ * The default value of a transaction timeout in seconds
+ */
+ private static final int DEFAULT_TIME_OUT = 60;
+
+ /**
+ * The default timeout
+ */
+ protected final int defaultTimeout;
+
+ /**
+ * Indicates if the timeout has to be enforced
+ */
+ protected final boolean forceTimeout;
+
+ /**
+ * The current Transaction Manager
+ */
+ private volatile TransactionManager tm;
+
+ /**
+ * The current User Transaction
+ */
+ private volatile UserTransaction ut;
+
+ public AbstractTransactionService()
+ {
+ this(null);
+ }
+
+ public AbstractTransactionService(InitParams params)
+ {
+ if (params != null && params.getValueParam("timeout") != null)
+ {
+ this.defaultTimeout = Integer.parseInt(params.getValueParam("timeout").getValue());
+ this.forceTimeout = true;
+ }
+ else
+ {
+ this.defaultTimeout = DEFAULT_TIME_OUT;
+ this.forceTimeout = false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean delistResource(final XAResource xares) throws RollbackException, SystemException
+ {
+ TransactionManager tm = getTransactionManager();
+ final Transaction tx = tm.getTransaction();
+ if (tx != null)
+ {
+ int flag = XAResource.TMSUCCESS;
+ switch (tx.getStatus())
+ {
+ case Status.STATUS_MARKED_ROLLBACK:
+ case Status.STATUS_ROLLEDBACK:
+ case Status.STATUS_ROLLING_BACK: flag = XAResource.TMFAIL;
+ }
+ return tx.delistResource(xares, flag);
+ }
+ else
+ {
+ throw new IllegalStateException("Could not delist the XA Resource since there is no active session");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean enlistResource(final XAResource xares) throws RollbackException, SystemException
+ {
+ TransactionManager tm = getTransactionManager();
+ final Transaction tx = tm.getTransaction();
+ if (tx != null)
+ {
+ return tx.enlistResource(xares);
+ }
+ else
+ {
+ throw new IllegalStateException("Could not enlist the XA Resource since there is no active session");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getDefaultTimeout()
+ {
+ return defaultTimeout;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public final TransactionManager getTransactionManager()
+ {
+ if (tm == null)
+ {
+ synchronized (this)
+ {
+ if (tm == null)
+ {
+ TransactionManager tm;
+ try
+ {
+ tm = findTransactionManager();
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("Transaction manager not found", e);
+ }
+ if (forceTimeout)
+ {
+ // Only set the timeout when a timeout has been given into the
+ // configuration otherwise we assume that the value will be
+ // set at the AS level
+ tm = new TransactionManagerTxTimeoutAware(tm, defaultTimeout);
+ }
+ this.tm = tm;
+ }
+ }
+ }
+ return tm;
+ }
+
+ /**
+ * Indicates whether or not the {@link TransactionManager} has been initialized
+ */
+ protected boolean isTMInitialized()
+ {
+ return tm != null;
+ }
+
+ /**
+ * This method will try to find the current {@link TransactionManager}
+ * @return the current {@link TransactionManager}
+ * @throws Exception if an error occurs while looking for the {@link TransactionManager}
+ */
+ protected abstract TransactionManager findTransactionManager() throws Exception;
+
+ /**
+ * {@inheritDoc}
+ */
+ public final UserTransaction getUserTransaction()
+ {
+ if (ut == null)
+ {
+ synchronized (this)
+ {
+ if (ut == null)
+ {
+ UserTransaction ut;
+ try
+ {
+ ut = findUserTransaction();
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("UserTransaction not found", e);
+ }
+ this.ut = ut;
+ }
+ }
+ }
+ return ut;
+ }
+
+
+ /**
+ * This method will try to find the current {@link UserTransaction}, by default it will
+ * simply wraps a {@link TransactionManager}
+ * @return the current {@link UserTransaction}
+ * @throws Exception if an error occurs while looking for the {@link UserTransaction}
+ */
+ protected UserTransaction findUserTransaction() throws Exception
+ {
+ return new UserTransactionWrapper(getTransactionManager());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setTransactionTimeout(int seconds) throws SystemException
+ {
+ TransactionManager tm = getTransactionManager();
+ tm.setTransactionTimeout(seconds);
+ }
+
+ /**
+ * This class is used to enforce the {@link Transaction} timeout when a new transaction is
+ * created through the nested {@link TransactionManager}
+ *
+ * Created by The eXo Platform SAS
+ * Author : Nicolas Filotto
+ * nicolas.filotto@exoplatform.com
+ * 1 f�vr. 2010
+ */
+ private static class TransactionManagerTxTimeoutAware implements TransactionManager
+ {
+ /**
+ * The nested {@link TransactionManager}
+ */
+ private final TransactionManager tm;
+
+ /**
+ * The default timeout of the {@link Transaction}
+ */
+ private final int defaultTimeout;
+
+ /**
+ * This is used to know if a timeout has already been set for the next transaction
+ */
+ private final ThreadLocal timeoutHasBeenSet = new ThreadLocal();
+
+ public TransactionManagerTxTimeoutAware(TransactionManager tm, int defaultTimeout)
+ {
+ this.tm = tm;
+ this.defaultTimeout = defaultTimeout;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void begin() throws NotSupportedException, SystemException
+ {
+ if (timeoutHasBeenSet.get() != null)
+ {
+ // clean the ThreadLocal
+ timeoutHasBeenSet.set(null);
+ }
+ else
+ {
+ try
+ {
+ // Set the default transaction timeout
+ tm.setTransactionTimeout(defaultTimeout);
+ }
+ catch (Exception e)
+ {
+ LOG.warn("Cannot set the transaction timeout", e);
+ }
+ }
+
+ // Start the transaction
+ tm.begin();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
+ SecurityException, IllegalStateException, SystemException
+ {
+ tm.commit();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getStatus() throws SystemException
+ {
+ return tm.getStatus();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Transaction getTransaction() throws SystemException
+ {
+ return tm.getTransaction();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void resume(final Transaction tx) throws InvalidTransactionException, IllegalStateException,
+ SystemException
+ {
+ tm.resume(tx);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void rollback() throws IllegalStateException, SecurityException, SystemException
+ {
+ tm.rollback();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setRollbackOnly() throws IllegalStateException, SystemException
+ {
+ tm.setRollbackOnly();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setTransactionTimeout(int timeout) throws SystemException
+ {
+ tm.setTransactionTimeout(timeout);
+ timeoutHasBeenSet.set(true);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Transaction suspend() throws SystemException
+ {
+ return tm.suspend();
+ }
+ }
+
+ /**
+ * This class is used to propose a default implementation of a {@link UserTransaction}
+ * from the {@link TransactionManager}
+ * @author Nicolas Filotto
+ * @version $Id$
+ *
+ */
+ private static class UserTransactionWrapper implements UserTransaction
+ {
+
+ /**
+ * The {@link TransactionManager} that we will use to simulate a {@link UserTransaction}
+ */
+ private final TransactionManager tm;
+
+ /**
+ * Default Constructor
+ * @param tm
+ */
+ public UserTransactionWrapper(TransactionManager tm)
+ {
+ this.tm = tm;
+ }
+
+ /**
+ * @see javax.transaction.UserTransaction#begin()
+ */
+ public void begin() throws NotSupportedException, SystemException
+ {
+ tm.begin();
+ }
+
+ /**
+ * @see javax.transaction.UserTransaction#commit()
+ */
+ public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
+ SecurityException, IllegalStateException, SystemException
+ {
+ tm.commit();
+ }
+
+ /**
+ * @see javax.transaction.UserTransaction#rollback()
+ */
+ public void rollback() throws IllegalStateException, SecurityException, SystemException
+ {
+ tm.rollback();
+ }
+
+ /**
+ * @see javax.transaction.UserTransaction#setRollbackOnly()
+ */
+ public void setRollbackOnly() throws IllegalStateException, SystemException
+ {
+ tm.setRollbackOnly();
+ }
+
+ /**
+ * @see javax.transaction.UserTransaction#getStatus()
+ */
+ public int getStatus() throws SystemException
+ {
+ return tm.getStatus();
+ }
+
+ /**
+ * @see javax.transaction.UserTransaction#setTransactionTimeout(int)
+ */
+ public void setTransactionTimeout(int timeout) throws SystemException
+ {
+ tm.setTransactionTimeout(timeout);
+ }
+ }
+}
diff --git a/exo.core.component.database/src/main/resources/conf/portal/jdbcexo-configuration.db.xml b/exo.core.component.database/src/main/resources/conf/portal/jdbcexo-configuration.db.xml
new file mode 100644
index 00000000..b578c0ea
--- /dev/null
+++ b/exo.core.component.database/src/main/resources/conf/portal/jdbcexo-configuration.db.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+ org.exoplatform.services.naming.InitialContextInitializer
+
+ bind.datasource
+ addPlugin
+ org.exoplatform.services.naming.BindReferencePlugin
+
+
+ bind-name
+ jdbcexo
+
+
+ class-name
+ javax.sql.DataSource
+
+
+ factory
+ org.apache.commons.dbcp.BasicDataSourceFactory
+
+
+ ref-addresses
+ ref-addresses
+
+
+
+
+
+
+
+
+
+
diff --git a/exo.core.component.database/src/main/resources/conf/portal/jdbcexo-configuration.hsql.xml b/exo.core.component.database/src/main/resources/conf/portal/jdbcexo-configuration.hsql.xml
new file mode 100644
index 00000000..95e989a4
--- /dev/null
+++ b/exo.core.component.database/src/main/resources/conf/portal/jdbcexo-configuration.hsql.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+ org.exoplatform.services.naming.InitialContextInitializer
+
+ bind.datasource
+ addPlugin
+ org.exoplatform.services.naming.BindReferencePlugin
+
+
+ bind-name
+ jdbexo
+
+
+ class-name
+ javax.sql.DataSource
+
+
+ factory
+ org.apache.commons.dbcp.BasicDataSourceFactory
+
+
+ ref-addresses
+ ref-addresses
+
+
+
+
+
+
+
+
+
+
diff --git a/exo.core.component.database/src/main/sql/create.sql b/exo.core.component.database/src/main/sql/create.sql
new file mode 100644
index 00000000..03335a6f
--- /dev/null
+++ b/exo.core.component.database/src/main/sql/create.sql
@@ -0,0 +1,16 @@
+--table name for mysql on linux is case sensitive
+create table hibernate_unique_key (
+ next_hi BIGINT
+ );
+INSERT INTO hibernate_unique_key(next_hi) VALUES ( 100 );
+/*
+create table RESOURCE_BUNDLE_DATA (
+ id VARCHAR(128) NOT NULL,
+ name VARCHAR(128) NOT NULL,
+ language VARCHAR(25),
+ country VARCHAR(25),
+ variant VARCHAR(25),
+ resourceType VARCHAR(128) NOT NULL,
+ data TEXT NOT NULL,
+ PRIMARY KEY (id));
+*/
diff --git a/exo.core.component.database/src/test/java/org/exoplatform/services/database/DBCreatorTest.java b/exo.core.component.database/src/test/java/org/exoplatform/services/database/DBCreatorTest.java
new file mode 100644
index 00000000..98a8af23
--- /dev/null
+++ b/exo.core.component.database/src/test/java/org/exoplatform/services/database/DBCreatorTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import junit.framework.TestCase;
+
+import org.exoplatform.container.PortalContainer;
+import org.exoplatform.services.database.jdbc.CreateDBSchemaPlugin;
+import org.exoplatform.services.database.jdbc.DBSchemaCreator;
+
+import java.util.List;
+
+/**
+ * Created by The eXo Platform SAS .
+ *
+ * @author Gennady Azarenkov
+ * @version $Id: DBCreatorTest.java 5569 2006-05-17 12:48:47Z lautarul $
+ */
+public class DBCreatorTest extends TestCase
+{
+
+ // private StandaloneContainer container;
+ private DBSchemaCreator dbcreator;
+
+ public void setUp() throws Exception
+ {
+ // >>>>> to avoid two top-level container exception
+ // StandaloneContainer.setConfigurationPath("src/main/java/conf/standalone/test-configuration.xml");
+ // container = StandaloneContainer.getInstance();
+ PortalContainer container = PortalContainer.getInstance();
+ dbcreator = (DBSchemaCreator)container.getComponentInstanceOfType(DBSchemaCreator.class);
+ }
+
+ public void testConf() throws Exception
+ {
+ // DBSchemaCreator dbcreator = (DBSchemaCreator) container.getComponentInstanceOfType(DBSchemaCreator.class);
+ List> plugins = (List>)dbcreator.getPlugins();
+ assertFalse(plugins.isEmpty());
+
+ assertTrue(plugins.get(0) instanceof CreateDBSchemaPlugin);
+ CreateDBSchemaPlugin plugin = (CreateDBSchemaPlugin)plugins.get(0);
+
+ assertNotNull(plugin.getDataSource());
+ assertNotNull(plugin.getScript());
+ }
+
+ public void tearDown() throws Exception
+ {
+ // container.stop();
+ }
+}
diff --git a/exo.core.component.database/src/test/java/org/exoplatform/services/database/Mock.java b/exo.core.component.database/src/test/java/org/exoplatform/services/database/Mock.java
new file mode 100644
index 00000000..73694d8c
--- /dev/null
+++ b/exo.core.component.database/src/test/java/org/exoplatform/services/database/Mock.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import org.exoplatform.services.database.annotation.Table;
+import org.exoplatform.services.database.annotation.TableField;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.Calendar;
+import java.util.HashMap;
+
+/**
+ * Created by The eXo Platform SAS Author : Tuan Nguyen
+ * tuan.nguyen@exoplatform.com Mar 16, 2007
+ */
+@Table(name = "MockTable", field = {
+ @TableField(name = "name", type = "string", length = 500, unique = true, nullable = false),
+ @TableField(name = "status", type = "int", defaultValue = "0"), @TableField(name = "start", type = "date"),
+ @TableField(name = "pass", type = "boolean", defaultValue = "false")})
+public class Mock extends DBObject
+{
+
+ private String name;
+
+ private int status;
+
+ private Calendar start = Calendar.getInstance();
+
+ private boolean pass = false;
+
+ public Mock()
+ {
+ }
+
+ public Mock(String name, int status)
+ {
+ this.name = name;
+ this.status = status;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public boolean isPass()
+ {
+ return pass;
+ }
+
+ public void setPass(boolean pass)
+ {
+ this.pass = pass;
+ }
+
+ public Calendar getStart()
+ {
+ return start;
+ }
+
+ public void setStart(Calendar start)
+ {
+ this.start = start;
+ }
+
+ public int getStatus()
+ {
+ return status;
+ }
+
+ public void setStatus(int status)
+ {
+ this.status = status;
+ }
+
+ static public class MockMapper implements DBObjectMapper
+ {
+
+ public String[][] toParameters(Mock bean) throws Exception
+ {
+ java.sql.Date date = new java.sql.Date(bean.getStart().getTimeInMillis());
+ return new String[][]{{"id", String.valueOf(bean.getDBObjectId())}, {"name", bean.getName()},
+ {"status", String.valueOf(bean.getStatus())}, {"start", date.toString()},
+ {"pass", String.valueOf(bean.isPass())}};
+ }
+
+ public void mapResultSet(ResultSet res, Mock bean) throws Exception
+ {
+ bean.setName(res.getString("name"));
+ bean.setPass(res.getBoolean("pass"));
+ Calendar calendar = Calendar.getInstance();
+ res.getDate("start", calendar);
+ bean.setStart(calendar);
+ bean.setStatus(res.getInt("status"));
+ }
+
+ public void mapUpdate(Mock bean, PreparedStatement statement) throws Exception
+ {
+ statement.setString(1, bean.getName());
+ statement.setInt(2, bean.getStatus());
+ statement.setDate(3, new java.sql.Date(bean.getStart().getTimeInMillis()));
+ statement.setBoolean(4, bean.isPass());
+ }
+ }
+
+ /**
+ * Query( name = "GetUserByUserName" oracle =
+ * "select * from user where username= N'?' and fname = $fname" +
+ * ".............................................................." +
+ * ".............................................................." ,
+ * standard="......................................................." , )
+ */
+ public void getUserByName(String s)
+ {
+ HashMap values = new HashMap();
+ values.put("username", s);
+ values.put("fname", s);
+ // Object[] params = {
+ // {"username", "value"},
+ // {"username", "value"},
+ // {"username", "value"}
+ // }
+ // String query = createQuery("GetUserByUserName", params) ;
+ }
+
+}
diff --git a/exo.core.component.database/src/test/java/org/exoplatform/services/database/TestDAO.java b/exo.core.component.database/src/test/java/org/exoplatform/services/database/TestDAO.java
new file mode 100644
index 00000000..cc8a8dc8
--- /dev/null
+++ b/exo.core.component.database/src/test/java/org/exoplatform/services/database/TestDAO.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import junit.framework.TestCase;
+
+import org.exoplatform.services.listener.ListenerService;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by The eXo Platform SAS Author : Tuan Nguyen
+ * tuan.nguyen@exoplatform.com Mar 27, 2007
+ */
+public class TestDAO extends TestCase
+{
+
+ public void testDummy()
+ {
+ // empty, to doesn't fail during the tests
+ }
+
+ private String printQueryResult(DatabaseService service) throws Exception
+ {
+ Connection conn = service.getConnection();
+ Statement statement = conn.createStatement();
+ String output = "\nQuery result: \n";
+ ResultSet rs = statement.executeQuery("SELECT * FROM ExoLongId");
+ while (rs.next())
+ {
+ output += rs.getString(1) + "\n" + rs.getString(2) + "\n" + rs.getString(3) + "====\n";
+ }
+
+ return output;
+ }
+
+ private void queries(DatabaseService service) throws Exception
+ {
+ }
+}
diff --git a/exo.core.component.database/src/test/java/org/exoplatform/services/database/TestDBCreator.java b/exo.core.component.database/src/test/java/org/exoplatform/services/database/TestDBCreator.java
new file mode 100644
index 00000000..6da60046
--- /dev/null
+++ b/exo.core.component.database/src/test/java/org/exoplatform/services/database/TestDBCreator.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import junit.framework.TestCase;
+
+import org.exoplatform.container.PortalContainer;
+import org.exoplatform.container.configuration.ConfigurationManager;
+import org.exoplatform.services.database.creator.DBConnectionInfo;
+import org.exoplatform.services.database.creator.DBCreator;
+import org.exoplatform.services.naming.InitialContextInitializer;
+
+import java.sql.Connection;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.sql.DataSource;
+
+/**
+ * @author Anatoliy Bazko
+ * @version $Id$
+ */
+public class TestDBCreator extends TestCase
+{
+
+ protected DBCreator dbCreator;
+
+ private InitialContextInitializer initContext;
+
+ private PortalContainer container;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ container = PortalContainer.getInstance();
+ dbCreator = (DBCreator)container.getComponentInstanceOfType(DBCreator.class);
+ initContext = (InitialContextInitializer)container.getComponentInstanceOfType(InitialContextInitializer.class);
+ }
+
+ public void testDBCreate() throws Exception
+ {
+ assertNotNull(dbCreator);
+
+ DBConnectionInfo dbInfo = dbCreator.createDatabase("testdb");
+ DBConnectionInfo dbInfo1 = dbCreator.getDBConnectionInfo("testdb");
+
+ Map connProps = dbInfo.getProperties();
+ Map connProps1 = dbInfo1.getProperties();
+
+ assertEquals(connProps.get("driverClassName"), connProps1.get("driverClassName"));
+ assertEquals(connProps.get("username"), connProps1.get("username"));
+ assertEquals(connProps.get("url"), connProps1.get("url"));
+ assertEquals(connProps.get("password"), connProps1.get("password"));
+
+ Map refAddr = dbInfo.getProperties();
+
+ initContext.getInitialContextBinder().bind("testjdbcjcr", "javax.sql.DataSource",
+ "org.apache.commons.dbcp.BasicDataSourceFactory", null,
+ refAddr);
+
+ DataSource ds = (DataSource)initContext.getInitialContext().lookup("testjdbcjcr");
+ assertNotNull(ds);
+
+ Connection conn = ds.getConnection();
+ assertNotNull(conn);
+ }
+
+ public void testDBCreateWithSpecificProperties() throws Exception
+ {
+ assertNotNull(dbCreator);
+
+ String serverUrl = "jdbc:hsqldb:file:target/temp/data/dbcreator_test";
+ Map connectionProperties = new HashMap();
+ connectionProperties.put("driverClassName", "org.hsqldb.jdbcDriver");
+ connectionProperties.put("username", "sa");
+ connectionProperties.put("password", "");
+
+ ConfigurationManager cm = (ConfigurationManager)container.getComponentInstanceOfType(ConfigurationManager.class);
+ DBCreator dbCreator =
+ new DBCreator(serverUrl, connectionProperties, "classpath:/dbcreator/test.sql", "sa", "", cm);
+
+ DBConnectionInfo dbInfo = dbCreator.createDatabase("testdb");
+ DBConnectionInfo dbInfo1 = dbCreator.getDBConnectionInfo("testdb");
+
+ Map connProps = dbInfo.getProperties();
+ Map connProps1 = dbInfo1.getProperties();
+
+ assertEquals(connProps.get("driverClassName"), connProps1.get("driverClassName"));
+ assertEquals(connProps.get("username"), connProps1.get("username"));
+ assertEquals(connProps.get("url"), connProps1.get("url"));
+ assertEquals(connProps.get("password"), connProps1.get("password"));
+
+ Map refAddr = dbInfo.getProperties();
+
+ initContext.getInitialContextBinder().bind("testjdbcjcr2", "javax.sql.DataSource",
+ "org.apache.commons.dbcp.BasicDataSourceFactory", null,
+ refAddr);
+
+ DataSource ds = (DataSource)initContext.getInitialContext().lookup("testjdbcjcr2");
+ assertNotNull(ds);
+
+ Connection conn = ds.getConnection();
+ assertNotNull(conn);
+ }
+
+ public void testDBCreateMultiThread() throws Exception
+ {
+ DBCreateThread[] queue = new DBCreateThread[100];
+
+ for (int i = 0; i < queue.length; i++)
+ {
+ queue[i] = new DBCreateThread(i);
+ queue[i].start();
+ }
+
+ for (int i = 0; i < queue.length; i++)
+ {
+ queue[i].join();
+ }
+
+ for (int i = 0; i < queue.length; i++)
+ {
+ DataSource ds = (DataSource)initContext.getInitialContext().lookup("testjdbcjcr_" + i);
+ assertNotNull(ds);
+
+ Connection conn = ds.getConnection();
+ assertNotNull(conn);
+ }
+
+ }
+
+ class DBCreateThread extends Thread
+ {
+
+ private final int threadNumber;
+
+ DBCreateThread(int threadNumber)
+ {
+ this.threadNumber = threadNumber;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void run()
+ {
+ try
+ {
+ DBConnectionInfo dbInfo = dbCreator.createDatabase("testdb_" + threadNumber);
+
+ Map refAddr = dbInfo.getProperties();
+
+ initContext.getInitialContextBinder().bind("testjdbcjcr_" + threadNumber, "javax.sql.DataSource",
+ "org.apache.commons.dbcp.BasicDataSourceFactory", null, refAddr);
+ }
+ catch (Exception e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+
+}
diff --git a/exo.core.component.database/src/test/java/org/exoplatform/services/database/TestDatabaseService.java b/exo.core.component.database/src/test/java/org/exoplatform/services/database/TestDatabaseService.java
new file mode 100644
index 00000000..766efbd0
--- /dev/null
+++ b/exo.core.component.database/src/test/java/org/exoplatform/services/database/TestDatabaseService.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import junit.framework.TestCase;
+
+import org.exoplatform.container.PortalContainer;
+import org.exoplatform.services.database.impl.XAPoolTxSupportDatabaseService;
+import org.exoplatform.services.database.table.ExoLongID;
+import org.exoplatform.services.database.table.IDGenerator;
+import org.exoplatform.services.transaction.TransactionService;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+
+import javax.transaction.UserTransaction;
+
+/**
+ * Thu, May 15, 2003 @
+ * @author Tuan Nguyen
+ * @version $Id: TestDatabaseService.java 5332 2006-04-29 18:32:44Z geaz $
+ * @since 0.0
+ * @email tuan08@yahoo.com
+ */
+public class TestDatabaseService extends TestCase
+{
+
+ public void testDatabaseService() throws Exception
+ {
+ PortalContainer pcontainer = PortalContainer.getInstance();
+ DatabaseService service =
+ (DatabaseService)pcontainer.getComponentInstanceOfType(XAPoolTxSupportDatabaseService.class);
+ assertNotNull(service);
+ assertConfiguration(service);
+ assertDBTableManager(service);
+ assertIDGenerator(service);
+ }
+
+ private void assertConfiguration(DatabaseService service) throws Exception
+ {
+ TransactionService txservice = service.getTransactionService();
+ assertTrue(service != null);
+ UserTransaction utx = txservice.getUserTransaction();
+ Connection conn = service.getConnection();
+ Statement s = null;
+ utx.begin();
+ try
+ {
+ s = conn.createStatement();
+ s.addBatch("create table test (name varchar(25), data varchar(25))");
+ s.addBatch("insert into test values('name1', 'value1')");
+ s.executeBatch();
+ s.close();
+ /*
+ * Call conn.commit() will cause an exception since the connection is now
+ * part of a global transaction. You should call utx.commit() here
+ */
+ conn.commit();
+ utx.commit();
+ }
+ catch (Exception ex)
+ {
+ utx.rollback();
+ }
+ // tm.rollback() ;
+ service.closeConnection(conn);
+ conn = service.getConnection();
+ s = conn.createStatement();
+ ResultSet rs = s.executeQuery("select name from test");
+ if (rs.next())
+ {
+ fail("Should not have any data in the test table");
+ }
+ }
+
+ private void assertDBTableManager(DatabaseService service) throws Exception
+ {
+ ExoDatasource datasource = service.getDatasource();
+ DBTableManager dbManager = datasource.getDBTableManager();
+ assertEquals(dbManager.hasTable(Mock.class), false);
+ dbManager.createTable(Mock.class, true);
+
+ assertEquals(dbManager.hasTable(Mock.class), true);
+ dbManager.dropTable(Mock.class);
+
+ assertEquals(dbManager.hasTable(Mock.class), false);
+ }
+
+ private void assertIDGenerator(DatabaseService service) throws Exception
+ {
+ ExoDatasource datasource = service.getDatasource();
+ IDGenerator idGenerator = new IDGenerator(datasource);
+
+ for (int i = 0; i < 10; i++)
+ {
+ idGenerator.generateLongId(ExoLongID.class);
+ }
+
+ idGenerator.restartTracker();
+ idGenerator.generateLongId(ExoLongID.class);
+ }
+
+}
diff --git a/exo.core.component.database/src/test/java/org/exoplatform/services/database/TestHibernateService.java b/exo.core.component.database/src/test/java/org/exoplatform/services/database/TestHibernateService.java
new file mode 100644
index 00000000..6b70fdd0
--- /dev/null
+++ b/exo.core.component.database/src/test/java/org/exoplatform/services/database/TestHibernateService.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import junit.framework.TestCase;
+
+import org.exoplatform.container.PortalContainer;
+
+/**
+ * Thu, May 15, 2003 @
+ * @author Tuan Nguyen
+ * @version $Id: TestDatabaseService.java 5332 2006-04-29 18:32:44Z geaz $
+ * @since 0.0
+ * @email tuan08@yahoo.com
+ */
+public class TestHibernateService extends TestCase
+{
+ HibernateService hservice_;
+
+ public TestHibernateService(String name)
+ {
+ super(name);
+ }
+
+ public void setUp() throws Exception
+ {
+ PortalContainer pcontainer = PortalContainer.getInstance();
+ hservice_ = (HibernateService)pcontainer.getComponentInstanceOfType(HibernateService.class);
+ }
+
+ public void testDabaseService() throws Exception
+ {
+ // assertTrue("Expect hibernate service instance" , hservice_ != null) ;
+ assertTrue("Expect database service instance", hservice_ != null);
+ }
+
+ protected String getDescription()
+ {
+ return "Test Database Service";
+ }
+}
diff --git a/exo.core.component.database/src/test/java/org/exoplatform/services/database/TestQueryManager.java b/exo.core.component.database/src/test/java/org/exoplatform/services/database/TestQueryManager.java
new file mode 100644
index 00000000..ee315141
--- /dev/null
+++ b/exo.core.component.database/src/test/java/org/exoplatform/services/database/TestQueryManager.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.database;
+
+import junit.framework.TestCase;
+
+/**
+ * Created by The eXo Platform SAS Author : Nhu Dinh Thuan
+ * nhudinhthuan@exoplatform.com Mar 30, 2007
+ */
+public class TestQueryManager extends TestCase
+{
+
+ QueryBuilder manager_;
+
+ public TestQueryManager(String name)
+ {
+ super(name);
+ }
+
+ public void setUp() throws Exception
+ {
+ manager_ = new QueryBuilder();
+ }
+
+ public void testPaser() throws Exception
+ {
+ String template = "select name from $table where id = $id and name like '&yahoo'";
+ String[][] parameters = {{"table", "student"}, {"id", "12345"}};
+ String pamameterSql = manager_.mapDataToSql(template, parameters);
+ }
+
+ static public class Student
+ {
+
+ String name, value;
+
+ public Student(String n, String v)
+ {
+ name = n;
+ value = v;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setValue(String value)
+ {
+ this.value = value;
+ }
+ }
+
+}
diff --git a/exo.core.component.database/src/test/java/org/exoplatform/services/transaction/impl/atomikos/TransactionsEssentialsTransactionService.java b/exo.core.component.database/src/test/java/org/exoplatform/services/transaction/impl/atomikos/TransactionsEssentialsTransactionService.java
new file mode 100644
index 00000000..304829a7
--- /dev/null
+++ b/exo.core.component.database/src/test/java/org/exoplatform/services/transaction/impl/atomikos/TransactionsEssentialsTransactionService.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.transaction.impl.atomikos;
+
+import com.atomikos.icatch.jta.UserTransactionManager;
+
+import org.exoplatform.services.transaction.TransactionService;
+import org.exoplatform.services.transaction.impl.AbstractTransactionService;
+import org.exoplatform.services.transaction.impl.jboss.JBossTransactionService;
+
+import org.picocontainer.Startable;
+
+import javax.transaction.TransactionManager;
+import javax.transaction.UserTransaction;
+
+/**
+ * An implementation of a {@link TransactionService} for TransactionsEssentials from Atomikos
+ * to be used in standalone mode
+ *
+ * @deprecated {@link JBossTransactionService} used in all cases instead
+ * @author Nicolas Filotto
+ * @version $Id$
+ *
+ */
+@Deprecated
+public class TransactionsEssentialsTransactionService extends AbstractTransactionService implements Startable
+{
+
+ /**
+ * @see org.exoplatform.services.transaction.impl.AbstractTransactionService#findTransactionManager()
+ */
+ @Override
+ protected TransactionManager findTransactionManager() throws Exception
+ {
+ UserTransactionManager tm = new UserTransactionManager();
+ tm.init();
+ return tm;
+ }
+
+ /**
+ * @see org.exoplatform.services.transaction.impl.AbstractTransactionService#findUserTransaction()
+ */
+ @Override
+ protected UserTransaction findUserTransaction() throws Exception
+ {
+ return (UserTransaction)getTransactionManager();
+ }
+
+ /**
+ * @see org.picocontainer.Startable#start()
+ */
+ public void start()
+ {
+ }
+
+ /**
+ * @see org.picocontainer.Startable#stop()
+ */
+ public void stop()
+ {
+ if (isTMInitialized())
+ {
+ TransactionManager tm = getTransactionManager();
+ if (tm instanceof UserTransactionManager)
+ {
+ UserTransactionManager utm = (UserTransactionManager)tm;
+ utm.close();
+ }
+ }
+ }
+}
diff --git a/exo.core.component.database/src/test/java/org/exoplatform/services/transaction/impl/jboss/JBossTransactionService.java b/exo.core.component.database/src/test/java/org/exoplatform/services/transaction/impl/jboss/JBossTransactionService.java
new file mode 100644
index 00000000..f9593a4b
--- /dev/null
+++ b/exo.core.component.database/src/test/java/org/exoplatform/services/transaction/impl/jboss/JBossTransactionService.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.transaction.impl.jboss;
+
+import org.exoplatform.services.transaction.impl.AbstractTransactionService;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.ObjectName;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.transaction.TransactionManager;
+import javax.transaction.UserTransaction;
+
+/**
+ * @author Julien Viet
+ * @version $Revision$
+ */
+public class JBossTransactionService extends AbstractTransactionService
+{
+
+ /**
+ * {@inheritDoc}
+ */
+ public TransactionManager findTransactionManager()
+ {
+ try
+ {
+ return (TransactionManager)new InitialContext().lookup("java:/TransactionManager");
+ }
+ catch (NamingException e)
+ {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public UserTransaction findUserTransaction()
+ {
+ try
+ {
+ return (UserTransaction)new InitialContext().lookup("java:comp/UserTransaction");
+ }
+ catch (NamingException e)
+ {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getDefaultTimeout()
+ {
+ try
+ {
+ MBeanServer server = (MBeanServer)MBeanServerFactory.findMBeanServer(null).iterator().next();
+ return (Integer)server.getAttribute(ObjectName.getInstance("jboss:service=TransactionManager"),
+ "TransactionTimeout");
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException(e);
+ }
+ }
+}
diff --git a/exo.core.component.database/src/test/resources/conf/portal/test-configuration.xml b/exo.core.component.database/src/test/resources/conf/portal/test-configuration.xml
new file mode 100644
index 00000000..7221e1d3
--- /dev/null
+++ b/exo.core.component.database/src/test/resources/conf/portal/test-configuration.xml
@@ -0,0 +1,134 @@
+
+
+
+
+
+ org.exoplatform.services.cache.CacheService
+ cache:type=CacheService
+ org.exoplatform.services.cache.impl.CacheServiceImpl
+
+
+ cache.config.default
+ The default cache configuration
+
+
+ default
+
+
+ 300
+
+
+ 300
+
+
+ false
+
+
+ org.exoplatform.services.cache.concurrent.ConcurrentFIFOExoCache
+
+
+
+
+
+
+
+ org.exoplatform.services.database.DatabaseService
+ org.exoplatform.services.database.impl.XAPoolTxSupportDatabaseService
+ support the transaction db connection pool implementation
+
+
+ connection.config
+ Connection configuration
+
+
+
+
+
+
+
+
+
+
+
+ org.exoplatform.services.transaction.TransactionService
+ org.exoplatform.services.transaction.impl.atomikos.TransactionsEssentialsTransactionService
+
+
+ timeout
+ 5
+
+
+
+
+
+ org.exoplatform.services.database.HibernateService
+ org.exoplatform.services.database.impl.HibernateServiceImpl
+
+
+ hibernate.properties
+ Default Hibernate Service
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jcr.datasource
+ org.exoplatform.services.database.impl.HibernateServiceImpl
+
+
+ hibernate.properties
+ JCR Workspace datasource
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ classpath:/conf/standalone/test-configuration.xml
+
diff --git a/exo.core.component.database/src/test/resources/conf/standalone/test-configuration.xml b/exo.core.component.database/src/test/resources/conf/standalone/test-configuration.xml
new file mode 100644
index 00000000..8eb12fa1
--- /dev/null
+++ b/exo.core.component.database/src/test/resources/conf/standalone/test-configuration.xml
@@ -0,0 +1,140 @@
+
+
+
+
+
+ org.exoplatform.services.log.LogConfigurationInitializer
+ org.exoplatform.services.log.LogConfigurationInitializer
+
+
+ logger
+ org.exoplatform.services.log.impl.BufferedLog4JLogger
+
+
+ configurator
+ org.exoplatform.services.log.impl.SimpleExoLogConfigurator
+
+
+
+
+
+ org.exoplatform.services.database.jdbc.DBSchemaCreator
+ org.exoplatform.services.database.jdbc.DBSchemaCreator
+
+
+ create.dbschema
+ addPlugin
+ org.exoplatform.services.database.jdbc.CreateDBSchemaPlugin
+
+
+ data-source
+ jdbcjcr
+
+
+ script
+
+
+
+
+
+
+
+
+
+
+ org.exoplatform.services.database.creator.DBCreator
+ org.exoplatform.services.database.creator.DBCreator
+
+
+ db-connection
+ database connection properties
+
+
+
+
+
+
+ db-creation
+ database creation properties
+
+
+
+
+
+
+
+
+ org.exoplatform.services.naming.InitialContextInitializer
+ org.exoplatform.services.naming.InitialContextInitializer
+
+
+ bind.datasource
+ addPlugin
+ org.exoplatform.services.naming.BindReferencePlugin
+
+
+ bind-name
+ jdbcjcr
+
+
+ class-name
+ javax.sql.DataSource
+
+
+ factory
+ org.apache.commons.dbcp.BasicDataSourceFactory
+
+
+ ref-addresses
+ ref-addresses
+
+
+
+
+
+
+
+
+
+
+ default-properties
+ Default initial context properties
+
+
+
+
+
+
+
diff --git a/exo.core.component.database/src/test/resources/dbcreator/test.sql b/exo.core.component.database/src/test/resources/dbcreator/test.sql
new file mode 100644
index 00000000..e69de29b
diff --git a/exo.core.component.database/src/test/resources/test.policy b/exo.core.component.database/src/test/resources/test.policy
new file mode 100644
index 00000000..f8801c31
--- /dev/null
+++ b/exo.core.component.database/src/test/resources/test.policy
@@ -0,0 +1,15 @@
+grant codeBase "@MAVEN_REPO@-"{
+ permission java.security.AllPermission;
+};
+
+grant codeBase "@MAIN_CLASSES@-"{
+ permission java.security.AllPermission;
+};
+
+grant codeBase "@TEST_CLASSES@-"{
+};
+
+
+
+
+
diff --git a/exo.kernel.component.command/pom.xml b/exo.kernel.component.command/pom.xml
new file mode 100644
index 00000000..8f1a50c9
--- /dev/null
+++ b/exo.kernel.component.command/pom.xml
@@ -0,0 +1,107 @@
+
+
+
+
+
+ 4.0.0
+
+
+ org.exoplatform.commons-exo
+ commons-exo
+ 7.0.x-SNAPSHOT
+
+
+ exo.kernel.component.command
+
+ Meeds:: PLF:: Kernel :: Component :: Command Service
+ Implementation of Command Service of Exoplatform SAS 'eXo Kernel' project.
+
+
+ 0.35
+
+
+
+
+ io.meeds.kernel
+ exo.kernel.container
+
+
+ io.meeds.kernel
+ exo.kernel.commons.test
+ test
+
+
+ io.github.weblegacy
+ commons-chain-web-jakarta-servlet
+
+
+ xml-apis
+ xml-apis
+
+
+
+
+ commons-digester
+ commons-digester
+
+
+ commons-logging
+ commons-logging
+
+
+
+
+
+
+
+ maven-antrun-plugin
+
+
+ prepare-test-policy
+ process-test-resources
+
+
+ Creating Access Policy for tests
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ run
+
+
+
+
+
+
+
diff --git a/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/action/Action.java b/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/action/Action.java
new file mode 100644
index 00000000..3adafff3
--- /dev/null
+++ b/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/action/Action.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.command.action;
+
+import org.apache.commons.chain.Command;
+
+/**
+ * Created by The eXo Platform SAS
+ *
+ * Action interface extends Command interface.
+ *
+ * @author Gennady Azarenkov
+ * @LevelAPI Platform
+ */
+
+public interface Action extends Command
+{
+
+}
diff --git a/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/action/ActionCatalog.java b/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/action/ActionCatalog.java
new file mode 100644
index 00000000..720d7aa1
--- /dev/null
+++ b/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/action/ActionCatalog.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.command.action;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * @author Gennady Azarenkov
+ * @version $Id: $
+ */
+
+public class ActionCatalog
+{
+
+ private Map commands;
+
+ public ActionCatalog()
+ {
+ this.commands = new HashMap();
+ }
+
+ public Set getAllActions()
+ {
+ return new HashSet(commands.values());
+ }
+
+ public Map getAllEntries()
+ {
+ return commands;
+ }
+
+ public Set getActions(Condition conditions)
+ {
+ HashSet actions = new HashSet();
+ for (Map.Entry entry : commands.entrySet())
+ {
+ if (entry.getKey().match(conditions))
+ actions.add(entry.getValue());
+ }
+ return actions;
+ }
+
+ public Action getAction(Condition conditions, int index)
+ {
+ Iterator actions = getActions(conditions).iterator();
+ for (int i = 0; actions.hasNext(); i++)
+ {
+ Action c = actions.next();
+ if (i == index)
+ return c;
+ }
+ return null;
+ }
+
+ public void addAction(ActionMatcher matcher, Action action)
+ {
+ commands.put(matcher, action);
+ }
+
+ public void clear()
+ {
+ commands.clear();
+ }
+}
diff --git a/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/action/ActionMatcher.java b/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/action/ActionMatcher.java
new file mode 100644
index 00000000..064c9b4e
--- /dev/null
+++ b/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/action/ActionMatcher.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.command.action;
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * @author Gennady Azarenkov
+ * @version $Id: $
+ */
+
+public interface ActionMatcher
+{
+ boolean match(Condition conditions);
+}
diff --git a/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/action/ActionService.java b/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/action/ActionService.java
new file mode 100644
index 00000000..3e6ecf0f
--- /dev/null
+++ b/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/action/ActionService.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.command.action;
+
+import java.util.HashMap;
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * @author Gennady Azarenkov
+ * @version $Id: $
+ */
+
+public class ActionService extends HashMap
+{
+
+ // public void addPlugin(ComponentPlugin plugin) {
+ // if (plugin instanceof AddActionCatalogPlugin) {
+ // AddActionCatalogPlugin cplugin = (AddActionCatalogPlugin) plugin;
+ // CatalogConfiguration conf = cplugin.getCatalogConfiguration();
+ // ActionCatalog catalog = new ActionCatalog();
+ // for(ActionConfiguration ac:(List )conf.getActions()) {
+ // try {
+ // ActionMatcher matcher =
+ // (ActionMatcher)Class.forName(ac.getMatcherFQCN()).newInstance();
+ // Action action = (Action)Class.forName(ac.getActionFQCN()).newInstance();
+ // catalog.addAction(matcher, action);
+ // } catch (Exception e) {
+ // e.printStackTrace();
+ // }
+ // }
+ // put(conf.getName(), catalog);
+ // }
+ // }
+
+}
diff --git a/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/action/Condition.java b/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/action/Condition.java
new file mode 100644
index 00000000..38f6f003
--- /dev/null
+++ b/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/action/Condition.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.command.action;
+
+import java.util.HashMap;
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * @author Gennady Azarenkov
+ * @version $Id: $
+ */
+
+public class Condition extends HashMap
+{
+
+}
diff --git a/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/action/package-info.java b/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/action/package-info.java
new file mode 100644
index 00000000..0941b965
--- /dev/null
+++ b/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/action/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * This package provides classes to manage {@link org.exoplatform.services.command.action.Action}
+ */
+package org.exoplatform.services.command.action;
\ No newline at end of file
diff --git a/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/impl/CommandLineParser.java b/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/impl/CommandLineParser.java
new file mode 100644
index 00000000..929a761b
--- /dev/null
+++ b/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/impl/CommandLineParser.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.command.impl;
+
+import org.apache.commons.chain.Context;
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * @author Gennady Azarenkov
+ * @version $Id: $
+ */
+public interface CommandLineParser
+{
+
+ /**
+ * parses command line and puts some parameters (if any) to the Context by
+ * some rules
+ *
+ * @param commandLine
+ * @param context
+ * @return command name
+ */
+ String parse(String commandLine, Context context);
+}
diff --git a/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/impl/CommandService.java b/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/impl/CommandService.java
new file mode 100644
index 00000000..5bfe05eb
--- /dev/null
+++ b/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/impl/CommandService.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.command.impl;
+
+import org.apache.commons.chain.Catalog;
+import org.apache.commons.chain.CatalogFactory;
+import org.apache.commons.chain.config.ConfigParser;
+import org.apache.commons.chain.impl.CatalogFactoryBase;
+import org.apache.commons.digester.Digester;
+import org.exoplatform.container.component.ComponentPlugin;
+import org.exoplatform.container.spi.DefinitionByType;
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Iterator;
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * @author Gennady
+ * Azarenkov
+ * @version $Id: CommandService.java 12832 2007-02-15 12:41:32Z geaz $
+ */
+@DefinitionByType
+public class CommandService
+{
+
+ // protected Catalog catalog;
+
+ protected CatalogFactory catalogFactory;
+
+ protected Digester digester;
+
+ public CommandService()
+ {
+ this.catalogFactory = CatalogFactoryBase.getInstance();
+
+ final ConfigParser parser = new ConfigParser();
+ this.digester = parser.getDigester();
+ }
+
+ public void addPlugin(ComponentPlugin plugin)
+ {
+ // no needs to do anything as CatalogFactory is initialized in plugin
+
+ // if (plugin instanceof CommonsXMLConfigurationPlugin) {
+ // CommonsXMLConfigurationPlugin cplugin = (CommonsXMLConfigurationPlugin)
+ // plugin;
+ // can just reinitialize it every time as have single instance
+ // catalog = cplugin.getCatalog();
+ // Iterator names = cplugin.getCatalogNames();
+ // while(names.hasNext()) {
+ // String name = (String)names.next();
+ // catalogs.put(name, cplugin.getCatalog(name));
+ // }
+ // }
+ }
+
+ /**
+ * puts catalog (add or update) using XML input stream
+ *
+ * @param xml
+ * @throws IOException
+ * @throws SAXException
+ */
+ public void putCatalog(final InputStream xml) throws IOException, SAXException
+ {
+ digester.clear();
+ digester.parse(xml);
+ }
+
+ /**
+ * @return default catalog
+ */
+ public Catalog getCatalog()
+ {
+ Catalog catalog = catalogFactory.getCatalog();
+ return catalog;
+ }
+
+ /**
+ * @param name
+ * @return named catalog
+ */
+ public Catalog getCatalog(String name)
+ {
+ Catalog catalog = catalogFactory.getCatalog(name);
+ return catalog;
+
+ }
+
+ /**
+ * @return iterator of catalog names. default catalog is not listed here!
+ */
+ public Iterator getCatalogNames()
+ {
+ return catalogFactory.getNames();
+ }
+
+}
diff --git a/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/impl/CommonsXMLConfigurationPlugin.java b/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/impl/CommonsXMLConfigurationPlugin.java
new file mode 100644
index 00000000..defb60e7
--- /dev/null
+++ b/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/impl/CommonsXMLConfigurationPlugin.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.command.impl;
+
+import org.apache.commons.chain.config.ConfigParser;
+import org.exoplatform.container.component.BaseComponentPlugin;
+import org.exoplatform.container.configuration.ConfigurationManager;
+import org.exoplatform.container.xml.InitParams;
+import org.exoplatform.container.xml.ValueParam;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+
+import java.net.URL;
+
+/**
+ * Created by The eXo Platform SAS. The plugin for configuring
+ * command/chain catalog using "native" Apache Commons Chain's XML file
+ *
+ * @author Gennady
+ * Azarenkov
+ * @version $Id: CommonsXMLConfigurationPlugin.java 9846 2006-10-27 11:03:37Z
+ * geaz $
+ */
+
+public class CommonsXMLConfigurationPlugin extends BaseComponentPlugin
+{
+
+ // protected Catalog defaultCatalog;
+
+ private static final Log LOG = ExoLogger.getLogger("exo.kernel.component.cache.CommonsXMLConfigurationPlugin");
+
+ public CommonsXMLConfigurationPlugin(InitParams params, ConfigurationManager configurationManager) throws Exception
+ {
+ ValueParam confFile = params.getValueParam("config-file");
+ if (confFile != null)
+ {
+ final String path = confFile.getValue();
+ final ConfigParser parser = new ConfigParser();
+ // may work for StandaloneContainer
+
+ URL res = Thread.currentThread().getContextClassLoader().getResource(path);
+
+ // for PortalContainer
+ if (res == null)
+ res = configurationManager.getResource(path);
+ if (res == null)
+ throw new Exception("Resource not found " + path);
+ LOG.info("Catalog configuration found at " + res);
+
+ final URL fRes = res;
+ parser.parse(fRes);
+ }
+
+ }
+}
diff --git a/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/impl/SimpleCommandLineParser.java b/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/impl/SimpleCommandLineParser.java
new file mode 100644
index 00000000..59bfe5d8
--- /dev/null
+++ b/exo.kernel.component.command/src/main/java/org/exoplatform/services/command/impl/SimpleCommandLineParser.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.command.impl;
+
+import org.apache.commons.chain.Context;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * @author Gennady Azarenkov
+ * @version $Id: $
+ */
+
+public class SimpleCommandLineParser implements CommandLineParser
+{
+
+ protected final String parametersPropertyName;
+
+ public SimpleCommandLineParser(String parametersPropertyName)
+ {
+ this.parametersPropertyName = parametersPropertyName;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see
+ * org.exoplatform.services.command.impl.CommandLineParser#parse(java.lang
+ * .String, org.apache.commons.chain.Context)
+ */
+ public String parse(String commandLine, Context context)
+ {
+
+ context.remove(parametersPropertyName);
+
+ // the rules:
+ // first word is command name (should be returned)
+ // else are parameters of command (should be put into Context under name ==
+ // parametersPropertyName as array of Strings)
+ // mind contained string parameters - should be quoted (" or ')
+ // /////////////////////
+
+ StringTokenizer parser = new StringTokenizer(commandLine);
+ String commandName = null;
+ List params = new ArrayList();
+
+ while (parser.hasMoreTokens())
+ {
+ String str = parser.nextToken();
+ if (commandName == null)
+ commandName = str;
+ else
+ params.add(str);
+ }
+ // //////////////////////
+ context.put(parametersPropertyName, params);
+ return commandName;
+ }
+
+ /**
+ * @return parameters Property Name
+ */
+ public String getParametersPropertyName()
+ {
+ return parametersPropertyName;
+ }
+
+}
diff --git a/exo.kernel.component.command/src/test/java/org/exoplatform/services/command/CommandServiceTest.java b/exo.kernel.component.command/src/test/java/org/exoplatform/services/command/CommandServiceTest.java
new file mode 100644
index 00000000..e2c09318
--- /dev/null
+++ b/exo.kernel.component.command/src/test/java/org/exoplatform/services/command/CommandServiceTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.command;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.chain.Catalog;
+import org.apache.commons.chain.Command;
+import org.apache.commons.chain.Context;
+import org.apache.commons.chain.impl.CatalogFactoryBase;
+import org.apache.commons.chain.impl.ContextBase;
+import org.exoplatform.container.StandaloneContainer;
+import org.exoplatform.services.command.impl.CommandService;
+
+import java.io.ByteArrayInputStream;
+
+/**
+ * Created by The eXo Platform SAS .
+ *
+ * @author Gennady Azarenkov
+ * @version $Id: CommandServiceTest.java 9296 2006-10-04 13:13:29Z geaz $
+ */
+public class CommandServiceTest extends TestCase
+{
+
+ private static final String IS = "" + " " + " ";
+
+ private StandaloneContainer container;
+
+ public void setUp() throws Exception
+ {
+ StandaloneContainer.setConfigurationPath("src/test/resources/conf/standalone/test-configuration.xml");
+
+ container = StandaloneContainer.getInstance();
+ }
+
+ public void testPluginConf() throws Exception
+ {
+
+ CommandService cservice = (CommandService)container.getComponentInstanceOfType(CommandService.class);
+ assertNotNull(cservice);
+
+ // preconfigured commands
+ assertTrue(cservice.getCatalog().getNames().hasNext());
+ assertNotNull(cservice.getCatalog().getNames().next());
+
+ }
+
+ public void testStringConf() throws Exception
+ {
+ CommandService cservice = (CommandService)container.getComponentInstanceOfType(CommandService.class);
+ Catalog c = cservice.getCatalog();
+
+ assertNull(c.getCommand("StrCommand"));
+ cservice.putCatalog(new ByteArrayInputStream(IS.getBytes()));
+ Catalog c1 = cservice.getCatalog();
+ assertNotNull(c1.getCommand("StrCommand"));
+
+ }
+
+ public void testInitWithFile() throws Exception
+ {
+ CommandService cservice = (CommandService)container.getComponentInstanceOfType(CommandService.class);
+ cservice.putCatalog(getClass().getResourceAsStream("/conf/test-commands3.xml"));
+ assertTrue(cservice.getCatalogNames().hasNext());
+ Catalog c1 = cservice.getCatalog("catalog1");
+ assertNotNull(c1.getCommand("Command2"));
+
+ }
+
+ public void testExcecute() throws Exception
+ {
+
+ CommandService cservice = (CommandService)container.getComponentInstanceOfType(CommandService.class);
+ Command c1 = cservice.getCatalog().getCommand("Execute2");
+ Command c2 = cservice.getCatalog().getCommand("Command1");
+
+ Catalog c = cservice.getCatalog();
+
+ Context ctx = new ContextBase();
+ ctx.put("test", Integer.valueOf(0));
+ c1.execute(ctx);
+ c2.execute(ctx);
+ assertEquals(3, ((Integer)ctx.get("test")).intValue());
+
+ }
+
+ public void tearDown() {
+ CatalogFactoryBase.clear();
+ container.stop();
+
+ }
+
+}
diff --git a/exo.kernel.component.command/src/test/java/org/exoplatform/services/command/MultiConfigServiceTest.java b/exo.kernel.component.command/src/test/java/org/exoplatform/services/command/MultiConfigServiceTest.java
new file mode 100644
index 00000000..10f865be
--- /dev/null
+++ b/exo.kernel.component.command/src/test/java/org/exoplatform/services/command/MultiConfigServiceTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.command;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.chain.impl.CatalogFactoryBase;
+import org.exoplatform.container.ExoContainer;
+import org.exoplatform.container.ExoContainerContext;
+import org.exoplatform.container.PortalContainer;
+import org.exoplatform.container.RootContainer;
+import org.exoplatform.container.StandaloneContainer;
+import org.exoplatform.services.command.impl.CommandService;
+
+import java.io.ByteArrayInputStream;
+import java.util.Iterator;
+
+/**
+ * Created by The eXo Platform SAS .
+ *
+ * @author Gennady Azarenkov
+ * @version $Id:$
+ */
+public class MultiConfigServiceTest extends TestCase
+{
+
+ private StandaloneContainer container;
+
+ private static final String IS =
+ "" + " " + " ";
+
+ // amount of commands configured in multiple plugins
+ // CHECK it if change test-multi-configuration.xml !!!
+ private final int NUMBER_OF_COMMANDS_IN_DEF = 4;
+
+ private final int NUMBER_OF_COMMANDS_IN_CATALOG1 = 2;
+
+ public void setUp() throws Exception
+ {
+ StandaloneContainer.setConfigurationPath("src/test/resources/conf/standalone/test-multi-configuration.xml");
+
+ container = StandaloneContainer.getInstance();
+ }
+
+ /**
+ * Tests if multiple configuration is allowed
+ *
+ * @throws Exception
+ */
+ public void testMultiConfig() throws Exception
+ {
+
+ CommandService cservice = (CommandService)container.getComponentInstanceOfType(CommandService.class);
+ assertNotNull(cservice);
+
+ assertTrue(cservice.getCatalogNames().hasNext());
+
+ Iterator commands = cservice.getCatalog().getNames();
+ int cnt = 0;
+ while (commands.hasNext())
+ {
+ commands.next();
+ cnt++;
+ }
+
+ assertEquals(NUMBER_OF_COMMANDS_IN_DEF, cnt);
+
+ commands = cservice.getCatalog("catalog1").getNames();
+ cnt = 0;
+ while (commands.hasNext())
+ {
+ commands.next();
+ cnt++;
+ }
+
+ assertEquals(NUMBER_OF_COMMANDS_IN_CATALOG1, cnt);
+
+ }
+
+ public void testIfPutCatalogDoesNotRemoveCommands() throws Exception
+ {
+
+ CommandService cservice = (CommandService)container.getComponentInstanceOfType(CommandService.class);
+ assertNotNull(cservice);
+
+ assertTrue(cservice.getCatalogNames().hasNext());
+ Iterator commands = cservice.getCatalog().getNames();
+ int cnt = 0;
+ while (commands.hasNext())
+ {
+ commands.next();
+ cnt++;
+ }
+
+ ByteArrayInputStream is = new ByteArrayInputStream(IS.getBytes());
+
+ cservice.putCatalog(is);
+
+ assertTrue(cservice.getCatalogNames().hasNext());
+ commands = cservice.getCatalog().getNames();
+ cnt = 0;
+ while (commands.hasNext())
+ {
+ commands.next();
+ cnt++;
+ }
+
+ commands = cservice.getCatalog("fromput").getNames();
+ cnt = 0;
+ while (commands.hasNext())
+ {
+ commands.next();
+ cnt++;
+ }
+
+ }
+
+ public void tearDown() {
+ CatalogFactoryBase.clear();
+ container.stop();
+
+ }
+}
diff --git a/exo.kernel.component.command/src/test/java/org/exoplatform/services/command/TestCommand1.java b/exo.kernel.component.command/src/test/java/org/exoplatform/services/command/TestCommand1.java
new file mode 100644
index 00000000..0613a380
--- /dev/null
+++ b/exo.kernel.component.command/src/test/java/org/exoplatform/services/command/TestCommand1.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.command;
+
+import org.apache.commons.chain.Command;
+import org.apache.commons.chain.Context;
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * @author Gennady
+ * Azarenkov
+ * @version $Id: TestCommand1.java 5799 2006-05-28 17:55:42Z geaz $
+ */
+
+public class TestCommand1 implements Command
+{
+
+ public boolean execute(Context ctx) throws Exception
+ {
+ int tval = ((Integer)ctx.get("test")).intValue() + 1;
+ ctx.put("test", Integer.valueOf(tval));
+ return false;
+ }
+
+}
diff --git a/exo.kernel.component.command/src/test/resources/conf/standalone/test-configuration.xml b/exo.kernel.component.command/src/test/resources/conf/standalone/test-configuration.xml
new file mode 100644
index 00000000..628a0cfd
--- /dev/null
+++ b/exo.kernel.component.command/src/test/resources/conf/standalone/test-configuration.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+ org.exoplatform.services.command.impl.CommandService
+ org.exoplatform.services.command.impl.CommandService
+
+
+ config.catalog
+ addPlugin
+ org.exoplatform.services.command.impl.CommonsXMLConfigurationPlugin
+
+
+ config-file
+ conf/test-commands.xml
+
+
+
+
+
+
+
+ org.exoplatform.services.command.action.ActionService
+
+
+
diff --git a/exo.kernel.component.command/src/test/resources/conf/standalone/test-multi-configuration.xml b/exo.kernel.component.command/src/test/resources/conf/standalone/test-multi-configuration.xml
new file mode 100644
index 00000000..99a3cb54
--- /dev/null
+++ b/exo.kernel.component.command/src/test/resources/conf/standalone/test-multi-configuration.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+ org.exoplatform.services.command.impl.CommandService
+ org.exoplatform.services.command.impl.CommandService
+
+
+ config.catalog
+ addPlugin
+ org.exoplatform.services.command.impl.CommonsXMLConfigurationPlugin
+
+
+ config-file
+ conf/test-commands.xml
+
+
+
+
+ config.catalog
+ addPlugin
+ org.exoplatform.services.command.impl.CommonsXMLConfigurationPlugin
+
+
+ config-file
+ conf/test-commands2.xml
+
+
+
+
+ config.catalog
+ addPlugin
+ org.exoplatform.services.command.impl.CommonsXMLConfigurationPlugin
+
+
+ config-file
+ conf/test-commands3.xml
+
+
+
+
+
+
+
diff --git a/exo.kernel.component.command/src/test/resources/conf/test-commands.xml b/exo.kernel.component.command/src/test/resources/conf/test-commands.xml
new file mode 100644
index 00000000..9c6dfc72
--- /dev/null
+++ b/exo.kernel.component.command/src/test/resources/conf/test-commands.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/exo.kernel.component.command/src/test/resources/conf/test-commands2.xml b/exo.kernel.component.command/src/test/resources/conf/test-commands2.xml
new file mode 100644
index 00000000..fa5fc842
--- /dev/null
+++ b/exo.kernel.component.command/src/test/resources/conf/test-commands2.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
diff --git a/exo.kernel.component.command/src/test/resources/conf/test-commands3.xml b/exo.kernel.component.command/src/test/resources/conf/test-commands3.xml
new file mode 100644
index 00000000..4d94991f
--- /dev/null
+++ b/exo.kernel.component.command/src/test/resources/conf/test-commands3.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
diff --git a/exo.kernel.component.command/src/test/resources/test.policy b/exo.kernel.component.command/src/test/resources/test.policy
new file mode 100644
index 00000000..4eb23700
--- /dev/null
+++ b/exo.kernel.component.command/src/test/resources/test.policy
@@ -0,0 +1,27 @@
+grant codeBase "@MAVEN_REPO@-"{
+ permission java.security.AllPermission;
+};
+
+grant codeBase "@MAIN_CLASSES@-"{
+ permission java.security.AllPermission;
+};
+
+grant codeBase "@TEST_CLASSES@-"{
+ permission java.lang.RuntimePermission "manageContainer";
+};
+
+grant codeBase "@MAIN_CLASSES@../../../exo.kernel.commons.test/-"{
+ permission java.security.AllPermission;
+};
+
+grant codeBase "@MAIN_CLASSES@../../../exo.kernel.commons/-"{
+ permission java.security.AllPermission;
+};
+
+grant codeBase "@MAIN_CLASSES@../../../exo.kernel.container/-"{
+ permission java.security.AllPermission;
+};
+
+
+
+
diff --git a/exo.kernel.component.ext.cache.impl.infinispan.v8/pom.xml b/exo.kernel.component.ext.cache.impl.infinispan.v8/pom.xml
new file mode 100644
index 00000000..d53f37b0
--- /dev/null
+++ b/exo.kernel.component.ext.cache.impl.infinispan.v8/pom.xml
@@ -0,0 +1,153 @@
+
+
+
+
+ 4.0.0
+
+ org.exoplatform.commons-exo
+ commons-exo
+ 7.0.x-SNAPSHOT
+
+ exo.kernel.component.ext.cache.impl.infinispan.v8
+ Meeds:: PLF:: Kernel :: Cache Extension :: Infinispan Implementation
+ Infinispan Implementation of Cache Service for Exoplatform SAS 'eXo Kernel' project.
+
+ 0.6
+
+
+
+ io.meeds.kernel
+ exo.kernel.component.cache
+
+
+ io.meeds.kernel
+ exo.kernel.component.common
+
+
+ ${project.groupId}
+ exo.core.component.database
+
+
+ org.infinispan
+ infinispan-core
+
+
+ org.jboss.spec.javax.transaction
+ jboss-transaction-api_1.1_spec
+
+
+ org.jboss.logging
+ jboss-logging
+
+
+ org.jgroups
+ jgroups
+
+
+
+
+ org.jboss.logging
+ jboss-logging
+
+
+ org.jboss.jbossts
+ jbossjta
+
+
+ org.jgroups
+ jgroups
+
+
+ io.meeds.kernel
+ exo.kernel.container
+
+
+ io.meeds.kernel
+ exo.kernel.commons.test
+ test
+
+
+ junit
+ junit
+ test
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+ @{argLine} @{surefire.argLine} -Djava.net.preferIPv4Stack=true
+
+
+
+ jgroups.bind_addr
+ 127.0.0.1
+
+
+ jgroups.stack
+ udp
+
+
+
+
+
+ maven-antrun-plugin
+
+
+ prepare-test-policy
+ process-test-resources
+
+
+ Creating Access Policy for tests
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ run
+
+
+
+
+
+ ant
+ ant-optional
+ 1.5.3-1
+
+
+
+
+
+
diff --git a/exo.kernel.component.ext.cache.impl.infinispan.v8/src/main/java/org/exoplatform/container/util/TemplateConfigurationHelper.java b/exo.kernel.component.ext.cache.impl.infinispan.v8/src/main/java/org/exoplatform/container/util/TemplateConfigurationHelper.java
new file mode 100644
index 00000000..223b0aac
--- /dev/null
+++ b/exo.kernel.component.ext.cache.impl.infinispan.v8/src/main/java/org/exoplatform/container/util/TemplateConfigurationHelper.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.container.util;
+
+import org.exoplatform.container.configuration.ConfigurationManager;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.regex.Pattern;
+
+/**
+ * Builds configuration from template using map of template-variables -- value.
+ * Class provides extra functionality for filtering parameters by pattern, excluding
+ * unnecessary parameters.
+ *
+ * @author Nikolay Zamosenchuk
+ * @version $Id: TemplateConfigurationHelper.java 34360 2009-07-22 23:58:59Z nzamosenchuk $
+ *
+ */
+public class TemplateConfigurationHelper
+{
+
+ private static final Log LOG = ExoLogger.getLogger("exo.kernel.container.TemplateConfigurationHelper");
+
+ // list with include-patterns
+ private List includes = new ArrayList();
+
+ // list with exclude-patterns
+ private List excludes = new ArrayList();
+
+ private ConfigurationManager cfm;
+
+ /**
+ * Creates instance of template configuration helper with given lists of filtering
+ * patterns. Parameter will be included only if it matches any include-pattern and
+ * doesn't match any exclude-pattern. I.e. You can include "extended-*" and exclude
+ * "extended-type". Please refer to Java regexp documentation. Filtering for this
+ * example, should be defined as following:
+ * include: "^extended-.*"
+ * exclude: "^extended-type"
+ *
+ * @param includes Array with string representation of include reg-exp patterns
+ * @param excludes Array with string representation of exclude reg-exp patterns
+ * @param cfm instance for looking up resources
+ */
+ public TemplateConfigurationHelper(String[] includes, String[] excludes, ConfigurationManager cfm)
+ {
+ super();
+ this.cfm = cfm;
+ // compile include patterns
+ for (String regex : includes)
+ {
+ this.includes.add(Pattern.compile(regex));
+ }
+ // compile exclude patterns
+ for (String regex : excludes)
+ {
+ this.excludes.add(Pattern.compile(regex));
+ }
+ }
+
+ /**
+ * Reads configuration file from a stream and replaces all the occurrences of template-variables
+ * (like : "${parameter.name}") with values provided in the map.
+ *
+ * @param inputStream
+ * @param parameters
+ * @return
+ * @throws IOException
+ */
+ public InputStream fillTemplate(InputStream inputStream, Map parameters) throws IOException
+ {
+ if (inputStream == null || parameters == null || parameters.size() == 0)
+ {
+ return inputStream;
+ }
+ // parameters filtering
+ Map preparedParams = prepareParameters(parameters);
+ // read stream
+ String configuration = Utils.readStream(inputStream);
+ for (Entry entry : preparedParams.entrySet())
+ {
+ configuration = configuration.replace(entry.getKey(), entry.getValue());
+ }
+ // create new stream
+ InputStream configurationStream = new ByteArrayInputStream(configuration.getBytes());
+ return configurationStream;
+ }
+
+ /**
+ * Reads configuration file from a stream and replaces all the occurrences of template-variables
+ * (like : "${parameter.name}") with values provided in the map.
+ *
+ * @param filename
+ * @param parameters
+ * @return
+ * @throws IOException
+ */
+ public InputStream fillTemplate(String filename, Map parameters) throws IOException
+ {
+ InputStream inputStream = getInputStream(cfm, filename);
+ // inputStream still remains null, so file was not opened
+ if (inputStream == null)
+ {
+ throw new IOException("Can't find or open file:" + filename);
+ }
+ return fillTemplate(inputStream, parameters);
+ }
+
+ /**
+ * Tries first to get the file content using the configuration manager, if it cannot
+ * be found it will then try to get it from the context class loader of the current thread,
+ * if it cannot be found it will try to get it from the class loader of the current class and
+ * finally it still cannot be found it will try to use the file name as a file path.
+ * @param cfm the configuration manager from which we want to try to find the file content
+ * @param filename the name of the file to found
+ * @return the {@link InputStream} corresponding to the file content if it can be found
+ * null
otherwise
+ */
+ public static InputStream getInputStream(ConfigurationManager cfm, String filename)
+ {
+ InputStream inputStream = null;
+ // try to get using configuration manager
+ try
+ {
+ inputStream = cfm.getInputStream(filename);
+ }
+ catch (Exception e)
+ {
+ if (LOG.isTraceEnabled())
+ {
+ LOG.trace("An exception occurred: " + e.getMessage());
+ }
+ }
+
+ // try to get resource by class loader
+ if (inputStream == null)
+ {
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ inputStream = cl == null ? null : cl.getResourceAsStream(filename);
+ }
+
+ // check system class loader
+ if (inputStream == null)
+ {
+ inputStream = TemplateConfigurationHelper.class.getClassLoader().getResourceAsStream(filename);
+ }
+
+ // try to get as file stream
+ if (inputStream == null)
+ {
+ try
+ {
+ inputStream = new FileInputStream(filename);
+ }
+ catch (IOException e)
+ {
+ if (LOG.isTraceEnabled())
+ {
+ LOG.trace("An exception occurred: " + e.getMessage());
+ }
+ }
+ }
+ return inputStream;
+ }
+
+ /**
+ * Checks if String mathes to any pattern from the list
+ *
+ * @param patterns
+ * @param parameter
+ * @return
+ */
+ private boolean matches(List patterns, String parameter)
+ {
+ for (Pattern pattern : patterns)
+ {
+ if (pattern.matcher(parameter).matches())
+ {
+ // string matched
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Filters the map of parameters, leaving only those than matches filtering regular expressions.
+ * Also adds "${}" to the parameter key:
+ * I.e. such map provided on input:
+ *
+ * "foo-cache.loader":"org.exoplatform"
+ * "foo-configuration":"/conf/test.xml"
+ * "max-volatile-size":"100Kb"
+ *
+ * the output will be like:
+ *
+ * "${foo-cache.loader}":"org.exoplatform"
+ *
+ * Other will be ignored (depending on includes/excludes lists provided in constructor).
+ *
+ * @param parameters
+ * @return
+ */
+ protected Map prepareParameters(Map parameters)
+ {
+ Map map = new HashMap();
+ for (Entry entry : parameters.entrySet())
+ {
+ if (matches(includes, entry.getKey()) && !matches(excludes, entry.getKey()))
+ {
+ map.put("${" + entry.getKey() + "}", entry.getValue());
+ }
+ }
+ return map;
+ }
+}
diff --git a/exo.kernel.component.ext.cache.impl.infinispan.v8/src/main/java/org/exoplatform/services/cache/impl/infinispan/AbstractExoCache.java b/exo.kernel.component.ext.cache.impl.infinispan.v8/src/main/java/org/exoplatform/services/cache/impl/infinispan/AbstractExoCache.java
new file mode 100644
index 00000000..25b2d5c7
--- /dev/null
+++ b/exo.kernel.component.ext.cache.impl.infinispan.v8/src/main/java/org/exoplatform/services/cache/impl/infinispan/AbstractExoCache.java
@@ -0,0 +1,752 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.cache.impl.infinispan;
+
+import org.exoplatform.services.cache.CacheInfo;
+import org.exoplatform.services.cache.CacheListener;
+import org.exoplatform.services.cache.CacheListenerContext;
+import org.exoplatform.services.cache.CacheMode;
+import org.exoplatform.services.cache.CachedObjectSelector;
+import org.exoplatform.services.cache.ExoCache;
+import org.exoplatform.services.cache.ExoCacheConfig;
+import org.exoplatform.services.cache.ObjectCacheInfo;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+import org.infinispan.AdvancedCache;
+import org.infinispan.Cache;
+import org.infinispan.container.entries.InternalCacheEntry;
+import org.infinispan.context.Flag;
+import org.infinispan.notifications.Listener;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntriesEvicted;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntryCreated;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntryModified;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved;
+import org.infinispan.notifications.cachelistener.event.CacheEntriesEvictedEvent;
+import org.infinispan.notifications.cachelistener.event.CacheEntryCreatedEvent;
+import org.infinispan.notifications.cachelistener.event.CacheEntryModifiedEvent;
+import org.infinispan.notifications.cachelistener.event.CacheEntryRemovedEvent;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * An {@link org.exoplatform.services.cache.ExoCache} implementation based on {@link Cache}.
+ *
+ * @author Nicolas Filotto
+ * @version $Id$
+ *
+ */
+public abstract class AbstractExoCache implements ExoCache
+{
+
+ /**
+ * Logger.
+ */
+ private static final Log LOG = ExoLogger.getLogger(AbstractExoCache.class);
+
+ private final AtomicInteger hits = new AtomicInteger(0);
+
+ private final AtomicInteger misses = new AtomicInteger(0);
+
+ private String label;
+
+ private String name;
+
+ private boolean distributed;
+
+ private boolean replicated;
+
+ private boolean asynchronous;
+
+ private boolean logEnabled;
+
+ private final CopyOnWriteArrayList> listeners;
+
+ protected final AdvancedCache cache;
+
+ public AbstractExoCache(ExoCacheConfig config, Cache cache)
+ {
+ this.cache = cache.getAdvancedCache();
+ this.listeners = new CopyOnWriteArrayList>();
+ setDistributed(config.isDistributed());
+ setLabel(config.getLabel());
+ setName(config.getName());
+ setLogEnabled(config.isLogEnabled());
+ setReplicated(config.isRepicated());
+ CacheMode cacheMode = config.getCacheMode();
+ setAsynchronous(cacheMode != null && !cacheMode.isSync());
+ cache.addListener(new CacheEventListener());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void addCacheListener(CacheListener super K, ? super V> listener)
+ {
+ if (listener == null)
+ {
+ throw new IllegalArgumentException("The listener cannot be null");
+ }
+ listeners.add(new ListenerContext(listener, this));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void clearCache()
+ {
+ cache.withFlags(Flag.CACHE_MODE_LOCAL).clear();
+ onClearCache();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ public V get(Serializable name)
+ {
+ if (name == null)
+ {
+ return null;
+ }
+ final V result = cache.get(name);
+ if (result == null)
+ {
+ misses.incrementAndGet();
+ }
+ else
+ {
+ hits.incrementAndGet();
+ }
+ onGet((K)name, result);
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getCacheHit()
+ {
+ return hits.get();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getCacheMiss()
+ {
+ return misses.get();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getCacheSize()
+ {
+ return cache.withFlags(Flag.CACHE_MODE_LOCAL).size();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List getCachedObjects()
+ {
+ Collection values = cache.withFlags(Flag.CACHE_MODE_LOCAL).values();
+ if (values == null || values.isEmpty())
+ {
+ return Collections.emptyList();
+ }
+ else
+ {
+ return new ArrayList(values);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getLabel()
+ {
+ return label;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isDistributed()
+ {
+ return distributed;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isLogEnabled()
+ {
+ return logEnabled;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isReplicated()
+ {
+ return replicated;
+ }
+
+ public void setAsynchronous(boolean asynchronous) {
+ this.asynchronous = asynchronous;
+ }
+
+ public boolean isAsynchronous() {
+ return asynchronous;
+ }
+
+ private void putOnlyAsync(K key, V value)
+ {
+ cache.withFlags(Flag.SKIP_REMOTE_LOOKUP, Flag.IGNORE_RETURN_VALUES, Flag.FORCE_ASYNCHRONOUS).putAsync(key, value);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void put(final K key, final V value) throws IllegalArgumentException
+ {
+ if (key == null)
+ {
+ throw new IllegalArgumentException("No null cache key accepted");
+ }
+ else if (value == null)
+ {
+ // ignore null values
+ return;
+ }
+ if(LOG.isDebugEnabled() && cache.getDataContainer().containsKey(key)) {
+ InternalCacheEntry internalCacheEntry = cache.getDataContainer().get(key);
+ if(internalCacheEntry != null) {
+ Object oldValue = internalCacheEntry.getValue();
+ if(oldValue != null) {
+ if(oldValue.equals(value)) {
+ LOG.debug("Need to optimize top layer cache management propably (depends on ValueClass.equals method pertinence). The same value putted into cache, cache = " + cache.getName() + ", key : class= " + key.getClass() + ", hashcode= " + key.hashCode() + "/ old hashcode: " + internalCacheEntry.getKey().hashCode());
+ } else {
+ try {
+ value.getClass().getDeclaredMethod("equals");
+ } catch (NoSuchMethodException e) {
+ LOG.debug("Need to implement equals method in " + value.getClass().getCanonicalName() + ". cache = " + cache.getName() + ", key : class= " + key.getClass() + ", hashcode= " + key.hashCode() + "/ old hashcode: " + internalCacheEntry.getKey().hashCode());
+ }
+ }
+ }
+ }
+ }
+ putOnly(key, value, false);
+ onPut(key, value);
+ }
+
+ @Override
+ public void putLocal(final K key, final V value) throws IllegalArgumentException {
+ if (key == null)
+ {
+ throw new IllegalArgumentException("No null cache key accepted");
+ }
+ else if (value == null)
+ {
+ // ignore null values
+ return;
+ }
+
+ putOnly(key, value, true);
+
+ onPutLocal(key, value);
+ }
+
+ /**
+ * Only puts the data into the cache nothing more
+ */
+ protected void putOnly(K key, V value, boolean isLocal)
+ {
+ if (isLocal)
+ {
+ if(isAsynchronous()) {
+ cache.withFlags(Flag.CACHE_MODE_LOCAL, Flag.SKIP_REMOTE_LOOKUP, Flag.IGNORE_RETURN_VALUES, Flag.FORCE_ASYNCHRONOUS).putAsync(key, value);
+ } else {
+ cache.withFlags(Flag.CACHE_MODE_LOCAL, Flag.SKIP_REMOTE_LOOKUP, Flag.IGNORE_RETURN_VALUES).put(key, value);
+ }
+ }
+ else
+ {
+ if(isAsynchronous()) {
+ cache.withFlags(Flag.SKIP_REMOTE_LOOKUP, Flag.IGNORE_RETURN_VALUES, Flag.FORCE_ASYNCHRONOUS).putAsync(key, value);
+ } else {
+ cache.withFlags(Flag.SKIP_REMOTE_LOOKUP, Flag.IGNORE_RETURN_VALUES).put(key, value);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void putMap(final Map extends K, ? extends V> objs) throws IllegalArgumentException
+ {
+ if (objs == null)
+ {
+ throw new IllegalArgumentException("No null map accepted");
+ }
+ for (Serializable name : objs.keySet())
+ {
+ if (name == null)
+ {
+ throw new IllegalArgumentException("No null cache key accepted");
+ }
+ }
+ // Start transaction
+ if(cache.getTransactionManager() != null) {
+ cache.startBatch();
+ }
+ try
+ {
+ // Make sure that the key and the value are valid
+ Map map = new LinkedHashMap();
+ for (Map.Entry extends K, ? extends V> entry : objs.entrySet())
+ {
+ map.put(entry.getKey(), entry.getValue());
+ }
+ cache.putAll(map);
+ if(cache.getTransactionManager() != null) {
+ cache.endBatch(true);
+ }
+ // End transaction
+ for (Map.Entry extends K, ? extends V> entry : objs.entrySet())
+ {
+ onPut(entry.getKey(), entry.getValue());
+ }
+ }
+ catch (Exception e) //NOSONAR
+ {
+ if(cache.getTransactionManager() != null) {
+ cache.endBatch(false);
+ }
+ LOG.warn("An error occurs while executing the putMap method", e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void putAsyncMap(final Map extends K, ? extends V> objs) throws IllegalArgumentException
+ {
+ if (objs == null)
+ {
+ throw new IllegalArgumentException("No null map accepted");
+ }
+ for (Serializable name : objs.keySet())
+ {
+ if (name == null)
+ {
+ throw new IllegalArgumentException("No null cache key accepted");
+ }
+ }
+ try
+ {
+ // Make sure that the key and the value are valid
+ Map map = new LinkedHashMap();
+ for (Map.Entry extends K, ? extends V> entry : objs.entrySet())
+ {
+ map.put(entry.getKey(), entry.getValue());
+ }
+ cache.putAllAsync(map);
+ // End transaction
+ for (Map.Entry extends K, ? extends V> entry : objs.entrySet())
+ {
+ onPut(entry.getKey(), entry.getValue());
+ }
+ }
+ catch (Exception e) //NOSONAR
+ {
+ LOG.warn("An error occurs while executing the putMap method", e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ public V remove(final Serializable key) throws NullPointerException
+ {
+ if (key == null)
+ {
+ throw new IllegalArgumentException("No null cache key accepted");
+ }
+ V result = cache.remove(key);
+ onRemove((K)key, result);
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ public void removeLocal(final Serializable key) throws NullPointerException
+ {
+ if (key == null)
+ {
+ throw new IllegalArgumentException("No null cache key accepted");
+ }
+ cache.withFlags(Flag.CACHE_MODE_LOCAL).removeAsync(key);
+ onRemove((K)key, null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List removeCachedObjects()
+ {
+ final List list = getCachedObjects();
+ clearCache();
+ return list;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void select(CachedObjectSelector super K, ? super V> selector) throws Exception
+ {
+ if (selector == null)
+ {
+ throw new IllegalArgumentException("No null selector");
+ }
+ for (Map.Entry extends K, ? extends V> entry : cache.withFlags(Flag.CACHE_MODE_LOCAL).entrySet())
+ {
+ K key = entry.getKey();
+ if (key == null)
+ {
+ continue;
+ }
+ final V value = entry.getValue();
+ ObjectCacheInfo info = new ObjectCacheInfo()
+ {
+ public V get()
+ {
+ return value;
+ }
+
+ public long getExpireTime()
+ {
+ // Cannot know: The expire time is managed by Infinispan itself
+ return -1;
+ }
+ };
+ if (selector.select(key, info))
+ {
+ selector.onSelect(this, key, info);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setDistributed(boolean distributed)
+ {
+ this.distributed = distributed;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setLabel(String label)
+ {
+ this.label = label;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setLogEnabled(boolean logEnabled)
+ {
+ this.logEnabled = logEnabled;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setReplicated(boolean replicated)
+ {
+ this.replicated = replicated;
+ }
+
+ public void onExpire(K key, V obj)
+ {
+ if (listeners.isEmpty())
+ {
+ return;
+ }
+ for (ListenerContext context : listeners)
+ {
+ try
+ {
+ context.onExpire(key, obj);
+ }
+ catch (Exception e)//NOSONAR
+ {
+ if (LOG.isWarnEnabled())
+ LOG.warn("Cannot execute the CacheListener properly", e);
+ }
+ }
+ }
+
+ public void onRemove(K key, V obj)
+ {
+ if (listeners.isEmpty())
+ {
+ return;
+ }
+ for (ListenerContext context : listeners)
+ {
+ try
+ {
+ context.onRemove(key, obj);
+ }
+ catch (Exception e)//NOSONAR
+ {
+ if (LOG.isWarnEnabled())
+ LOG.warn("Cannot execute the CacheListener properly", e);
+ }
+ }
+ }
+
+ public void onPut(K key, V obj)
+ {
+ if (listeners.isEmpty())
+ {
+ return;
+ }
+ for (ListenerContext context : listeners)
+ try
+ {
+ context.onPut(key, obj);
+ }
+ catch (Exception e)//NOSONAR
+ {
+ if (LOG.isWarnEnabled())
+ LOG.warn("Cannot execute the CacheListener properly", e);
+ }
+ }
+
+ public void onPutLocal(K key, V value)
+ {
+ if (listeners.isEmpty())
+ {
+ return;
+ }
+ for (ListenerContext context : listeners)
+ try
+ {
+ context.onPutLocal(key, value);
+ }
+ catch (Exception e)//NOSONAR
+ {
+ if (LOG.isWarnEnabled())
+ LOG.warn("Cannot execute the CacheListener properly", e);
+ }
+ }
+
+ public void onGet(K key, V obj)
+ {
+ if (listeners.isEmpty())
+ {
+ return;
+ }
+ for (ListenerContext context : listeners)
+ try
+ {
+ context.onGet(key, obj);
+ }
+ catch (Exception e)//NOSONAR
+ {
+ if (LOG.isWarnEnabled())
+ LOG.warn("Cannot execute the CacheListener properly", e);
+ }
+ }
+
+ public void onClearCache()
+ {
+ if (listeners.isEmpty())
+ {
+ return;
+ }
+ for (ListenerContext context : listeners)
+ try
+ {
+ context.onClearCache();
+ }
+ catch (Exception e)//NOSONAR
+ {
+ if (LOG.isWarnEnabled())
+ LOG.warn("Cannot execute the CacheListener properly", e);
+ }
+ }
+
+ @Listener
+ public class CacheEventListener
+ {
+ /**
+ * Warning Infinispan triggers a CacheEntryEvictedEvent
only at explicit eviction
+ * that is done lazily which is not exactly what we expect, we still use it to be
+ * able to use it with avoidValueReplication
set to true
.
+ */
+ @CacheEntriesEvicted
+ public void cacheEntryEvicted(CacheEntriesEvictedEvent evt)
+ {
+ if (evt.isPre())
+ {
+ for (Map.Entry entry : evt.getEntries().entrySet())
+ {
+ onExpire(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+
+ @CacheEntryRemoved
+ public void cacheEntryRemoved(CacheEntryRemovedEvent evt)
+ {
+ if (evt.isPre() && !evt.isOriginLocal())
+ {
+ final K key = evt.getKey();
+ final V value = evt.getValue();
+ onRemove(key, value);
+ }
+ }
+
+ @CacheEntryModified
+ public void cacheEntryModified(CacheEntryModifiedEvent evt)
+ {
+ if (!evt.isOriginLocal() && !evt.isPre())
+ {
+ final K key = evt.getKey();
+ final V value = evt.getValue();
+ onPut(key, value);
+ }
+ }
+
+ @CacheEntryCreated
+ public void CacheEntryCreated(CacheEntryCreatedEvent event) {
+ if (!event.isOriginLocal() && !event.isPre())
+ {
+ final K key = event.getKey();
+ final V value = event.getValue();
+ onPut(key, value);;
+ }
+ }
+ }
+
+ private static class ListenerContext implements CacheListenerContext, CacheInfo
+ {
+
+ /** . */
+ private final ExoCache cache;
+
+ /** . */
+ final CacheListener super K, ? super V> listener;
+
+ public ListenerContext(CacheListener super K, ? super V> listener, ExoCache cache)
+ {
+ this.listener = listener;
+ this.cache = cache;
+ }
+
+ public CacheInfo getCacheInfo()
+ {
+ return this;
+ }
+
+ public String getName()
+ {
+ return cache.getName();
+ }
+
+ public int getMaxSize()
+ {
+ return cache.getMaxSize();
+ }
+
+ public long getLiveTime()
+ {
+ return cache.getLiveTime();
+ }
+
+ public int getSize()
+ {
+ return cache.getCacheSize();
+ }
+
+ void onExpire(K key, V obj) throws Exception
+ {
+ listener.onExpire(this, key, obj);
+ }
+
+ void onRemove(K key, V obj) throws Exception
+ {
+ listener.onRemove(this, key, obj);
+ }
+
+ void onPut(K key, V obj) throws Exception
+ {
+ listener.onPut(this, key, obj);
+ }
+
+ void onPutLocal(K key, V obj) throws Exception
+ {
+ listener.onPutLocal(this, key, obj);
+ }
+
+ void onGet(K key, V obj) throws Exception
+ {
+ listener.onGet(this, key, obj);
+ }
+
+ void onClearCache() throws Exception
+ {
+ listener.onClearCache(this);
+ }
+ }
+}
diff --git a/exo.kernel.component.ext.cache.impl.infinispan.v8/src/main/java/org/exoplatform/services/cache/impl/infinispan/ExoCacheCreator.java b/exo.kernel.component.ext.cache.impl.infinispan.v8/src/main/java/org/exoplatform/services/cache/impl/infinispan/ExoCacheCreator.java
new file mode 100644
index 00000000..8c2f9f4d
--- /dev/null
+++ b/exo.kernel.component.ext.cache.impl.infinispan.v8/src/main/java/org/exoplatform/services/cache/impl/infinispan/ExoCacheCreator.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.cache.impl.infinispan;
+
+import org.exoplatform.services.cache.ExoCache;
+import org.exoplatform.services.cache.ExoCacheConfig;
+import org.exoplatform.services.cache.ExoCacheInitException;
+import org.infinispan.Cache;
+import org.infinispan.configuration.cache.ConfigurationBuilder;
+
+import java.io.Serializable;
+import java.util.Set;
+import java.util.concurrent.Callable;
+
+/**
+ * This class is used to create the cache according to the given
+ * configuration {@link org.exoplatform.services.cache.ExoCacheConfig}
+ *
+ * @author Nicolas Filotto
+ * @version $Id$
+ */
+public interface ExoCacheCreator
+{
+
+ /**
+ * Creates an eXo cache according to the given configuration {@link org.exoplatform.services.cache.ExoCacheConfig}
+ * @param config the configuration of the cache to apply
+ * @param confBuilder the configuration builder of the infinispan cache
+ * @param cacheGetter a {@link Callable} instance from which we can get the cache
+ * @exception ExoCacheInitException if an exception happens while initializing the cache
+ */
+ public ExoCache create(ExoCacheConfig config, ConfigurationBuilder confBuilder,
+ Callable> cacheGetter) throws ExoCacheInitException;
+
+ /**
+ * Returns the type of {@link org.exoplatform.services.cache.ExoCacheConfig} expected by the creator
+ * @return the expected type
+ */
+ public Class extends ExoCacheConfig> getExpectedConfigType();
+
+ /**
+ * Returns a set of all the implementations expected by the creator. This is mainly used to be backward compatible
+ * @return the expected by the creator
+ */
+ public Set getExpectedImplementations();
+}
diff --git a/exo.kernel.component.ext.cache.impl.infinispan.v8/src/main/java/org/exoplatform/services/cache/impl/infinispan/ExoCacheCreatorPlugin.java b/exo.kernel.component.ext.cache.impl.infinispan.v8/src/main/java/org/exoplatform/services/cache/impl/infinispan/ExoCacheCreatorPlugin.java
new file mode 100644
index 00000000..bd772095
--- /dev/null
+++ b/exo.kernel.component.ext.cache.impl.infinispan.v8/src/main/java/org/exoplatform/services/cache/impl/infinispan/ExoCacheCreatorPlugin.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.cache.impl.infinispan;
+
+import org.exoplatform.container.component.BaseComponentPlugin;
+import org.exoplatform.container.xml.InitParams;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class allows us to define new creators
+ * @author Nicolas Filotto
+ * @version $Id$
+ */
+public class ExoCacheCreatorPlugin extends BaseComponentPlugin
+{
+
+ /**
+ * The list of all the creators defined for this ComponentPlugin
+ */
+ private final List creators;
+
+ public ExoCacheCreatorPlugin(InitParams params)
+ {
+ creators = new ArrayList();
+ List> configs = params.getObjectParamValues(ExoCacheCreator.class);
+ for (int i = 0; i < configs.size(); i++)
+ {
+ ExoCacheCreator config = (ExoCacheCreator)configs.get(i);
+ creators.add(config);
+ }
+ }
+
+ /**
+ * Returns all the creators defined for this ComponentPlugin
+ */
+ public List getCreators()
+ {
+ return creators;
+ }
+}
diff --git a/exo.kernel.component.ext.cache.impl.infinispan.v8/src/main/java/org/exoplatform/services/cache/impl/infinispan/ExoCacheFactoryConfigPlugin.java b/exo.kernel.component.ext.cache.impl.infinispan.v8/src/main/java/org/exoplatform/services/cache/impl/infinispan/ExoCacheFactoryConfigPlugin.java
new file mode 100644
index 00000000..8cbaf5e7
--- /dev/null
+++ b/exo.kernel.component.ext.cache.impl.infinispan.v8/src/main/java/org/exoplatform/services/cache/impl/infinispan/ExoCacheFactoryConfigPlugin.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.cache.impl.infinispan;
+
+import org.exoplatform.container.component.BaseComponentPlugin;
+import org.exoplatform.container.xml.InitParams;
+import org.exoplatform.container.xml.ValueParam;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * This class is used to define custom configurations
+ *
+ * @author Nicolas Filotto
+ * @version $Id$
+ */
+public class ExoCacheFactoryConfigPlugin extends BaseComponentPlugin
+{
+
+ /**
+ * The map of all the creators defined for this ComponentPlugin
+ */
+ private final Map configs;
+
+ public ExoCacheFactoryConfigPlugin(InitParams params)
+ {
+ configs = new HashMap();
+ for (Iterator iterator = params.getValueParamIterator(); iterator.hasNext();)
+ {
+ ValueParam vParam = iterator.next();
+ configs.put(vParam.getName(), vParam.getValue());
+ }
+ }
+
+ /**
+ * Returns all the configurations defined for this ComponentPlugin
+ */
+ public Map getConfigs()
+ {
+ return configs;
+ }
+}
diff --git a/exo.kernel.component.ext.cache.impl.infinispan.v8/src/main/java/org/exoplatform/services/cache/impl/infinispan/ExoCacheFactoryImpl.java b/exo.kernel.component.ext.cache.impl.infinispan.v8/src/main/java/org/exoplatform/services/cache/impl/infinispan/ExoCacheFactoryImpl.java
new file mode 100644
index 00000000..a6c41c80
--- /dev/null
+++ b/exo.kernel.component.ext.cache.impl.infinispan.v8/src/main/java/org/exoplatform/services/cache/impl/infinispan/ExoCacheFactoryImpl.java
@@ -0,0 +1,483 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.cache.impl.infinispan;
+
+import org.exoplatform.container.ExoContainerContext;
+import org.exoplatform.container.configuration.ConfigurationManager;
+import org.exoplatform.container.xml.InitParams;
+import org.exoplatform.container.xml.ValueParam;
+import org.exoplatform.services.cache.ExoCache;
+import org.exoplatform.services.cache.ExoCacheConfig;
+import org.exoplatform.services.cache.ExoCacheFactory;
+import org.exoplatform.services.cache.ExoCacheInitException;
+import org.exoplatform.services.cache.impl.infinispan.distributed.DistributedExoCache;
+import org.exoplatform.services.cache.impl.infinispan.generic.GenericExoCacheCreator;
+import org.exoplatform.services.ispn.DistributedCacheManager;
+import org.exoplatform.services.ispn.Utils;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+import org.infinispan.Cache;
+import org.infinispan.configuration.cache.CacheMode;
+import org.infinispan.configuration.cache.Configuration;
+import org.infinispan.configuration.cache.ConfigurationBuilder;
+import org.infinispan.configuration.global.GlobalConfiguration;
+import org.infinispan.configuration.global.GlobalConfigurationBuilder;
+import org.infinispan.configuration.parsing.ConfigurationBuilderHolder;
+import org.infinispan.configuration.parsing.ParserRegistry;
+import org.infinispan.eviction.EvictionStrategy;
+import org.infinispan.jmx.MBeanServerLookup;
+import org.infinispan.manager.DefaultCacheManager;
+import org.picocontainer.Startable;
+
+import java.io.InputStream;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.Callable;
+
+import javax.management.MBeanServer;
+
+/**
+ * This class is the Infinispan implementation of the {@link org.exoplatform.services.cache.ExoCacheFactory}
+ *
+ * @author Nicolas Filotto
+ * @version $Id$
+ *
+ */
+public class ExoCacheFactoryImpl implements ExoCacheFactory, Startable {
+
+ /**
+ * The logger
+ */
+ private static final Log LOG = ExoLogger.getLogger(ExoCacheFactoryImpl.class);
+
+ /**
+ * The initial parameter key that defines the full path of the configuration template
+ */
+ private static final String CACHE_CONFIG_TEMPLATE_KEY = "cache.config.template";
+
+ /**
+ * The initial parameter key that defines the full path of the optional async configuration template
+ */
+ private static final String CACHE_ASYNC_TEMPLATE_KEY = "cache.async.config.template";
+
+ /**
+ * The cache manager for the distributed cache
+ */
+ private final DistributedCacheManager distributedCacheManager;
+
+ /**
+ * The current {@link ExoContainerContext}
+ */
+ private final ExoContainerContext ctx;
+
+ /**
+ * The configuration manager that allows us to retrieve a configuration file in several different
+ * manners
+ */
+ private final ConfigurationManager configManager;
+
+ /**
+ * The {@link DefaultCacheManager} used for all sync cache regions
+ */
+ private final DefaultCacheManager cacheManager;
+
+ /**
+ * The {@link DefaultCacheManager} used for all async cache regions
+ */
+ private DefaultCacheManager asyncCacheManager = null;
+
+ /**
+ * The mapping between the configuration types and the creators
+ */
+ private final Map, ExoCacheCreator> mappingConfigTypeCreators =
+ new HashMap, ExoCacheCreator>();
+
+ /**
+ * The mapping between the implementations and the creators. This is mainly used for backward compatibility
+ */
+ private final Map mappingImplCreators = new HashMap();
+
+ /**
+ * The mapping between the cache names and the configuration paths
+ */
+ private final Map mappingCacheNameConfig = new HashMap();
+
+ /**
+ * The async cache template path
+ */
+ private final String asyncCacheTemplate;
+
+ /**
+ * The mapping between the cluster name and the cache managers
+ */
+ private final Map mappingGlobalConfigCacheManager =
+ new HashMap();
+
+ /**
+ * The default creator
+ */
+ private final ExoCacheCreator defaultCreator = new GenericExoCacheCreator();
+
+ private static final MBeanServerLookup MBEAN_SERVER_LOOKUP = new MBeanServerLookup()
+ {
+ public MBeanServer getMBeanServer(Properties properties)
+ {
+ return ExoContainerContext.getTopContainer().getMBeanServer();
+ }
+ };
+
+ public ExoCacheFactoryImpl(ExoContainerContext ctx, InitParams params, ConfigurationManager configManager)
+ throws ExoCacheInitException
+ {
+ this(ctx, getValueParam(params, CACHE_CONFIG_TEMPLATE_KEY), getValueParam(params, CACHE_ASYNC_TEMPLATE_KEY), configManager, null);
+ }
+
+ public ExoCacheFactoryImpl(ExoContainerContext ctx, InitParams params, ConfigurationManager configManager,
+ DistributedCacheManager dcm) throws ExoCacheInitException
+ {
+ this(ctx, getValueParam(params, CACHE_CONFIG_TEMPLATE_KEY), getValueParam(params, CACHE_ASYNC_TEMPLATE_KEY), configManager, dcm);
+ }
+
+ public ExoCacheFactoryImpl(ExoContainerContext ctx, String cacheConfigTemplate, String cacheAsyncConfigTemplate, ConfigurationManager configManager,
+ DistributedCacheManager dcm) throws ExoCacheInitException
+ {
+ this.distributedCacheManager = dcm;
+ this.ctx = ctx;
+ this.configManager = configManager;
+ if (cacheConfigTemplate == null)
+ {
+ throw new IllegalArgumentException("The parameter '" + CACHE_CONFIG_TEMPLATE_KEY + "' must be set");
+ }
+ // Initialize the main cache manager
+ this.cacheManager = initCacheManager(cacheConfigTemplate);
+
+ this.asyncCacheTemplate = cacheAsyncConfigTemplate;
+ }
+
+ /**
+ * Initializes the {@link DefaultCacheManager}
+ * @throws ExoCacheInitException if the cache manager cannot be initialized
+ */
+ private DefaultCacheManager initCacheManager(final String cacheConfigTemplate) throws ExoCacheInitException
+ {
+ InputStream is = null;
+ try
+ {
+ // Read the configuration file of the cache
+ is = configManager.getInputStream(cacheConfigTemplate);
+ }
+ catch (Exception e)//NOSONAR
+ {
+ throw new ExoCacheInitException("The configuration of the CacheManager cannot be loaded from '"
+ + cacheConfigTemplate + "'", e);
+ }
+ if (is == null)
+ {
+ throw new ExoCacheInitException("The configuration of the CacheManager cannot be found at '"
+ + cacheConfigTemplate + "'");
+ }
+ GlobalConfigurationBuilder configBuilder;
+ Configuration config;
+ try
+ {
+ ParserRegistry parser = new ParserRegistry(Thread.currentThread().getContextClassLoader());
+ // Loads the configuration from the input stream
+ ConfigurationBuilderHolder holder = parser.parse(is);
+ configBuilder = holder.getGlobalConfigurationBuilder();
+ config = holder.getDefaultConfigurationBuilder().build();
+ }
+ catch (RuntimeException e) //NOSONAR
+ {
+ throw new ExoCacheInitException("Cannot parse the configuration '" + cacheConfigTemplate + "'", e);
+ }
+ configureCacheManager(configBuilder);
+ DefaultCacheManager cacheManager;
+ try
+ {
+ // Create the CacheManager from the new configuration
+ cacheManager = new DefaultCacheManager(configBuilder.build(), config);
+ }
+ catch (RuntimeException e) //NOSONAR
+ {
+ throw new ExoCacheInitException(
+ "Cannot initialize the CacheManager corresponding to the configuration '" + cacheConfigTemplate
+ + "'", e);
+ }
+ // Register the main cache manager
+ mappingGlobalConfigCacheManager.put(cacheManager.getCacheManagerConfiguration().transport().clusterName(),
+ cacheManager);
+ return cacheManager;
+ }
+
+ /**
+ * Configure the cache manager
+ *
+ * @param configBuilder the configuration builder on which we applied all the required changes
+ * @throws ExoCacheInitException
+ */
+ private void configureCacheManager(GlobalConfigurationBuilder configBuilder) throws ExoCacheInitException
+ {
+ GlobalConfiguration config = configBuilder.build();
+ // Configure JGroups
+ configureJGroups(config, configBuilder);
+ // Configure the name of the cache manager
+ configBuilder.globalJmxStatistics().enable()
+ .cacheManagerName(config.globalJmxStatistics().cacheManagerName() + "_" + ctx.getName()).
+ // Configure the MBeanServerLookup
+ mBeanServerLookup(MBEAN_SERVER_LOOKUP);
+ }
+
+ /**
+ * If some JGoups properties has been set, it will load the configuration and set
+ * the cluster name by adding as suffix the name of the {@link ExoContainerContext}
+ *
+ * @param config the global configuration from which the JGroups config will be extracted
+ * @param configBuilder the related configuration builder
+ * @throws ExoCacheInitException if any exception occurs while configuring JGroups
+ */
+ private void configureJGroups(GlobalConfiguration config, GlobalConfigurationBuilder configBuilder)
+ throws ExoCacheInitException
+ {
+ if (loadJGroupsConfig(config, configBuilder))
+ {
+ // The JGroups Config could be loaded which means that the configuration is for a cluster
+ configBuilder.transport().clusterName(config.transport().clusterName() + "-" + ctx.getName());
+ }
+ }
+
+ /**
+ * Load the JGroups configuration file thanks to the {@link ConfigurationManager}
+ * @param config the global configuration from which the JGroups config will be extracted
+ * @param configBuilder the related configuration builder
+ * @return true
if the JGoups config could be loaded successfully,
+ * false
if there were no JGroups config to load
+ * @throws ExoCacheInitException if the JGroups config could not be loaded
+ */
+ private boolean loadJGroupsConfig(GlobalConfiguration config, GlobalConfigurationBuilder configBuilder)
+ throws ExoCacheInitException
+ {
+ return Utils.loadJGroupsConfig(configManager, config, configBuilder);
+ }
+
+ /**
+ * To create a new cache instance according to the given configuration, we follow the steps below:
+ *
+ * We first try to find if a specific location of the cache configuration has been defined thanks
+ * to an external component plugin of type ExoCacheFactoryConfigPlugin. If so we use the default cache
+ * configuration defined in this file otherwise we use the default cache configuration defined in
+ * "${CACHE_CONFIG_TEMPLATE_KEY}"
+ */
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public ExoCache createCache(final ExoCacheConfig config) throws ExoCacheInitException
+ {
+ final String region = config.getName();
+ String CacheConfig = mappingCacheNameConfig.get(region);
+ if(CacheConfig == null && config.isAsync() && asyncCacheTemplate !=null && asyncCacheManager == null)
+ {
+ //use async template if cache use async mode
+ this.asyncCacheManager = initCacheManager(asyncCacheTemplate);
+ }
+ final String customConfig = CacheConfig;
+ final ExoCache eXoCache;
+ final DefaultCacheManager cacheManager;
+ try
+ {
+ final ConfigurationBuilder confBuilder = new ConfigurationBuilder();
+ if (customConfig != null)
+ {
+ // A custom configuration has been set
+ if (LOG.isInfoEnabled())
+ LOG.info("A custom configuration has been set for the cache '" + region + "'.");
+ ParserRegistry parser = new ParserRegistry(Thread.currentThread().getContextClassLoader());
+ // Load the configuration
+ ConfigurationBuilderHolder holder = parser.parse(configManager.getInputStream(customConfig));
+ GlobalConfigurationBuilder configBuilder = holder.getGlobalConfigurationBuilder();
+ // Configure JGroups and JMX since it could affect the state of the Global Config
+ configureCacheManager(configBuilder);
+ GlobalConfiguration gc = configBuilder.build();
+
+ // Check if a CacheManager with the same GlobalConfiguration exists
+ DefaultCacheManager currentCacheManager =
+ mappingGlobalConfigCacheManager.get(gc.transport().clusterName());
+ if (currentCacheManager == null)
+ {
+ // Use a different cache manager name to prevent naming conflict
+ configBuilder.globalJmxStatistics().cacheManagerName(
+ gc.globalJmxStatistics().cacheManagerName() + "_" + region + "_" + ctx.getName());
+ // No cache manager has been defined so far for this Cache Configuration
+ currentCacheManager =
+ new DefaultCacheManager(configBuilder.build(), holder.getDefaultConfigurationBuilder()
+ .build(), false);
+ for (Entry entry : holder.getNamedConfigurationBuilders().entrySet())
+ {
+ currentCacheManager.defineConfiguration(entry.getKey(), entry.getValue().build());
+ }
+ currentCacheManager.start();
+ // We register this new cache manager
+ mappingGlobalConfigCacheManager.put(gc.transport().clusterName(), currentCacheManager);
+ }
+ cacheManager = currentCacheManager;
+ confBuilder.read(cacheManager.getDefaultCacheConfiguration());
+ }
+ else if (config.isDistributed())
+ {
+ // We expect a distributed cache
+ if (distributedCacheManager == null)
+ {
+ throw new IllegalArgumentException(
+ "The DistributedCacheManager has not been defined in the configuration,"
+ + " please configure it at root container level if you want to use a distributed cache.");
+ }
+ return new DistributedExoCache(ctx, config,
+ distributedCacheManager.getCache(DistributedExoCache.CACHE_NAME));
+ }
+ else
+ {
+ cacheManager = (config.isAsync() && asyncCacheManager != null) ? this.asyncCacheManager : this.cacheManager;
+ // No custom configuration has been found, a configuration template will be used
+ if (LOG.isInfoEnabled())
+ LOG.info("The configuration template will be used for the cache '" + region + "'.");
+ confBuilder.read(cacheManager.getDefaultCacheConfiguration());
+ if (!config.isRepicated())
+ {
+ // The cache is local
+ confBuilder.clustering().cacheMode(CacheMode.LOCAL);
+ }
+ }
+ // Reset the configuration to avoid conflicts
+ resetConfiguration(confBuilder);
+ final ExoCacheCreator creator = getExoCacheCreator(config);
+ // Create the cache
+ eXoCache = creator.create(config, confBuilder, new Callable>()
+ {
+ public Cache call() throws Exception
+ {
+ cacheManager.defineConfiguration(region, confBuilder.build());
+ // create and start the cache
+ return cacheManager.getCache(region);
+ }
+ });
+ }
+ catch (Exception e) //NOSONAR
+ {
+ throw new ExoCacheInitException("The cache '" + region + "' could not be initialized", e);
+ }
+ return eXoCache;
+ }
+
+ /**
+ * Add a list of creators to register
+ * @param plugin the plugin that contains the creators
+ */
+ public void addCreator(ExoCacheCreatorPlugin plugin)
+ {
+ final List creators = plugin.getCreators();
+ for (ExoCacheCreator creator : creators)
+ {
+ mappingConfigTypeCreators.put(creator.getExpectedConfigType(), creator);
+ Set implementations = creator.getExpectedImplementations();
+ if (implementations == null)
+ {
+ throw new IllegalArgumentException("The set of implementations cannot be null");
+ }
+ for (String imp : implementations)
+ {
+ mappingImplCreators.put(imp, creator);
+ }
+ }
+ }
+
+ /**
+ * Add a list of custom configuration to register
+ * @param plugin the plugin that contains the configs
+ */
+ public void addConfig(ExoCacheFactoryConfigPlugin plugin)
+ {
+ final Map configs = plugin.getConfigs();
+ mappingCacheNameConfig.putAll(configs);
+ }
+
+ @Override
+ public void start() {
+ // Nothing to start
+ }
+
+ @Override
+ public void stop() {
+ if (cacheManager != null) {
+ cacheManager.stop();
+ }
+ }
+ /**
+ * Returns the value of the ValueParam if and only if the value is not empty
+ */
+ private static String getValueParam(InitParams params, String key)
+ {
+ if (params == null)
+ {
+ return null;
+ }
+ final ValueParam vp = params.getValueParam(key);
+ String result;
+ if (vp == null || (result = vp.getValue()) == null || (result = result.trim()).length() == 0)
+ {
+ return null;
+ }
+ return result;
+ }
+
+ /**
+ * Returns the most relevant ExoCacheCreator according to the give configuration
+ */
+ protected ExoCacheCreator getExoCacheCreator(ExoCacheConfig config)
+ {
+ ExoCacheCreator creator = mappingConfigTypeCreators.get(config.getClass());
+ if (creator == null)
+ {
+ // No creator for this type has been found, let's try the implementation field
+ creator = mappingImplCreators.get(config.getImplementation());
+ if (creator == null)
+ {
+ // No creator can be found, we will use the default creator
+ if (LOG.isInfoEnabled())
+ LOG.info("No cache creator has been found for the cache '" + config.getName()
+ + "', the default one will be used.");
+ return defaultCreator;
+ }
+ }
+ if (LOG.isInfoEnabled())
+ LOG.info("The cache '" + config.getName() + "' will be created with '" + creator.getClass() + "'.");
+ return creator;
+ }
+
+ /**
+ * Clean the configuration template to prevent conflicts
+ */
+ protected void resetConfiguration(ConfigurationBuilder confBuilder)
+ {
+ confBuilder.eviction().strategy(EvictionStrategy.NONE).size(-1).expiration()
+ .lifespan(-1L).maxIdle(-1L).wakeUpInterval(60000L);
+ }
+
+}
diff --git a/exo.kernel.component.ext.cache.impl.infinispan.v8/src/main/java/org/exoplatform/services/cache/impl/infinispan/distributed/DistributedExoCache.java b/exo.kernel.component.ext.cache.impl.infinispan.v8/src/main/java/org/exoplatform/services/cache/impl/infinispan/distributed/DistributedExoCache.java
new file mode 100644
index 00000000..1e74abb4
--- /dev/null
+++ b/exo.kernel.component.ext.cache.impl.infinispan.v8/src/main/java/org/exoplatform/services/cache/impl/infinispan/distributed/DistributedExoCache.java
@@ -0,0 +1,1126 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.cache.impl.infinispan.distributed;
+
+import org.exoplatform.container.ExoContainer;
+import org.exoplatform.container.ExoContainerContext;
+import org.exoplatform.management.annotations.Managed;
+import org.exoplatform.management.annotations.ManagedDescription;
+import org.exoplatform.management.annotations.ManagedName;
+import org.exoplatform.services.cache.CacheInfo;
+import org.exoplatform.services.cache.CacheListener;
+import org.exoplatform.services.cache.CacheListenerContext;
+import org.exoplatform.services.cache.CachedObjectSelector;
+import org.exoplatform.services.cache.ExoCache;
+import org.exoplatform.services.cache.ExoCacheConfig;
+import org.exoplatform.services.cache.ObjectCacheInfo;
+import org.exoplatform.services.ispn.AbstractMapper;
+import org.exoplatform.services.ispn.DistributedCacheManager;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+import org.infinispan.AdvancedCache;
+import org.infinispan.Cache;
+import org.infinispan.context.Flag;
+import org.infinispan.distexec.mapreduce.Collector;
+import org.infinispan.distexec.mapreduce.MapReduceTask;
+import org.infinispan.distexec.mapreduce.Reducer;
+import org.infinispan.notifications.Listener;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntriesEvicted;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntryCreated;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntryModified;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved;
+import org.infinispan.notifications.cachelistener.event.CacheEntriesEvictedEvent;
+import org.infinispan.notifications.cachelistener.event.CacheEntryCreatedEvent;
+import org.infinispan.notifications.cachelistener.event.CacheEntryModifiedEvent;
+import org.infinispan.notifications.cachelistener.event.CacheEntryRemovedEvent;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * @author Nicolas Filotto
+ * @version $Id$
+ *
+ */
+public class DistributedExoCache implements ExoCache
+{
+
+ /**
+ * Logger.
+ */
+ private static final Log LOG = ExoLogger.getLogger(DistributedExoCache.class);//NOSONAR
+
+ public static final String CACHE_NAME = "eXoCache";
+
+ private final AtomicInteger hits = new AtomicInteger(0);
+
+ private final AtomicInteger misses = new AtomicInteger(0);
+
+ private String label;
+
+ private String name;
+
+ private final String fullName;
+
+ private boolean distributed;
+
+ private boolean replicated;
+
+ private boolean logEnabled;
+
+ @SuppressWarnings("rawtypes")
+ private static final ConcurrentMap>> ALL_LISTENERS =
+ new ConcurrentHashMap>>();
+
+ protected final AdvancedCache, V> cache;
+
+ @SuppressWarnings("unchecked")
+ public DistributedExoCache(ExoContainerContext ctx, ExoCacheConfig config, Cache cache)
+ {
+ this.fullName = ctx.getName() + "-" + config.getName();
+ this.cache = (AdvancedCache, V>)cache.getAdvancedCache();
+ setDistributed(config.isDistributed());
+ setLabel(config.getLabel());
+ setName(config.getName());
+ setLogEnabled(config.isLogEnabled());
+ setReplicated(config.isRepicated());
+ }
+
+ AdvancedCache, V> getCache()
+ {
+ return cache;
+ }
+
+ /**
+ * @return the fullName
+ */
+ String getFullName()
+ {
+ return fullName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("rawtypes")
+ public void addCacheListener(CacheListener super K, ? super V> listener)
+ {
+ if (listener == null)
+ {
+ throw new IllegalArgumentException("The listener cannot be null");
+ }
+ List lListeners = getListeners(fullName);
+ if (lListeners == null)
+ {
+ lListeners = new CopyOnWriteArrayList();
+ boolean alreadyAdded = false;
+ ConcurrentMap> listeners = getOrCreateListeners();
+ if (listeners.isEmpty())
+ {
+ synchronized (listeners)
+ {
+ if (listeners.isEmpty())
+ {
+ // Ensure that the listener is added only once
+ cache.addListener(new CacheEventListener());
+ listeners.put(fullName, lListeners);
+ alreadyAdded = true;
+ }
+ }
+ }
+ if (!alreadyAdded)
+ {
+ List oldValue = listeners.putIfAbsent(fullName, lListeners);
+ if (oldValue != null)
+ {
+ lListeners = oldValue;
+ }
+ }
+ }
+ lListeners.add(new ListenerContext(listener, this));
+ }
+
+ @SuppressWarnings("rawtypes")
+ private ConcurrentMap> getOrCreateListeners()
+ {
+ ConcurrentMap> listeners = ALL_LISTENERS.get(cache);
+ if (listeners == null)
+ {
+ listeners = new ConcurrentHashMap>();
+ ConcurrentMap> oldValue = ALL_LISTENERS.putIfAbsent(cache, listeners);
+ if (oldValue != null)
+ {
+ listeners = oldValue;
+ }
+ }
+ return listeners;
+ }
+
+ @SuppressWarnings("rawtypes")
+ private List getListeners(String fullName)
+ {
+ ConcurrentMap> listeners = ALL_LISTENERS.get(cache);
+ return listeners == null ? null : listeners.get(fullName);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void clearCache()
+ {
+ MapReduceTask, V, Void, Void> task = new MapReduceTask, V, Void, Void>(cache);
+ task.mappedWith(new ClearCacheMapper(fullName)).reducedWith(new ClearCacheReducer());
+ task.execute();
+ onClearCache();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ public V get(Serializable name)
+ {
+ if (name == null)
+ {
+ return null;
+ }
+ @SuppressWarnings("rawtypes")
+ final CacheKey key = new CacheKey(fullName, name);
+ final V result = cache.get(key);
+ if (result == null)
+ {
+ misses.incrementAndGet();
+ }
+ else
+ {
+ hits.incrementAndGet();
+ }
+ onGet(key, result);
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getCacheHit()
+ {
+ return hits.get();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getCacheMiss()
+ {
+ return misses.get();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getCacheSize()
+ {
+ MapReduceTask, V, String, Integer> task = new MapReduceTask, V, String, Integer>(cache);
+ task.mappedWith(new GetSizeMapper(fullName)).reducedWith(new GetSizeReducer());
+ Map map = task.execute();
+ int sum = 0;
+ for (Integer i : map.values())
+ {
+ sum += i;
+ }
+ return sum;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List getCachedObjects()
+ {
+ MapReduceTask, V, String, List> task =
+ new MapReduceTask, V, String, List>(cache);
+ task.mappedWith(new GetCachedObjectsMapper(fullName)).reducedWith(
+ new GetCachedObjectsReducer());
+ Map> map = task.execute();
+ List