/*
* Copyright (C) 2005-2012 BetaCONCEPT Limited
*
* This file is part of Astroboa.
*
* Astroboa 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 3 of the License, or
* (at your option) any later version.
*
* Astroboa 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 Astroboa. If not, see <http://www.gnu.org/licenses/>.
*/
package org.betaconceptframework.astroboa.cache;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.betaconceptframework.astroboa.api.model.ValueType;
import org.betaconceptframework.astroboa.api.model.definition.CmsDefinition;
import org.betaconceptframework.astroboa.api.model.definition.CmsPropertyDefinition;
import org.betaconceptframework.astroboa.api.model.definition.ComplexCmsPropertyDefinition;
import org.betaconceptframework.astroboa.api.model.definition.ContentObjectTypeDefinition;
import org.betaconceptframework.astroboa.context.AstroboaClientContextHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Gregory Chomatas (gchomatas@betaconcept.com)
* @author Savvas Triantafyllou (striantafyllou@betaconcept.com)
*
*/
public class DefinitionCacheManager {
private final Logger logger = LoggerFactory.getLogger(DefinitionCacheManager.class);
//This map holds definitions for all repositories
//First key is repository id
//Second Key is ValueType of Definition
//Third key is property name
private Map<String, Map<ValueType, Map<String, CmsDefinition>>> definitionCache =
new ConcurrentHashMap<String, Map<ValueType, Map<String,CmsDefinition>>>();
public void clearAllDefinitionsForCurrentRepository() {
clearAllDefinitionsForRepository(AstroboaClientContextHolder.getActiveRepositoryId());
}
public CmsDefinition getPropertyDefinition(ValueType valueType, String propertyName) {
Map<String, CmsDefinition> map = getPropertyDefinitionsForValueType(valueType);
if (map != null)
return map.get(propertyName);
return null;
}
public Map<String, CmsDefinition> getPropertyDefinitionsForValueType(ValueType valueType) {
String currentRepositoryId = AstroboaClientContextHolder.getActiveRepositoryId();
if (StringUtils.isNotBlank(currentRepositoryId) && definitionCache.containsKey(currentRepositoryId)){
Map<ValueType, Map<String, CmsDefinition>> currentRepositoryCache = definitionCache.get(currentRepositoryId);
if (!currentRepositoryCache.containsKey(valueType))
return null;
return currentRepositoryCache.get(valueType);
}
return null;
}
public void addPropertyDefinitionsForValueType(ValueType valueType, Map<String, CmsDefinition> propertyDefinitions) {
if (MapUtils.isNotEmpty(propertyDefinitions))
{
for (Entry<String,CmsDefinition> propertyDefinition: propertyDefinitions.entrySet())
{
addPropertyDefinition(valueType, propertyDefinition.getKey(), propertyDefinition.getValue());
}
}
}
public void addPropertyDefinition(ValueType valueType, String propertyName, CmsDefinition propertyDefinition) {
String currentRepositoryId = AstroboaClientContextHolder.getActiveRepositoryId();
if (StringUtils.isNotBlank(currentRepositoryId)){
if (!definitionCache.containsKey(currentRepositoryId)){
definitionCache.put(currentRepositoryId, new ConcurrentHashMap<ValueType, Map<String,CmsDefinition>>());
}
Map<ValueType, Map<String, CmsDefinition>> currentRepositoryCache = definitionCache.get(currentRepositoryId);
if (!currentRepositoryCache.containsKey(valueType))
currentRepositoryCache.put(valueType, new ConcurrentHashMap<String,CmsDefinition>());
currentRepositoryCache.get(valueType).put(propertyName, propertyDefinition);
}
}
public boolean atLeastOneDefinitionExistsForValueType(ValueType valueType) {
String currentRepositoryId = AstroboaClientContextHolder.getActiveRepositoryId();
if (StringUtils.isNotBlank(currentRepositoryId)){
return definitionCache.containsKey(currentRepositoryId) && definitionCache.get(currentRepositoryId).containsKey(valueType);
}
return false;
}
public boolean definitionExistsForProperty(ValueType valueType, String propertyName) {
String currentRepositoryId = AstroboaClientContextHolder.getActiveRepositoryId();
if (StringUtils.isNotBlank(currentRepositoryId)){
return definitionCache.containsKey(currentRepositoryId) //Definitions for repository must exist
&& definitionCache.get(currentRepositoryId).containsKey(valueType) //Definitions for provided value type must exist
&& definitionCache.get(currentRepositoryId).get(valueType).containsKey(propertyName); //Definition for provided property must exist
}
return false;
}
public void printDefinitionsToLog(){
if (logger.isDebugEnabled()){
StringBuilder sb = new StringBuilder();
//Detailed debug info for all definition tree
Set<Entry<String, Map<ValueType, Map<String, CmsDefinition>>>> definitionsPerRepository = definitionCache.entrySet();
for (Entry<String, Map<ValueType, Map<String, CmsDefinition>>> repositoryDefinitions : definitionsPerRepository){
sb.append("Definitions for repository ").append(repositoryDefinitions.getKey());
Map<ValueType, Map<String, CmsDefinition>> definitions = repositoryDefinitions.getValue();
for (Entry<ValueType, Map<String, CmsDefinition>> definitionForValueType : definitions.entrySet()){
if (ValueType.ContentType == definitionForValueType.getKey() || ValueType.Complex == definitionForValueType.getKey()){
printDefinitions(definitionForValueType.getValue(), 0, sb);
}
}
}
logger.debug("{}", sb.toString());
}
}
private void printDefinitions(Map<String, CmsDefinition> cmsPropertyDefinitions, int depth, StringBuilder sb) {
String tabs = generateTabs(depth);
if (MapUtils.isNotEmpty(cmsPropertyDefinitions)){
for (CmsDefinition def : cmsPropertyDefinitions.values()){
sb.append(tabs).append(def.getName()).append(", instance ").append(System.identityHashCode(def));
if (def instanceof ContentObjectTypeDefinition){
printPropertyDefinitions(((ContentObjectTypeDefinition)def).getPropertyDefinitions(), depth+1, sb);
}
else if (def instanceof ComplexCmsPropertyDefinition){
printPropertyDefinitions(((ComplexCmsPropertyDefinition)def).getChildCmsPropertyDefinitions(), depth+1, sb);
}
}
}
}
private String generateTabs(int depth) {
StringBuilder tabs = new StringBuilder();
for (int i=0;i<depth;i++){
tabs.append("\t");
}
return tabs.toString();
}
private void printPropertyDefinitions(Map<String, CmsPropertyDefinition> cmsPropertyDefinitions, int depth, StringBuilder sb) {
String tabs = generateTabs(depth);
if (MapUtils.isNotEmpty(cmsPropertyDefinitions)){
for (CmsPropertyDefinition def : cmsPropertyDefinitions.values()){
sb.append(tabs).append(def.getName()).append(", instance ").append(System.identityHashCode(def));
if (def instanceof ContentObjectTypeDefinition){
printPropertyDefinitions(((ContentObjectTypeDefinition)def).getPropertyDefinitions(), depth+1, sb);
}
else if (def instanceof ComplexCmsPropertyDefinition){
if (def.getName().equals(def.getParentDefinition().getName())){
//Child definition is the same. Detected a recursion
sb.append(tabs).append("\t Detecting recursion ");
}
else{
printPropertyDefinitions(((ComplexCmsPropertyDefinition)def).getChildCmsPropertyDefinitions(), depth+1, sb);
}
}
}
}
}
public void clearAllDefinitionsForRepository(String repositoryId) {
if (StringUtils.isNotBlank(repositoryId) && definitionCache.containsKey(repositoryId)){
definitionCache.get(repositoryId).clear();
}
}
}