/* * 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.engine.jcr.renderer; import java.util.Locale; import javax.jcr.AccessDeniedException; import javax.jcr.ItemNotFoundException; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.RepositoryException; import javax.jcr.Session; import org.apache.commons.lang.StringUtils; import org.apache.jackrabbit.util.ISO9075; import org.betaconceptframework.astroboa.api.model.ContentObjectFolder; import org.betaconceptframework.astroboa.api.model.ContentObjectFolder.Type; import org.betaconceptframework.astroboa.api.model.definition.ContentObjectTypeDefinition; import org.betaconceptframework.astroboa.engine.jcr.dao.ContentDefinitionDao; import org.betaconceptframework.astroboa.engine.jcr.query.CmsQueryHandler; import org.betaconceptframework.astroboa.engine.jcr.query.CmsQueryResult; import org.betaconceptframework.astroboa.engine.jcr.util.CmsRepositoryEntityUtils; import org.betaconceptframework.astroboa.model.impl.ContentObjectFolderImpl; import org.betaconceptframework.astroboa.model.impl.item.CmsBuiltInItem; import org.betaconceptframework.astroboa.model.impl.query.xpath.XPathUtils; import org.betaconceptframework.astroboa.util.CmsConstants; import org.betaconceptframework.astroboa.util.CmsUtils; import org.betaconceptframework.astroboa.util.TreeDepth; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; /** * * @author Gregory Chomatas (gchomatas@betaconcept.com) * @author Savvas Triantafyllou (striantafyllou@betaconcept.com) * */ public class ContentObjectFolderRenderer { @Autowired private ContentDefinitionDao contentDefinitionDao; @Autowired private CmsRepositoryEntityUtils cmsRepositoryEntityUtils; @Autowired private CmsQueryHandler cmsQueryHandler; private final Logger logger = LoggerFactory.getLogger(ContentObjectFolderRenderer.class); public ContentObjectFolder render(Session session, Node contentObjectFolderNode, int depth, boolean renderContentObjectIds, String locale) throws Exception { ContentObjectFolder contentObjectFolder = new ContentObjectFolderImpl(); contentObjectFolder.setId(contentObjectFolderNode.getIdentifier()); contentObjectFolder.setType(renderType(contentObjectFolderNode)); ((ContentObjectFolderImpl)contentObjectFolder).setFullPath(getFullPath(contentObjectFolderNode, contentObjectFolder.getType())); final String name = contentObjectFolderNode.getName(); if (contentObjectFolder.getType() == ContentObjectFolder.Type.CONTENT_TYPE){ //Extract type from node name String typeName = StringUtils.remove(name,CmsConstants.TYPE_FOLDER); contentObjectFolder.setName(typeName); //Search for definition for this type and get localized label ContentObjectTypeDefinition typeDefinition = contentDefinitionDao.getContentObjectTypeDefinition(typeName); if (typeDefinition == null){ logger.warn("Unable to render localized label for content object folder {} for type {}",name, typeName); contentObjectFolder.setLocalizedLabelForCurrentLocale(name); } else{ if (StringUtils.isBlank(locale)){ locale = Locale.ENGLISH.toString(); } contentObjectFolder.setLocalizedLabelForCurrentLocale(typeDefinition.getDisplayName().getLocalizedLabelForLocale(locale)); } } else{ String label = name; if ((contentObjectFolder.getType() == ContentObjectFolder.Type.DAY || contentObjectFolder.getType() == ContentObjectFolder.Type.HOUR || contentObjectFolder.getType() == ContentObjectFolder.Type.MINUTE || contentObjectFolder.getType() == ContentObjectFolder.Type.SECOND) && label != null && label.length() == 1){ label = "0"+label; } contentObjectFolder.setLocalizedLabelForCurrentLocale(name); contentObjectFolder.setName(name); } final int nextDepth = CmsUtils.getNextDepth(depth); if (contentObjectFolder.getType() == ContentObjectFolder.Type.CONTENT_TYPE || contentObjectFolder.getType() == ContentObjectFolder.Type.YEAR || contentObjectFolder.getType() == ContentObjectFolder.Type.MONTH || contentObjectFolder.getType() == ContentObjectFolder.Type.HOUR || contentObjectFolder.getType() == ContentObjectFolder.Type.MINUTE ){ contentObjectFolder.setNumberOfContentObjects(0); if (depth != TreeDepth.ZERO.asInt()){ //Render children NodeIterator subFolders = contentObjectFolderNode.getNodes(); while (subFolders.hasNext()){ Node subFolderNode = subFolders.nextNode(); if (getFolderType(subFolderNode) != null) contentObjectFolder.addSubFolder(render(session, subFolderNode, nextDepth,renderContentObjectIds,locale)); } } } else if (contentObjectFolder.getType() == ContentObjectFolder.Type.DAY || contentObjectFolder.getType() == ContentObjectFolder.Type.SECOND){ //Backwards compatibility. DAY may contain content object nodes as well thus we need to make a query in order //to retrieve all content object child nodes //Perform a query to load all nodes representing content object nodes String contentObjectFolderPathCriterion = ISO9075.encodePath(contentObjectFolderNode.getPath()).replaceFirst("/", ""); String contentObjectNodeQuery = XPathUtils.createXPathSelect(contentObjectFolderPathCriterion, null, CmsBuiltInItem.StructuredContentObject, true); //If we do not want to render content object ids then we are only interested in their number int limit = renderContentObjectIds? -1: 0; CmsQueryResult contentObjectNodes = cmsQueryHandler.getNodesFromXPathQuery(session, contentObjectNodeQuery, 0, limit); contentObjectFolder.setNumberOfContentObjects(contentObjectNodes.getTotalRowCount()); if (renderContentObjectIds){ //Iterate over the nodes in order to retrieve content object ids NodeIterator childNodes = contentObjectNodes.getNodeIterator(); while (childNodes.hasNext()){ Node childNode = childNodes.nextNode(); contentObjectFolder.addContentObjectId(cmsRepositoryEntityUtils.getCmsIdentifier(childNode)); } } //Finally, if folder is a DAY folder and depth is > 0 //then load its subfolders if (contentObjectFolder.getType() == ContentObjectFolder.Type.DAY && depth != TreeDepth.ZERO.asInt()){ //We need to make a query to distinguish nodes, as DAY folder node may have content object nodes (version 2.x.x) //or hour folder nodes (version 3.x.x). In cases where both type of nodes exists then repository has been migrated from version //2.x.x to 3.x.x String hourFolderNodeQuery = XPathUtils.createXPathSelect(contentObjectFolderPathCriterion, null, CmsBuiltInItem.GenericHourFolder, true); CmsQueryResult hourFolderNodes = cmsQueryHandler.getNodesFromXPathQuery(session, hourFolderNodeQuery, 0, -1); NodeIterator subFolderNodes = hourFolderNodes.getNodeIterator(); while (subFolderNodes.hasNext()){ contentObjectFolder.addSubFolder(render(session, subFolderNodes.nextNode(), nextDepth,renderContentObjectIds,locale)); } } } return contentObjectFolder; } private String getFullPath(Node contentObjectFolderNode, Type type) throws RepositoryException { if (type == null){ return ""; } switch (type) { case CONTENT_TYPE: case YEAR: return contentObjectFolderNode.getName(); case MONTH: case DAY: case HOUR: case MINUTE: case SECOND: //locate contentTypeFolder folder Node contentTypeFolder = contentObjectFolderNode.getParent(); while (contentTypeFolder!= null && ! contentTypeFolder.isNodeType(CmsBuiltInItem.GenericContentTypeFolder.getJcrName())){ contentTypeFolder = contentTypeFolder.getParent(); } if (contentTypeFolder == null){ return contentObjectFolderNode.getName(); } String path = StringUtils.remove(contentObjectFolderNode.getPath(), contentTypeFolder.getPath()); if (path != null && path.startsWith("/")){ return StringUtils.removeStart(path, "/"); } return path; default: break; } if (Type.MONTH == type){ return getMonthName(contentObjectFolderNode)+"/"+contentObjectFolderNode.getName(); } else if (Type.DAY == type){ return getDayPath(contentObjectFolderNode)+"/"+ getMonthName(contentObjectFolderNode)+"/"+contentObjectFolderNode.getName(); } else if (Type.HOUR == type){ return getHourPath(contentObjectFolderNode)+"/"+ getDayPath(contentObjectFolderNode)+"/"+ getMonthName(contentObjectFolderNode)+"/"+contentObjectFolderNode.getName(); } else if (Type.MINUTE == type){ return getMinutePath(contentObjectFolderNode)+"/"+ getHourPath(contentObjectFolderNode)+"/"+ getDayPath(contentObjectFolderNode)+"/"+ getMonthName(contentObjectFolderNode)+"/"+contentObjectFolderNode.getName(); } else if (Type.SECOND == type){ return contentObjectFolderNode.getParent().getParent().getParent().getParent().getParent().getName()+"/"+ getMinutePath(contentObjectFolderNode)+"/"+ getHourPath(contentObjectFolderNode)+"/"+ getDayPath(contentObjectFolderNode)+"/"+ getMonthName(contentObjectFolderNode)+"/"+contentObjectFolderNode.getName(); } // Type.YEAR == type || Type.CONTENT_TYPE == type return contentObjectFolderNode.getName(); } private String getMinutePath(Node contentObjectFolderNode) throws RepositoryException, ItemNotFoundException, AccessDeniedException { return contentObjectFolderNode.getParent().getParent().getParent().getParent().getName(); } private String getHourPath(Node contentObjectFolderNode) throws RepositoryException, ItemNotFoundException, AccessDeniedException { return contentObjectFolderNode.getParent().getParent().getParent().getName(); } private String getDayPath(Node contentObjectFolderNode) throws RepositoryException, ItemNotFoundException, AccessDeniedException { return contentObjectFolderNode.getParent().getParent().getName(); } private String getMonthName(Node contentObjectFolderNode) throws RepositoryException, ItemNotFoundException, AccessDeniedException { return contentObjectFolderNode.getParent().getName(); } private Type getFolderType(Node folderNode) throws RepositoryException { if (folderNode.isNodeType(CmsBuiltInItem.GenericContentTypeFolder.getJcrName())){ return ContentObjectFolder.Type.CONTENT_TYPE; } else if (folderNode.isNodeType(CmsBuiltInItem.GenericYearFolder.getJcrName())){ return ContentObjectFolder.Type.YEAR; } else if (folderNode.isNodeType(CmsBuiltInItem.GenericMonthFolder.getJcrName())){ return ContentObjectFolder.Type.MONTH; } else if (folderNode.isNodeType(CmsBuiltInItem.GenericDayFolder.getJcrName())){ return ContentObjectFolder.Type.DAY; } else if (folderNode.isNodeType(CmsBuiltInItem.GenericHourFolder.getJcrName())){ return ContentObjectFolder.Type.HOUR; } else if (folderNode.isNodeType(CmsBuiltInItem.GenericMinuteFolder.getJcrName())){ return ContentObjectFolder.Type.MINUTE; } else if (folderNode.isNodeType(CmsBuiltInItem.GenericSecondFolder.getJcrName())){ return ContentObjectFolder.Type.SECOND; } else return null; } private Type renderType(Node folderNode) throws Exception{ Type folderType = getFolderType(folderNode); if (folderType == null) throw new Exception("Unknown content object folder type "+ folderNode.getPath()); else return folderType; } }