001/* 002 Licensed to the Apache Software Foundation (ASF) under one 003 or more contributor license agreements. See the NOTICE file 004 distributed with this work for additional information 005 regarding copyright ownership. The ASF licenses this file 006 to you under the Apache License, Version 2.0 (the 007 "License"); you may not use this file except in compliance 008 with the License. You may obtain a copy of the License at 009 010 http://www.apache.org/licenses/LICENSE-2.0 011 012 Unless required by applicable law or agreed to in writing, 013 software distributed under the License is distributed on an 014 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 KIND, either express or implied. See the License for the 016 specific language governing permissions and limitations 017 under the License. 018 */ 019package org.apache.wiki.auth.permissions; 020 021import org.apache.wiki.api.core.Page; 022 023import java.util.WeakHashMap; 024 025 026/** 027 * Provides a factory for Permission objects. Since the Permissions are immutable, 028 * and creating them takes a bit of time, caching them makes sense. 029 * <p> 030 * This class stores the permissions in a static HashMap. 031 * @since 2.5.54 032 */ 033public final class PermissionFactory 034{ 035 /** 036 * Prevent instantiation. 037 */ 038 private PermissionFactory() {} 039 040 /** 041 * This is a WeakHashMap<Integer,PagePermission>, which stores the 042 * cached page permissions. 043 */ 044 private static final WeakHashMap<Integer, PagePermission> c_cache = new WeakHashMap<>(); 045 046 /** 047 * Get a permission object for a WikiPage and a set of actions. 048 * 049 * @param page The page object. 050 * @param actions A list of actions. 051 * @return A PagePermission object, presenting this page+actions combination. 052 */ 053 public static PagePermission getPagePermission( final Page page, final String actions ) 054 { 055 return getPagePermission( page.getWiki(), page.getName(), actions ); 056 } 057 058 /** 059 * Get a permission object for a WikiPage and a set of actions. 060 * 061 * @param page The name of the page. 062 * @param actions A list of actions. 063 * @return A PagePermission object, presenting this page+actions combination. 064 */ 065 public static PagePermission getPagePermission( final String page, final String actions ) 066 { 067 return getPagePermission( "", page, actions ); 068 } 069 070 /** 071 * Get a page permission based on a wiki, page, and actions. 072 * 073 * @param wiki The name of the wiki. Can be an empty string, but must not be null. 074 * @param page The page name 075 * @param actions A list of actions. 076 * @return A PagePermission object. 077 */ 078 private static PagePermission getPagePermission( final String wiki, String page, final String actions ) 079 { 080 PagePermission perm; 081 // 082 // Since this is pretty speed-critical, we try to avoid the StringBuffer creation 083 // overhead by XORring the hashcodes. However, if page name length > 32 characters, 084 // this might result in two same hashCodes. 085 // FIXME: Make this work for page-name lengths > 32 characters (use the alt implementation 086 // if page.length() > 32?) 087 // Alternative implementation below, but it does create an extra StringBuffer. 088 //String key = wiki+":"+page+":"+actions; 089 090 final Integer key = wiki.hashCode() ^ page.hashCode() ^ actions.hashCode(); 091 092 // 093 // It's fine if two threads update the cache, since the objects mean the same 094 // thing anyway. And this avoids nasty blocking effects. 095 // 096 synchronized( c_cache ) 097 { 098 perm = c_cache.get( key ); 099 } 100 101 if( perm == null ) 102 { 103 if( !wiki.isEmpty() ) page = wiki+":"+page; 104 perm = new PagePermission( page, actions ); 105 106 synchronized( c_cache ) 107 { 108 c_cache.put( key, perm ); 109 } 110 } 111 112 return perm; 113 } 114 115}