This is an automated email from the ASF dual-hosted git repository. juanpablo pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/jspwiki.git
commit e1f7f93b3518397e2f1b050f4cb71a249e52756a Author: Juan Pablo Santos RodrÃguez <[email protected]> AuthorDate: Thu Dec 2 16:54:01 2021 +0100 New jspwiki-cache module * Cache backend can now be overriden by providing a custom CachingManager via [classmappings-extra.xml](https://jspwiki-wiki.apache.org/Wiki.jsp?page=JSPWikiPublicAPI#section-JSPWikiPublicAPI-RegisteringCustomManagersInTheWikiEngine) * Default cache manager remains ehcache-based, with default configuration file located at ehcache-jspwiki.xml * Tests wanting to invalidate cache(s) should call either `Engine#shutdown()` or `Engine#getManager( CachingManager.class ).shutdown()` * The `jspwiki.cache.config-file` setting on the `jspwiki[-custom].properties` file allows to use a custom ehcache configuration file, located elsewhere on classpath Also, Introduced `TextUtil#getStringProperty( Properties, String key, String deprecatedKey, String defval )` to allow deprecation of properties, so they can be removed later on Also, deprecated property jspwiki.usePageCache in favour of jspwiki.cache.enable --- jspwiki-cache/pom.xml | 95 ++++++++++++ .../main/java/org/apache/wiki/cache/CacheInfo.java | 62 ++++++++ .../java/org/apache/wiki/cache/CachingManager.java | 124 +++++++++++++++ .../apache/wiki/cache/EhcacheCachingManager.java | 166 +++++++++++++++++++++ .../main/java/org/apache/wiki/cache/package.html | 29 ++++ .../src/main/resources/ehcache-jspwiki.xml | 22 +-- .../wiki/cache/EhcacheCachingManagerTest.java | 85 +++++++++++ .../src/test/resources/ehcache-jspwiki-test.xml | 18 +-- .../src/main/resources/ini/classmappings.xml | 4 + .../src/main/resources/ini/jspwiki.properties | 4 +- .../src/test/resources/ini/jspwiki.properties | 2 +- .../WEB-INF/classes/ehcache-woas-department.xml} | 0 .../WEB-INF/classes/jspwiki-custom.properties | 3 +- .../WEB-INF/classes/ehcache-woas-personal.xml} | 0 .../WEB-INF/classes/jspwiki-custom.properties | 3 +- .../java/org/apache/wiki/util/CheckedSupplier.java | 39 +++++ .../main/java/org/apache/wiki/util/TextUtil.java | 60 +++++--- .../java/org/apache/wiki/util/TextUtilTest.java | 9 ++ .../src/test/resources/ini/jspwiki.properties | 2 +- 19 files changed, 676 insertions(+), 51 deletions(-) diff --git a/jspwiki-cache/pom.xml b/jspwiki-cache/pom.xml new file mode 100644 index 0000000..f6a1d01 --- /dev/null +++ b/jspwiki-cache/pom.xml @@ -0,0 +1,95 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + <parent> + <groupId>org.apache.jspwiki</groupId> + <artifactId>jspwiki-builder</artifactId> + <version>2.11.1-SNAPSHOT</version> + </parent> + + <modelVersion>4.0.0</modelVersion> + <artifactId>jspwiki-cache</artifactId> + <name>Apache JSPWiki cache abstraction</name> + + <dependencies> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>jspwiki-api</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>jspwiki-util</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-api</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-1.2-api</artifactId> + </dependency> + + <dependency> <!-- ehcache brings slf4j, so we route it to log4j2 --> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-slf4j-impl</artifactId> + </dependency> + + <dependency> + <groupId>net.sf.ehcache</groupId> + <artifactId>ehcache</artifactId> + </dependency> + + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-api</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-params</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-engine</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-junit-jupiter</artifactId> + <scope>test</scope> + </dependency> + </dependencies> +</project> diff --git a/jspwiki-cache/src/main/java/org/apache/wiki/cache/CacheInfo.java b/jspwiki-cache/src/main/java/org/apache/wiki/cache/CacheInfo.java new file mode 100644 index 0000000..32ada21 --- /dev/null +++ b/jspwiki-cache/src/main/java/org/apache/wiki/cache/CacheInfo.java @@ -0,0 +1,62 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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.apache.wiki.cache; + +/** + * Simple pojo that holds cache information. + */ +public class CacheInfo { + + private final String name; + private final long maxElementsAllowed; + private long misses; + private long hits; + + public CacheInfo( final String name, final long maxElementsAllowed ) { + this.name = name; + this.maxElementsAllowed = maxElementsAllowed; + this.hits = 0L; + this.misses = 0L; + } + + public void hit() { + hits++; + } + + public void miss() { + misses++; + } + + public String getName() { + return name; + } + + public long getMisses() { + return misses; + } + + public long getHits() { + return hits; + } + + public long getMaxElementsAllowed() { + return maxElementsAllowed; + } +} diff --git a/jspwiki-cache/src/main/java/org/apache/wiki/cache/CachingManager.java b/jspwiki-cache/src/main/java/org/apache/wiki/cache/CachingManager.java new file mode 100644 index 0000000..245e1ef --- /dev/null +++ b/jspwiki-cache/src/main/java/org/apache/wiki/cache/CachingManager.java @@ -0,0 +1,124 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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.apache.wiki.cache; + + +import org.apache.wiki.util.CheckedSupplier; + +import java.io.Serializable; +import java.util.List; + +/** + * Cache manager abstraction. + */ +public interface CachingManager { + + /** + * The property value for setting the cache on/off. Value is {@value}. + * This key is deprecated, use instead {@link #PROP_CACHE_ENABLE}. + */ + @Deprecated + String PROP_USECACHE_DEPRECATED = "jspwiki.usePageCache"; + + /** The property value for setting the cache on/off. Value is {@value}. */ + String PROP_CACHE_ENABLE = "jspwiki.cache.enable"; + + /** The property value with the location of the cache configuration file. Value is {@value}. */ + String PROP_CACHE_CONF_FILE = "jspwiki.cache.config-file"; + + /** Name of the attachment cache. */ + String CACHE_ATTACHMENTS = "jspwiki.attachmentsCache"; + + /** Name of the collection attachment cache. */ + String CACHE_ATTACHMENTS_COLLECTION = "jspwiki.attachmentCollectionsCache"; + + /** Name of the dynamic attachment cache. */ + String CACHE_ATTACHMENTS_DYNAMIC = "jspwiki.dynamicAttachmentCache"; + + /** Name of the page cache. */ + String CACHE_PAGES = "jspwiki.pageCache"; + + /** Name of the page text cache. */ + String CACHE_PAGES_TEXT = "jspwiki.pageTextCache"; + + /** Name of the page history cache. */ + String CACHE_PAGES_HISTORY = "jspwiki.pageHistoryCache"; + + /** Name of the rendering cache. */ + String CACHE_DOCUMENTS = "jspwiki.renderingCache"; + + /** + * Shuts down the underlying cache manager + */ + void shutdown(); + + /** + * Checks if the requested cache is enabled or not. + * + * @param cacheName The cache to be queried. + * @return {@code true} if the cache is enabled, {@code false} otherwise. + */ + boolean enabled( String cacheName ); + + /** + * Retrieves cache usage information. + * + * @param cacheName The cache to be queried. + * @return cache usage information, or {@code null} if the requested cache is not enabled. + */ + CacheInfo info( String cacheName ); + + /** + * Returns the list of keys from elements present in a cache. + * + * @param cacheName The cache to be queried. + * @return list of keys from elements present in a cache. + */ + < T extends Serializable > List< T > keys( String cacheName ); + + /** + * Returns an item from a cache. If it is not found on the cache, try to retrieve from the provided supplier. If + * found there, put the value in the cache, and return it. Otherwise, return {@code null}. + * + * @param cacheName The cache in which the item lives. + * @param key item's identifier. + * @param supplier if the element is not cached, try to retrieve from the cached system. + * @throws E the supplier may throw a checked exception, which is propagated upwards. + * @return The requested item or {@code null} if either the cache is not enabled or the item is not present on the cache / cached service. + */ + < T, E extends Exception > T get( String cacheName, Serializable key, CheckedSupplier< T, E > supplier ) throws E; + + /** + * Puts an item on a cache. + * + * @param cacheName The cache in which the item will live. + * @param key item's identifier. + * @param val item to insert in the cache. + */ + void put( String cacheName, Serializable key, Object val ); + + /** + * Removes an item from a cache. + * + * @param cacheName The cache in which the item to be removed lives. + * @param key item's identifier. + */ + void remove( String cacheName, Serializable key ); + +} diff --git a/jspwiki-cache/src/main/java/org/apache/wiki/cache/EhcacheCachingManager.java b/jspwiki-cache/src/main/java/org/apache/wiki/cache/EhcacheCachingManager.java new file mode 100644 index 0000000..6e6942d --- /dev/null +++ b/jspwiki-cache/src/main/java/org/apache/wiki/cache/EhcacheCachingManager.java @@ -0,0 +1,166 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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.apache.wiki.cache; + +import net.sf.ehcache.Cache; +import net.sf.ehcache.CacheManager; +import net.sf.ehcache.Element; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.wiki.api.core.Engine; +import org.apache.wiki.api.engine.Initializable; +import org.apache.wiki.api.exceptions.WikiException; +import org.apache.wiki.util.CheckedSupplier; +import org.apache.wiki.util.TextUtil; + +import java.io.Serializable; +import java.net.URL; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; + + +/** + * Ehcache-based {@link CachingManager}. + */ +public class EhcacheCachingManager implements CachingManager, Initializable { + + private static final Logger LOG = LogManager.getLogger( EhcacheCachingManager.class ); + private static final int DEFAULT_CACHE_SIZE = 1_000; + private static final int DEFAULT_CACHE_EXPIRY_PERIOD = 24*60*60; + + final Map< String, Cache > cacheMap = new ConcurrentHashMap<>(); + final Map< String, CacheInfo > cacheStats = new ConcurrentHashMap<>(); + CacheManager cacheManager; + + /** {@inheritDoc} */ + @Override + public void shutdown() { + if( cacheMap.size() > 0 ) { + CacheManager.getInstance().shutdown(); + cacheMap.clear(); + cacheStats.clear(); + } + } + + /** {@inheritDoc} */ + @Override + public void initialize( final Engine engine, final Properties props ) throws WikiException { + final String cacheEnabled = TextUtil.getStringProperty( props, PROP_CACHE_ENABLE, PROP_USECACHE_DEPRECATED, "true" ); + final boolean useCache = "true".equalsIgnoreCase( cacheEnabled ); + final String confLocation = "/" + TextUtil.getStringProperty( props, PROP_CACHE_CONF_FILE, "ehcache-jspwiki.xml" ); + if( useCache ) { + final URL location = this.getClass().getResource( confLocation ); + LOG.info( "Reading ehcache configuration file from classpath on /{}", location ); + cacheManager = CacheManager.create( location ); + registerCache( CACHE_ATTACHMENTS ); + registerCache( CACHE_ATTACHMENTS_COLLECTION ); + registerCache( CACHE_ATTACHMENTS_DYNAMIC ); + registerCache( CACHE_DOCUMENTS ); + registerCache( CACHE_PAGES ); + registerCache( CACHE_PAGES_HISTORY ); + registerCache( CACHE_PAGES_TEXT ); + } + } + + void registerCache( final String cacheName ) { + final Cache cache; + if( cacheManager.cacheExists( cacheName ) ) { + cache = cacheManager.getCache( cacheName ); + } else { + LOG.info( "cache with name {} not found in ehcache configuration file, creating it with defaults.", cacheName ); + cache = new Cache( cacheName, DEFAULT_CACHE_SIZE, false, false, DEFAULT_CACHE_EXPIRY_PERIOD, DEFAULT_CACHE_EXPIRY_PERIOD ); + cacheManager.addCache( cache ); + } + cacheMap.put( cacheName, cache ); + cacheStats.put( cacheName, new CacheInfo( cacheName, cache.getCacheConfiguration().getMaxEntriesLocalHeap() ) ); + } + + /** {@inheritDoc} */ + @Override + public boolean enabled( final String cacheName ) { + return cacheMap.get( cacheName ) != null; + } + + /** {@inheritDoc} */ + @Override + public CacheInfo info( final String cacheName ) { + if( enabled( cacheName ) ) { + return cacheStats.get( cacheName ); + } + return null; + } + + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings( "unchecked" ) + public List< String > keys( final String cacheName ) { + if( enabled( cacheName ) ) { + return cacheMap.get( cacheName ).getKeysWithExpiryCheck(); + } + return Collections.emptyList(); + } + + /** {@inheritDoc} */ + @Override + @SuppressWarnings( "unchecked" ) + public < T, E extends Exception > T get( final String cacheName, final Serializable key, final CheckedSupplier< T, E > supplier ) throws E { + if( keyAndCacheAreNotNull( cacheName, key ) ) { + final Element element = cacheMap.get( cacheName ).get( key ); + if( element != null ) { + cacheStats.get( cacheName ).hit(); + return ( T )element.getObjectValue(); + } else { + // element doesn't exist in cache, try to retrieve from the cached service instead. + final T value = supplier.get(); + if( value != null ) { + cacheStats.get( cacheName ).miss(); + cacheMap.get( cacheName ).put( new Element( key, value ) ); + } + return value; + } + } + return null; + } + + /** {@inheritDoc} */ + @Override + public void put( final String cacheName, final Serializable key, final Object val ) { + if( keyAndCacheAreNotNull( cacheName, key ) ) { + cacheMap.get( cacheName ).put( new Element( key, val ) ); + } + } + + /** {@inheritDoc} */ + @Override + public void remove( final String cacheName, final Serializable key ) { + if( keyAndCacheAreNotNull( cacheName, key ) ) { + cacheMap.get( cacheName ).remove( key ); + } + } + + boolean keyAndCacheAreNotNull( final String cacheName, final Serializable key ) { + return enabled( cacheName ) && key != null; + } + +} diff --git a/jspwiki-cache/src/main/java/org/apache/wiki/cache/package.html b/jspwiki-cache/src/main/java/org/apache/wiki/cache/package.html new file mode 100644 index 0000000..ad29a2c --- /dev/null +++ b/jspwiki-cache/src/main/java/org/apache/wiki/cache/package.html @@ -0,0 +1,29 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. +--> + +<body> + +Provides a cache abstraction for JSPWiki. + +<h2>Package Specification</h2> + +Contains a Caching facade, with the default Ehcache-based implementation. + +<hr> +</body> diff --git a/jspwiki-main/src/main/resources/ehcache.xml b/jspwiki-cache/src/main/resources/ehcache-jspwiki.xml similarity index 84% copy from jspwiki-main/src/main/resources/ehcache.xml copy to jspwiki-cache/src/main/resources/ehcache-jspwiki.xml index 4ae77a4..bc47135 100644 --- a/jspwiki-main/src/main/resources/ehcache.xml +++ b/jspwiki-cache/src/main/resources/ehcache-jspwiki.xml @@ -58,20 +58,14 @@ First In First Out (specified as FIFO) and Less Frequently Used (specified as LFU) --> - <!-- the default JSPWiki caches --> - <cache name="JSPWiki.jspwiki.renderingCache" maxElementsInMemory="1000" /> - - <cache name="JSPWiki.jspwiki.pageCache" maxElementsInMemory="1000" /> - - <cache name="JSPWiki.jspwiki.pageTextCache" maxElementsInMemory="1000" /> - - <cache name="JSPWiki.jspwiki.pageHistoryCache" maxElementsInMemory="1000" /> - <cache name="JSPWiki.jspwiki.attachmentsCache" maxElementsInMemory="1000" /> - - <cache name="JSPWiki.jspwiki.attachmentCollectionsCache" maxElementsInMemory="1000" /> - - <cache name="JSPWiki.jspwiki.dynamicAttachmentCache" maxElementsInMemory="1000" /> + <!-- the default JSPWiki caches --> + <cache name="jspwiki.renderingCache" maxElementsInMemory="1000" /> + <cache name="jspwiki.pageCache" maxElementsInMemory="1000" /> + <cache name="jspwiki.pageTextCache" maxElementsInMemory="1000" /> + <cache name="jspwiki.pageHistoryCache" maxElementsInMemory="1000" /> + <cache name="jspwiki.attachmentsCache" maxElementsInMemory="1000" /> + <cache name="jspwiki.attachmentCollectionsCache" maxElementsInMemory="1000" /> + <cache name="jspwiki.dynamicAttachmentCache" maxElementsInMemory="1000" /> - <cache name="JSPWiki.jspwiki.rssCache" maxElementsInMemory="250" /> </ehcache> diff --git a/jspwiki-cache/src/test/java/org/apache/wiki/cache/EhcacheCachingManagerTest.java b/jspwiki-cache/src/test/java/org/apache/wiki/cache/EhcacheCachingManagerTest.java new file mode 100644 index 0000000..90441f5 --- /dev/null +++ b/jspwiki-cache/src/test/java/org/apache/wiki/cache/EhcacheCachingManagerTest.java @@ -0,0 +1,85 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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.apache.wiki.cache; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.util.Properties; + + +public class EhcacheCachingManagerTest { + + static EhcacheCachingManager ecm = new EhcacheCachingManager(); + + @BeforeAll + static void beforeAll() throws Exception { + ecm.initialize( null, new Properties() ); + } + + @Test + void testInitAndShutdown() throws Exception { + final Properties props = new Properties(); + props.setProperty( CachingManager.PROP_CACHE_CONF_FILE, "ehcache-jspwiki-test.xml" ); + EhcacheCachingManager ecm = new EhcacheCachingManager(); + ecm.initialize( null, props ); + Assertions.assertEquals( 7, ecm.cacheMap.size() ); + + ecm.registerCache( "anotherCache" ); + Assertions.assertEquals( 8, ecm.cacheMap.size() ); + + ecm.shutdown(); + ecm.shutdown(); // does nothing if already shutdown + Assertions.assertEquals( 0, ecm.cacheMap.size() ); + + props.setProperty( CachingManager.PROP_CACHE_ENABLE, "false" ); ecm = new EhcacheCachingManager(); + ecm.initialize( null, props ); + Assertions.assertEquals( 0, ecm.cacheMap.size() ); + } + + @Test + void testEnabled() { + Assertions.assertTrue( ecm.enabled( CachingManager.CACHE_PAGES ) ); + Assertions.assertFalse( ecm.enabled( "Trucutru" ) ); + } + + @Test + void testInfo() { + Assertions.assertNotNull( ecm.info( CachingManager.CACHE_PAGES ) ); + Assertions.assertNull( ecm.info( "Trucutru" ) ); + } + + @Test + void testPutGetRemoveAndKeys() { + final String retrieveFromBackend = "item"; + ecm.put( CachingManager.CACHE_PAGES, "key", "test" ); + ecm.put( "trucutru", "key", "test" ); + Assertions.assertEquals( "test", ecm.get( CachingManager.CACHE_PAGES, "key", () -> retrieveFromBackend ) ); + ecm.remove( CachingManager.CACHE_PAGES, "key" ); + ecm.remove( CachingManager.CACHE_PAGES, null ); + Assertions.assertEquals( "item", ecm.get( CachingManager.CACHE_PAGES, "key", () -> retrieveFromBackend ) ); + Assertions.assertEquals( 1, ecm.keys( CachingManager.CACHE_PAGES ).size() ); + Assertions.assertEquals( 0, ecm.keys( "trucutru" ).size() ); + + Assertions.assertNull( ecm.get( CachingManager.CACHE_PAGES, null, () -> retrieveFromBackend ) ); + Assertions.assertNull( ecm.get( "trucutru", "key", () -> retrieveFromBackend ) ); + } + +} diff --git a/jspwiki-main/src/main/resources/ehcache.xml b/jspwiki-cache/src/test/resources/ehcache-jspwiki-test.xml similarity index 83% rename from jspwiki-main/src/main/resources/ehcache.xml rename to jspwiki-cache/src/test/resources/ehcache-jspwiki-test.xml index 4ae77a4..4f97530 100644 --- a/jspwiki-main/src/main/resources/ehcache.xml +++ b/jspwiki-cache/src/test/resources/ehcache-jspwiki-test.xml @@ -58,20 +58,10 @@ First In First Out (specified as FIFO) and Less Frequently Used (specified as LFU) --> - <!-- the default JSPWiki caches --> - <cache name="JSPWiki.jspwiki.renderingCache" maxElementsInMemory="1000" /> - <cache name="JSPWiki.jspwiki.pageCache" maxElementsInMemory="1000" /> + <cache name="jspwiki.renderingCache" maxElementsInMemory="1" /> + <cache name="jspwiki.pageCache" maxElementsInMemory="1" /> + <cache name="jspwiki.pageTextCache" maxElementsInMemory="1" /> + <cache name="notManagedByJSPWikiCache" maxElementsInMemory="100" /> - <cache name="JSPWiki.jspwiki.pageTextCache" maxElementsInMemory="1000" /> - - <cache name="JSPWiki.jspwiki.pageHistoryCache" maxElementsInMemory="1000" /> - - <cache name="JSPWiki.jspwiki.attachmentsCache" maxElementsInMemory="1000" /> - - <cache name="JSPWiki.jspwiki.attachmentCollectionsCache" maxElementsInMemory="1000" /> - - <cache name="JSPWiki.jspwiki.dynamicAttachmentCache" maxElementsInMemory="1000" /> - - <cache name="JSPWiki.jspwiki.rssCache" maxElementsInMemory="250" /> </ehcache> diff --git a/jspwiki-main/src/main/resources/ini/classmappings.xml b/jspwiki-main/src/main/resources/ini/classmappings.xml index 6cff675..bd5c91b 100644 --- a/jspwiki-main/src/main/resources/ini/classmappings.xml +++ b/jspwiki-main/src/main/resources/ini/classmappings.xml @@ -88,6 +88,10 @@ <mappedClass>org.apache.wiki.auth.authorize.DefaultGroupManager</mappedClass> </mapping> <mapping> + <requestedClass>org.apache.wiki.cache.CachingManager</requestedClass> + <mappedClass>org.apache.wiki.cache.EhcacheCachingManager</mappedClass> + </mapping> + <mapping> <requestedClass>org.apache.wiki.content.PageRenamer</requestedClass> <mappedClass>org.apache.wiki.content.DefaultPageRenamer</mappedClass> </mapping> diff --git a/jspwiki-main/src/main/resources/ini/jspwiki.properties b/jspwiki-main/src/main/resources/ini/jspwiki.properties index 1f0ee8a..7a54fe7 100644 --- a/jspwiki-main/src/main/resources/ini/jspwiki.properties +++ b/jspwiki-main/src/main/resources/ini/jspwiki.properties @@ -77,7 +77,9 @@ jspwiki.pageProvider = FileSystemProvider # # NB: This replaces the JSPWiki 1.x "CachingProvider" setting, since it probably was too confusing. # -jspwiki.usePageCache = true +jspwiki.cache.enable = true +# This property superseedes +#jspwiki.usePageCache = true (which has been thus deprecated) # # Specify file from classpath that holds ehcache configuration. diff --git a/jspwiki-main/src/test/resources/ini/jspwiki.properties b/jspwiki-main/src/test/resources/ini/jspwiki.properties index 4e93ae1..cdc4fb5 100644 --- a/jspwiki-main/src/test/resources/ini/jspwiki.properties +++ b/jspwiki-main/src/test/resources/ini/jspwiki.properties @@ -17,7 +17,7 @@ # jspwiki.applicationName = JSPWiki jspwiki.pageProvider = FileSystemProvider -jspwiki.usePageCache = true +jspwiki.cache.enable = true jspwiki.attachmentProvider = BasicAttachmentProvider jspwiki.diffProvider = TraditionalDiffProvider jspwiki.encoding = UTF-8 diff --git a/jspwiki-portable/src/overlay/woas/webapps/personal/WEB-INF/classes/ehcache.xml b/jspwiki-portable/src/overlay/woas/webapps/department/WEB-INF/classes/ehcache-woas-department.xml similarity index 100% rename from jspwiki-portable/src/overlay/woas/webapps/personal/WEB-INF/classes/ehcache.xml rename to jspwiki-portable/src/overlay/woas/webapps/department/WEB-INF/classes/ehcache-woas-department.xml diff --git a/jspwiki-portable/src/overlay/woas/webapps/department/WEB-INF/classes/jspwiki-custom.properties b/jspwiki-portable/src/overlay/woas/webapps/department/WEB-INF/classes/jspwiki-custom.properties index 01cb186..f712c85 100644 --- a/jspwiki-portable/src/overlay/woas/webapps/department/WEB-INF/classes/jspwiki-custom.properties +++ b/jspwiki-portable/src/overlay/woas/webapps/department/WEB-INF/classes/jspwiki-custom.properties @@ -30,7 +30,8 @@ jspwiki.attachment.maxsize=4000000 jspwiki.breakTitleWithSpaces=true jspwiki.searchProvider=LuceneSearchProvider jspwiki.security=jaas -jspwiki.usePageCache=true +jspwiki.cache.enable=true +jspwiki.cache.config-file=ehcache-woas-department.xml # jspwiki.xmlGroupDatabaseFile=/usr/local/tomcat/lib/groupdatabase.xml # jspwiki.xmlUserDatabaseFile=/usr/local/tomcat/lib/userdatabase.xml diff --git a/jspwiki-portable/src/overlay/woas/webapps/department/WEB-INF/classes/ehcache.xml b/jspwiki-portable/src/overlay/woas/webapps/personal/WEB-INF/classes/ehcache-woas-personal.xml similarity index 100% rename from jspwiki-portable/src/overlay/woas/webapps/department/WEB-INF/classes/ehcache.xml rename to jspwiki-portable/src/overlay/woas/webapps/personal/WEB-INF/classes/ehcache-woas-personal.xml diff --git a/jspwiki-portable/src/overlay/woas/webapps/personal/WEB-INF/classes/jspwiki-custom.properties b/jspwiki-portable/src/overlay/woas/webapps/personal/WEB-INF/classes/jspwiki-custom.properties index d23c2bc..dd33774 100644 --- a/jspwiki-portable/src/overlay/woas/webapps/personal/WEB-INF/classes/jspwiki-custom.properties +++ b/jspwiki-portable/src/overlay/woas/webapps/personal/WEB-INF/classes/jspwiki-custom.properties @@ -30,7 +30,8 @@ jspwiki.breakTitleWithSpaces=true jspwiki.pageProvider=FileSystemProvider jspwiki.searchProvider=BasicSearchProvider jspwiki.security=jaas -jspwiki.usePageCache=true +jspwiki.cache.enable=true +jspwiki.cache.config-file=ehcache-woas-personal.xml # jspwiki.xmlGroupDatabaseFile=/usr/local/tomcat/lib/groupdatabase.xml # jspwiki.xmlUserDatabaseFile=/usr/local/tomcat/lib/userdatabase.xml diff --git a/jspwiki-util/src/main/java/org/apache/wiki/util/CheckedSupplier.java b/jspwiki-util/src/main/java/org/apache/wiki/util/CheckedSupplier.java new file mode 100644 index 0000000..6ee0a1f --- /dev/null +++ b/jspwiki-util/src/main/java/org/apache/wiki/util/CheckedSupplier.java @@ -0,0 +1,39 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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.apache.wiki.util; + + +/** + * A {@code Supplier} cousin that also throws Checked Exceptions. + * + * @param <T> type returned by this functional interface. + * @param <E> {@link Exception} thrown by this functional interface. + */ +@FunctionalInterface +public interface CheckedSupplier< T, E extends Exception > { + + /** + * Gets a result. + * + * @throws E a checked exception. + * @return a result. + */ + T get() throws E; + +} diff --git a/jspwiki-util/src/main/java/org/apache/wiki/util/TextUtil.java b/jspwiki-util/src/main/java/org/apache/wiki/util/TextUtil.java index 68a2498..49115aa 100644 --- a/jspwiki-util/src/main/java/org/apache/wiki/util/TextUtil.java +++ b/jspwiki-util/src/main/java/org/apache/wiki/util/TextUtil.java @@ -19,6 +19,8 @@ package org.apache.wiki.util; import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.io.File; import java.io.IOException; @@ -35,9 +37,11 @@ import java.util.Random; */ public final class TextUtil { + private static final Logger LOG = LogManager.getLogger( TextUtil.class ); + static final String HEX_DIGITS = "0123456789ABCDEF"; - /** Pick from some letters that won't be easily mistaken for each other to compose passwords. So, for example, omit o O and 0, 1 l and L.*/ + /** Pick from some letters that won't be easily mistaken for each other to compose passwords. So, for example, omit o, O and 0, or 1, l and L.*/ static final String PWD_BASE = "abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789+@"; /** Length of password. {@link #generateRandomPassword() */ @@ -170,7 +174,7 @@ public final class TextUtil { * * @param data A string to encode * @param encoding The encoding in which to encode - * @return An URL encoded string. + * @return A URL encoded string. */ public static String urlEncode( final String data, final String encoding ) { // Presumably, the same caveats apply as in FileSystemProvider. Don't see why it would be horribly kludgy, though. @@ -217,7 +221,7 @@ public final class TextUtil { } /** - * Replaces a string with an other string. + * Replaces a string with another string. * * @param orig Original string. Null is safe. * @param src The string to find. @@ -271,11 +275,11 @@ public final class TextUtil { } /** - * Replaces a string with an other string. Case insensitive matching is used + * Replaces a string with another string. Case-insensitive matching is used * * @param orig Original string. Null is safe. * @param src The string to find. - * @param dest The string to replace <I>src</I> with. + * @param dest The string to replace <em>src</em> with. * @return A string with all instances of src replaced with dest. */ public static String replaceStringCaseUnsensitive( final String orig, final String src, final String dest ) { @@ -368,18 +372,18 @@ public final class TextUtil { } /** - * Fetches a String property from the set of Properties. This differs from Properties.getProperty() in a - * couple of key respects: First, property value is trim()med (so no extra whitespace back and front). - * - * Before inspecting the props, we first check if there is a Java System Property with the same name, if it exists - * we use that value, if not we check an environment variable with that (almost) same name, almost meaning we replace - * dots with underscores. - * - * @param props The Properties to search through - * @param key The property key - * @param defval A default value to return, if the property does not exist. - * @return The property value. - * @since 2.1.151 + * Fetches a String property from the set of Properties. This differs from Properties.getProperty() in a + * couple of key respects: First, property value is trim()med (so no extra whitespace back and front). + * + * Before inspecting the props, we first check if there is a Java System Property with the same name, if it exists + * we use that value, if not we check an environment variable with that (almost) same name, almost meaning we replace + * dots with underscores. + * + * @param props The Properties to search through + * @param key The property key + * @param defval A default value to return, if the property does not exist. + * @return The property value. + * @since 2.1.151 */ public static String getStringProperty( final Properties props, final String key, final String defval ) { String val = System.getProperties().getProperty( key, System.getenv( StringUtils.replace( key,".","_" ) ) ); @@ -393,6 +397,26 @@ public final class TextUtil { } /** + * {@link #getStringProperty(Properties, String, String)} overload that handles deprecated keys, so that a key and its + * deprecated counterpart can coexist in a given version of JSPWiki. + * + * @param props The Properties to search through + * @param key The property key + * @param deprecatedKey the property key being superseeded by key + * @param defval A default value to return, if the property does not exist. + * @return The property value. + */ + public static String getStringProperty( final Properties props, final String key, final String deprecatedKey, final String defval ) { + final String val = getStringProperty( props, deprecatedKey, null ); + if( val != null ) { + LOG.warn( "{} is being deprecated and will be removed on a future version, please consider using {} instead" + + "in your jspwiki[-custom].properties file", key, key ); + return val; + } + return getStringProperty( props, key, defval ); + } + + /** * Throws an exception if a property is not found. * * @param props A set of properties to search the key in. @@ -470,7 +494,7 @@ public final class TextUtil { * <LI>The CR/LF/CRLF mess is normalized to plain CRLF. * </UL> * - * The reason why we're using CRLF is that most browser already return CRLF since that is the closest thing to a HTTP standard. + * The reason why we're using CRLF is that most browser already return CRLF since that is the closest thing to an HTTP standard. * * @param postData The data to normalize * @return Normalized data diff --git a/jspwiki-util/src/test/java/org/apache/wiki/util/TextUtilTest.java b/jspwiki-util/src/test/java/org/apache/wiki/util/TextUtilTest.java index 0bc4a81..812bca7 100644 --- a/jspwiki-util/src/test/java/org/apache/wiki/util/TextUtilTest.java +++ b/jspwiki-util/src/test/java/org/apache/wiki/util/TextUtilTest.java @@ -292,6 +292,15 @@ public class TextUtilTest { } @Test + public void testGetStringPropertyDeprecated() { + final String[] vals = { "foo", " this is a property ", "foo-dep", "deprecated" }; + final Properties props = TextUtil.createProperties(vals); + Assertions.assertEquals( "deprecated", TextUtil.getStringProperty( props, "foo", "foo-dep", "err" ) ); + Assertions.assertEquals( "this is a property", TextUtil.getStringProperty( props, "foo", "bar-dep", "err" ) ); + Assertions.assertEquals( "err", TextUtil.getStringProperty( props, "fooo", "bar-dep", "err" ) ); + } + + @Test public void testGetStringPropertyDefaultValue() { final String defaultValue = System.getProperty( "user.home" ) + File.separator + "jspwiki-files"; final String[] vals = { "foo", " this is a property " }; diff --git a/jspwiki-util/src/test/resources/ini/jspwiki.properties b/jspwiki-util/src/test/resources/ini/jspwiki.properties index a45cf7b..93a5adc 100644 --- a/jspwiki-util/src/test/resources/ini/jspwiki.properties +++ b/jspwiki-util/src/test/resources/ini/jspwiki.properties @@ -17,7 +17,7 @@ # jspwiki.applicationName = JSPWiki jspwiki.pageProvider = FileSystemProvider -jspwiki.usePageCache = true +jspwiki.cache.enable = true jspwiki.attachmentProvider = BasicAttachmentProvider jspwiki.diffProvider = TraditionalDiffProvider jspwiki.encoding = UTF-8
