
org.broadleafcommerce.cms.structure.service.StructuredContentServiceImpl Maven / Gradle / Ivy
/*
* Copyright 2008-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.broadleafcommerce.cms.structure.service;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.broadleafcommerce.cms.common.AbstractContentService;
import org.broadleafcommerce.cms.file.service.StaticAssetService;
import org.broadleafcommerce.cms.structure.dao.StructuredContentDao;
import org.broadleafcommerce.cms.structure.domain.StructuredContent;
import org.broadleafcommerce.cms.structure.domain.StructuredContentField;
import org.broadleafcommerce.cms.structure.domain.StructuredContentImpl;
import org.broadleafcommerce.cms.structure.domain.StructuredContentItemCriteria;
import org.broadleafcommerce.cms.structure.domain.StructuredContentRule;
import org.broadleafcommerce.cms.structure.domain.StructuredContentType;
import org.broadleafcommerce.cms.structure.dto.ItemCriteriaDTO;
import org.broadleafcommerce.cms.structure.dto.StructuredContentDTO;
import org.broadleafcommerce.cms.structure.message.ArchivedStructuredContentPublisher;
import org.broadleafcommerce.common.locale.domain.Locale;
import org.broadleafcommerce.openadmin.server.dao.SandBoxDao;
import org.broadleafcommerce.openadmin.server.dao.SandBoxItemDao;
import org.broadleafcommerce.openadmin.server.domain.SandBox;
import org.broadleafcommerce.openadmin.server.domain.SandBoxItem;
import org.broadleafcommerce.openadmin.server.domain.SandBoxItemType;
import org.broadleafcommerce.openadmin.server.domain.SandBoxOperationType;
import org.broadleafcommerce.openadmin.server.domain.SandBoxType;
import org.hibernate.Criteria;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* @author bpolster
*/
@Service("blStructuredContentService")
public class StructuredContentServiceImpl extends AbstractContentService implements StructuredContentService {
private static final Log LOG = LogFactory.getLog(StructuredContentServiceImpl.class);
private static String AND = " && ";
@Resource(name="blStructuredContentDao")
protected StructuredContentDao structuredContentDao;
@Resource(name="blSandBoxItemDao")
protected SandBoxItemDao sandBoxItemDao;
@Resource(name="blSandBoxDao")
protected SandBoxDao sandBoxDao;
@Resource(name="blStaticAssetService")
protected StaticAssetService staticAssetService;
private List contentRuleProcessors;
protected Cache structuredContentCache;
protected List archivedStructuredContentListeners;
@Override
public StructuredContent findStructuredContentById(Long contentId) {
return structuredContentDao.findStructuredContentById(contentId);
}
@Override
public StructuredContentType findStructuredContentTypeById(Long id) {
return structuredContentDao.findStructuredContentTypeById(id);
}
@Override
public StructuredContentType findStructuredContentTypeByName(String name) {
return structuredContentDao.findStructuredContentTypeByName(name);
}
@Override
public List retrieveAllStructuredContentTypes() {
return structuredContentDao.retrieveAllStructuredContentTypes();
}
@Override
public Map findFieldsByContentId(Long contentId) {
StructuredContent sc = findStructuredContentById(contentId);
return structuredContentDao.readFieldsForStructuredContentItem(sc);
}
@Override
public List findContentItems(SandBox sandbox, Criteria c) {
return (List) findItems(sandbox, c, StructuredContent.class, StructuredContentImpl.class, "originalItemId");
}
@Override
public Long countContentItems(SandBox sandbox, Criteria c) {
return countItems(sandbox, c, StructuredContentImpl.class, "originalItemId");
}
@Override
public StructuredContent addStructuredContent(StructuredContent content, SandBox destinationSandbox) {
content.setSandbox(destinationSandbox);
content.setArchivedFlag(false);
content.setDeletedFlag(false);
StructuredContent sc = structuredContentDao.addOrUpdateContentItem(content);
if (! isProductionSandBox(destinationSandbox)) {
sandBoxItemDao.addSandBoxItem(destinationSandbox, SandBoxOperationType.ADD, SandBoxItemType.STRUCTURED_CONTENT, sc.getContentName(), sc.getId(), null);
}
return sc;
}
@Override
public StructuredContent updateStructuredContent(StructuredContent content, SandBox destSandbox) {
if (content.getLockedFlag()) {
throw new IllegalArgumentException("Unable to update a locked record");
}
if (checkForSandboxMatch(content.getSandbox(), destSandbox)) {
if (content.getDeletedFlag()) {
SandBoxItem item = sandBoxItemDao.retrieveBySandboxAndTemporaryItemId(content.getSandbox(), SandBoxItemType.STRUCTURED_CONTENT, content.getId());
if (content.getOriginalItemId() == null) {
// This page was added in this sandbox and now needs to be deleted.
content.setArchivedFlag(true);
item.setArchivedFlag(true);
} else {
// This page was being updated but now is being deleted - so change the
// sandbox operation type to deleted
item.setSandBoxOperationType(SandBoxOperationType.DELETE);
sandBoxItemDao.updateSandBoxItem(item);
}
}
return structuredContentDao.addOrUpdateContentItem(content);
} else if (checkForProductionSandbox(content.getSandbox())) {
// The passed in content is an existing content item whose values were updated
// Instead, we want to create a clone of this item for the destSandbox
// Create the clone
StructuredContent clonedContent = content.cloneEntity();
clonedContent.setOriginalItemId(content.getId());
clonedContent.setSandbox(destSandbox);
// Detach the old item so it doesn't get updated
structuredContentDao.detach(content);
// Update the new item
StructuredContent returnContent = structuredContentDao.addOrUpdateContentItem(clonedContent);
// Lookup the previous item so that we can update its locked status
StructuredContent prod = findStructuredContentById(content.getId());
prod.setLockedFlag(true);
prod = structuredContentDao.addOrUpdateContentItem(prod);
SandBoxOperationType type = SandBoxOperationType.UPDATE;
if (clonedContent.getDeletedFlag()) {
type = SandBoxOperationType.DELETE;
}
sandBoxItemDao.addSandBoxItem(destSandbox, type, SandBoxItemType.STRUCTURED_CONTENT, returnContent.getContentName(), returnContent.getId(), returnContent.getOriginalItemId());
return returnContent;
} else {
// This should happen via a promote, revert, or reject in the sandbox service
throw new IllegalArgumentException("Update called when promote or reject was expected.");
}
}
private boolean checkForSandboxMatch(SandBox src, SandBox dest) {
if (src != null) {
if (dest != null) {
return src.getId().equals(dest.getId());
}
}
return (src == null && dest == null);
}
private boolean checkForProductionSandbox(SandBox dest) {
boolean productionSandbox = false;
if (dest == null) {
productionSandbox = true;
} else {
if (dest.getSite() != null && dest.getSite().getProductionSandbox() != null && dest.getSite().getProductionSandbox().getId() != null) {
productionSandbox = dest.getSite().getProductionSandbox().getId().equals(dest.getId());
}
}
return productionSandbox;
}
@Override
public void deleteStructuredContent(StructuredContent content, SandBox destinationSandbox) {
content.setDeletedFlag(true);
updateStructuredContent(content, destinationSandbox);
}
private String buildRuleExpression(StructuredContent sc) {
StringBuffer ruleExpression = null;
Map ruleMap = sc.getStructuredContentMatchRules();
if (ruleMap != null) {
for (String ruleKey : ruleMap.keySet()) {
if (ruleExpression == null) {
ruleExpression = new StringBuffer(ruleMap.get(ruleKey).getMatchRule());
} else {
ruleExpression.append(AND);
ruleExpression.append(ruleMap.get(ruleKey).getMatchRule());
}
}
}
if (ruleExpression != null) {
return ruleExpression.toString();
} else {
return null;
}
}
private List buildItemCriteriaDTOList(StructuredContent sc) {
List itemCriteriaDTOList = new ArrayList();
for(StructuredContentItemCriteria criteria : sc.getQualifyingItemCriteria()) {
ItemCriteriaDTO criteriaDTO = new ItemCriteriaDTO();
criteriaDTO.setMatchRule(criteria.getOrderItemMatchRule());
criteriaDTO.setQty(criteria.getQuantity());
itemCriteriaDTOList.add(criteriaDTO);
}
return itemCriteriaDTOList;
}
private void buildFieldValues(StructuredContent sc, StructuredContentDTO scDTO, boolean secure) {
String envPrefix = staticAssetService.getStaticAssetEnvironmentUrlPrefix();
if (envPrefix != null && secure) {
envPrefix = staticAssetService.getStaticAssetEnvironmentSecureUrlPrefix();
}
String cmsPrefix = staticAssetService.getStaticAssetUrlPrefix();
for (String fieldKey : sc.getStructuredContentFields().keySet()) {
StructuredContentField scf = sc.getStructuredContentFields().get(fieldKey);
String originalValue = scf.getValue();
if (envPrefix != null && originalValue != null && originalValue.contains(cmsPrefix)) {
if (originalValue.startsWith("/")) {
originalValue = originalValue.substring(1);
}
String fldValue = originalValue.replaceAll(cmsPrefix, envPrefix+cmsPrefix);
scDTO.getValues().put(fieldKey, fldValue);
} else {
scDTO.getValues().put(fieldKey, originalValue);
}
}
}
/**
* Converts a list of structured content items to a list of structured content DTOs.
* Internally calls buildStructuredContentDTO(...).
*
* @param structuredContentList
* @param secure
* @return
*/
protected List buildStructuredContentDTOList(List structuredContentList, boolean secure) {
List dtoList = new ArrayList();
if (structuredContentList != null) {
for(StructuredContent sc : structuredContentList) {
dtoList.add(buildStructuredContentDTO(sc, secure));
}
}
return dtoList;
}
/**
* Converts a StructuredContent into a StructuredContentDTO. If the item contains fields with
* broadleaf cms urls, the urls are converted to utilize the domain
* @param sc
* @param secure
* @return
*/
protected StructuredContentDTO buildStructuredContentDTO(StructuredContent sc, boolean secure) {
StructuredContentDTO scDTO = new StructuredContentDTO();
scDTO.setContentName(sc.getContentName());
scDTO.setContentType(sc.getStructuredContentType().getName());
scDTO.setId(sc.getId());
scDTO.setPriority(sc.getPriority());
if (sc.getLocale() != null) {
scDTO.setLocaleCode(sc.getLocale().getLocaleCode());
}
if (sc.getSandbox() != null) {
scDTO.setSandboxId(sc.getSandbox().getId());
}
scDTO.setRuleExpression(buildRuleExpression(sc));
buildFieldValues(sc, scDTO, secure);
if (sc.getQualifyingItemCriteria() != null && sc.getQualifyingItemCriteria().size() > 0) {
scDTO.setItemCriteriaDTOList(buildItemCriteriaDTOList(sc));
}
return scDTO;
}
private List mergeContent(List productionList, List sandboxList, boolean secure) {
if (sandboxList == null || sandboxList.size() == 0) {
return productionList;
}
Map scMap = new LinkedHashMap();
if (productionList != null) {
for(StructuredContentDTO sc : productionList) {
scMap.put(sc.getId(), sc);
}
}
for(StructuredContent sc : sandboxList) {
if (sc.getOriginalItemId() != null) {
scMap.remove(sc.getOriginalItemId());
}
if (! sc.getDeletedFlag() && ! sc.getOfflineFlag()) {
StructuredContentDTO convertedItem = buildStructuredContentDTO(sc, secure);
scMap.put(sc.getId(), convertedItem);
}
}
ArrayList returnList = new ArrayList(scMap.values());
if (returnList.size() > 1) {
Collections.sort(returnList, new BeanComparator("priority"));
}
return returnList;
}
private List evaluateAndPriortizeContent(List structuredContentList, int count, Map ruleDTOs) {
// some optimization for single item lists which don't require prioritization
if (structuredContentList.size() == 1) {
if (processContentRules(structuredContentList.get(0), ruleDTOs)) {
return structuredContentList;
} else {
return new ArrayList();
}
}
Iterator structuredContentIterator = structuredContentList.iterator();
List returnList = new ArrayList();
List tmpList = new ArrayList();
Integer lastPriority = Integer.MIN_VALUE;
while (structuredContentIterator.hasNext()) {
StructuredContentDTO sc = structuredContentIterator.next();
if (! lastPriority.equals(sc.getPriority())) {
// If we've moved to another priority, then shuffle all of the items
// with the previous priority and add them to the return list.
if (tmpList.size() > 1) {
Collections.shuffle(tmpList);
}
returnList.addAll(tmpList);
tmpList.clear();
// If we've added enough items to satisfy the count, then return the
// list.
if (returnList.size() == count) {
return returnList;
} else if (returnList.size() > count) {
return returnList.subList(0, count);
} else {
if (processContentRules(sc, ruleDTOs)) {
tmpList.add(sc);
}
}
} else {
if (processContentRules(sc, ruleDTOs)) {
tmpList.add(sc);
}
}
lastPriority = sc.getPriority();
}
if (tmpList.size() > 1) {
Collections.shuffle(tmpList);
}
returnList.addAll(tmpList);
if (returnList.size() > count) {
return returnList.subList(0, count);
}
return returnList;
}
private boolean processContentRules(StructuredContentDTO sc, Map ruleDTOs) {
if (contentRuleProcessors != null) {
for (StructuredContentRuleProcessor processor : contentRuleProcessors) {
boolean matchFound = processor.checkForMatch(sc, ruleDTOs);
if (! matchFound) {
return false;
}
}
}
return true;
}
@Override
public List lookupStructuredContentItemsByType(SandBox sandBox, StructuredContentType contentType, Locale locale, Integer count, Map ruleDTOs, boolean secure) {
List sandBoxContentList = null;
String cacheKey = buildTypeKey(getProductionSandBox(sandBox), locale, contentType.getName());
cacheKey = cacheKey+"-"+secure;
List productionContentDTOList = getStructuredContentListFromCache(cacheKey);
if (productionContentDTOList == null) {
List productionContentList = structuredContentDao.findActiveStructuredContentByType(getProductionSandBox(sandBox), contentType, locale);
productionContentDTOList = buildStructuredContentDTOList(productionContentList, secure);
if (productionContentDTOList != null) {
addStructuredContentListToCache(cacheKey, productionContentDTOList);
}
}
final List contentList;
if (! isProductionSandBox(sandBox)) {
sandBoxContentList = structuredContentDao.findActiveStructuredContentByType(sandBox, contentType, locale);
contentList = mergeContent(productionContentDTOList, sandBoxContentList, secure);
} else {
contentList = productionContentDTOList;
}
return evaluateAndPriortizeContent(contentList, count, ruleDTOs);
}
@Override
public List lookupStructuredContentItemsByName(SandBox sandBox, StructuredContentType contentType, String contentName, org.broadleafcommerce.common.locale.domain.Locale locale, Integer count, Map ruleDTOs, boolean secure) {
List sandBoxContentList = null;
String cacheKey = buildNameKey(getProductionSandBox(sandBox), locale, contentType.getName(), contentName);
cacheKey = cacheKey+"-"+secure;
List productionContentDTOList = getStructuredContentListFromCache(cacheKey);
if (productionContentDTOList == null) {
List productionContentList = structuredContentDao.findActiveStructuredContentByNameAndType(getProductionSandBox(sandBox), contentType, contentName, locale);
productionContentDTOList = buildStructuredContentDTOList(productionContentList, secure);
if (productionContentDTOList != null) {
addStructuredContentListToCache(cacheKey, productionContentDTOList);
}
}
final List contentList;
if (! isProductionSandBox(sandBox)) {
sandBoxContentList = structuredContentDao.findActiveStructuredContentByNameAndType(sandBox, contentType, contentName, locale);
contentList = mergeContent(productionContentDTOList, sandBoxContentList, secure);
} else {
contentList = productionContentDTOList;
}
return evaluateAndPriortizeContent(contentList, count, ruleDTOs);
}
@Override
public List lookupStructuredContentItemsByName(SandBox sandBox, String contentName, org.broadleafcommerce.common.locale.domain.Locale locale, Integer count, Map ruleDTOs, boolean secure) {
List sandBoxContentList = null;
String cacheKey = buildNameKey(getProductionSandBox(sandBox), locale, "any", contentName);
cacheKey = cacheKey+"-"+secure;
List productionContentDTOList = getStructuredContentListFromCache(cacheKey);
if (productionContentDTOList == null) {
List productionContentList = structuredContentDao.findActiveStructuredContentByName(getProductionSandBox(sandBox), contentName, locale);
productionContentDTOList = buildStructuredContentDTOList(productionContentList, secure);
if (productionContentDTOList != null) {
addStructuredContentListToCache(cacheKey, productionContentDTOList);
}
}
final List contentList;
if (! isProductionSandBox(sandBox)) {
sandBoxContentList = structuredContentDao.findActiveStructuredContentByName(sandBox, contentName, locale);
contentList = mergeContent(productionContentDTOList, sandBoxContentList, secure);
} else {
contentList = productionContentDTOList;
}
return evaluateAndPriortizeContent(contentList, count, ruleDTOs);
}
private SandBox getProductionSandBox(SandBox currentSandBox) {
SandBox productionSandBox = null;
if (currentSandBox == null || SandBoxType.PRODUCTION.equals(currentSandBox.getSandBoxType())) {
productionSandBox = currentSandBox;
} else if (currentSandBox.getSite() != null) {
productionSandBox = currentSandBox.getSite().getProductionSandbox();
}
return productionSandBox;
}
private boolean isProductionSandBox(SandBox dest) {
if (dest == null) {
return true;
} else {
return SandBoxType.PRODUCTION.equals(dest.getSandBoxType());
}
}
protected void productionItemArchived(StructuredContent sc) {
// Immediately remove the content from this VM.
removeStructuredContentFromCache(sc);
if (archivedStructuredContentListeners != null) {
for (ArchivedStructuredContentPublisher listener : archivedStructuredContentListeners) {
listener.processStructuredContentArchive(sc, buildTypeKey(sc), buildNameKey(sc));
}
}
}
@Override
public void itemPromoted(SandBoxItem sandBoxItem, SandBox destinationSandBox) {
if (! SandBoxItemType.STRUCTURED_CONTENT.equals(sandBoxItem.getSandBoxItemType())) {
return;
}
StructuredContent sc = structuredContentDao.findStructuredContentById(sandBoxItem.getTemporaryItemId());
if (sc == null) {
if (LOG.isDebugEnabled()) {
LOG.debug("Structured Content Item not found " + sandBoxItem.getTemporaryItemId());
}
} else {
boolean productionSandBox = isProductionSandBox(destinationSandBox);
if (productionSandBox) {
sc.setLockedFlag(false);
} else {
sc.setLockedFlag(true);
}
if (productionSandBox && sc.getOriginalItemId() != null) {
if (LOG.isDebugEnabled()) {
LOG.debug("Structured content promoted to production. " + sc.getId() + ". Archiving original item " + sc.getOriginalItemId());
}
StructuredContent originalSC = structuredContentDao.findStructuredContentById(sc.getOriginalItemId());
originalSC.setArchivedFlag(Boolean.TRUE);
structuredContentDao.addOrUpdateContentItem(originalSC);
productionItemArchived(originalSC);
if (sc.getDeletedFlag()) {
// if this deleted content is being pushed to production, set it as archived.
sc.setArchivedFlag(true);
}
// We are archiving the old content and making this the new "production page content", so
// null out the original page id before saving.
sc.setOriginalItemId(null);
}
}
if (sc.getOriginalSandBox() == null) {
sc.setOriginalSandBox(sc.getSandbox());
}
sc.setSandbox(destinationSandBox);
structuredContentDao.addOrUpdateContentItem(sc);
}
@Override
public void itemRejected(SandBoxItem sandBoxItem, SandBox destinationSandBox) {
if (! SandBoxItemType.STRUCTURED_CONTENT.equals(sandBoxItem.getSandBoxItemType())) {
return;
}
StructuredContent sc = structuredContentDao.findStructuredContentById(sandBoxItem.getTemporaryItemId());
if (sc != null) {
sc.setSandbox(destinationSandBox);
sc.setOriginalSandBox(null);
sc.setLockedFlag(false);
structuredContentDao.addOrUpdateContentItem(sc);
}
}
@Override
public void itemReverted(SandBoxItem sandBoxItem) {
if (! SandBoxItemType.STRUCTURED_CONTENT.equals(sandBoxItem.getSandBoxItemType())) {
return;
}
StructuredContent sc = structuredContentDao.findStructuredContentById(sandBoxItem.getTemporaryItemId());
if (sc != null) {
if (sandBoxItem.getOriginalItemId() != null) {
sc.setArchivedFlag(Boolean.TRUE);
sc.setLockedFlag(Boolean.FALSE);
structuredContentDao.addOrUpdateContentItem(sc);
StructuredContent originalSc = structuredContentDao.findStructuredContentById(sandBoxItem.getOriginalItemId());
originalSc.setLockedFlag(false);
structuredContentDao.addOrUpdateContentItem(originalSc);
}
}
}
public List getContentRuleProcessors() {
return contentRuleProcessors;
}
public void setContentRuleProcessors(List contentRuleProcessors) {
this.contentRuleProcessors = contentRuleProcessors;
}
private Cache getStructuredContentCache() {
if (structuredContentCache == null) {
structuredContentCache = CacheManager.getInstance().getCache("cmsStructuredContentCache");
}
return structuredContentCache;
}
private String buildNameKey(StructuredContent sc) {
return buildNameKey(sc.getSandbox(), sc.getLocale(), sc.getStructuredContentType().getName(), sc.getContentName());
}
private String buildTypeKey(StructuredContent sc) {
return buildTypeKey(sc.getSandbox(), sc.getLocale(), sc.getStructuredContentType().getName());
}
private String buildNameKey(SandBox currentSandbox, Locale locale, String contentType, String contentName) {
StringBuffer key = new StringBuffer(contentType).append("-").append(contentName);
if (locale != null) {
key.append("-").append(locale.getLocaleCode());
}
if (currentSandbox != null) {
key.append("-").append(currentSandbox.getId());
}
return key.toString();
}
private String buildTypeKey(SandBox currentSandbox, Locale locale, String contentType) {
StringBuffer key = new StringBuffer(contentType);
if (locale != null) {
key.append("-").append(locale.getLocaleCode());
}
if (currentSandbox != null) {
key.append("-").append(currentSandbox.getId());
}
return key.toString();
}
private void addStructuredContentListToCache(String key, List scDTOList) {
getStructuredContentCache().put(new Element(key, scDTOList));
}
private List getStructuredContentListFromCache(String key) {
Element scElement = getStructuredContentCache().get(key);
if (scElement != null) {
return (List) scElement.getValue();
}
return null;
}
/**
* Call to evict an item from the cache.
* @param sc
*/
public void removeStructuredContentFromCache(StructuredContent sc) {
// Remove secure and non-secure instances of the page.
// Typically the page will be in one or the other if at all.
removeItemFromCache(buildNameKey(sc), buildTypeKey(sc));
}
/**
* Call to evict both secure and non-secure SC items matching
* the passed in key.
*
* @param nameKey
*/
public void removeItemFromCache(String nameKey, String typeKey) {
// Remove secure and non-secure instances of the structured content.
// Typically the structured content will be in one or the other if at all.
getStructuredContentCache().remove(nameKey+"-"+true);
getStructuredContentCache().remove(nameKey+"-"+false);
getStructuredContentCache().remove(typeKey+"-"+true);
getStructuredContentCache().remove(typeKey+"-"+false);
}
public List getArchivedStructuredContentListeners() {
return archivedStructuredContentListeners;
}
public void setArchivedStructuredContentListeners(List archivedStructuredContentListeners) {
this.archivedStructuredContentListeners = archivedStructuredContentListeners;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy