/* * Copyright 2000-2013 Enonic AS * http://www.enonic.com/license */ package com.enonic.vertical.engine.handlers; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.w3c.dom.Document; import org.w3c.dom.Element; import com.enonic.esl.sql.model.Column; import com.enonic.esl.util.ArrayUtil; import com.enonic.esl.util.RelationAggregator; import com.enonic.esl.util.RelationNode; import com.enonic.esl.util.RelationTree; import com.enonic.esl.xml.XMLTool; import com.enonic.vertical.engine.VerticalEngineLogger; import com.enonic.vertical.engine.XDG; import com.enonic.vertical.engine.criteria.CategoryCriteria; import com.enonic.vertical.engine.dbmodel.CategoryTable; import com.enonic.vertical.engine.dbmodel.CategoryView; import com.enonic.vertical.engine.dbmodel.ConAccessRight2Table; import com.enonic.vertical.engine.dbmodel.ContentPublishedView; import com.enonic.cms.framework.hibernate.support.InClauseBuilder; import com.enonic.cms.framework.util.TIntArrayList; import com.enonic.cms.framework.xml.XMLDocument; import com.enonic.cms.core.CalendarUtil; import com.enonic.cms.core.content.ContentKey; import com.enonic.cms.core.content.category.CategoryAccessResolver; import com.enonic.cms.core.content.category.CategoryAccessRightsAccumulated; import com.enonic.cms.core.content.category.CategoryEntity; import com.enonic.cms.core.content.category.CategoryKey; import com.enonic.cms.core.content.category.CategoryStatistics; import com.enonic.cms.core.content.category.CategoryXmlCreator; import com.enonic.cms.core.content.contenttype.ContentTypeKey; import com.enonic.cms.core.security.user.User; import com.enonic.cms.core.security.user.UserEntity; import com.enonic.cms.store.dao.CategoryDao; @Component public class CategoryHandler extends BaseHandler { private final static String CAT_TABLE = "tCategory"; private final static String CAT_SELECT_COUNT = "SELECT count(cat_lKey) FROM " + CAT_TABLE; private final static String CAT_WHERE_CLAUSE_CAT_NOT_DELETED = " cat_bDeleted = 0"; private final static String CAT_WHERE_CLAUSE_SCA_ONE = " cat_cat_lSuper = ?"; private final static String CAT_WHERE_CLAUSE_CTY = " cat_cty_lKey = ?"; private final static String CAT_WHERE_CLAUSE_UNI = " cat_uni_lKey = ?"; // SQL objects: private CategoryStatisticsHelper categoryStatisticsHelper; @Autowired private CategoryDao categoryDao; @PostConstruct public void init() { categoryStatisticsHelper = new CategoryStatisticsHelper( this ); } public int getCategoryKey( int superCategoryKey, String name ) { CategoryView view = CategoryView.getInstance(); StringBuffer sql = XDG.generateSelectSQL( view, view.cat_lKey, null ); XDG.appendWhereSQL( sql, view.cat_cat_lSuper, XDG.OPERATOR_EQUAL, superCategoryKey ); XDG.appendWhereSQL( sql, view.cat_sName, name ); CommonHandler commonHandler = getCommonHandler(); return commonHandler.getInt( sql.toString(), (int[]) null ); } private int[] getCategoryKeysBySuperCategory( CategoryKey superCategoryKey ) { return getCategoryKeysBySuperCategories( new int[]{superCategoryKey.toInt()} ); } public int[] getCategoryKeysBySuperCategories( int[] superCategoryKeys ) { if ( superCategoryKeys == null || superCategoryKeys.length == 0 ) { return new int[0]; } TIntArrayList categoryKeys = new TIntArrayList(); for ( int i = 0; i < superCategoryKeys.length; i++ ) { categoryKeys.add( getSubCategoriesByParent( new CategoryKey( superCategoryKeys[i] ), false ).toArray() ); } return categoryKeys.toArray(); } private TIntArrayList getSubCategoriesByParent( CategoryKey parentKey, boolean recursive ) { TIntArrayList categoryKeys = new TIntArrayList(); CategoryEntity parent = categoryDao.findByKey( parentKey ); if ( parent == null ) { return categoryKeys; } for ( CategoryKey categoryKey : parent.getChildrenKeys() ) { categoryKeys.add( categoryKey.toInt() ); if ( recursive ) { categoryKeys.add( getSubCategoriesByParent( categoryKey, true ).toArray() ); } } return categoryKeys; } public Document getCategory( User olduser, CategoryKey categoryKey ) { CategoryXmlCreator xmlCreator = new CategoryXmlCreator(); UserEntity user = securityService.getUser( olduser ); if ( user == null ) { return xmlCreator.createEmptyCategoriesDocument( "No user given" ).getAsDOMDocument(); } CategoryEntity category = categoryDao.findByKey( categoryKey ); xmlCreator.setCategoryAccessResolver( new CategoryAccessResolver( groupDao ) ); xmlCreator.setUser( user ); xmlCreator.setIncludeAccessRightsInfo( false ); xmlCreator.setIncludeDisabledInfo( false ); return xmlCreator.createCategory( category ).getAsDOMDocument(); } public Document getCategoryNameDoc( CategoryKey categoryKey ) { CategoryXmlCreator xmlCreator = new CategoryXmlCreator(); CategoryEntity category = categoryDao.findByKey( categoryKey ); return xmlCreator.createCategoryNames( category ).getAsDOMDocument(); } public String getCategoryName( CategoryKey categoryKey ) { String name = ""; if ( categoryKey != null ) { CategoryEntity category = categoryDao.findByKey( categoryKey ); if ( category != null ) { name = category.getName(); } } return name; } public int getContentCount( CategoryKey categoryKey, boolean recursive ) { if ( categoryKey == null ) { return 0; } return getContentCount( new int[]{categoryKey.toInt()}, recursive ); } private int getContentCount( int[] categoryKeys, boolean recursive ) { if ( categoryKeys == null || categoryKeys.length == 0 ) { return 0; } int contentCount = 0; for ( int i = 0; i < categoryKeys.length; i++ ) { CategoryKey categoryKey = new CategoryKey( categoryKeys[i] ); CategoryEntity category = categoryDao.findByKey( categoryKey ); List<ContentKey> contents = contentDao.findContentKeysByCategory( categoryKey ); contentCount += contents.size(); if ( recursive ) { List<CategoryKey> childrenKeys = category.getChildrenKeys(); int[] catKeys = new int[childrenKeys.size()]; for ( int j = 0; j < childrenKeys.size(); j++ ) { catKeys[j] = childrenKeys.get( j ).toInt(); } if ( childrenKeys.size() > 0 ) { contentCount += getContentCount( catKeys, recursive ); } } } return contentCount; } public int getContentTypeKey( CategoryKey categoryKey ) { int contentTypeKey = -1; CategoryEntity category = categoryDao.findByKey( categoryKey ); if ( category != null && category.getContentType() != null ) { contentTypeKey = category.getContentType().getKey(); } return contentTypeKey; } public XMLDocument getSuperCategoryNames( CategoryKey categoryKey, boolean withContentCount, boolean includeCategory ) { Map<CategoryEntity, Integer> contentCountMap = new HashMap<CategoryEntity, Integer>(); List<CategoryEntity> categories = new ArrayList<CategoryEntity>(); CategoryXmlCreator xmlCreator = new CategoryXmlCreator(); if ( categoryKey == null ) { return xmlCreator.createEmptyCategoryNamesDocument( "No categorykey given" ); } CategoryEntity category = categoryDao.findByKey( categoryKey ); if ( category == null ) { return xmlCreator.createEmptyCategoryNamesDocument( "No category found" ); } CategoryEntity currCategory; if ( includeCategory ) { currCategory = category; } else { currCategory = category.getParent(); } while ( currCategory != null ) { categories.add( currCategory ); if ( withContentCount ) { contentCountMap.put( category, getContentCount( category.getKey(), true ) ); } currCategory = currCategory.getParent(); } // Reverse list to get the root first in result Collections.reverse( categories ); XMLDocument newDoc = xmlCreator.createCategoryNames( categories, contentCountMap ); return newDoc; } public int getUnitKey( CategoryKey categoryKey ) { if ( categoryKey == null ) { return -1; } CategoryEntity category = categoryDao.findByKey( categoryKey ); if ( category == null || category.getUnitExcludeDeleted() == null ) { return -1; } return category.getUnitExcludeDeleted().getKey().toInt(); } public boolean hasSubCategories( CategoryKey categoryKey ) { return hasSubCategories( null, categoryKey, null, false ); } private boolean hasSubCategories( User olduser, CategoryKey categoryKey, int[] contentTypeKeys, boolean adminRead ) { Connection con; PreparedStatement preparedStmt = null; ResultSet resultSet = null; boolean subCategories; try { StringBuffer sql = new StringBuffer( CAT_SELECT_COUNT ); sql.append( " WHERE" ); sql.append( CAT_WHERE_CLAUSE_CAT_NOT_DELETED ); sql.append( " AND" ); sql.append( CAT_WHERE_CLAUSE_SCA_ONE ); if ( contentTypeKeys != null && contentTypeKeys.length > 0 ) { sql.append( " AND cat_cty_lKey IN (" ); for ( int i = 0; i < contentTypeKeys.length; i++ ) { if ( i > 0 ) { sql.append( ", " ); } sql.append( contentTypeKeys[i] ); } sql.append( ")" ); } if ( adminRead ) { getSecurityHandler().appendCategorySQL( olduser, sql, true ); } con = getConnection(); preparedStmt = con.prepareStatement( sql.toString() ); preparedStmt.setInt( 1, categoryKey.toInt() ); resultSet = preparedStmt.executeQuery(); if ( resultSet.next() ) { int count = resultSet.getInt( 1 ); subCategories = ( count > 0 ); } else { subCategories = false; String message = "Failed to count sub-categories. No result given"; VerticalEngineLogger.error( message ); } if ( !subCategories ) { int keys[] = getCategoryKeysBySuperCategory( categoryKey ); for ( int i = 0; !subCategories && i < keys.length; i++ ) { subCategories = hasSubCategories( olduser, new CategoryKey( keys[i] ), contentTypeKeys, adminRead ); } } } catch ( SQLException sqle ) { String message = "Failed to count sub-categories: %t"; VerticalEngineLogger.error( message, sqle ); subCategories = false; } finally { close( resultSet ); close( preparedStmt ); } return subCategories; } public CategoryKey getParentCategoryKey( CategoryKey categoryKey ) { if ( categoryKey == null ) { return null; } CategoryEntity category = categoryDao.findByKey( categoryKey ); if ( category != null && category.getParent() != null ) { return category.getParent().getKey(); } return null; } public boolean hasContent( CategoryKey categoryKey ) { return getContentCount( categoryKey, true ) > 0; } public boolean hasCategoriesWithRights( Connection _con, User olduser, int unitKey, int contentTypeKey ) { Connection con; PreparedStatement statement = null; ResultSet resultSet = null; int count = 0; List<Integer> paramValues = new ArrayList<Integer>( 2 ); StringBuilder sql = new StringBuilder(); sql.append( "SELECT COUNT(*) FROM " ); sql.append( CAT_TABLE ); sql.append( " WHERE" ); sql.append( CAT_WHERE_CLAUSE_CAT_NOT_DELETED ); if ( unitKey >= 0 ) { sql.append( " AND" ); sql.append( CAT_WHERE_CLAUSE_UNI ); paramValues.add( unitKey ); } if ( contentTypeKey >= 0 ) { sql.append( " AND" ); sql.append( CAT_WHERE_CLAUSE_CTY ); paramValues.add( contentTypeKey ); } String sqlString = sql.toString(); if ( olduser != null ) { sqlString = getSecurityHandler().appendCategorySQL( olduser, sqlString ); } try { if ( _con == null ) { con = getConnection(); } else { con = _con; } statement = con.prepareStatement( sqlString ); int i = 1; for ( Iterator<Integer> iter = paramValues.iterator(); iter.hasNext(); i++ ) { Object paramValue = iter.next(); statement.setObject( i, paramValue ); } resultSet = statement.executeQuery(); if ( resultSet.next() ) { count = resultSet.getInt( 1 ); } } catch ( SQLException sqle ) { String message = "Failed to count categories: %t"; VerticalEngineLogger.error( message, sqle ); } finally { close( resultSet ); close( statement ); } return ( count > 0 ); } public void getMenu( User olduser, Element root, CategoryCriteria categoryCriteria ) { UserHandler userHandler = getUserHandler(); List<Integer> paramValues = new ArrayList<Integer>(); StringBuilder sqlCategories = new StringBuilder( "SELECT cat_lKey, cat_uni_lKey, cat_cat_lSuper, cat_sName, cat_cty_lKey FROM " ); sqlCategories.append( CategoryView.getInstance().getReplacementSql() ); StringBuffer sqlCategoriesWHERE = new StringBuffer( " WHERE " ); // If a category key is specified, get only this (and parents) if ( categoryCriteria.getCategoryKey() != -1 ) { sqlCategoriesWHERE.append( " cat_lKey = ?" ); paramValues.add( categoryCriteria.getCategoryKey() ); sqlCategoriesWHERE.append( " AND " ); } else if ( categoryCriteria.getCategoryKeys() != null ) { sqlCategoriesWHERE.append( " cat_lKey IN (" ); List<Integer> categoryKeys = categoryCriteria.getCategoryKeys(); for ( int i = 0; i < categoryKeys.size(); i++ ) { sqlCategoriesWHERE.append( "?" ); paramValues.add( categoryKeys.get( i ) ); if ( i < categoryKeys.size() - 1 ) { sqlCategoriesWHERE.append( ", " ); } } sqlCategoriesWHERE.append( ") AND " ); } TIntArrayList contentTypes = new TIntArrayList(); if ( sqlCategoriesWHERE.length() == 7 ) { sqlCategoriesWHERE.append( " 1 = 1" ); } else { sqlCategoriesWHERE.setLength( sqlCategoriesWHERE.length() - 5 ); } if ( olduser != null ) { getSecurityHandler().appendCategorySQL( olduser, sqlCategoriesWHERE, true ); } Connection con; PreparedStatement preparedStmt = null; ResultSet resultSet = null; Document doc = root.getOwnerDocument(); root = XMLTool.createElement( doc, root, "categories" ); if ( categoryCriteria.useDisableAttribute() ) { root.setAttribute( "disable", "true" ); } try { con = getConnection(); String sql = sqlCategories.toString() + sqlCategoriesWHERE.toString(); preparedStmt = con.prepareStatement( sql ); int i = 1; for ( Iterator<Integer> iter = paramValues.iterator(); iter.hasNext(); i++ ) { Object paramValue = iter.next(); preparedStmt.setObject( i, paramValue ); } HashMap<Integer, Integer> processedKeys = new HashMap<Integer, Integer>(); HashMap<Integer, Integer> missingKeys = new HashMap<Integer, Integer>(); resultSet = preparedStmt.executeQuery(); CategoryAccessResolver categoryAccessResolver = new CategoryAccessResolver( groupDao ); while ( resultSet.next() ) { String categoryName = resultSet.getString( "cat_sName" ); Element catElem = XMLTool.createElement( doc, root, "category", null, "name", categoryName ); catElem.setAttribute( "name", categoryName ); // unit key int unitKey = resultSet.getInt( "cat_uni_lKey" ); if ( !resultSet.wasNull() ) { catElem.setAttribute( "unitkey", Integer.toString( unitKey ) ); } // category key CategoryKey categoryKey = new CategoryKey( resultSet.getInt( "cat_lKey" ) ); Integer catKey = categoryKey.toInt(); catElem.setAttribute( "key", catKey.toString() ); // supercategory key int superCategoryKey = resultSet.getInt( "cat_cat_lSuper" ); Integer superCatKey = null; if ( !resultSet.wasNull() ) { superCatKey = superCategoryKey; catElem.setAttribute( "superkey", superCatKey.toString() ); } int ctyKey = resultSet.getInt( "cat_cty_lKey" ); if ( !resultSet.wasNull() ) { catElem.setAttribute( "contenttypekey", Integer.toString( ctyKey ) ); // Set handler String handlerClass = getContentHandler().getContentHandlerClassForContentType( ctyKey ); catElem.setAttribute( "handler", handlerClass ); } if ( categoryCriteria.useDisableAttribute() && ( contentTypes.size() > 0 && !contentTypes.contains( ctyKey ) || resultSet.wasNull() ) ) { catElem.setAttribute( "disable", "true" ); } // Does anonymous have access? User anonUser = userHandler.getAnonymousUser(); final CategoryEntity category = categoryDao.findByKey( categoryKey ); CategoryAccessRightsAccumulated categoryAccessRightsAccumulated = categoryAccessResolver.getAccumulatedAccessRights( securityService.getUser( anonUser ), category ); final boolean anonReadAcccess = categoryAccessRightsAccumulated.isRead(); catElem.setAttribute( "anonaccess", Boolean.valueOf( anonReadAcccess ).toString() ); if ( superCatKey != null && !processedKeys.containsKey( superCatKey ) ) { missingKeys.put( superCatKey, superCatKey ); } if ( missingKeys.containsKey( catKey ) ) { missingKeys.remove( catKey ); } processedKeys.put( catKey, catKey ); } // Find all missing parent categories while ( missingKeys.size() > 0 ) { StringBuilder sqlCategoriesWHEREPK = new StringBuilder( " WHERE cat_lKey IN (" ); Iterator<Integer> iter = missingKeys.values().iterator(); while ( iter.hasNext() ) { Integer missingKey = iter.next(); sqlCategoriesWHEREPK.append( missingKey ); if ( iter.hasNext() ) { sqlCategoriesWHEREPK.append( ", " ); } else { sqlCategoriesWHEREPK.append( ")" ); } missingKeys.remove( missingKey ); iter = missingKeys.values().iterator(); } sql = sqlCategories.toString() + sqlCategoriesWHEREPK.toString(); preparedStmt = con.prepareStatement( sql ); resultSet = preparedStmt.executeQuery(); while ( resultSet.next() ) { String categoryName = resultSet.getString( "cat_sName" ); Element catElem = XMLTool.createElement( doc, root, "category", null, "name", categoryName ); // category key CategoryKey categoryKey = new CategoryKey( resultSet.getInt( "cat_lKey" ) ); Integer catKey = categoryKey.toInt(); catElem.setAttribute( "key", catKey.toString() ); // unit key int unitKey = resultSet.getInt( "cat_uni_lKey" ); if ( !resultSet.wasNull() ) { catElem.setAttribute( "unitkey", Integer.toString( unitKey ) ); } // supercategory key int superCategoryKey = resultSet.getInt( "cat_cat_lSuper" ); Integer superCatKey = null; new Integer( superCategoryKey ); if ( !resultSet.wasNull() ) { superCatKey = superCategoryKey; catElem.setAttribute( "superkey", superCatKey.toString() ); } // category name catElem.setAttribute( "name", categoryName ); int ctyKey = resultSet.getInt( "cat_cty_lKey" ); if ( !resultSet.wasNull() ) { catElem.setAttribute( "contenttypekey", Integer.toString( ctyKey ) ); // Set handler String handlerClass = getContentHandler().getContentHandlerClassForContentType( ctyKey ); catElem.setAttribute( "handler", handlerClass ); } // Does anonymous have access? User anonUser = userHandler.getAnonymousUser(); final CategoryEntity category = categoryDao.findByKey( categoryKey ); CategoryAccessRightsAccumulated categoryAccessRightsAccumulated = categoryAccessResolver.getAccumulatedAccessRights( securityService.getUser( anonUser ), category ); final boolean anonReadAcccess = categoryAccessRightsAccumulated.isRead(); catElem.setAttribute( "anonaccess", Boolean.valueOf( anonReadAcccess ).toString() ); // disable attribute int cty = resultSet.getInt( "cat_cty_lKey" ); // Set disabled if it does not have the correct content type if ( !resultSet.wasNull() ) { // Set handler String handlerClass = getContentHandler().getContentHandlerClassForContentType( ctyKey ); catElem.setAttribute( "handler", handlerClass ); } if ( categoryCriteria.useDisableAttribute() && ( contentTypes.size() > 0 && !contentTypes.contains( cty ) || resultSet.wasNull() ) ) { catElem.setAttribute( "disable", "true" ); } if ( superCatKey != null && !processedKeys.containsKey( superCatKey ) ) { missingKeys.put( superCatKey, superCatKey ); } if ( missingKeys.containsKey( catKey ) ) { missingKeys.remove( catKey ); } } } XMLTool.makeTree( XMLTool.getElements( root, "category" ) ); } catch ( SQLException sqle ) { String message = "Failed to get the categories: %t"; VerticalEngineLogger.error( message, sqle ); } finally { close( resultSet ); close( preparedStmt ); } } public void getPathXML( Document doc, Element child, CategoryKey categoryKey, int[] contentTypes ) { CategoryKey superCategoryKey = null; Element elem = null; if ( categoryKey != null ) { CategoryEntity entity = categoryDao.findByKey( categoryKey ); if ( entity != null ) { elem = XMLTool.createElement( doc, doc.getDocumentElement(), "category" ); elem.setAttribute( "key", String.valueOf( categoryKey ) ); elem.setAttribute( "name", entity.getName() ); if ( child != null ) { elem.appendChild( child ); } Integer contentTypeKey = null; if ( entity.getContentType() != null ) { contentTypeKey = entity.getContentType().getKey(); elem.setAttribute( "contenttypekey", String.valueOf( contentTypeKey ) ); } if ( contentTypeKey == null || ( contentTypes != null && !ArrayUtil.contains( contentTypes, contentTypeKey ) ) ) { elem.setAttribute( "disable", "true" ); } if ( entity.getParent() != null ) { superCategoryKey = entity.getParent().getKey(); } } } if ( superCategoryKey != null ) { getPathXML( doc, elem, superCategoryKey, contentTypes ); } else { Element topCat = XMLTool.createElement( doc, doc.getDocumentElement(), "categories" ); topCat.setAttribute( "disable", "true" ); if ( elem != null ) { topCat.appendChild( elem ); } } } public Document getCategories( User olduser, CategoryKey categoryKey, int levels, boolean topLevel, boolean details, boolean catCount, boolean contentCount ) { Document doc = XMLTool.createDocument(); try { RelationNode node = getCategoryTree( olduser, categoryKey, contentCount ); if ( node != null ) { fetchCategories( doc, node, levels, topLevel, details, catCount, contentCount ); } else { doc = XMLTool.createDocument( "categories" ); if ( contentCount ) { doc.getDocumentElement().setAttribute( "count", "0" ); } } } catch ( SQLException e ) { VerticalEngineLogger.error( "Failed to fetch relation keys: %t", e ); } return doc; } private void fetchCategories( Document doc, RelationNode node, int levels, boolean topLevel, boolean details, boolean catCount, boolean contentCount ) throws SQLException { node.selectLevels( levels == 0 ? Integer.MAX_VALUE : levels ); Map<Number, Element> entryMap = fetchCategoryElements( doc, node.findSelectedKeys(), details ); Element root = buildCategoriesElement( doc, entryMap, node, topLevel, catCount, contentCount ); doc.appendChild( root ); } private Element buildCategoriesElement( Document doc, Map<Number, Element> entryMap, RelationNode node, boolean topLevel, boolean catCount, boolean contentCount ) { Element elem = doc.createElement( "categories" ); if ( catCount ) { int count = node != null ? node.getChildCount() : 0; int totalCount = node != null ? node.getTotalChildCount() : 0; if ( topLevel ) { count = 1; totalCount += 1; } elem.setAttribute( "count", String.valueOf( count ) ); elem.setAttribute( "totalcount", String.valueOf( totalCount ) ); } if ( topLevel ) { Element tmp = buildCategoryElement( doc, entryMap, node, catCount, contentCount ); if ( tmp != null ) { elem.appendChild( tmp ); } } else { List entries = node.getChildren(); for ( Iterator i = entries.iterator(); i.hasNext(); ) { Element tmp = buildCategoryElement( doc, entryMap, (RelationNode) i.next(), catCount, contentCount ); if ( tmp != null ) { elem.appendChild( tmp ); } } } return elem; } private Element buildCategoryElement( Document doc, Map<Number, Element> entryMap, RelationNode node, boolean catCount, boolean contentCount ) { if ( node == null ) { return null; } if ( !node.isSelected() ) { return null; } Element elem = entryMap.get( node.getKey() ); if ( elem == null ) { return null; } if ( contentCount ) { int[] count = findContentCount( node ); elem.setAttribute( "contentcount", String.valueOf( count[0] ) ); elem.setAttribute( "totalcontentcount", String.valueOf( count[1] ) ); } Element tmp = buildCategoriesElement( doc, entryMap, node, false, catCount, contentCount ); if ( tmp != null ) { elem.appendChild( tmp ); } return elem; } private int[] findContentCount( RelationNode node ) { int count = 0; int totalCount = 0; Object data = node.getData(); if ( data instanceof Number ) { count = ( (Number) data ).intValue(); } data = node.accept( new RelationAggregator() ); if ( data instanceof Number ) { totalCount = ( (Number) data ).intValue(); } return new int[]{count, totalCount}; } private Map<Number, Element> fetchCategoryElements( Document doc, Set keys, boolean details ) throws SQLException { Connection conn; PreparedStatement stmt = null; ResultSet result = null; Map<Number, Element> map = new HashMap<Number, Element>(); if ( keys.isEmpty() ) { return map; } try { conn = getConnection(); String sql = getSelectCategoryByKeysSQL( keys ); stmt = conn.prepareStatement( sql ); result = stmt.executeQuery(); while ( result.next() ) { Number key = (Number) result.getObject( 1 ); Number ctyKey = (Number) result.getObject( 2 ); Number superKey = (Number) result.getObject( 3 ); String ownerKey = (String) result.getObject( 4 ); String ownerUID = result.getString( 5 ); String ownerName = result.getString( 6 ); String modifierKey = (String) result.getObject( 7 ); String modifierUID = result.getString( 8 ); String modifierName = result.getString( 9 ); Timestamp created = result.getTimestamp( 10 ); Timestamp timestamp = result.getTimestamp( 11 ); String name = result.getString( 12 ); String description = result.getString( 13 ); Element root = doc.createElement( "category" ); root.setAttribute( "key", key.toString() ); if ( superKey != null ) { root.setAttribute( "superkey", superKey.toString() ); } if ( details ) { if ( ctyKey != null ) { root.setAttribute( "contenttypekey", ctyKey.toString() ); } root.setAttribute( "created", CalendarUtil.formatTimestamp( created, false ) ); root.setAttribute( "timestamp", CalendarUtil.formatTimestamp( timestamp, false ) ); Element owner = XMLTool.createElement( doc, root, "owner", ownerName ); owner.setAttribute( "key", ownerKey ); owner.setAttribute( "uid", ownerUID ); Element modifier = XMLTool.createElement( doc, root, "modifier", modifierName ); modifier.setAttribute( "key", modifierKey ); modifier.setAttribute( "uid", modifierUID ); if ( description != null ) { Element descr = XMLTool.createElement( doc, root, "description" ); XMLTool.createCDATASection( doc, descr, description ); } } XMLTool.createElement( doc, root, "title", name ); map.put( key, root ); } } finally { close( result ); close( stmt ); } return map; } private RelationNode getCategoryTree( User olduser, CategoryKey categoryKey, boolean contentCount ) throws SQLException { GroupHandler handler = getGroupHandler(); SecurityHandler secHandler = getSecurityHandler(); String[] groups = null; if ( !secHandler.isEnterpriseAdmin( olduser ) ) { groups = handler.getAllGroupMembershipsForUser( olduser ); } return getCategoryTree( olduser, categoryKey, groups, contentCount ); } private RelationNode getCategoryTree( User olduser, CategoryKey categoryKey, String[] groups, boolean contentCount ) throws SQLException { Connection con; PreparedStatement stmt = null; ResultSet result = null; RelationTree tree = new RelationTree(); RelationNode node = null; int oldstyleCategoryKey = categoryKey != null ? categoryKey.toInt() : -1; try { con = getConnection(); int unitKey = getUnitKey( categoryKey ); String sql = getSelectCategoriesSQL( olduser ); stmt = con.prepareStatement( sql ); stmt.setInt( 1, unitKey ); result = stmt.executeQuery(); while ( result.next() ) { Number child = (Number) result.getObject( 1 ); Number parent = (Number) result.getObject( 2 ); if ( parent == null ) { tree.addChild( child ); } else { tree.addChild( parent, child ); } } tree.setRoot( oldstyleCategoryKey ); node = tree.getNode( oldstyleCategoryKey ); close( result ); result = null; close( stmt ); stmt = null; boolean anyCategoriesFound = node != null; if ( contentCount && anyCategoriesFound ) { sql = getSelectContentCountSQL( categoryKey, groups ); stmt = con.prepareStatement( sql ); result = stmt.executeQuery(); while ( result.next() ) { Integer entry = result.getInt( 1 ); Integer count = result.getInt( 2 ); RelationNode current = node.getNode( entry ); if ( current != null ) { current.setData( count ); } } } } finally { close( result ); close( stmt ); } return node; } private String getSelectCategoriesSQL( User olduser ) { SecurityHandler securityHandler = getSecurityHandler(); CategoryView view = CategoryView.getInstance(); Column[] selectColumns = {view.cat_lKey, view.cat_cat_lSuper}; Column[] whereColumns = {view.cat_uni_lKey}; StringBuffer sql = XDG.generateSelectSQL( view, selectColumns, false, whereColumns ); securityHandler.appendCategorySQL( olduser, sql, false ); return sql.toString(); } private String getKeySetSQL( String[] keys ) { if ( keys != null ) { StringBuilder sql = new StringBuilder(); if ( keys.length == 0 ) { sql.append( "IS NULL" ); } else if ( keys.length == 1 ) { sql.append( "= '" ).append( String.valueOf( keys[0] ) ).append( "'" ); } else { sql.append( "IN (" ); for ( int i = 0; i < keys.length; i++ ) { if ( i > 0 ) { sql.append( ", " ); } sql.append( "'" ); sql.append( keys[i] ); sql.append( "'" ); } sql.append( ")" ); } return sql.toString(); } else { return null; } } private String getSelectContentCountSQL( CategoryKey key, String[] groups ) { ContentPublishedView view = ContentPublishedView.getInstance(); ConAccessRight2Table accessTable = this.db.tConAccessRight2; StringBuilder sql = new StringBuilder(); sql.append( "SELECT " ).append( view.cat_lKey.getName() ); sql.append( ", COUNT(" ).append( view.con_lKey.getName() ).append( ")" ); sql.append( " FROM " ).append( view.getReplacementSql() ); String groupSql = getKeySetSQL( groups ); if ( groupSql != null ) { sql.append( " LEFT JOIN " ).append( accessTable.getName() ); sql.append( " ON " ).append( accessTable.coa_con_lKey.getName() ); sql.append( " = " ).append( view.con_lKey ); } sql.append( " WHERE " ).append( view.cat_uni_lKey.getName() ); sql.append( " IN (" ).append( getSelectUnitByCategorySQL( key ) ).append( ")" ); if ( groupSql != null ) { sql.append( " AND " ).append( accessTable.coa_grp_hKey.getName() ); sql.append( " " ).append( groupSql ); sql.append( " AND " ).append( accessTable.coa_bRead.getName() ).append( " = 1" ); } sql.append( " GROUP BY " ).append( view.cat_lKey.getName() ); return sql.toString(); } private String getSelectUnitByCategorySQL( CategoryKey key ) { CategoryTable table = this.db.tCategory; StringBuilder sql = new StringBuilder(); sql.append( "SELECT " ).append( table.cat_uni_lKey.getName() ); sql.append( " FROM " ).append( table.getName() ); sql.append( " WHERE " ).append( table.cat_lKey.getName() ); sql.append( " = " ).append( key.toInt() ); return sql.toString(); } private String getSelectCategoryByKeysSQL( Set keys ) { CategoryView table = CategoryView.getInstance(); StringBuilder sql = new StringBuilder(); sql.append( "SELECT " ).append( table.cat_lKey.getName() ); sql.append( ", " ).append( table.cat_cty_lKey.getName() ); sql.append( ", " ).append( table.cat_cat_lSuper.getName() ); sql.append( ", " ).append( table.usr_hOwner.getName() ); sql.append( ", " ).append( table.usr_sOwnerUID.getName() ); sql.append( ", " ).append( table.usr_sOwnerName.getName() ); sql.append( ", " ).append( table.usr_hModifier.getName() ); sql.append( ", " ).append( table.usr_sModifierUID.getName() ); sql.append( ", " ).append( table.usr_sModifierName.getName() ); sql.append( ", " ).append( table.cat_dteCreated.getName() ); sql.append( ", " ).append( table.cat_dteTimestamp.getName() ); sql.append( ", " ).append( table.cat_sName.getName() ); sql.append( ", " ).append( table.cat_sDescription.getName() ); sql.append( " FROM " ).append( table.getReplacementSql() ); sql.append( " WHERE " ); InClauseBuilder inClauseFilter = new InClauseBuilder<Object>( table.cat_lKey.getName(), keys ) { public void appendValue( StringBuffer sql, Object value ) { sql.append( value ); } }; sql.append( inClauseFilter ); return sql.toString(); } public Document getCategoryMenu( User olduser, CategoryKey categoryKey, int[] contentTypes, boolean includeRootCategories ) { final CategoryXmlCreator xmlCreator = new CategoryXmlCreator(); final UserEntity user = securityService.getUser( olduser ); if ( user == null ) { return xmlCreator.createEmptyCategoriesDocument( "No user given" ).getAsDOMDocument(); } xmlCreator.setCategoryAccessResolver( new CategoryAccessResolver( groupDao ) ); xmlCreator.setUser( user ); xmlCreator.setAnonymousUser( securityService.getUser( securityService.getAnonymousUserKey() ) ); xmlCreator.setAllowedContentTypes( ContentTypeKey.convertToSet( contentTypes ) ); xmlCreator.setIncludeOwnerAndModiferInfo( false ); xmlCreator.setIncludeCreatedAndTimestampInfo( false ); xmlCreator.setIncludeAutoApproveInfo( false ); xmlCreator.setIncludeDescriptionInfo( false ); xmlCreator.setIncludeSuperCategoryKeyInfo( false ); if ( includeRootCategories ) { final List<CategoryEntity> rootCategories = getRootCategories( user ); if ( rootCategories.isEmpty() ) { return xmlCreator.createEmptyCategoriesDocument( "No result" ).getAsDOMDocument(); } final CategoryKey topCategoryKey = getTopCategoryKey( categoryKey ); final XMLDocument newCategoryTree = xmlCreator.createCategoryBranch( rootCategories, topCategoryKey ); return newCategoryTree.getAsDOMDocument(); } else { final CategoryEntity category = categoryDao.findByKey( categoryKey ); final XMLDocument newCategoryTree = xmlCreator.createCategoryBranch( category ); return newCategoryTree.getAsDOMDocument(); } } private List<CategoryEntity> getRootCategories( UserEntity user ) { List<CategoryEntity> rootCategories; if ( user.isEnterpriseAdmin() ) { rootCategories = categoryDao.findRootCategories(); } else { rootCategories = categoryDao.findRootCategories( user.getAllMembershipsGroupKeys() ); } return rootCategories; } private CategoryKey getTopCategoryKey( CategoryKey categoryKey ) { if ( categoryKey == null ) { return null; } CategoryEntity category = categoryDao.findByKey( categoryKey ); if ( category == null ) { return null; } while ( category.getParent() != null ) { category = category.getParent(); } return category.getKey(); } public long getArchiveSizeByUnit( int unitKey ) { return categoryStatisticsHelper.getArchiveSizeByUnit( unitKey ); } public long getArchiveSizeByCategory( CategoryKey categoryKey ) { return categoryStatisticsHelper.getArchiveSizeByCategory( categoryKey ); } public Map<Integer, CategoryStatistics> getCategoryStatistics( int unitKey ) { StringBuilder sql = new StringBuilder(); sql.append( "select" ); sql.append( " cat_lkey," ); sql.append( " cat_cat_lsuper" ); sql.append( " from tcategory" ); sql.append( " where cat_uni_lkey = ?" ); sql.append( " order by cat_cat_lsuper asc, cat_lkey asc" ); Connection con; PreparedStatement preparedStmt = null; ResultSet resultSet = null; Map<Integer, CategoryStatistics> categoryStatistics = new HashMap<Integer, CategoryStatistics>(); try { con = getConnection(); preparedStmt = con.prepareStatement( sql.toString() ); preparedStmt.setInt( 1, unitKey ); resultSet = preparedStmt.executeQuery(); while ( resultSet.next() ) { CategoryStatistics cs = new CategoryStatistics( resultSet.getInt( 1 ) ); cs.setParentCategoryKey( resultSet.getInt( 2 ) ); categoryStatistics.put( cs.getCategoryKey(), cs ); } } catch ( SQLException sqle ) { throw new RuntimeException( "Failed to get category tree", sqle ); } finally { close( resultSet ); close( preparedStmt ); } return categoryStatistics; } public void collectStatisticsFromContent( int unitKey, Map<Integer, CategoryStatistics> catStats ) { StringBuilder sql = new StringBuilder(); sql.append( "select" ); sql.append( " cat_lkey," ); sql.append( " cat_cat_lsuper," ); sql.append( " sum(@length@(cov_stitle))," ); sql.append( " sum(@length@(cov_sdescription))," ); sql.append( " sum(@length@(cov_xmlcontentdata))" ); sql.append( " from tcontentversion" ); sql.append( " left join tcontent on cov_con_lkey = con_lkey" ); sql.append( " left join tcategory on con_cat_lkey = cat_lkey" ); sql.append( " where cat_uni_lkey = ?" ); sql.append( " group by cat_lkey, cat_cat_lsuper" ); sql.append( " order by cat_cat_lsuper asc, cat_lkey asc" ); Connection con; PreparedStatement preparedStmt = null; ResultSet resultSet = null; // 4 bytes times 6 for the number columns int constantSize = 4 * 6; // 20 bytes times 2 for the user columns constantSize += 20 * 2; try { con = getConnection(); preparedStmt = con.prepareStatement( sql.toString() ); preparedStmt.setInt( 1, unitKey ); resultSet = preparedStmt.executeQuery(); while ( resultSet.next() ) { Integer categoryKey = resultSet.getInt( 1 ); CategoryStatistics cs = catStats.get( categoryKey ); if ( cs != null ) { long amount = constantSize + resultSet.getLong( 3 ) + resultSet.getLong( 4 ) + resultSet.getLong( 5 ); cs.addAmount( amount ); } } } catch ( SQLException sqle ) { throw new RuntimeException( "Failed to get category statistics", sqle ); } finally { close( resultSet ); close( preparedStmt ); } } public void collectStatisticsFromBinaryData( int unitKey, Map<Integer, CategoryStatistics> catStats ) { StringBuilder sql = new StringBuilder(); sql.append( "select" ); sql.append( " cat_lkey," ); sql.append( " cat_cat_lsuper," ); sql.append( " sum(@length@(bda_sfilename))," ); sql.append( " sum(bda_lfilesize * 1.0)" ); sql.append( " from tbinarydata" ); sql.append( " left join tcontentbinarydata on bda_lkey = cbd_bda_lkey" ); sql.append( " left join tcontentversion on cbd_cov_lkey = cov_lkey" ); sql.append( " left join tcontent on cov_con_lkey = con_lkey" ); sql.append( " left join tcategory on con_cat_lkey = cat_lkey" ); sql.append( " where cat_uni_lkey = ?" ); sql.append( " group by cat_lkey, cat_cat_lsuper" ); sql.append( " order by cat_cat_lsuper asc, cat_lkey asc" ); Connection con; PreparedStatement preparedStmt = null; ResultSet resultSet = null; // 4 bytes times 6 for the number columns int constantSize = 4 * 8; // 20 bytes times 2 for the user columns constantSize += 20 * 2; try { con = getConnection(); preparedStmt = con.prepareStatement( sql.toString() ); preparedStmt.setInt( 1, unitKey ); resultSet = preparedStmt.executeQuery(); while ( resultSet.next() ) { Integer categoryKey = resultSet.getInt( 1 ); CategoryStatistics cs = catStats.get( categoryKey ); if ( cs != null ) { long filenameSize = resultSet.getLong( 3 ) * 2; // two times because it is in content version too long amount = constantSize + filenameSize + new Double( resultSet.getDouble( 4 ) ).longValue(); cs.addAmount( amount ); } } } catch ( SQLException sqle ) { throw new RuntimeException( "Failed to get category statistics", sqle ); } finally { close( resultSet ); close( preparedStmt ); } } }