dbforumcategory.java
来自「Jive是基于JSP/JAVA技术构架的一个大型BBS论坛系统,这是Jive论坛」· Java 代码 · 共 1,544 行 · 第 1/4 页
JAVA
1,544 行
// Delete category and all sub-categories. category.deleteFromDb(con); // Fix tree. pstmt = con.prepareStatement(CHANGE_LFT); pstmt.setInt(1, delta); pstmt.setInt(2, lft); pstmt.setInt(3, rgt); pstmt.execute(); pstmt.close(); pstmt = con.prepareStatement(CHANGE_RGT); pstmt.setInt(1, delta); pstmt.setInt(2, rgt); pstmt.execute(); pstmt.close(); } catch (Exception e) { e.printStackTrace(); abortTransaction = true; } finally { try { pstmt.close(); } catch (Exception e) { e.printStackTrace(); } ConnectionManager.closeTransactionConnection(con, abortTransaction); } refreshCategoryTree(); } } public PermissionsManager getPermissionsManager() { return new DbPermissionsManager(JiveGlobals.FORUM_CATEGORY, id); } public ForumPermissions getPermissions(Authorization authorization) { ForumPermissions catPerms = factory.permissionsManager.getFinalUserPerms( JiveGlobals.FORUM_CATEGORY, this.id, authorization.getUserID()); ForumCategory parentCat = getParentCategory(); if (parentCat != null) { int parentPerms = parentCat.getPermissions(authorization).toInt(); // Never inherit the show category permission. ForumPermissions newPerms = new ForumPermissions( ForumPermissions.setBit(parentPerms, ForumPermissions.SHOW_CATEGORY, false)); catPerms = new ForumPermissions(catPerms, newPerms); } return catPerms; } public boolean hasPermission(int type) { return true; } // OTHER METHODS // /** * Clears caches related to the object. */ protected void clearCache() { synchronized (queryKeys) { // Clear out query cache of lists and counts. Object [] listElements = queryKeys.toArray(); queryKeys.clear(); for (int i=0; i<listElements.length; i++) { Object key = listElements[i]; // If the short-term query cache is enabled, move the object // there. if (factory.cacheManager.isShortTermQueryCacheEnabled()) { Object value = factory.cacheManager.queryCache.get(key); // Add the object to the short-term cache and then remove it // from the normal cache. if (value != null) { factory.cacheManager.shortTermQueryCache.put(key, value); } } factory.cacheManager.queryCache.remove(key); } } // Re-add category to cache. factory.cacheManager.categoryCache.put(new Long(this.id), this); } /** * Loads the entire category tree into memory. */ private void refreshCategoryTree() { synchronized (lock) { // First, wipe out the entire category cache. If the tree has // been changed, then cached lft and rgt values stored with each // category will no longer be correct. factory.cacheManager.categoryCache.clear(); factory.cacheManager.queryCache.clear(); Connection con = null; PreparedStatement pstmt = null; try { con = ConnectionManager.getConnection(); pstmt = con.prepareStatement(CATEGORY_COUNT); ResultSet rs = pstmt.executeQuery(); rs.next(); int categoryCount = rs.getInt(1); pstmt.close(); categoryTree = new LongTree(1, categoryCount); // Load the category tree. pstmt = con.prepareStatement(LOAD_CATEGORY_TREE); rs = pstmt.executeQuery(); // Skip over root rs.next(); // Because of the way the SQL structure works the elements will be // in depth-first when we get them in order of their lft value. By // using stacks, we can determine parentage without resorting // to recursion. LinkedList categoryStack = new LinkedList(); categoryStack.addFirst(new Long(1)); LinkedList lftStack = new LinkedList(); lftStack.addFirst(new Integer(rs.getInt(2))); LinkedList rgtStack = new LinkedList(); rgtStack.addFirst(new Integer(rs.getInt(3))); // Load in all other values. while (rs.next()) { long categoryID = rs.getLong(1); int lft = rs.getInt(2); int rgt = rs.getInt(3); int stackLft = ((Integer)lftStack.getFirst()).intValue(); int stackRgt = ((Integer)rgtStack.getFirst()).intValue(); // If the category we're examining is the caller of this method, save the // lft and rgt values. This ensures that this instance of the object remains // consistent for further category operations. if (categoryID == this.id) { this.lft = lft; this.rgt = rgt; } // The basic test of whether the next element is a sibling // or child of the previous element is if the lft and rgt // values are between the previous element's values. If lft and // rgt are *not* between the previous elements values, we've // found a sibling. Keep popping values off the stack until we // find the level that the sibling is at. while (!(lft > stackLft && rgt < stackRgt)) { // Pop values off the stacks since this is a sibling. categoryStack.removeFirst(); lftStack.removeFirst(); rgtStack.removeFirst(); stackLft = ((Integer)lftStack.getFirst()).intValue(); stackRgt = ((Integer)rgtStack.getFirst()).intValue(); } // Add the element to the tree. long parent = ((Long)categoryStack.getFirst()).longValue(); categoryTree.addChild(parent, categoryID); // Push values onto the stacks. categoryStack.addFirst(new Long(categoryID)); lftStack.addFirst(new Integer(lft)); rgtStack.addFirst(new Integer(rgt)); } } catch (SQLException sqle) { sqle.printStackTrace(); } finally { try { pstmt.close(); } catch (Exception e) { e.printStackTrace(); } try { con.close(); } catch (Exception e) { e.printStackTrace(); } } } } /** * Updates the modified date of this category and all parent categories. It accepts a * Connection so that it can participate in trasactions. */ protected void updateModifiedDate(long date, Connection con) throws SQLException { // Only update the modified date if it is newer than the current one. if (date > this.modifiedDate.getTime()) { this.modifiedDate.setTime(date); PreparedStatement pstmt = null; try { pstmt = con.prepareStatement(UPDATE_CATEGORY_MODIFIED_DATE); pstmt.setString(1, StringUtils.dateToMillis(modifiedDate)); pstmt.setInt(2, lft); pstmt.setInt(3, rgt); pstmt.executeUpdate(); } finally { try { pstmt.close(); } catch (Exception e) { e.printStackTrace(); } } } } public int getCachedSize() { int size = 0; size += CacheSizes.sizeOfObject(); // overhead of object size += CacheSizes.sizeOfLong(); // id size += CacheSizes.sizeOfString(name); // name size += CacheSizes.sizeOfString(description); // description size += CacheSizes.sizeOfMap(properties); // properties // Make rough estimation of size of queryKeys size += queryKeys.size() * 212; return size; } /** * Returns the SQL statement corresponding to a ResultFilter for threads. * * @param resultFilter the result filter to build the SQL from. * @param countQuery true if this should be a count query. * @param recursiveQuery if forums from all sub-categories should be in * the results. */ protected String getForumListSQL(ResultFilter resultFilter, boolean countQuery, boolean recursiveQuery) { int sortField = resultFilter.getSortField(); // Make sure the sort field is valid. if (!countQuery && ! ( sortField == JiveGlobals.MODIFIED_DATE || sortField == JiveGlobals.CREATION_DATE || sortField == JiveGlobals.FORUM_CATEGORY_INDEX || sortField == JiveGlobals.FORUM_NAME || ( sortField == JiveGlobals.EXTENDED_PROPERTY && resultFilter.getSortPropertyName() != null ) ) ) { throw new IllegalArgumentException("The specified sort field is not valid."); } StringBuffer query = new StringBuffer(80); if (!countQuery) { query.append("SELECT jiveForum.forumID"); } else { query.append("SELECT count(1)"); } boolean filterCreationDate = resultFilter.getCreationDateRangeMin() != null || resultFilter.getCreationDateRangeMax() != null; boolean filterModifiedDate = resultFilter.getModifiedDateRangeMin() != null || resultFilter.getModifiedDateRangeMax() != null; int propertyCount = resultFilter.getPropertyCount(); // SELECT -- need to add value that we sort on if (!countQuery) { switch(sortField) { case JiveGlobals.FORUM_NAME: query.append(", jiveForum.name"); break; case JiveGlobals.FORUM_CATEGORY_INDEX: query.append(", jiveForum.categoryIndex"); break; case JiveGlobals.MODIFIED_DATE: query.append(", jiveForum.modifiedDate"); break; case JiveGlobals.CREATION_DATE: query.append(", jiveForum.creationDate"); break; case JiveGlobals.EXTENDED_PROPERTY: query.append(", propTable.propValue"); break; } } // FROM -- values (in addition to jiveForum) query.append(" FROM jiveForum"); for (int i=0; i<propertyCount; i++) { query.append(", jiveForumProp p").append(i); } if (resultFilter.getSortField() == JiveGlobals.EXTENDED_PROPERTY) { query.append(", jiveForumProp propTable"); } if (recursiveQuery) { query.append(", jiveCategory"); } // WHERE BLOCK if (!recursiveQuery) { query.append(" WHERE jiveForum.categoryID=").append(this.id); } else { query.append(" WHERE jiveForum.categoryID=jiveCategory.categoryID"); query.append(" AND lft >= ").append(this.lft); query.append(" AND rgt <= ").append(this.rgt); } // Properties for (int i=0; i<propertyCount; i++) { query.append(" AND jiveForum.forumID=p").append(i).append(".forumID"); query.append(" AND p").append(i).append(".name='"); query.append(resultFilter.getPropertyName(i)); query.append("' AND p").append(i).append(".propValue='"); query.append(resultFilter.getPropertyValue(i)).append("'"); } // Sort on properties if (sortField == JiveGlobals.EXTENDED_PROPERTY) { query.append(" AND jiveForum.forumID=propTable.forumID"); query.append(" AND propTable.name='"); query.append(resultFilter.getSortPropertyName()).append("'"); } // Creation date range if (filterCreationDate) { if (resultFilter.getCreationDateRangeMin() != null) { query.append(" AND jiveForum.creationDate >= '"); query.append(StringUtils.dateToMillis( resultFilter.getCreationDateRangeMin())); query.append("'"); } if (resultFilter.getCreationDateRangeMax() != null) { query.append(" AND jiveForum.creationDate <= '"); query.append(StringUtils.dateToMillis( resultFilter.getCreationDateRangeMax())); query.append("'"); } } // Modified date range if (filterModifiedDate) { if (resultFilter.getModifiedDateRangeMin() != null) { query.append(" AND jiveForum.modifiedDate >= '"); query.append(StringUtils.dateToMillis( resultFilter.getModifiedDateRangeMin())); query.append("'"); } if (resultFilter.getModifiedDateRangeMax() != null) { query.append(" AND jiveForum.modifiedDate <= '"); query.append(StringUtils.dateToMillis( resultFilter.getModifiedDateRangeMax())); query.append("'"); } } // ORDER BY if (!countQuery) { switch(sortField) { case JiveGlobals.FORUM_CATEGORY_INDEX: query.append(" ORDER BY jiveForum.categoryIndex"); break; case JiveGlobals.FORUM_NAME: query.append(" ORDER BY jiveForum.name"); break; case JiveGlobals.MODIFIED_DATE: query.append(" ORDER BY jiveForum.modifiedDate"); break; case JiveGlobals.CREATION_DATE: query.append(" ORDER BY jiveForum.creationDate"); break; case JiveGlobals.EXTENDED_PROPERTY: query.append(" ORDER BY propTable.propValue"); break; } if (resultFilter.getSortOrder() == ResultFilter.DESCENDING) { query.append(" DESC"); } else { query.append(" ASC"); } } return query.toString(); } /** * Returns a block of objectID's (threads or messages) from a query and * performs transparent caching of those blocks. The two parameters specify * a database query and a startIndex for the results in that query. * * @param query the SQL message list query to cache blocks from. * @param startIndex the startIndex in the list to get a block for. */ protected long [] getBlock(String query, int startIndex) { // First, find what block number the results will be in. int blockID = startIndex / BLOCK_SIZE; int blockStart = blockID * BLOCK_SIZE; // Now, check cache to see if the block is already cached. QueryCacheKey key = new QueryCacheKey(JiveGlobals.FORUM_CATEGORY, id, query, blockID); // Synchronize on the sql query so that only one thread can try to load a // block at once. This should help to prevent the database from // becoming overloaded on busy sites. StringBuffer internKey = new StringBuffer(query.length()+4).append(query).append(blockID); synchronized (internKey.toString().intern()) { // First, look in long-term cache. long [] objectIDs = (long [])factory.cacheManager.queryCache.get(key); // If lookup in long-term cache failed, look in short-term cache.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?