├── .gitignore ├── CONTRIBUTORS.markdown ├── LICENSE.txt ├── README.md ├── azure-pipelines.yml ├── ehcache-jcache ├── README.md ├── checkstyle │ ├── ClassHeader.txt │ ├── checkstyle.xml │ └── suppressions.xml ├── pom.xml └── src │ ├── assemble │ ├── CHANGELOG.txt │ ├── LICENSE.txt │ ├── README.txt │ ├── distribution.xml │ └── filter.properties │ ├── main │ ├── java │ │ └── org │ │ │ └── ehcache │ │ │ └── jcache │ │ │ ├── JCache.java │ │ │ ├── JCacheCacheWriterAdapter.java │ │ │ ├── JCacheCachingProvider.java │ │ │ ├── JCacheConfiguration.java │ │ │ ├── JCacheCopyOnWriteStrategy.java │ │ │ ├── JCacheEntry.java │ │ │ ├── JCacheEntryEventAdapter.java │ │ │ ├── JCacheListenerAdapter.java │ │ │ ├── JCacheMXBean.java │ │ │ ├── JCacheManagementMXBean.java │ │ │ ├── JCacheManager.java │ │ │ ├── JCacheStatMXBean.java │ │ │ ├── package-info.java │ │ │ └── tck │ │ │ └── TCKMBeanServerBuilder.java │ └── resources │ │ └── META-INF │ │ └── services │ │ └── javax.cache.spi.CachingProvider │ └── test │ ├── java │ └── org │ │ └── ehcache │ │ └── jcache │ │ ├── JCacheAndEhcacheAccessTest.java │ │ ├── JCacheCachingProviderTest.java │ │ ├── JCacheConfigurationTest.java │ │ └── JCacheManagerTest.java │ └── resources │ ├── ehcache-basic.xml │ └── ehcache.xml ├── jcache-tck-runner ├── pom.xml └── src │ └── test │ └── resources │ └── ExcludeList └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .idea/ 3 | atlassian-ide-plugin.xml 4 | *.iml 5 | *.ipr 6 | *.iws 7 | *.DS_Store 8 | -------------------------------------------------------------------------------- /CONTRIBUTORS.markdown: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehcache/ehcache-jcache/e6e01577390822794438b5580031169d4688cf9a/CONTRIBUTORS.markdown -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2003-2010 Terracotta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Ehcache-JCache For Ehcache 2.x. 2 | ============== 3 | 4 | **Important:** This project isn't maintained anymore as Ehcache 2.x will slowly retire. Please consider migrating to [Ehcache 3.x](https://github.com/ehcache/ehcache3) which has built-in JSR107 support. 5 | 6 | About 7 | ----- 8 | 9 | *ehcache-jcache* is a full implementation of the API and SPI from JSR-107 (aka JCache). It provides a wrapper around an Ehcache cache 10 | that allows allows you to use Ehcache as the caching provider using only JSR-107 APIs. 11 | 12 | More detailed information about how to use this is found under the [ehcache-jcache](https://github.com/Terracotta-OSS/ehcache-jcache/tree/master/ehcache-jcache) 13 | module 14 | 15 | Modules 16 | -------------------- 17 | * [ehcache-jcache](https://github.com/Terracotta-OSS/ehcache-jcache/tree/master/ehcache-jcache) 18 | This contains the ehcache-jcache implementation 19 | * [jcache-tck-runner](https://github.com/Terracotta-OSS/ehcache-jcache/tree/master/jcache-tck-runner) 20 | This runs the JSR107 TCK suite against the ehcache-jcache implementation to verify compliance with the spec. 21 | 22 | 23 | Build 24 | -------------------- 25 | * Just run the following command line (provided you have maven 3 already installed) : 26 | 27 | mvn clean install 28 | 29 | 30 | * You may want to disable the run-tck profile (if you don't have the TCK in your local maven repository since it's not published to a maven repository) : 31 | 32 | mvn clean install -P -run-tck 33 | 34 | * Current build status: [![Build Status](https://ehcache.ci.cloudbees.com/buildStatus/icon?job=ehcache-jcache)](https://ehcache.ci.cloudbees.com/job/ehcache-jcache/) 35 | 36 | [![Build Status](http://www.cloudbees.com/sites/default/files/Button-Powered-by-CB.png)](http://www.cloudbees.com/) 37 | 38 | Development 39 | -------- 40 | 41 | Active development of the ehcache-jcache module follows changes to the spec. There will be no attempt to maintain backwards 42 | compatibility between release versions; the focus of each release will be compliance with the latest JSR107 spec. 43 | 44 | Release 45 | -------- 46 | 47 | Following releases of the JSR107 spec APIs, an updated release milestone will be released and the latest stable release code will sit on the master 48 | branch of the ehcache-jcache github repository. 49 | 50 | Issue tracker 51 | ------------- 52 | 53 | Please log issues to: 54 | 55 | 56 | License 57 | ------- 58 | 59 | This software is provided under an Apache 2 open source license, read the `LICENSE.txt` file for details. 60 | 61 | 62 | Contributors 63 | ------------ 64 | 65 | This free, open source software was made possible by Terracotta, Inc.. See the `CONTRIBUTORS.markdown` file for details. 66 | 67 | 68 | Copyright 69 | --------- 70 | 71 | Copyright (c) Terracotta 72 | 73 | Using it 74 | ======== 75 | 76 | Maven 77 | ----- 78 | 79 | Releases are available from Maven Central. 80 | 81 | Snapshots are available from the Sonatype OSS snapshot repository. 82 | In order to access the snapshots, you need to add the following repository to your pom.xml: 83 | ```xml 84 | 85 | sonatype-nexus-snapshots 86 | Sonatype Nexus Snapshots 87 | https://oss.sonatype.org/content/repositories/snapshots 88 | 89 | false 90 | 91 | 92 | true 93 | 94 | 95 | ``` 96 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Terracotta, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # See shared code location for steps and parameters: 18 | # https://dev.azure.com/TerracottaCI/_git/terracotta 19 | 20 | resources: 21 | repositories: 22 | - repository: templates 23 | type: git 24 | name: terracotta/terracotta 25 | 26 | jobs: 27 | - template: build-templates/maven-common.yml@templates 28 | -------------------------------------------------------------------------------- /ehcache-jcache/README.md: -------------------------------------------------------------------------------- 1 | Ehcache-JCache 2 | ============== 3 | 4 | About 5 | ----- 6 | 7 | *ehcache-jcache* is a full implementation of the API and SPI from from JSR107 (aka JCache). 8 | It provides a wrapper around an Ehcache cache that allows allows you to use Ehcache as the 9 | caching provider using only JSR107 APIs. 10 | 11 | Getting Started 12 | --------------- 13 | ### Including in your project ### 14 | To include this in your project, you need to include: 15 | 16 | ```xml 17 | 18 | org.ehcache 19 | jcache 20 | [version] 21 | 22 | ``` 23 | 24 | ### Configuring a JCache ### 25 | 26 | There are two ways to configure a JCache. 27 | 28 | 1. Programatically using a CacheBuilder 29 | 2. Declaratively using an ehcache-*.xml file 30 | 31 | ### Configuring a JCache Programatically ### 32 | 33 | The `JCacheCacheManager` is responsible for creating a JCache that delegates the storage and retrieval of cache 34 | elements to an underlying ehcache. 35 | 36 | The `CacheManager` can be created manually, or you can use the `Caching` singleton entrypoint to retrieve it. 37 | 38 | ```java 39 | Cache foo = Caching.getCacheManager().createCacheBuilder("foo").build(); 40 | ```` 41 | 42 | You can set additional parameters on the cache as well. For instance, to create a new cache that will have entries 43 | expire 10 minutes after they are created (or last modified) that stores cache values as references: 44 | 45 | ```java 46 | Cache blarg = Caching.getCacheManager().createCacheBuilder("blarg") 47 | .setExpiry(CacheConfiguration.ExpiryType.MODIFIED, new Duration(TimeUnit.MINUTES, 10)) 48 | .setStoreByValue(false) 49 | .build(); 50 | ``` 51 | 52 | Currently only the configuration parameters specified in the JSR107 spec are exposed via the builder interface. 53 | You can also configure caches declartively in ehcache's well-known xml cache configuration format. 54 | 55 | When you create a named cache manager, the jcache-ehcache provider will look in the classpath for a file named 56 | "`ehcache-NAME.xml`" (where NAME is the name of the cache manager you are creating). 57 | 58 | If you have a file named `ehcache-jcache-example.xml`, for instance, then when you call: 59 | 60 | ```java 61 | Cache boo = Caching.getCacheManager("jcache-example").getCache("boo"); 62 | ``` 63 | 64 | The cache will be configured based on the parameters set in the `ehcache-jcache-example.xml` file in the classpath. 65 | In that xml file additional parameters (such as the size of the cache) can be configured. 66 | 67 | **Note: The defaultCache entry in an xml configuration file is not used for caches created by the JCacheManager** 68 | 69 | As part of the specification of JSR107, every cache created programatically via ```getCacheManager().getCache()``` 70 | uses the same default settings regardless of the underlying caching provider. This implementation honors that part of the specification which means that you will 71 | need to explicitly define the entries in the cache config file. 72 | 73 | Using with JSR107 annotations 74 | ------------- 75 | The reference implementation of the JSR107 annotations can be used with any JSR107 caching provider. 76 | There are annotation implementations provided for both CDI and Spring that will work with ehcache-jcache. 77 | For more information on annotations, see 78 | 79 | If you want to use annotations with this (or any other JSR107 provider) you need to also include: 80 | 81 | **For spring annotations** _(compatible with Spring 3.0.6+)_: 82 | 83 | ```xml 84 | 85 | org.jsr107.ri 86 | cache-annotations-ri-spring 87 | 0.4 88 | 89 | ``` 90 | 91 | **For CDI annotations:** 92 | 93 | ```xml 94 | 95 | org.jsr107.ri 96 | cache-annotations-ri-cdi 97 | 0.4 98 | 99 | ``` 100 | 101 | Copyright 102 | --------- 103 | 104 | Copyright (c) Terracotta -------------------------------------------------------------------------------- /ehcache-jcache/checkstyle/ClassHeader.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2003-2010 Terracotta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ -------------------------------------------------------------------------------- /ehcache-jcache/checkstyle/checkstyle.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 136 | 137 | 138 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | -------------------------------------------------------------------------------- /ehcache-jcache/checkstyle/suppressions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /ehcache-jcache/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | org.ehcache 7 | ehcache-jcache-parent 8 | 1.0.2-SNAPSHOT 9 | 10 | 11 | jcache 12 | jar 13 | 14 | Ehcache JCache Implementation 15 | 16 | 17 | 18 | 19 | 20 | net.sf.ehcache 21 | ehcache 22 | 2.8.3 23 | 24 | 25 | javax.cache 26 | cache-api 27 | 28 | 29 | org.slf4j 30 | slf4j-api 31 | 1.6.1 32 | 33 | 34 | junit 35 | junit 36 | 4.8.2 37 | test 38 | 39 | 40 | javax.transaction 41 | jta 42 | 1.1 43 | provided 44 | 45 | 46 | 47 | 48 | log4j 49 | log4j 50 | 1.2.16 51 | test 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | maven-compiler-plugin 60 | 2.3.2 61 | 62 | 1.6 63 | 1.6 64 | 65 | 66 | 67 | 68 | org.apache.maven.plugins 69 | maven-source-plugin 70 | 2.1.2 71 | 72 | 73 | attach-sources 74 | verify 75 | 76 | jar-no-fork 77 | 78 | 79 | 80 | 81 | 82 | 83 | org.apache.maven.plugins 84 | maven-javadoc-plugin 85 | 2.8 86 | 87 | 88 | attach-javadocs 89 | 90 | jar 91 | 92 | 93 | 94 | 95 | 96 | 97 | org.apache.maven.plugins 98 | maven-checkstyle-plugin 99 | 2.8 100 | 101 | ${basedir}/checkstyle/checkstyle.xml 102 | ${basedir}/checkstyle/suppressions.xml 103 | 104 | ${basedir}/checkstyle/ClassHeader.txt 105 | false 106 | true 107 | true 108 | true 109 | true 110 | false 111 | true 112 | 113 | 114 | 115 | 116 | org.apache.maven.plugins 117 | maven-surefire-plugin 118 | 2.9 119 | true 120 | 121 | false 122 | 123 | **/*Test.java 124 | 125 | 126 | **/*$* 127 | **/web/**/* 128 | **/Abstract*Test.java 129 | **/constructs/web/** 130 | 131 | pertest 132 | false 133 | false 134 | true 135 | true 136 | 137 | 138 | net.sf.ehcache.skipUpdateCheck 139 | true 140 | 141 | 142 | java.awt.headless 143 | true 144 | 145 | 146 | 147 | net.sf.ehcache.speedAdjustmentFactor 148 | 149 | 150 | ${net.sf.ehcache.speedAdjustmentFactor} 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | maven-assembly-plugin 159 | 160 | 161 | src/assemble/filter.properties 162 | 163 | 164 | src/assemble/distribution.xml 165 | 166 | 167 | 168 | 169 | 170 | 171 | -------------------------------------------------------------------------------- /ehcache-jcache/src/assemble/CHANGELOG.txt: -------------------------------------------------------------------------------- 1 | $Id: CHANGELOG.txt,v 1.31 2006/03/07 00:05:56 gregluck Exp $ 2 | 3 | 4 | 5 | Refactored Caching interfaces to use javax.cache version 0.3 6 | 7 | 8 | 9 | 10 | 11 | 12 | Change logging to SLF4J 13 | 14 | 15 | Change ehcache dependency to 1.7.1 and higher 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | Initial release of the standalone module. 26 | 27 | 28 | javax.cache was updated to remove checked exceptions from CacheLoader, so as to make the standalone 29 | implementation possible. 30 | 31 | 32 | The jsr107 CacheManager concept is broken. This version adds a new JCacheManager, which works like the 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /ehcache-jcache/src/assemble/LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2003-2010 Terracotta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ -------------------------------------------------------------------------------- /ehcache-jcache/src/assemble/README.txt: -------------------------------------------------------------------------------- 1 | README For ehcache-jcache 2 | ================================ 3 | 4 | Ehcache core at least version 2.4, together with Java 5 is required. 5 | 6 | -------------------------------------------------------------------------------- /ehcache-jcache/src/assemble/distribution.xml: -------------------------------------------------------------------------------- 1 | 2 | distribution 3 | 4 | tar.gz 5 | 6 | 7 | 8 | target 9 | 10 | *.jar 11 | *.sources.jar 12 | *.javadoc.jar 13 | 14 | / 15 | 16 | 17 | ${basedir}/src/assemble 18 | 19 | *.txt 20 | 21 | / 22 | 23 | 24 | 25 | 26 | lib 27 | false 28 | runtime 29 | 30 | 31 | -------------------------------------------------------------------------------- /ehcache-jcache/src/assemble/filter.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehcache/ehcache-jcache/e6e01577390822794438b5580031169d4688cf9a/ehcache-jcache/src/assemble/filter.properties -------------------------------------------------------------------------------- /ehcache-jcache/src/main/java/org/ehcache/jcache/JCache.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2003-2010 Terracotta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.ehcache.jcache; 17 | 18 | import net.sf.ehcache.Ehcache; 19 | import net.sf.ehcache.Element; 20 | 21 | import java.util.Collection; 22 | import java.util.HashMap; 23 | import java.util.HashSet; 24 | import java.util.Iterator; 25 | import java.util.Map; 26 | import java.util.NoSuchElementException; 27 | import java.util.Set; 28 | import java.util.concurrent.Callable; 29 | import java.util.concurrent.TimeUnit; 30 | 31 | import javax.cache.Cache; 32 | import javax.cache.CacheException; 33 | import javax.cache.CacheManager; 34 | import javax.cache.configuration.CacheEntryListenerConfiguration; 35 | import javax.cache.configuration.Configuration; 36 | import javax.cache.configuration.Factory; 37 | import javax.cache.event.CacheEntryListener; 38 | import javax.cache.expiry.Duration; 39 | import javax.cache.integration.CacheLoader; 40 | import javax.cache.integration.CacheLoaderException; 41 | import javax.cache.integration.CacheWriter; 42 | import javax.cache.integration.CacheWriterException; 43 | import javax.cache.integration.CompletionListener; 44 | import javax.cache.processor.EntryProcessor; 45 | import javax.cache.processor.EntryProcessorException; 46 | import javax.cache.processor.EntryProcessorResult; 47 | import javax.cache.processor.MutableEntry; 48 | 49 | /** 50 | * Implementation of a {@link Cache} that wraps an underlying ehcache. 51 | * 52 | * @param the type of keys used by this JCache 53 | * @param the type of values that are loaded by this JCache 54 | * @author Ryan Gardner 55 | * @since 1.4.0-beta1 56 | */ 57 | public class JCache implements Cache { 58 | 59 | private static final Object NOT_THERE = new Object(); 60 | 61 | private final JCacheConfiguration cfg; 62 | private final Ehcache ehcache; 63 | private final JCacheManager cacheManager; 64 | private final CacheLoader cacheLoader; 65 | private final CacheWriter cacheWriter; 66 | private volatile boolean closed = false; 67 | 68 | public JCache(final JCacheManager cacheManager, final JCacheConfiguration cfg, final Ehcache ehcache) { 69 | if(ehcache == null) throw new NullPointerException(); 70 | this.cacheManager = cacheManager; 71 | this.cfg = cfg; 72 | this.ehcache = ehcache; 73 | final Factory> cacheLoaderFactory = cfg.getCacheLoaderFactory(); 74 | if (cacheLoaderFactory != null) { 75 | this.cacheLoader = cacheLoaderFactory.create(); 76 | } else { 77 | this.cacheLoader = null; 78 | } 79 | final Factory> cacheWriterFactory = cfg.getCacheWriterFactory(); 80 | if (cacheWriterFactory != null) { 81 | this.cacheWriter = cacheWriterFactory.create(); 82 | } else { 83 | this.cacheWriter = null; 84 | } 85 | ehcache.registerCacheWriter(new JCacheCacheWriterAdapter(cacheWriter, cfg.getKeyType(), cfg.getValueType())); 86 | 87 | final Iterable> cacheEntryListenerConfigurations = cfg.getInitialCacheEntryListenerConfigurations(); 88 | if(cacheEntryListenerConfigurations != null) { 89 | for (CacheEntryListenerConfiguration listenerCfg : cacheEntryListenerConfigurations) { 90 | registerCacheEntryListener(listenerCfg); 91 | } 92 | } 93 | 94 | } 95 | 96 | 97 | @Override 98 | public V get(final K key) { 99 | checkNotClosed(); 100 | if(key == null) throw new NullPointerException(); 101 | final Element element = getElement(key); 102 | if (element == null) { 103 | V value = null; 104 | if(cfg.isReadThrough()) { 105 | value = load(key); 106 | } 107 | return value; 108 | } 109 | return cfg.getValueType().cast(element.getObjectValue()); 110 | } 111 | 112 | V load(K key) { 113 | V value; 114 | ehcache.acquireWriteLockOnKey(key); 115 | final Element e = ehcache.get(key); 116 | if(e != null) { 117 | return (V)e.getObjectValue(); 118 | } 119 | try { 120 | try { 121 | value = cacheLoader.load(key); 122 | } catch (Exception ex) { 123 | throw new CacheLoaderException(ex); 124 | } 125 | if(value != null) { 126 | putWithoutWriter(key, value); 127 | } 128 | } finally { 129 | ehcache.releaseWriteLockOnKey(key); 130 | } 131 | return value; 132 | } 133 | 134 | private Element getElement(final K key) { 135 | final Element element = ehcache.get(key); 136 | if (element == null) 137 | return null; 138 | final Duration expiryForUpdate = cfg.getExpiryPolicy().getExpiryForAccess(); 139 | if(expiryForUpdate != null && expiryForUpdate.isZero()) { 140 | ehcache.removeElement(element); 141 | } 142 | return element; 143 | } 144 | 145 | @Override 146 | public Map getAll(final Set keys) { 147 | checkNotClosed(); 148 | for (K key : keys) { 149 | if(key == null) throw new NullPointerException(); 150 | } 151 | final Map result = new HashMap(); 152 | final Map all = ehcache.getAll(keys); 153 | for (Map.Entry entry : all.entrySet()) { 154 | final Element e = entry.getValue(); 155 | final K key = (K)entry.getKey(); 156 | if(key != null) { 157 | V value = null; 158 | if(e != null) { 159 | value = (V)e.getObjectValue(); 160 | } else if (cfg.isReadThrough()) { 161 | value = load(key); 162 | } 163 | if (value != null) { 164 | result.put(key, value); 165 | } 166 | } 167 | } 168 | return result; 169 | } 170 | 171 | @Override 172 | public boolean containsKey(final K key) { 173 | checkNotClosed(); 174 | if(key == null) throw new NullPointerException(); 175 | return ehcache.isKeyInCache(key); 176 | } 177 | 178 | @Override 179 | public void loadAll(final Set keys, final boolean replaceExistingValues, final CompletionListener completionListener) { 180 | checkNotClosed(); 181 | if(keys == null) { 182 | throw new NullPointerException(); 183 | } 184 | for (K key : keys) { 185 | if (key == null) throw new NullPointerException(); 186 | } 187 | if(cacheLoader == null) { 188 | if (completionListener != null) { 189 | completionListener.onCompletion(); 190 | } 191 | return; 192 | } 193 | cacheManager.getExecutorService().submit(new Callable() { 194 | @Override 195 | public Void call() throws Exception { 196 | for (K key : keys) { 197 | try { 198 | ehcache.acquireWriteLockOnKey(key); 199 | try { 200 | if (!ehcache.isKeyInCache(key) || replaceExistingValues) { 201 | final V value = cacheLoader.load(key); 202 | if (value != null) { 203 | JCache.this.putWithoutWriter(key, value); 204 | } 205 | } 206 | } finally { 207 | ehcache.releaseWriteLockOnKey(key); 208 | } 209 | } catch (Exception e) { 210 | if (completionListener != null) { 211 | completionListener.onException(new CacheLoaderException(e)); 212 | } 213 | return null; 214 | } 215 | } 216 | if (completionListener != null) { 217 | completionListener.onCompletion(); 218 | } 219 | return null; 220 | } 221 | }); 222 | } 223 | 224 | @Override 225 | public void put(final K key, final V value) { 226 | checkNotClosed(); 227 | if(key == null) throw new NullPointerException(); 228 | if(value == null) throw new NullPointerException(); 229 | ehcache.acquireWriteLockOnKey(key); 230 | try { 231 | final Duration expiry; 232 | final boolean inCache = ehcache.isKeyInCache(key); 233 | if(inCache) { 234 | expiry = cfg.getExpiryPolicy().getExpiryForUpdate(); 235 | } else { 236 | expiry = cfg.getExpiryPolicy().getExpiryForCreation(); 237 | } 238 | final Element element = new Element(key, value); 239 | if(setTimeTo(cfg.overrideDefaultExpiry(), expiry, element)) { 240 | putAndWriteIfNeeded(element); 241 | } else if(inCache) { 242 | removeAndWriteIfNeeded(key); 243 | } 244 | } finally { 245 | ehcache.releaseWriteLockOnKey(key); 246 | } 247 | } 248 | 249 | void putWithoutWriter(final K key, final V value) { 250 | checkNotClosed(); 251 | if(key == null) throw new NullPointerException(); 252 | if(value == null) throw new NullPointerException(); 253 | ehcache.acquireWriteLockOnKey(key); 254 | try { 255 | final Duration expiry; 256 | final boolean inCache = ehcache.isKeyInCache(key); 257 | if(inCache) { 258 | expiry = cfg.getExpiryPolicy().getExpiryForUpdate(); 259 | } else { 260 | expiry = cfg.getExpiryPolicy().getExpiryForCreation(); 261 | } 262 | final Element element = new Element(key, value); 263 | if(setTimeTo(cfg.overrideDefaultExpiry(), expiry, element)) { 264 | ehcache.put(element); 265 | } else if(inCache) { 266 | ehcache.remove(key); 267 | } 268 | } finally { 269 | ehcache.releaseWriteLockOnKey(key); 270 | } 271 | } 272 | 273 | private boolean setTimeTo(final boolean overrideDefaults, final Duration duration, final Element element) { 274 | 275 | if(!overrideDefaults) { 276 | return true; 277 | } 278 | 279 | if (duration != null) { 280 | if (duration.isZero()) { 281 | return false; 282 | } 283 | if (duration.isEternal()) { 284 | element.setEternal(true); 285 | } else { 286 | final int d = (int)TimeUnit.SECONDS.convert(duration.getDurationAmount(), duration.getTimeUnit()); 287 | element.setTimeToLive(d == 0 ? 1 : d); 288 | element.setTimeToIdle(d); 289 | } 290 | } 291 | return true; 292 | } 293 | 294 | @Override 295 | public V getAndPut(final K key, final V value) { 296 | checkNotClosed(); 297 | if(key == null) throw new NullPointerException(); 298 | if(value == null) throw new NullPointerException(); 299 | ehcache.acquireWriteLockOnKey(key); 300 | try { 301 | final Element previousElement = ehcache.get(key); 302 | final Element element = new Element(key, value); 303 | final Duration expiry; 304 | final boolean inCache = ehcache.isKeyInCache(key); 305 | if(inCache) { 306 | expiry = cfg.getExpiryPolicy().getExpiryForUpdate(); 307 | } else { 308 | expiry = cfg.getExpiryPolicy().getExpiryForCreation(); 309 | } 310 | if(setTimeTo(cfg.overrideDefaultExpiry(), expiry, element)) { 311 | putAndWriteIfNeeded(element); 312 | } else if(inCache) { 313 | removeAndWriteIfNeeded(key); 314 | } 315 | 316 | return previousElement == null ? null : (V) previousElement.getObjectValue(); 317 | } finally { 318 | ehcache.releaseWriteLockOnKey(key); 319 | } 320 | } 321 | 322 | private boolean removeAndWriteIfNeeded(final K key) { 323 | if (cfg.isWriteThrough()) { 324 | ehcache.acquireWriteLockOnKey(key); 325 | final Element previous = ehcache.getQuiet(key); 326 | try { 327 | return ehcache.removeWithWriter(key); 328 | } catch (RuntimeException e) { 329 | if(previous != null) { 330 | ehcache.putQuiet(previous); 331 | } 332 | throw new CacheWriterException(e); 333 | } 334 | } else { 335 | if (ehcache.isKeyInCache(key)) { 336 | return ehcache.remove(key); 337 | } 338 | return false; 339 | } 340 | } 341 | 342 | private void putAndWriteIfNeeded(final Element element) { 343 | if (cfg.isWriteThrough()) { 344 | try { 345 | ehcache.putWithWriter(element); 346 | } catch (RuntimeException e) { 347 | ehcache.removeElement(element); 348 | throw new CacheWriterException(e); 349 | } 350 | } else { 351 | ehcache.put(element); 352 | } 353 | } 354 | 355 | @Override 356 | public void putAll(final Map map) { 357 | checkNotClosed(); 358 | final Collection elements = new HashSet(map.size(), 1f); 359 | final Collection entries = new HashSet(); 360 | for (Map.Entry entry : map.entrySet()) { 361 | if(entry.getValue() == null) throw new NullPointerException(); 362 | final Element e = new Element(entry.getKey(), entry.getValue()); 363 | final Duration expiry; 364 | if(ehcache.isKeyInCache(entry.getKey())) { 365 | expiry = cfg.getExpiryPolicy().getExpiryForUpdate(); 366 | } else { 367 | expiry = cfg.getExpiryPolicy().getExpiryForCreation(); 368 | } 369 | if(setTimeTo(cfg.overrideDefaultExpiry(), expiry, e)) { 370 | elements.add(e); 371 | if (cfg.isWriteThrough()) { 372 | entries.add(new JCacheEntry(e, cfg.getKeyType(), cfg.getValueType())); 373 | } 374 | } else { 375 | ehcache.remove(entry.getKey()); 376 | } 377 | } 378 | for (Element element : elements) { 379 | ehcache.put(element); 380 | } 381 | if (cfg.isWriteThrough()) { 382 | try { 383 | try { 384 | cacheWriter.writeAll(entries); 385 | } catch (RuntimeException e) { 386 | throw new CacheWriterException(e); 387 | } 388 | } catch (Exception e) { 389 | for (Entry entry : entries) { 390 | ehcache.remove(entry.getKey()); 391 | } 392 | throw new CacheWriterException(e); 393 | } 394 | } 395 | } 396 | 397 | @Override 398 | public boolean putIfAbsent(final K key, final V value) { 399 | checkNotClosed(); 400 | if(key == null) throw new NullPointerException(); 401 | if(value == null) throw new NullPointerException(); 402 | ehcache.acquireWriteLockOnKey(key); 403 | try { 404 | if (!ehcache.isKeyInCache(key)) { 405 | final Element element = new Element(key, value); 406 | final Duration expiryForCreation; 407 | expiryForCreation = cfg.getExpiryPolicy().getExpiryForCreation(); 408 | if(setTimeTo(cfg.overrideDefaultExpiry(), expiryForCreation, element)) { 409 | putAndWriteIfNeeded(element); 410 | } 411 | return true; 412 | } 413 | } finally { 414 | ehcache.releaseWriteLockOnKey(key); 415 | } 416 | return false; 417 | } 418 | 419 | @Override 420 | public boolean remove(final K key) { 421 | checkNotClosed(); 422 | if(key == null) throw new NullPointerException(); 423 | return removeAndWriteIfNeeded(key); 424 | } 425 | 426 | @Override 427 | public boolean remove(final K key, final V oldValue) { 428 | checkNotClosed(); 429 | if(key == null) throw new NullPointerException(); 430 | if(oldValue == null) throw new NullPointerException(); 431 | ehcache.acquireWriteLockOnKey(key); 432 | try { 433 | if(ehcache.isKeyInCache(key)) { 434 | final Element e = ehcache.get(key); 435 | if(e != null && e.getObjectValue().equals(oldValue)) { 436 | removeAndWriteIfNeeded(key); 437 | return true; 438 | } else if (e != null) { 439 | final Duration expiryForAccess = cfg.getExpiryPolicy().getExpiryForAccess(); 440 | if(expiryForAccess != null && expiryForAccess.isZero()) { 441 | removeAndWriteIfNeeded(key); 442 | } 443 | } 444 | } else { 445 | ehcache.get(NOT_THERE); 446 | } 447 | return false; 448 | } finally { 449 | ehcache.releaseWriteLockOnKey(key); 450 | } 451 | } 452 | 453 | @Override 454 | public V getAndRemove(final K key) { 455 | checkNotClosed(); 456 | if(key == null) throw new NullPointerException(); 457 | ehcache.acquireWriteLockOnKey(key); 458 | try { 459 | Element previousElement; 460 | previousElement = ehcache.get(key); 461 | removeAndWriteIfNeeded(key); 462 | return previousElement == null ? null : (V) previousElement.getObjectValue(); 463 | } finally { 464 | ehcache.releaseWriteLockOnKey(key); 465 | } 466 | } 467 | 468 | @Override 469 | public boolean replace(final K key, final V oldValue, final V newValue) { 470 | checkNotClosed(); 471 | if(key == null) throw new NullPointerException(); 472 | if(oldValue == null) throw new NullPointerException(); 473 | if(newValue == null) throw new NullPointerException(); 474 | final Element element = new Element(key, newValue); 475 | ehcache.acquireWriteLockOnKey(key); 476 | try { 477 | final Element current = ehcache.get(key); 478 | if(current != null) { 479 | if(!current.getObjectValue().equals(oldValue)) { 480 | final Duration expiryForAccess = cfg.getExpiryPolicy().getExpiryForAccess(); 481 | if(expiryForAccess != null && expiryForAccess.isZero()) { 482 | ehcache.remove(key); 483 | } 484 | } else { 485 | final Duration expiry = cfg.getExpiryPolicy().getExpiryForUpdate(); 486 | if(setTimeTo(cfg.overrideDefaultExpiry(), expiry, element)) { 487 | ehcache.put(new Element(key, newValue)); 488 | return true; 489 | } else { 490 | ehcache.remove(key); 491 | } 492 | } 493 | } 494 | } finally { 495 | ehcache.releaseWriteLockOnKey(key); 496 | } 497 | return false; 498 | } 499 | 500 | @Override 501 | public boolean replace(final K key, final V value) { 502 | checkNotClosed(); 503 | if(key == null) throw new NullPointerException(); 504 | if(value == null) throw new NullPointerException(); 505 | ehcache.acquireWriteLockOnKey(key); 506 | try { 507 | final Element element = new Element(key, value); 508 | final Duration expiry; 509 | final boolean inCache = ehcache.isKeyInCache(key); 510 | if(inCache) { 511 | ehcache.get(key); 512 | expiry = cfg.getExpiryPolicy().getExpiryForUpdate(); 513 | if (setTimeTo(cfg.overrideDefaultExpiry(), expiry, element)) { 514 | putAndWriteIfNeeded(element); 515 | return true; 516 | } else { 517 | removeAndWriteIfNeeded(key); 518 | } 519 | return true; 520 | } 521 | ehcache.get(NOT_THERE); 522 | return false; 523 | } finally { 524 | ehcache.releaseWriteLockOnKey(key); 525 | } 526 | } 527 | 528 | @Override 529 | public V getAndReplace(final K key, final V value) { 530 | checkNotClosed(); 531 | if(key == null) throw new NullPointerException(); 532 | if(value == null) throw new NullPointerException(); 533 | ehcache.acquireWriteLockOnKey(key); 534 | try { 535 | Duration expiry; 536 | final Element previous = ehcache.get(key); 537 | if(previous != null) { 538 | expiry = cfg.getExpiryPolicy().getExpiryForUpdate(); 539 | final Element element = new Element(key, value); 540 | if (setTimeTo(cfg.overrideDefaultExpiry(), expiry, element)) { 541 | putAndWriteIfNeeded(element); 542 | return (V)previous.getObjectValue(); 543 | } 544 | } 545 | return null; 546 | } finally { 547 | ehcache.releaseWriteLockOnKey(key); 548 | } 549 | } 550 | 551 | @Override 552 | public void removeAll(final Set keys) { 553 | checkNotClosed(); 554 | if(keys == null) throw new NullPointerException(); 555 | for (K key : keys) { 556 | if(key == null) 557 | throw new NullPointerException(); 558 | } 559 | checkNotClosed(); 560 | if(cfg.isWriteThrough()) { 561 | for (K key : keys) { 562 | ehcache.acquireWriteLockOnKey(key); 563 | try { 564 | final Element previous = ehcache.getQuiet(key); 565 | try { 566 | ehcache.removeWithWriter(key); 567 | } catch (RuntimeException e) { 568 | if(previous != null) { 569 | ehcache.putQuiet(previous); 570 | } 571 | throw new CacheWriterException(e); 572 | } 573 | } finally { 574 | ehcache.releaseWriteLockOnKey(key); 575 | } 576 | } 577 | } else { 578 | if (cfg.isStatisticsEnabled()) { 579 | for (K key : keys) { 580 | if (ehcache.isKeyInCache(key)) { 581 | ehcache.remove(key); 582 | } 583 | } 584 | } else { 585 | ehcache.removeAll(keys); 586 | } 587 | } 588 | } 589 | 590 | @Override 591 | public void removeAll() { 592 | checkNotClosed(); 593 | if (cfg.isWriteThrough()) { 594 | for (Object key : ehcache.getKeys()) { 595 | ehcache.acquireWriteLockOnKey(key); 596 | final Element previous = ehcache.getQuiet(key); 597 | try { 598 | try { 599 | ehcache.removeWithWriter(key); 600 | } catch (RuntimeException e) { 601 | if(previous != null) { 602 | ehcache.putQuiet(previous); 603 | } 604 | throw new CacheWriterException(e); 605 | } 606 | } finally { 607 | ehcache.releaseWriteLockOnKey(key); 608 | } 609 | } 610 | } else { 611 | if (cfg.isStatisticsEnabled()) { 612 | for (Object o : ehcache.getKeys()) { 613 | final Element element = ehcache.getQuiet(o); 614 | if(element != null) { 615 | if(element.getTimeToLive() == 1 && element.getTimeToIdle() == 0) { 616 | ehcache.removeQuiet(element.getObjectKey()); 617 | } else { 618 | ehcache.remove(element.getObjectKey()); 619 | } 620 | } 621 | } 622 | } else { 623 | ehcache.removeAll(); 624 | } 625 | } 626 | } 627 | 628 | @Override 629 | public void clear() { 630 | checkNotClosed(); 631 | ehcache.removeAll(); 632 | } 633 | 634 | @Override 635 | public > C getConfiguration(final Class clazz) { 636 | if(clazz.isAssignableFrom(cfg.getClass())) { 637 | return clazz.cast(cfg); 638 | } 639 | return null; 640 | } 641 | 642 | @Override 643 | public T invoke(final K key, final EntryProcessor entryProcessor, final Object... arguments) throws EntryProcessorException { 644 | checkNotClosed(); 645 | if(key == null) { 646 | throw new NullPointerException(); 647 | } 648 | if(entryProcessor == null) { 649 | throw new NullPointerException(); 650 | } 651 | final T outcome; 652 | ehcache.acquireWriteLockOnKey(key); 653 | try { 654 | Element element = ehcache.get(key); 655 | try { 656 | boolean fromLoader = false; 657 | if(element == null) { 658 | if(cfg.isReadThrough() && load(key) != null) { 659 | element = ehcache.get(key); 660 | fromLoader = true; 661 | } 662 | } 663 | final JMutableEntry entry = new JMutableEntry(this, element, key, fromLoader); 664 | outcome = entryProcessor.process(entry, arguments); 665 | entry.apply(this); 666 | } catch (RuntimeException t) { 667 | if(t instanceof CacheException) { 668 | throw t; 669 | } 670 | throw new EntryProcessorException(t); 671 | } 672 | } finally { 673 | ehcache.releaseWriteLockOnKey(key); 674 | } 675 | return outcome; 676 | } 677 | 678 | @Override 679 | public Map> invokeAll(final Set keys, final EntryProcessor entryProcessor, final Object... arguments) { 680 | checkNotClosed(); 681 | if(entryProcessor == null) { 682 | throw new NullPointerException(); 683 | } 684 | final Map> results = new HashMap>(); 685 | for (K key : keys) { 686 | final T result = invoke(key, entryProcessor, arguments); 687 | if(result != null) { 688 | results.put(key, new EntryProcessorResult() { 689 | @Override 690 | public T get() throws EntryProcessorException { 691 | return result; 692 | } 693 | }); 694 | } 695 | } 696 | return results; 697 | } 698 | 699 | @Override 700 | public String getName() { 701 | return ehcache.getName(); 702 | } 703 | 704 | @Override 705 | public CacheManager getCacheManager() { 706 | checkNotClosed(); 707 | return cacheManager; 708 | } 709 | 710 | @Override 711 | public void close() { 712 | cacheManager.shutdown(this); 713 | } 714 | 715 | void shutdown() { 716 | closed = true; 717 | ehcache.dispose(); 718 | } 719 | 720 | @Override 721 | public boolean isClosed() { 722 | return closed; 723 | } 724 | 725 | @Override 726 | public T unwrap(final Class clazz) { 727 | if(clazz.isAssignableFrom(ehcache.getClass())) { 728 | return clazz.cast(ehcache); 729 | } 730 | if(clazz.isAssignableFrom(getClass())) { 731 | return clazz.cast(this); 732 | } 733 | return null; 734 | } 735 | 736 | @Override 737 | public void registerCacheEntryListener(final CacheEntryListenerConfiguration cacheEntryListenerConfiguration) { 738 | final Factory> factory = cacheEntryListenerConfiguration.getCacheEntryListenerFactory(); 739 | final CacheEntryListener cacheEntryListener = factory.create(); 740 | final JCacheListenerAdapter cacheEventListener = new JCacheListenerAdapter(cacheEntryListener, this, cacheEntryListenerConfiguration); 741 | if(cfg.addCacheEntryListenerConfiguration(cacheEntryListenerConfiguration, cacheEventListener)) { 742 | ehcache.getCacheEventNotificationService().registerListener(cacheEventListener); 743 | } else { 744 | throw new IllegalArgumentException(); 745 | } 746 | } 747 | 748 | @Override 749 | public void deregisterCacheEntryListener(final CacheEntryListenerConfiguration cacheEntryListenerConfiguration) { 750 | JCacheListenerAdapter adapter = cfg.removeCacheEntryListenerConfiguration(cacheEntryListenerConfiguration); 751 | if(adapter != null) { 752 | ehcache.getCacheEventNotificationService().unregisterListener(adapter); 753 | } 754 | } 755 | 756 | @Override 757 | public Iterator> iterator() { 758 | checkNotClosed(); 759 | return new JEntryIterator(this); 760 | } 761 | 762 | private void checkNotClosed() { 763 | if(closed) throw new IllegalStateException(); 764 | } 765 | 766 | private static class JEntryIterator implements Iterator> { 767 | private final Iterator keyIterator; 768 | private final JCache jCache; 769 | private Entry next; 770 | private Entry current; 771 | 772 | public JEntryIterator(final JCache jCache) { 773 | this.jCache = jCache; 774 | this.keyIterator = jCache.ehcache.getKeys().iterator(); 775 | advance(); 776 | } 777 | 778 | @Override 779 | public boolean hasNext() { 780 | return next != null; 781 | } 782 | 783 | @Override 784 | public Entry next() { 785 | if(next == null) { 786 | throw new NoSuchElementException(); 787 | } 788 | current = next; 789 | final Duration expiryForAccess = jCache.cfg.getExpiryPolicy().getExpiryForAccess(); 790 | advance(); 791 | if(expiryForAccess != null && expiryForAccess.isZero()) { 792 | remove(); 793 | } 794 | return current; 795 | } 796 | 797 | @Override 798 | public void remove() { 799 | if(current == null) { 800 | throw new IllegalStateException(); 801 | } 802 | jCache.ehcache.acquireWriteLockOnKey(current.getKey()); 803 | try { 804 | final Element element = jCache.ehcache.getQuiet(current.getKey()); 805 | if(element != null && element.getObjectValue().equals(current.getValue())) { 806 | jCache.removeAndWriteIfNeeded(current.getKey()); 807 | } 808 | } finally { 809 | jCache.ehcache.releaseWriteLockOnKey(current.getKey()); 810 | } 811 | } 812 | 813 | private void advance() { 814 | next = null; 815 | while(keyIterator.hasNext() && next == null) { 816 | Element e = jCache.getElement(keyIterator.next()); 817 | if(e != null) { 818 | next = new JCacheEntry(e, jCache.cfg.getKeyType(), jCache.cfg.getValueType()); 819 | } 820 | } 821 | } 822 | } 823 | 824 | private static class JMutableEntry implements MutableEntry { 825 | private final JCache jCache; 826 | private final K key; 827 | private final boolean fromLoader; 828 | private final V initialValue; 829 | private volatile V newValue; 830 | private volatile boolean updated; 831 | private volatile boolean deleted; 832 | private volatile boolean skipDelete; 833 | 834 | public JMutableEntry(final JCache jCache, final Element element, final K key, final boolean fromLoader) { 835 | this.jCache = jCache; 836 | this.key = key; 837 | this.fromLoader = fromLoader; 838 | if (element != null) { 839 | initialValue = (V)element.getObjectValue(); 840 | } else { 841 | initialValue = null; 842 | } 843 | newValue = initialValue; 844 | } 845 | 846 | @Override 847 | public boolean exists() { 848 | return !deleted && newValue != null; 849 | } 850 | 851 | @Override 852 | public void remove() { 853 | skipDelete = initialValue == null && newValue != null; 854 | newValue = null; 855 | deleted = true; 856 | updated = false; 857 | } 858 | 859 | @Override 860 | public void setValue(final V value) { 861 | if(value == null) { 862 | throw new EntryProcessorException(); 863 | } 864 | deleted = false; 865 | updated = true; 866 | newValue = value; 867 | } 868 | 869 | @Override 870 | public K getKey() { 871 | return key; 872 | } 873 | 874 | @Override 875 | public V getValue() { 876 | if(newValue != initialValue) return newValue; 877 | if (initialValue != null && !fromLoader) { 878 | final Duration expiryForAccess = jCache.cfg.getExpiryPolicy().getExpiryForAccess(); 879 | if (expiryForAccess != null && expiryForAccess.isZero()) { 880 | remove(); 881 | } 882 | } 883 | return initialValue; 884 | } 885 | 886 | @Override 887 | public T unwrap(final Class clazz) { 888 | throw new UnsupportedOperationException("Implement me!"); 889 | } 890 | 891 | void apply(final JCache jCache) { 892 | if(deleted && !skipDelete) { 893 | jCache.remove(key); 894 | } 895 | if(updated && newValue != null) { 896 | jCache.put(key, newValue); 897 | } 898 | } 899 | } 900 | } 901 | -------------------------------------------------------------------------------- /ehcache-jcache/src/main/java/org/ehcache/jcache/JCacheCacheWriterAdapter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2003-2010 Terracotta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.ehcache.jcache; 17 | 18 | import net.sf.ehcache.CacheEntry; 19 | import net.sf.ehcache.CacheException; 20 | import net.sf.ehcache.Ehcache; 21 | import net.sf.ehcache.Element; 22 | import net.sf.ehcache.writer.CacheWriter; 23 | import net.sf.ehcache.writer.writebehind.operations.SingleOperationType; 24 | 25 | import javax.cache.Cache; 26 | import java.util.Collection; 27 | import java.util.HashSet; 28 | import java.util.Set; 29 | 30 | /** 31 | * Adapt a {@link javax.cache.integration.CacheWriter} to the interface of {@link net.sf.ehcache.writer.CacheWriter} 32 | * 33 | * @param the type of keys used by this JCacheCacheLoaderAdapter 34 | * @param the type of values that are loaded by this JCacheCacheLoaderAdapter 35 | * @author Ryan Gardner 36 | * @since 1.4.0-beta1 37 | */ 38 | class JCacheCacheWriterAdapter implements CacheWriter { 39 | private final javax.cache.integration.CacheWriter jsr107CacheWriter; 40 | private final Class keyType; 41 | private final Class valueType; 42 | 43 | /** 44 | * Construct a JCacheCacheWriterAdapter to adapt the {@code jsr107CacheWriter} to the 45 | * {@link CacheWriter} interface 46 | * 47 | * @param jsr107CacheWriter the {@link CacheWriter to adapt} 48 | */ 49 | public JCacheCacheWriterAdapter(javax.cache.integration.CacheWriter jsr107CacheWriter, Class keyType, Class valueType) { 50 | this.jsr107CacheWriter = jsr107CacheWriter; 51 | this.keyType = keyType; 52 | this.valueType = valueType; 53 | } 54 | 55 | /** 56 | * {@inheritDoc} 57 | * 58 | * Creates a clone of this writer. This method will only be called by ehcache before a 59 | * cache is initialized. 60 | *
61 | * Implementations should throw CloneNotSupportedException if they do not support clone 62 | * but that will stop them from being used with defaultCache. 63 | */ 64 | public CacheWriter clone(Ehcache cache) throws CloneNotSupportedException { 65 | return (JCacheCacheWriterAdapter) super.clone(); 66 | } 67 | 68 | /** 69 | * Notifies writer to initialise themselves. 70 | *
71 | * This method is called during the Cache's initialise method after it has changed it's 72 | * status to alive. Cache operations are legal in this method. If you register a cache writer 73 | * manually after a cache has been initialised already, this method will be called on the 74 | * cache writer as soon as it has been registered. 75 | *
76 | * Note that if you reuse cache writer instances or create a factory that returns the 77 | * same cache writer instance as a singleton, your {@code init} method should be able 78 | * to handle that situation. Unless you perform this multiple usage of a cache writer yourself, 79 | * Ehcache will not do this though. So in the majority of the use cases, you don't need to do 80 | * anything special. 81 | * 82 | * @throws net.sf.ehcache.CacheException 83 | */ 84 | public void init() { 85 | 86 | } 87 | 88 | /** 89 | * Providers may be doing all sorts of exotic things and need to be able to clean up on 90 | * dispose. 91 | *
92 | * Cache operations are illegal when this method is called. The cache itself is partly 93 | * disposed when this method is called. 94 | * 95 | * @throws net.sf.ehcache.CacheException if any. 96 | */ 97 | public void dispose() throws CacheException { 98 | 99 | } 100 | 101 | /** 102 | * {@inheritDoc} 103 | * 104 | * Write the specified value under the specified key to the underlying store. 105 | * This method is intended to support both key/value creation and value update for a specific key. 106 | */ 107 | public void write(Element element) throws CacheException { 108 | jsr107CacheWriter.write(new JCacheEntry(element, keyType, valueType)); 109 | } 110 | 111 | /** 112 | * {@inheritDoc} 113 | * 114 | * Write the specified Elements to the underlying store. This method is intended to support both insert and update. 115 | * If this operation fails (by throwing an exception) after a partial success, 116 | * the convention is that entries which have been written successfully are to be removed from the specified mapEntries, 117 | * indicating that the write operation for the entries left in the map has failed or has not been attempted. 118 | */ 119 | public void writeAll(Collection elements) throws CacheException { 120 | Collection> javaxCacheEntries = new HashSet>(); 121 | for (Element e : elements) { 122 | javaxCacheEntries.add(new JCacheEntry(e, keyType, valueType)); 123 | } 124 | jsr107CacheWriter.writeAll(javaxCacheEntries); 125 | } 126 | 127 | /** 128 | * {@inheritDoc} 129 | * 130 | * Delete the cache entry from the store 131 | */ 132 | public void delete(CacheEntry entry) throws CacheException { 133 | jsr107CacheWriter.delete(entry.getKey()); 134 | } 135 | 136 | /** 137 | * {@inheritDoc} 138 | * 139 | * Remove data and keys from the underlying store for the given collection of keys, if present. If this operation fails 140 | * (by throwing an exception) after a partial success, the convention is that keys which have been erased successfully 141 | * are to be removed from the specified keys, indicating that the erase operation for the keys left in the collection 142 | * has failed or has not been attempted. 143 | */ 144 | public void deleteAll(Collection entries) throws CacheException { 145 | Set> javaxCacheEntries = new HashSet>(); 146 | for (CacheEntry e : entries) { 147 | javaxCacheEntries.add(new JCacheEntry(e.getElement(), keyType, valueType)); 148 | } 149 | jsr107CacheWriter.deleteAll(javaxCacheEntries); 150 | } 151 | 152 | /** 153 | * {@inheritDoc} 154 | * 155 | * This method will be called, whenever an Element couldn't be handled by the writer and all 156 | * the {@link net.sf.ehcache.config.CacheWriterConfiguration#getRetryAttempts() retryAttempts} have been tried. 157 | *

When batching is enabled all the elements in the failing batch will be passed to this methods 158 | *

Try to not throw RuntimeExceptions from this method. Should an Exception occur, it will be logged, but 159 | * the element will be lost anyways. 160 | */ 161 | @Override 162 | public void throwAway(Element element, SingleOperationType operationType, RuntimeException e) { 163 | 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /ehcache-jcache/src/main/java/org/ehcache/jcache/JCacheCachingProvider.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2003-2010 Terracotta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.ehcache.jcache; 17 | 18 | import net.sf.ehcache.Ehcache; 19 | import net.sf.ehcache.config.Configuration; 20 | import net.sf.ehcache.config.ConfigurationFactory; 21 | 22 | import java.net.MalformedURLException; 23 | import java.net.URI; 24 | import java.net.URISyntaxException; 25 | import java.net.URL; 26 | import java.util.Map; 27 | import java.util.Properties; 28 | import java.util.WeakHashMap; 29 | import java.util.concurrent.ConcurrentHashMap; 30 | import java.util.concurrent.ConcurrentMap; 31 | 32 | import javax.cache.CacheManager; 33 | import javax.cache.configuration.OptionalFeature; 34 | import javax.cache.spi.CachingProvider; 35 | 36 | 37 | /** 38 | * A JSR107 adapter for EHCache. 39 | *
40 | * 41 | * @author Ryan Gardner 42 | * @since 1.4.0-beta1 43 | */ 44 | public class JCacheCachingProvider implements CachingProvider { 45 | 46 | private static final URI URI_DEFAULT; 47 | 48 | private final Map> cacheManagers = new WeakHashMap>(); 49 | 50 | static { 51 | URI uri; 52 | try { 53 | URL resource = JCacheCachingProvider.class.getResource("/ehcache.xml"); 54 | if(resource == null) { 55 | resource = Ehcache.class.getResource("/ehcache-failsafe.xml"); 56 | } 57 | uri = new URI(resource.toString()); 58 | } catch (URISyntaxException e) { 59 | uri = null; 60 | } 61 | URI_DEFAULT = uri; 62 | } 63 | 64 | 65 | @Override 66 | public CacheManager getCacheManager() { 67 | return getCacheManager(getDefaultURI(), getDefaultClassLoader()); 68 | } 69 | 70 | @Override 71 | public CacheManager getCacheManager(final URI uri, final ClassLoader classLoader) { 72 | return getCacheManager(uri, classLoader, null); 73 | } 74 | 75 | @Override 76 | public CacheManager getCacheManager(URI uri, ClassLoader classLoader, Properties properties) { 77 | uri = uri == null ? getDefaultURI() : uri; 78 | classLoader = classLoader == null ? getDefaultClassLoader() : classLoader; 79 | properties = new Properties(properties); 80 | 81 | JCacheManager cacheManager; 82 | final URL configurationURL; 83 | try { 84 | configurationURL = uri.toURL(); 85 | } catch (MalformedURLException e) { 86 | throw new RuntimeException(e); 87 | } 88 | ConcurrentMap byURI; 89 | synchronized (cacheManagers) { 90 | byURI = cacheManagers.get(classLoader); 91 | if(byURI == null) { 92 | byURI = new ConcurrentHashMap(); 93 | cacheManagers.put(classLoader, byURI); 94 | } 95 | cacheManager = byURI.get(uri); 96 | if(cacheManager == null) { 97 | final Configuration configuration = ConfigurationFactory.parseConfiguration(configurationURL); 98 | if(configuration.getName() == null) { 99 | configuration.setName(uri.toString() + "::" + classLoader.toString() + "::" + this.toString()); 100 | } 101 | configuration.setClassLoader(classLoader); 102 | final net.sf.ehcache.CacheManager ehcacheManager = new net.sf.ehcache.CacheManager(configuration); 103 | cacheManager = new JCacheManager(this, ehcacheManager, uri, properties); 104 | byURI.put(uri, cacheManager); 105 | } 106 | } 107 | return cacheManager; 108 | } 109 | 110 | @Override 111 | public ClassLoader getDefaultClassLoader() { 112 | return getClass().getClassLoader(); 113 | } 114 | 115 | @Override 116 | public URI getDefaultURI() { 117 | return URI_DEFAULT; 118 | } 119 | 120 | @Override 121 | public Properties getDefaultProperties() { 122 | throw new UnsupportedOperationException("Implement me!"); 123 | } 124 | 125 | @Override 126 | public void close() { 127 | synchronized (cacheManagers) { 128 | for (Map.Entry> entry : cacheManagers.entrySet()) { 129 | for (JCacheManager jCacheManager : entry.getValue().values()) { 130 | jCacheManager.close(); 131 | } 132 | } 133 | cacheManagers.clear(); 134 | } 135 | } 136 | 137 | @Override 138 | public void close(final ClassLoader classLoader) { 139 | synchronized (cacheManagers) { 140 | final ConcurrentMap map = cacheManagers.remove(classLoader); 141 | if(map != null) { 142 | for (JCacheManager cacheManager : map.values()) { 143 | cacheManager.shutdown(); 144 | } 145 | } 146 | } 147 | } 148 | 149 | @Override 150 | public void close(final URI uri, final ClassLoader classLoader) { 151 | synchronized (cacheManagers) { 152 | final ConcurrentMap map = cacheManagers.get(classLoader); 153 | if(map != null) { 154 | final JCacheManager jCacheManager = map.remove(uri); 155 | if(jCacheManager != null) { 156 | jCacheManager.shutdown(); 157 | } 158 | } 159 | } 160 | } 161 | 162 | @Override 163 | public boolean isSupported(final OptionalFeature optionalFeature) { 164 | return optionalFeature == OptionalFeature.STORE_BY_REFERENCE; 165 | } 166 | 167 | void shutdown(final JCacheManager jCacheManager) { 168 | synchronized (cacheManagers) { 169 | final ConcurrentMap map = cacheManagers.get(jCacheManager.getClassLoader()); 170 | if(map != null && map.remove(jCacheManager.getURI()) != null) { 171 | jCacheManager.shutdown(); 172 | } 173 | } 174 | } 175 | 176 | } 177 | -------------------------------------------------------------------------------- /ehcache-jcache/src/main/java/org/ehcache/jcache/JCacheConfiguration.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2003-2010 Terracotta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.ehcache.jcache; 17 | 18 | import net.sf.ehcache.config.CacheConfiguration; 19 | 20 | import java.util.Collections; 21 | import java.util.HashSet; 22 | import java.util.Set; 23 | import java.util.concurrent.ConcurrentHashMap; 24 | import java.util.concurrent.ConcurrentMap; 25 | import java.util.concurrent.TimeUnit; 26 | 27 | import javax.cache.configuration.CacheEntryListenerConfiguration; 28 | import javax.cache.configuration.CompleteConfiguration; 29 | import javax.cache.configuration.Configuration; 30 | import javax.cache.configuration.Factory; 31 | import javax.cache.configuration.FactoryBuilder; 32 | import javax.cache.expiry.Duration; 33 | import javax.cache.expiry.EternalExpiryPolicy; 34 | import javax.cache.expiry.ExpiryPolicy; 35 | import javax.cache.integration.CacheLoader; 36 | import javax.cache.integration.CacheWriter; 37 | 38 | /** 39 | * Configuration for a JSR107 Cache 40 | * 41 | * @author Ryan Gardner 42 | * @since 1.4.0-beta1 43 | */ 44 | public class JCacheConfiguration implements javax.cache.configuration.CompleteConfiguration { 45 | 46 | private final Class keyType; 47 | private final Class valueType; 48 | private final ExpiryPolicy expiryPolicy; 49 | private final ConcurrentMap, JCacheListenerAdapter> cacheEntryListenerConfigurations = new ConcurrentHashMap, JCacheListenerAdapter>(); 50 | private final boolean storeByValue; 51 | private final boolean readThrough; 52 | private final boolean writeThrough; 53 | private final Factory> cacheLoaderFactory; 54 | private final Factory> cacheWristerFactory; 55 | private final Factory expiryPolicyFactory; 56 | private final boolean useJCacheExpiry; 57 | private final Set> initialCacheEntryListenerConfigurations; 58 | 59 | private boolean statisticsEnabled; 60 | private boolean managementEnabled; 61 | 62 | public JCacheConfiguration(final CacheConfiguration cacheConfiguration, final Configuration configuration, final Class keyType, final Class valueType) { 63 | this.keyType = keyType; 64 | this.valueType = valueType; 65 | if (configuration instanceof CompleteConfiguration) { 66 | CompleteConfiguration cConfiguration = (CompleteConfiguration) configuration; 67 | Factory expiryPolicyFactory = cConfiguration.getExpiryPolicyFactory(); 68 | this.expiryPolicy = expiryPolicyFactory.create(); 69 | storeByValue = configuration.isStoreByValue(); 70 | readThrough = cConfiguration.isReadThrough(); 71 | writeThrough = cConfiguration.isWriteThrough(); 72 | statisticsEnabled = cConfiguration.isStatisticsEnabled(); 73 | managementEnabled = cConfiguration.isManagementEnabled(); 74 | cacheLoaderFactory = cConfiguration.getCacheLoaderFactory(); 75 | cacheWristerFactory = cConfiguration.getCacheWriterFactory(); 76 | this.expiryPolicyFactory = cConfiguration.getExpiryPolicyFactory(); 77 | useJCacheExpiry = this.expiryPolicyFactory != null; 78 | final HashSet> set = new HashSet>(); 79 | for (CacheEntryListenerConfiguration kvCacheEntryListenerConfiguration : cConfiguration.getCacheEntryListenerConfigurations()) { 80 | set.add(kvCacheEntryListenerConfiguration); 81 | } 82 | initialCacheEntryListenerConfigurations = Collections.unmodifiableSet(set); 83 | } else { 84 | if (cacheConfiguration == null) { 85 | expiryPolicyFactory = EternalExpiryPolicy.factoryOf(); 86 | useJCacheExpiry = true; 87 | expiryPolicy = expiryPolicyFactory.create(); 88 | storeByValue = true; 89 | readThrough = false; 90 | writeThrough = false; 91 | cacheLoaderFactory = null; 92 | cacheWristerFactory = null; 93 | initialCacheEntryListenerConfigurations = new HashSet>(); 94 | } else { 95 | if (cacheConfiguration.isEternal()) { 96 | expiryPolicy = EternalExpiryPolicy.factoryOf().create(); 97 | } else { 98 | expiryPolicy = new ExpiryPolicy() { 99 | @Override 100 | public Duration getExpiryForCreation() { 101 | return new Duration(TimeUnit.SECONDS, cacheConfiguration.getTimeToLiveSeconds()); 102 | } 103 | 104 | @Override 105 | public Duration getExpiryForAccess() { 106 | return new Duration(TimeUnit.SECONDS, cacheConfiguration.getTimeToLiveSeconds()); 107 | } 108 | 109 | @Override 110 | public Duration getExpiryForUpdate() { 111 | return getExpiryForCreation(); 112 | } 113 | }; 114 | } 115 | 116 | expiryPolicyFactory = new FactoryBuilder.SingletonFactory(expiryPolicy); 117 | useJCacheExpiry = false; 118 | storeByValue = false; 119 | readThrough = false; 120 | writeThrough = false; 121 | cacheLoaderFactory = null; 122 | cacheWristerFactory = null; 123 | initialCacheEntryListenerConfigurations = new HashSet>(); 124 | } 125 | } 126 | } 127 | 128 | public JCacheConfiguration(final CacheConfiguration cacheConfiguration) { 129 | this(cacheConfiguration, null, null, null); 130 | } 131 | 132 | public JCacheConfiguration(final Configuration configuration) { 133 | this(null, configuration, configuration.getKeyType(), configuration.getValueType()); 134 | } 135 | 136 | @Override 137 | public Class getKeyType() { 138 | return keyType == null ? (Class)Object.class : keyType; 139 | } 140 | 141 | @Override 142 | public Class getValueType() { 143 | return valueType == null ? (Class)Object.class : valueType; 144 | } 145 | 146 | @Override 147 | public boolean isStoreByValue() { 148 | return storeByValue; 149 | } 150 | 151 | @Override 152 | public boolean isReadThrough() { 153 | return readThrough; 154 | } 155 | 156 | @Override 157 | public boolean isWriteThrough() { 158 | return writeThrough; 159 | } 160 | 161 | @Override 162 | public boolean isStatisticsEnabled() { 163 | return statisticsEnabled; 164 | } 165 | 166 | @Override 167 | public boolean isManagementEnabled() { 168 | return managementEnabled; 169 | } 170 | 171 | @Override 172 | public Iterable> getCacheEntryListenerConfigurations() { 173 | return cacheEntryListenerConfigurations.keySet(); 174 | } 175 | 176 | @Override 177 | public Factory> getCacheLoaderFactory() { 178 | return cacheLoaderFactory; 179 | } 180 | 181 | @Override 182 | public Factory> getCacheWriterFactory() { 183 | return cacheWristerFactory; 184 | } 185 | 186 | @Override 187 | public Factory getExpiryPolicyFactory() { 188 | return expiryPolicyFactory; 189 | } 190 | 191 | public ExpiryPolicy getExpiryPolicy() { 192 | return expiryPolicy; 193 | } 194 | 195 | public boolean addCacheEntryListenerConfiguration(final CacheEntryListenerConfiguration cacheEntryListenerConfiguration, final JCacheListenerAdapter cacheEventListener) { 196 | return cacheEntryListenerConfigurations.putIfAbsent(cacheEntryListenerConfiguration, cacheEventListener) == null; 197 | } 198 | 199 | public JCacheListenerAdapter removeCacheEntryListenerConfiguration(final CacheEntryListenerConfiguration cacheEntryListenerConfiguration) { 200 | return cacheEntryListenerConfigurations.remove(cacheEntryListenerConfiguration); 201 | } 202 | 203 | void setStatisticsEnabled(final boolean statisticsEnabled) { 204 | this.statisticsEnabled = statisticsEnabled; 205 | } 206 | 207 | void setManagementEnabled(final boolean managementEnabled) { 208 | this.managementEnabled = managementEnabled; 209 | } 210 | 211 | public Iterable> getInitialCacheEntryListenerConfigurations() { 212 | return initialCacheEntryListenerConfigurations; 213 | } 214 | 215 | public boolean overrideDefaultExpiry() { 216 | return useJCacheExpiry; 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /ehcache-jcache/src/main/java/org/ehcache/jcache/JCacheCopyOnWriteStrategy.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2003-2010 Terracotta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.ehcache.jcache; 17 | 18 | 19 | import net.sf.ehcache.CacheException; 20 | import net.sf.ehcache.Element; 21 | import net.sf.ehcache.store.compound.ReadWriteCopyStrategy; 22 | 23 | import java.io.ByteArrayInputStream; 24 | import java.io.ByteArrayOutputStream; 25 | import java.io.IOException; 26 | import java.io.InputStream; 27 | import java.io.ObjectInputStream; 28 | import java.io.ObjectOutputStream; 29 | import java.io.ObjectStreamClass; 30 | 31 | /** 32 | * This class provides a copy strategy that is compatible with JSR107's requirement that 33 | * storeByValue caches will store the keys by value as well as the values. 34 | *
35 | * Once ehcache handles these concerns natively, this class will be either deleted or 36 | * deprecated. 37 | *
38 | * (in other words, you should not use this class directly) 39 | *
40 | * (some code was copied from net.sf.ehcache.store.compound.ReadWriteSerializationCopyStrategy which was written by 41 | * 42 | * @author Alex Snaps 43 | * @author Ludovic Orban 44 | * ) 45 | * @author Ryan Gardner 46 | * @since 0.4 47 | */ 48 | class JCacheCopyOnWriteStrategy implements ReadWriteCopyStrategy { 49 | 50 | /** 51 | * {@inheritDoc} 52 | * 53 | * Deep copies some object and returns an internal storage-ready copy 54 | */ 55 | @Override 56 | public Element copyForWrite(final Element value, final ClassLoader classLoader) { 57 | if (value == null) { 58 | return null; 59 | } else { 60 | Object elementValue = value.getObjectValue(); 61 | Object elementKey = value.getObjectKey(); 62 | 63 | Object newKey = toObject(toByteArray(elementKey), classLoader); 64 | Object serializedValue = toObject(toByteArray(elementValue), classLoader); 65 | 66 | return duplicateElementWithNewValue(value, newKey, serializedValue); 67 | } 68 | } 69 | 70 | byte[] toByteArray(Object elementValue) { 71 | ByteArrayOutputStream bout = new ByteArrayOutputStream(); 72 | ObjectOutputStream oos = null; 73 | 74 | try { 75 | oos = new ObjectOutputStream(bout); 76 | oos.writeObject(elementValue); 77 | } catch (Exception e) { 78 | throw new CacheException("When configured copyOnRead or copyOnWrite, a Store will only accept Serializable values", e); 79 | } finally { 80 | try { 81 | if (oos != null) { 82 | oos.close(); 83 | } 84 | } catch (Exception e) { 85 | // 86 | } 87 | } 88 | return bout.toByteArray(); 89 | } 90 | 91 | 92 | /** 93 | * {@inheritDoc} 94 | * 95 | * Reconstruct an object from its storage-ready copy. 96 | */ 97 | @Override 98 | public Element copyForRead(final Element storedValue, final ClassLoader classLoader) { 99 | if (storedValue == null) { 100 | return null; 101 | } else { 102 | Object newKey = toObject(toByteArray(storedValue.getObjectKey()), classLoader); 103 | Object deserializedValue = toObject(toByteArray(storedValue.getObjectValue()), classLoader); 104 | return duplicateElementWithNewValue(storedValue, newKey, deserializedValue); 105 | } 106 | } 107 | 108 | Object toObject(byte[] bytes, ClassLoader loader) { 109 | if (bytes == null) { 110 | return null; 111 | } 112 | ByteArrayInputStream bin = new ByteArrayInputStream(bytes); 113 | ObjectInputStream ois = null; 114 | Object deserializedElement; 115 | try { 116 | ois = new PreferredClassLoaderObjectInputSteam(bin, loader); 117 | deserializedElement = ois.readObject(); 118 | } catch (Exception e) { 119 | throw new CacheException("When configured copyOnRead or copyOnWrite, a Store will only accept Serializable values", e); 120 | } finally { 121 | try { 122 | if (ois != null) { 123 | ois.close(); 124 | } 125 | } catch (Exception e) { 126 | // 127 | } 128 | } 129 | return deserializedElement; 130 | } 131 | 132 | /** 133 | * Make a duplicate of an element but using the specified value 134 | * 135 | * @param element the element to duplicate 136 | * @param newValue the new element's value 137 | * @return the duplicated element 138 | * @see net.sf.ehcache.store.compound.ReadWriteSerializationCopyStrategy#duplicateElementWithNewValue(net.sf.ehcache.Element, Object) 139 | * @since 1.4.0-beta1 140 | */ 141 | Element duplicateElementWithNewValue(final Element element, final Object newKey, final Object newValue) { 142 | return new Element(newKey, newValue, element.getVersion(), 143 | element.getCreationTime(), element.getLastAccessTime(), element.getHitCount(), element.usesCacheDefaultLifespan(), 144 | element.getTimeToLive(), element.getTimeToIdle(), element.getLastUpdateTime()); 145 | } 146 | 147 | /** 148 | * This class provides a way to satisfy the requirements of JSR107 in being able to specify a classloader to deserialize 149 | * objects with 150 | */ 151 | private static class PreferredClassLoaderObjectInputSteam extends ObjectInputStream { 152 | private ClassLoader classLoader; 153 | 154 | /** 155 | * Constructor 156 | * 157 | * @param in the input stream 158 | * @throws IOException if the constructor of ObjectInputStream throws an exception 159 | */ 160 | public PreferredClassLoaderObjectInputSteam(InputStream in, ClassLoader classLoader) throws IOException { 161 | super(in); 162 | this.classLoader = classLoader; 163 | } 164 | 165 | @Override 166 | protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { 167 | 168 | return Class.forName(desc.getName(), false, classLoader); 169 | 170 | } 171 | 172 | } 173 | 174 | } 175 | -------------------------------------------------------------------------------- /ehcache-jcache/src/main/java/org/ehcache/jcache/JCacheEntry.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2003-2010 Terracotta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.ehcache.jcache; 17 | 18 | import net.sf.ehcache.Element; 19 | 20 | import javax.cache.Cache; 21 | 22 | /** 23 | * An implementation of CacheEntry. 24 | *
25 | * A CacheEntry is metadata about an entry in the cache. It does not include the value. 26 | * 27 | * @param the type of keys used by this JCacheEntry 28 | * @param the type of values that are loaded by this JCacheEntry 29 | * @author Greg Luck, Ryan Gardner 30 | * @since 1.4.0-beta1 31 | */ 32 | public class JCacheEntry implements Cache.Entry { 33 | 34 | private final Element element; 35 | private final Class keyType; 36 | private final Class valueType; 37 | 38 | public JCacheEntry(final Element e, final Class keyType, final Class valueType) { 39 | this.element = e; 40 | this.keyType = keyType; 41 | this.valueType = valueType; 42 | } 43 | 44 | @Override 45 | public K getKey() { 46 | if (element != null) { 47 | return keyType.cast(element.getObjectKey()); 48 | } else { 49 | return null; 50 | } 51 | } 52 | 53 | @Override 54 | public V getValue() { 55 | if (element != null) { 56 | return valueType.cast(element.getObjectValue()); 57 | } else { 58 | return null; 59 | } 60 | } 61 | 62 | @Override 63 | public T unwrap(final Class clazz) { 64 | if(clazz.isAssignableFrom(getClass())) { 65 | return clazz.cast(this); 66 | } 67 | if(clazz.isAssignableFrom(Element.class)) { 68 | return clazz.cast(element); 69 | } 70 | throw new IllegalArgumentException(); 71 | } 72 | } 73 | 74 | -------------------------------------------------------------------------------- /ehcache-jcache/src/main/java/org/ehcache/jcache/JCacheEntryEventAdapter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2003-2010 Terracotta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.ehcache.jcache; 17 | 18 | import net.sf.ehcache.Element; 19 | 20 | import javax.cache.configuration.CompleteConfiguration; 21 | import javax.cache.event.CacheEntryEvent; 22 | import javax.cache.event.EventType; 23 | 24 | /** 25 | * Adapt an ehcache event to a JSR107 event 26 | * 27 | * @author Ryan Gardner 28 | * @since 1.4.0-beta1 29 | */ 30 | class JCacheEntryEventAdapter extends CacheEntryEvent { 31 | private final Element element; 32 | private final Class keyType; 33 | private final Class valueType; 34 | 35 | /** 36 | *

Constructor for JCacheEntryEventAdapter.

37 | * 38 | * @param source a {@link JCache} object. 39 | * @param element a {@link net.sf.ehcache.Element} object. 40 | * @param eventType type 41 | */ 42 | public JCacheEntryEventAdapter(JCache source, Element element, final EventType eventType) { 43 | super(source, eventType); 44 | this.element = element; 45 | final CompleteConfiguration cfg = source.getConfiguration(CompleteConfiguration.class); 46 | this.keyType = cfg.getKeyType(); 47 | this.valueType = cfg.getValueType(); 48 | } 49 | 50 | /** {@inheritDoc} */ 51 | @Override 52 | public K getKey() { 53 | return keyType.cast(element.getObjectKey()); 54 | } 55 | 56 | /** {@inheritDoc} */ 57 | @Override 58 | public V getValue() { 59 | return valueType.cast(element.getObjectValue()); 60 | } 61 | 62 | @Override 63 | public T unwrap(final Class clazz) { 64 | if(clazz.isAssignableFrom(this.getClass())) { 65 | return clazz.cast(this); 66 | } else if(clazz.isAssignableFrom(Element.class)) { 67 | return clazz.cast(element); 68 | } 69 | return null; 70 | } 71 | 72 | /** 73 | * Returns the value of the cache entry with the event 74 | * 75 | * @return the value 76 | */ 77 | @Override 78 | public V getOldValue() { 79 | if (isOldValueAvailable()) { 80 | //todo not available in this version of Ehcache return oldValue; 81 | return null; 82 | } else { 83 | throw new UnsupportedOperationException("The old value is not available for key " + getKey()); 84 | } 85 | } 86 | 87 | /** 88 | * Whether the old value is available 89 | * 90 | * @return true if the old value is populated 91 | */ 92 | @Override 93 | public boolean isOldValueAvailable() { 94 | return false; //todo not available in this version of Ehcache 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /ehcache-jcache/src/main/java/org/ehcache/jcache/JCacheListenerAdapter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2003-2010 Terracotta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.ehcache.jcache; 17 | 18 | import net.sf.ehcache.CacheException; 19 | import net.sf.ehcache.Ehcache; 20 | import net.sf.ehcache.Element; 21 | import net.sf.ehcache.event.CacheEventListener; 22 | 23 | import javax.cache.configuration.CacheEntryListenerConfiguration; 24 | import javax.cache.event.CacheEntryCreatedListener; 25 | import javax.cache.event.CacheEntryEventFilter; 26 | import javax.cache.event.CacheEntryExpiredListener; 27 | import javax.cache.event.CacheEntryListener; 28 | import javax.cache.event.CacheEntryRemovedListener; 29 | import javax.cache.event.CacheEntryUpdatedListener; 30 | import javax.cache.event.EventType; 31 | 32 | import java.util.ArrayList; 33 | 34 | 35 | /** 36 | * Adapt a {@link CacheEntryListener} to the {@link CacheEventListener} interface 37 | * 38 | * @param the type of keys used by this JCacheListenerAdapter 39 | * @param the type of values that are loaded by this JCacheListenerAdapter 40 | * @author Ryan Gardner 41 | * @since 1.4.0-beta1 42 | */ 43 | public class JCacheListenerAdapter implements CacheEventListener { 44 | private final CacheEntryListener cacheListener; 45 | private final CacheEntryEventFilter cacheEntryEventFilter; 46 | private final JCache jCache; 47 | private final boolean removedListener; 48 | private final boolean createdListener; 49 | private final boolean updatedListener; 50 | private final boolean expiredListener; 51 | private final boolean oldValueRequired; 52 | private final boolean synchronous; 53 | 54 | /** 55 | * Construct an adapter that wraps the {@code cacheListener} to be used by Ehcache 56 | *
57 | * The interfaces of {@link CacheEntryListener} are more fine-grained than the 58 | * CacheEntryListener interface - and may only implement one or more of the following 59 | * sub-interfaces: 60 | * {@link CacheEntryRemovedListener} 61 | * {@link CacheEntryCreatedListener} 62 | * {@link CacheEntryUpdatedListener} 63 | * {@link CacheEntryExpiredListener} 64 | *
65 | * When this constructor is called, the {@code cacheListener} will be inspected 66 | * and based upon which sub-interfaces of CacheEntryListener the {@code cacheListener} 67 | * implements, listeners on the corresponding EHCache events will be adapted to it. 68 | *
69 | * It is expected that the EventListener model of JSR107 will change, so this class 70 | * will likely be refactored several times before the final release of JSR107. 71 | * 72 | * @param cacheListener the cacheListener to wrap 73 | * @param jCache 74 | * @param cacheEntryListenerConfiguration 75 | */ 76 | public JCacheListenerAdapter(CacheEntryListener cacheListener, final JCache jCache, 77 | final CacheEntryListenerConfiguration cacheEntryListenerConfiguration) { 78 | this.cacheListener = cacheListener; 79 | this.jCache = jCache; 80 | removedListener = implementsMethods(CacheEntryRemovedListener.class); 81 | createdListener = implementsMethods(CacheEntryCreatedListener.class); 82 | updatedListener = implementsMethods(CacheEntryUpdatedListener.class); 83 | expiredListener = implementsMethods(CacheEntryExpiredListener.class); 84 | oldValueRequired = cacheEntryListenerConfiguration.isOldValueRequired(); 85 | synchronous = cacheEntryListenerConfiguration.isSynchronous(); 86 | if(cacheEntryListenerConfiguration.getCacheEntryEventFilterFactory() != null) { 87 | cacheEntryEventFilter = cacheEntryListenerConfiguration.getCacheEntryEventFilterFactory().create(); 88 | } else { 89 | cacheEntryEventFilter = null; 90 | } 91 | } 92 | 93 | private boolean implementsMethods(Class cls) { 94 | return cls.isAssignableFrom(cacheListener.getClass()); 95 | } 96 | 97 | /** 98 | * {@inheritDoc} 99 | * 100 | * Called immediately after an attempt to remove an element. The remove method will block until 101 | * this method returns. 102 | *
103 | * This notification is received regardless of whether the cache had an element matching 104 | * the removal key or not. If an element was removed, the element is passed to this method, 105 | * otherwise a synthetic element, with only the key set is passed in. 106 | *
107 | * This notification is not called for the following special cases: 108 | *
    109 | *
  1. removeAll was called. See {@link #notifyRemoveAll(net.sf.ehcache.Ehcache)} 110 | *
  2. An element was evicted from the cache. 111 | * See {@link #notifyElementEvicted(net.sf.ehcache.Ehcache, net.sf.ehcache.Element)} 112 | *
113 | */ 114 | @Override 115 | public void notifyElementRemoved(Ehcache cache, Element element) throws CacheException { 116 | if (removedListener) { 117 | final JCacheEntryEventAdapter e = new JCacheEntryEventAdapter(jCache, element, EventType.REMOVED); 118 | if (evaluate(e)) { 119 | ArrayList arrayList = new ArrayList(); 120 | arrayList.add(e); 121 | if (element != null) { 122 | ((CacheEntryRemovedListener) cacheListener) 123 | .onRemoved( 124 | arrayList 125 | ); 126 | } 127 | } 128 | } 129 | } 130 | 131 | /** 132 | * {@inheritDoc} 133 | * 134 | * Called immediately after an element has been put into the cache. The 135 | * {@link net.sf.ehcache.Cache#put(net.sf.ehcache.Element)} method 136 | * will block until this method returns. 137 | *
138 | * Implementers may wish to have access to the Element's fields, including value, so the 139 | * element is provided. Implementers should be careful not to modify the element. The 140 | * effect of any modifications is undefined. 141 | */ 142 | @Override 143 | public void notifyElementPut(Ehcache cache, Element element) throws CacheException { 144 | if (createdListener) { 145 | final JCacheEntryEventAdapter e = new JCacheEntryEventAdapter(jCache, element, EventType.CREATED); 146 | if (evaluate(e)) { 147 | ArrayList arrayList = new ArrayList(); 148 | arrayList.add(e); 149 | if (element != null) { 150 | ((CacheEntryCreatedListener)cacheListener) 151 | .onCreated( 152 | arrayList 153 | ); 154 | } 155 | } 156 | } 157 | } 158 | 159 | /** 160 | * {@inheritDoc} 161 | * 162 | * Called immediately after an element has been put into the cache and the element already 163 | * existed in the cache. This is thus an update. 164 | *
165 | * The {@link net.sf.ehcache.Cache#put(net.sf.ehcache.Element)} method 166 | * will block until this method returns. 167 | *
168 | * Implementers may wish to have access to the Element's fields, including value, so the 169 | * element is provided. Implementers should be careful not to modify the element. The 170 | * effect of any modifications is undefined. 171 | */ 172 | @Override 173 | public void notifyElementUpdated(Ehcache cache, Element element) throws CacheException { 174 | if (updatedListener) { 175 | final JCacheEntryEventAdapter e = new JCacheEntryEventAdapter(jCache, element, EventType.UPDATED); 176 | if (evaluate(e)) { 177 | ArrayList arrayList = new ArrayList(); 178 | arrayList.add(e); 179 | if (element != null) { 180 | ((CacheEntryUpdatedListener)cacheListener) 181 | .onUpdated( 182 | arrayList 183 | ); 184 | } 185 | } 186 | } 187 | } 188 | 189 | /** 190 | * {@inheritDoc} 191 | * 192 | * Called immediately after an element is found to be expired. The 193 | * {@link net.sf.ehcache.Cache#remove(Object)} method will block until this method returns. 194 | *
195 | * As the {@link net.sf.ehcache.Element} has been expired, only what was the key of the element is known. 196 | *
197 | * Elements are checked for expiry in ehcache at the following times: 198 | *
    199 | *
  • When a get request is made 200 | *
  • When an element is spooled to the diskStore in accordance with a MemoryStore 201 | * eviction policy 202 | *
  • In the DiskStore when the expiry thread runs, which by default is 203 | * {@link net.sf.ehcache.Cache#DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS} 204 | *
205 | * If an element is found to be expired, it is deleted and this method is notified. 206 | */ 207 | @Override 208 | public void notifyElementExpired(Ehcache cache, Element element) { 209 | if (expiredListener) { 210 | final JCacheEntryEventAdapter e = new JCacheEntryEventAdapter(jCache, element, EventType.EXPIRED); 211 | if (evaluate(e)) { 212 | ArrayList arrayList = new ArrayList(); 213 | arrayList.add(e); 214 | if (element != null) { 215 | ((CacheEntryExpiredListener) cacheListener) 216 | .onExpired( 217 | arrayList 218 | ); 219 | } 220 | } 221 | } 222 | } 223 | 224 | /** 225 | * {@inheritDoc} 226 | * 227 | * Called immediately after an element is evicted from the cache. Evicted in this sense 228 | * means evicted from one store and not moved to another, so that it exists nowhere in the 229 | * local cache. 230 | *
231 | * In a sense the Element has been removed from the cache, but it is different, 232 | * thus the separate notification. 233 | */ 234 | @Override 235 | public void notifyElementEvicted(Ehcache cache, Element element) { 236 | if (expiredListener) { 237 | final JCacheEntryEventAdapter e = new JCacheEntryEventAdapter(jCache, element, EventType.REMOVED); 238 | if (evaluate(e)) { 239 | ArrayList arrayList = new ArrayList(); 240 | arrayList.add(e); 241 | if (element != null) { 242 | ((CacheEntryExpiredListener) cacheListener).onExpired( 243 | arrayList); 244 | } 245 | } 246 | } 247 | } 248 | 249 | /** 250 | * {@inheritDoc} 251 | * 252 | * Called during {@link net.sf.ehcache.Ehcache#removeAll()} to indicate that the all 253 | * elements have been removed from the cache in a bulk operation. The usual 254 | * {@link #notifyElementRemoved(net.sf.ehcache.Ehcache, net.sf.ehcache.Element)} 255 | * is not called. 256 | *
257 | * This notification exists because clearing a cache is a special case. It is often 258 | * not practical to serially process notifications where potentially millions of elements 259 | * have been bulk deleted. 260 | */ 261 | @Override 262 | public void notifyRemoveAll(Ehcache cache) { 263 | // TODO: 264 | // does ehCache have the ability to pass this up natively? If not, decorating over the native events might not work 265 | // and we might need to have our JCache adapter layer handle talking to CacheEntryListeners directly (which wouldn't be 266 | // ideal because then only things happening through the JCache wrapper would be sent out through the event system) 267 | } 268 | 269 | /** 270 | * {@inheritDoc} 271 | * 272 | * Give the listener a chance to cleanup and free resources when no longer needed 273 | */ 274 | @Override 275 | public void dispose() { 276 | 277 | } 278 | 279 | /** 280 | * {@inheritDoc} 281 | * 282 | * Creates and returns a copy of this object. The precise meaning 283 | * of "copy" may depend on the class of the object. The general 284 | * intent is that, for any object {@code x}, the expression: 285 | *
286 | *
287 |      * x.clone() != x
288 | * will be true, and that the expression: 289 | *
290 | *
291 |      * x.clone().getClass() == x.getClass()
292 | * will be {@code true}, but these are not absolute requirements. 293 | * While it is typically the case that: 294 | *
295 | *
296 |      * x.clone().equals(x)
297 | * will be {@code true}, this is not an absolute requirement. 298 | * 299 | * By convention, the returned object should be obtained by calling 300 | * {@code super.clone}. If a class and all of its superclasses (except 301 | * {@code Object}) obey this convention, it will be the case that 302 | * {@code x.clone().getClass() == x.getClass()}. 303 | * 304 | * By convention, the object returned by this method should be independent 305 | * of this object (which is being cloned). To achieve this independence, 306 | * it may be necessary to modify one or more fields of the object returned 307 | * by {@code super.clone} before returning it. Typically, this means 308 | * copying any mutable objects that comprise the internal "deep structure" 309 | * of the object being cloned and replacing the references to these 310 | * objects with references to the copies. If a class contains only 311 | * primitive fields or references to immutable objects, then it is usually 312 | * the case that no fields in the object returned by {@code super.clone} 313 | * need to be modified. 314 | * 315 | * The method {@code clone} for class {@code Object} performs a 316 | * specific cloning operation. First, if the class of this object does 317 | * not implement the interface {@code Cloneable}, then a 318 | * {@code CloneNotSupportedException} is thrown. Note that all arrays 319 | * are considered to implement the interface {@code Cloneable} and that 320 | * the return type of the {@code clone} method of an array type {@code T[]} 321 | * is {@code T[]} where T is any reference or primitive type. 322 | * Otherwise, this method creates a new instance of the class of this 323 | * object and initializes all its fields with exactly the contents of 324 | * the corresponding fields of this object, as if by assignment; the 325 | * contents of the fields are not themselves cloned. Thus, this method 326 | * performs a "shallow copy" of this object, not a "deep copy" operation. 327 | * 328 | * The class {@code Object} does not itself implement the interface 329 | * {@code Cloneable}, so calling the {@code clone} method on an object 330 | * whose class is {@code Object} will result in throwing an 331 | * exception at run time. 332 | * @see Cloneable 333 | */ 334 | @Override 335 | public Object clone() throws CloneNotSupportedException { 336 | return super.clone(); 337 | } 338 | 339 | /** {@inheritDoc} */ 340 | @Override 341 | public boolean equals(Object o) { 342 | if (this == o) { 343 | return true; 344 | } 345 | if (o == null || getClass() != o.getClass()) { 346 | return false; 347 | } 348 | 349 | JCacheListenerAdapter that = (JCacheListenerAdapter) o; 350 | 351 | if (createdListener != that.createdListener) { 352 | return false; 353 | } 354 | if (expiredListener != that.expiredListener) { 355 | return false; 356 | } 357 | if (removedListener != that.removedListener) { 358 | return false; 359 | } 360 | if (updatedListener != that.updatedListener) { 361 | return false; 362 | } 363 | if (!cacheListener.equals(that.cacheListener)) { 364 | return false; 365 | } 366 | 367 | return true; 368 | } 369 | 370 | /** {@inheritDoc} */ 371 | @Override 372 | public int hashCode() { 373 | int result = cacheListener.hashCode(); 374 | result = 31 * result + (removedListener ? 1 : 0); 375 | result = 31 * result + (createdListener ? 1 : 0); 376 | result = 31 * result + (updatedListener ? 1 : 0); 377 | result = 31 * result + (expiredListener ? 1 : 0); 378 | return result; 379 | } 380 | 381 | private boolean evaluate(final JCacheEntryEventAdapter entry) { 382 | return cacheEntryEventFilter == null || cacheEntryEventFilter.evaluate(entry); 383 | } 384 | 385 | } 386 | -------------------------------------------------------------------------------- /ehcache-jcache/src/main/java/org/ehcache/jcache/JCacheMXBean.java: -------------------------------------------------------------------------------- 1 | package org.ehcache.jcache; 2 | 3 | import net.sf.ehcache.Ehcache; 4 | 5 | /** 6 | * @author Alex Snaps 7 | */ 8 | public class JCacheMXBean { 9 | protected final JCache jCache; 10 | private final String name; 11 | 12 | public JCacheMXBean(final JCache jCache, final String name) { 13 | this.jCache = jCache; 14 | this.name = name; 15 | } 16 | 17 | private String sanitize(String string) { 18 | return string == null ? "" : string.replaceAll(",|:|=|\n", "."); 19 | } 20 | 21 | String getObjectName() { 22 | String cacheManagerName = sanitize(jCache.getCacheManager().getURI().toString()); 23 | String cacheName = sanitize(jCache.getName()); 24 | 25 | return "javax.cache:type=Cache" + name + ",CacheManager=" 26 | + cacheManagerName + ",Cache=" + cacheName; 27 | } 28 | 29 | Ehcache getEhcache() { 30 | return (Ehcache) jCache.unwrap(Ehcache.class); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /ehcache-jcache/src/main/java/org/ehcache/jcache/JCacheManagementMXBean.java: -------------------------------------------------------------------------------- 1 | package org.ehcache.jcache; 2 | 3 | import javax.cache.configuration.CompleteConfiguration; 4 | import javax.cache.management.CacheMXBean; 5 | 6 | /** 7 | * @author Alex Snaps 8 | */ 9 | public class JCacheManagementMXBean extends JCacheMXBean implements CacheMXBean { 10 | 11 | public JCacheManagementMXBean(final JCache jCache) { 12 | super(jCache, "Configuration"); 13 | } 14 | 15 | @Override 16 | public String getKeyType() { 17 | return jCache.getConfiguration(CompleteConfiguration.class).getKeyType().getName(); 18 | } 19 | 20 | @Override 21 | public String getValueType() { 22 | return jCache.getConfiguration(CompleteConfiguration.class).getValueType().getName(); 23 | } 24 | 25 | @Override 26 | public boolean isReadThrough() { 27 | return ((CompleteConfiguration) jCache.getConfiguration(CompleteConfiguration.class)).isReadThrough(); 28 | } 29 | 30 | @Override 31 | public boolean isWriteThrough() { 32 | return ((CompleteConfiguration) jCache.getConfiguration(CompleteConfiguration.class)).isWriteThrough(); 33 | } 34 | 35 | @Override 36 | public boolean isStoreByValue() { 37 | return jCache.getConfiguration(CompleteConfiguration.class).isStoreByValue(); 38 | } 39 | 40 | @Override 41 | public boolean isStatisticsEnabled() { 42 | return ((CompleteConfiguration) jCache.getConfiguration(CompleteConfiguration.class)).isStatisticsEnabled(); 43 | } 44 | 45 | @Override 46 | public boolean isManagementEnabled() { 47 | return ((CompleteConfiguration) jCache.getConfiguration(CompleteConfiguration.class)).isManagementEnabled(); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /ehcache-jcache/src/main/java/org/ehcache/jcache/JCacheManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2003-2010 Terracotta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.ehcache.jcache; 17 | 18 | 19 | import net.sf.ehcache.CacheManager; 20 | import net.sf.ehcache.Ehcache; 21 | import net.sf.ehcache.Status; 22 | import net.sf.ehcache.config.CacheConfiguration; 23 | import net.sf.ehcache.config.CacheWriterConfiguration; 24 | import net.sf.ehcache.config.CopyStrategyConfiguration; 25 | 26 | import java.lang.management.ManagementFactory; 27 | import java.net.URI; 28 | import java.util.Collections; 29 | import java.util.HashSet; 30 | import java.util.Properties; 31 | import java.util.concurrent.ConcurrentHashMap; 32 | import java.util.concurrent.ConcurrentMap; 33 | import java.util.concurrent.ExecutorService; 34 | import java.util.concurrent.Executors; 35 | 36 | import javax.cache.Cache; 37 | import javax.cache.CacheException; 38 | import javax.cache.configuration.CompleteConfiguration; 39 | import javax.cache.configuration.Configuration; 40 | import javax.management.InstanceAlreadyExistsException; 41 | import javax.management.InstanceNotFoundException; 42 | import javax.management.MBeanRegistrationException; 43 | import javax.management.MBeanServer; 44 | import javax.management.MalformedObjectNameException; 45 | import javax.management.NotCompliantMBeanException; 46 | import javax.management.ObjectName; 47 | 48 | /** 49 | * The CacheManager that allows EHCache caches to be retrieved and accessed via JSR107 APIs 50 | * 51 | * @author Ryan Gardner 52 | * @since 1.4.0-beta1 53 | */ 54 | public class JCacheManager implements javax.cache.CacheManager { 55 | 56 | private static MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); 57 | private static final int DEFAULT_SIZE = 1000; 58 | 59 | private final JCacheCachingProvider jCacheCachingProvider; 60 | private final CacheManager cacheManager; 61 | private final URI uri; 62 | private final Properties props; 63 | private final ConcurrentHashMap allCaches = new ConcurrentHashMap(); 64 | private volatile boolean closed = false; 65 | private final ExecutorService executorService = Executors.newSingleThreadExecutor(); 66 | private final ConcurrentMap cfgMXBeans = new ConcurrentHashMap(); 67 | private final ConcurrentMap statMXBeans = new ConcurrentHashMap(); 68 | 69 | public JCacheManager(final JCacheCachingProvider jCacheCachingProvider, final CacheManager cacheManager, final URI uri, final Properties props) { 70 | this.jCacheCachingProvider = jCacheCachingProvider; 71 | this.cacheManager = cacheManager; 72 | this.uri = uri; 73 | this.props = props; 74 | refreshAllCaches(); 75 | } 76 | 77 | @Override 78 | public JCacheCachingProvider getCachingProvider() { 79 | return jCacheCachingProvider; 80 | } 81 | 82 | @Override 83 | public URI getURI() { 84 | return uri; 85 | } 86 | 87 | @Override 88 | public ClassLoader getClassLoader() { 89 | return cacheManager.getConfiguration().getClassLoader(); 90 | } 91 | 92 | @Override 93 | public Properties getProperties() { 94 | return props; 95 | } 96 | 97 | @Override 98 | public > Cache createCache(final String cacheName, final C configuration) throws IllegalArgumentException { 99 | checkNotClosed(); 100 | if(configuration == null) { 101 | throw new NullPointerException(); 102 | } 103 | 104 | JCache jCache = allCaches.get(cacheName); 105 | if (jCache != null) { 106 | throw new CacheException(); 107 | } 108 | cacheManager.addCacheIfAbsent(new net.sf.ehcache.Cache(toEhcacheConfig(cacheName, configuration))); 109 | Ehcache ehcache = cacheManager.getEhcache(cacheName); 110 | final JCacheConfiguration cfg = new JCacheConfiguration(configuration); 111 | jCache = new JCache(this, cfg, ehcache); 112 | JCache previous = allCaches.putIfAbsent(cacheName, jCache); 113 | if(previous != null) { 114 | // todo validate config 115 | return previous; 116 | } 117 | if(cfg.isStatisticsEnabled()) { 118 | enableStatistics(cacheName, true); 119 | } 120 | if(cfg.isManagementEnabled()) { 121 | enableManagement(cacheName, true); 122 | } 123 | return jCache; 124 | } 125 | 126 | @Override 127 | public Cache getCache(final String cacheName, final Class keyType, final Class valueType) { 128 | checkNotClosed(); 129 | if(valueType == null) { 130 | throw new NullPointerException(); 131 | } 132 | JCache jCache = allCaches.get(cacheName); 133 | if(jCache != null) { 134 | if(!keyType.isAssignableFrom(jCache.getConfiguration(CompleteConfiguration.class).getKeyType())) { 135 | throw new ClassCastException(); 136 | } 137 | if(!valueType.isAssignableFrom(jCache.getConfiguration(CompleteConfiguration.class).getValueType())) { 138 | throw new ClassCastException(); 139 | } 140 | return jCache; 141 | } 142 | final net.sf.ehcache.Cache cache = cacheManager.getCache(cacheName); 143 | if (cache == null) { 144 | return null; 145 | } 146 | jCache = new JCache(this, new JCacheConfiguration(null, null, keyType, valueType), cache); 147 | final JCache previous = allCaches.putIfAbsent(cacheName, jCache); 148 | if(previous != null) { 149 | jCache = previous; 150 | } 151 | if(!keyType.isAssignableFrom(jCache.getConfiguration(CompleteConfiguration.class).getKeyType())) { 152 | throw new ClassCastException(); 153 | } 154 | if(!valueType.isAssignableFrom(jCache.getConfiguration(CompleteConfiguration.class).getValueType())) { 155 | throw new ClassCastException(); 156 | } 157 | return jCache; 158 | } 159 | 160 | @Override 161 | public Cache getCache(final String cacheName) { 162 | final JCache jCache = allCaches.get(cacheName); 163 | if(jCache == null) { 164 | refreshAllCaches(); 165 | return allCaches.get(cacheName); 166 | } 167 | if(jCache.getConfiguration(CompleteConfiguration.class).getKeyType() != Object.class || 168 | jCache.getConfiguration(CompleteConfiguration.class).getValueType() != Object.class) { 169 | throw new IllegalArgumentException(); 170 | } 171 | return jCache; 172 | } 173 | 174 | @Override 175 | public Iterable getCacheNames() { 176 | return Collections.unmodifiableSet(new HashSet(allCaches.keySet())); 177 | } 178 | 179 | @Override 180 | public void destroyCache(final String cacheName) { 181 | checkNotClosed(); 182 | final JCache jCache = allCaches.get(cacheName); 183 | if (jCache != null) { 184 | jCache.close(); 185 | } 186 | } 187 | 188 | @Override 189 | public void enableManagement(final String cacheName, final boolean enabled) { 190 | checkNotClosed(); 191 | if(cacheName == null) throw new NullPointerException(); 192 | final JCache jCache = allCaches.get(cacheName); 193 | if(jCache == null) { 194 | throw new NullPointerException(); 195 | } 196 | enableManagement(enabled, jCache); 197 | } 198 | 199 | private void enableManagement(final boolean enabled, final JCache jCache) { 200 | try { 201 | if(enabled) { 202 | registerObject(getOrCreateCfgObject(jCache)); 203 | } else { 204 | unregisterObject(cfgMXBeans.remove(jCache)); 205 | } 206 | ((JCacheConfiguration)jCache.getConfiguration(JCacheConfiguration.class)).setManagementEnabled(enabled); 207 | } catch (NotCompliantMBeanException e) { 208 | throw new CacheException(e); 209 | } catch (InstanceAlreadyExistsException e) { 210 | // throw new CacheException(e); 211 | } catch (MBeanRegistrationException e) { 212 | throw new CacheException(e); 213 | } catch (InstanceNotFoundException e) { 214 | // throw new CacheException(e); 215 | } catch (MalformedObjectNameException e) { 216 | throw new CacheException(e); 217 | } 218 | } 219 | 220 | @Override 221 | public void enableStatistics(final String cacheName, final boolean enabled) { 222 | checkNotClosed(); 223 | if(cacheName == null) throw new NullPointerException(); 224 | final JCache jCache = allCaches.get(cacheName); 225 | if(jCache == null) { 226 | throw new NullPointerException(); 227 | } 228 | enableStatistics(enabled, jCache); 229 | } 230 | 231 | private void enableStatistics(final boolean enabled, final JCache jCache) { 232 | try { 233 | if(enabled) { 234 | registerObject(getOrCreateStatObject(jCache)); 235 | } else { 236 | unregisterObject(statMXBeans.remove(jCache)); 237 | } 238 | ((JCacheConfiguration)jCache.getConfiguration(JCacheConfiguration.class)).setStatisticsEnabled(enabled); 239 | } catch (NotCompliantMBeanException e) { 240 | throw new CacheException(e); 241 | } catch (InstanceAlreadyExistsException e) { 242 | // throw new CacheException(e); 243 | } catch (MBeanRegistrationException e) { 244 | throw new CacheException(e); 245 | } catch (InstanceNotFoundException e) { 246 | // throw new CacheException(e); 247 | } catch (MalformedObjectNameException e) { 248 | throw new CacheException("Illegal ObjectName for Management Bean. " + 249 | "CacheManager=[" + getURI().toString() + "], Cache=[" + jCache.getName() + "]", e); 250 | } 251 | } 252 | 253 | private void registerObject(final JCacheMXBean cacheMXBean) throws NotCompliantMBeanException, 254 | InstanceAlreadyExistsException, MBeanRegistrationException, MalformedObjectNameException { 255 | final ObjectName objectName = new ObjectName(cacheMXBean.getObjectName()); 256 | if(mBeanServer.queryNames(objectName, null).isEmpty()) { 257 | mBeanServer.registerMBean(cacheMXBean, objectName); 258 | } 259 | } 260 | 261 | private void unregisterObject(final JCacheMXBean cacheMXBean) throws MBeanRegistrationException, InstanceNotFoundException, MalformedObjectNameException { 262 | if(cacheMXBean == null) return; 263 | final String name = cacheMXBean.getObjectName(); 264 | final ObjectName objectName = new ObjectName(name); 265 | for (ObjectName n : mBeanServer.queryNames(objectName, null)) { 266 | mBeanServer.unregisterMBean(n); 267 | } 268 | } 269 | 270 | private JCacheManagementMXBean getOrCreateCfgObject(final JCache jCache) { 271 | JCacheManagementMXBean cacheMXBean = cfgMXBeans.get(jCache); 272 | if(cacheMXBean == null) { 273 | cacheMXBean = new JCacheManagementMXBean(jCache); 274 | final JCacheManagementMXBean previous = cfgMXBeans.putIfAbsent(jCache, cacheMXBean); 275 | if(previous != null) { 276 | cacheMXBean = previous; 277 | } 278 | } 279 | return cacheMXBean; 280 | } 281 | 282 | private JCacheStatMXBean getOrCreateStatObject(final JCache jCache) { 283 | JCacheStatMXBean cacheMXBean = statMXBeans.get(jCache); 284 | if(cacheMXBean == null) { 285 | cacheMXBean = new JCacheStatMXBean(jCache); 286 | final JCacheStatMXBean previous = statMXBeans.putIfAbsent(jCache, cacheMXBean); 287 | if(previous != null) { 288 | cacheMXBean = previous; 289 | } 290 | } 291 | return cacheMXBean; 292 | } 293 | 294 | @Override 295 | public void close() { 296 | jCacheCachingProvider.shutdown(this); 297 | } 298 | 299 | void shutdown() { 300 | closed = true; 301 | for (JCache jCache : allCaches.values()) { 302 | jCache.close(); 303 | } 304 | cacheManager.shutdown(); 305 | allCaches.clear(); 306 | } 307 | 308 | @Override 309 | public boolean isClosed() { 310 | return cacheManager.getStatus() == Status.STATUS_SHUTDOWN; 311 | } 312 | 313 | @Override 314 | public T unwrap(final Class clazz) { 315 | if(clazz.isAssignableFrom(getClass())) { 316 | return clazz.cast(this); 317 | } 318 | if(clazz.isAssignableFrom(cacheManager.getClass())) { 319 | return clazz.cast(cacheManager); 320 | } 321 | throw new IllegalArgumentException(); 322 | } 323 | 324 | private void refreshAllCaches() { 325 | for (String s : cacheManager.getCacheNames()) { 326 | final net.sf.ehcache.Cache cache = cacheManager.getCache(s); 327 | if(cache != null) { 328 | allCaches.put(s, new JCache(this, new JCacheConfiguration(cache.getCacheConfiguration()), cache)); 329 | } 330 | } 331 | } 332 | 333 | private CacheConfiguration toEhcacheConfig(final String name, final Configuration configuration) { 334 | final int maxSize = cacheManager.getConfiguration().isMaxBytesLocalHeapSet() ? 0 : DEFAULT_SIZE; 335 | CacheConfiguration cfg = new CacheConfiguration(name, maxSize); 336 | cfg.setClassLoader(cacheManager.getConfiguration().getClassLoader()); 337 | if(configuration.isStoreByValue()) { 338 | final CopyStrategyConfiguration copyStrategyConfiguration = new CopyStrategyConfiguration(); 339 | copyStrategyConfiguration.setCopyStrategyInstance(new JCacheCopyOnWriteStrategy()); 340 | cfg.copyOnRead(true).copyOnWrite(true) 341 | .addCopyStrategy(copyStrategyConfiguration); 342 | } 343 | if(configuration instanceof CompleteConfiguration) { 344 | if(((CompleteConfiguration)configuration).isWriteThrough()) { 345 | cfg.addCacheWriter(new CacheWriterConfiguration().writeMode(CacheWriterConfiguration.WriteMode.WRITE_THROUGH)); 346 | } 347 | } 348 | return cfg; 349 | } 350 | 351 | private void checkNotClosed() { 352 | if(closed) throw new IllegalStateException(); 353 | } 354 | 355 | void shutdown(final JCache jCache) { 356 | final JCache r = allCaches.remove(jCache.getName()); 357 | if (r == jCache) { 358 | enableStatistics(false, jCache); 359 | enableManagement(false, jCache); 360 | cacheManager.removeCache(jCache.getName()); 361 | jCache.shutdown(); 362 | } 363 | } 364 | 365 | public ExecutorService getExecutorService() { 366 | return executorService; 367 | } 368 | 369 | } 370 | -------------------------------------------------------------------------------- /ehcache-jcache/src/main/java/org/ehcache/jcache/JCacheStatMXBean.java: -------------------------------------------------------------------------------- 1 | package org.ehcache.jcache; 2 | 3 | import javax.cache.management.CacheStatisticsMXBean; 4 | 5 | /** 6 | * @author Alex Snaps 7 | */ 8 | public class JCacheStatMXBean extends JCacheMXBean implements CacheStatisticsMXBean { 9 | 10 | private long pCacheHits; 11 | private long pCacheMisses; 12 | private long pCacheGets; 13 | private long pCachePuts; 14 | private long pCacheRemovals; 15 | private long pCacheEvictions; 16 | 17 | public JCacheStatMXBean(final JCache jCache) { 18 | super(jCache, "Statistics"); 19 | } 20 | 21 | @Override 22 | public void clear() { 23 | pCacheHits = getEhcache().getStatistics().cacheHitCount(); 24 | pCacheMisses = getEhcache().getStatistics().cacheMissCount(); 25 | pCacheGets = getEhcache().getStatistics().cacheGetOperation().count().value(); 26 | pCachePuts = getEhcache().getStatistics().cachePutCount(); 27 | pCacheRemovals = getEhcache().getStatistics().cacheRemoveCount(); 28 | pCacheEvictions = getEhcache().getStatistics().cacheEvictedCount(); 29 | } 30 | 31 | @Override 32 | public long getCacheHits() { 33 | return getEhcache().getStatistics().cacheHitCount() - pCacheHits; 34 | } 35 | 36 | @Override 37 | public float getCacheHitPercentage() { 38 | final double v = getEhcache().getStatistics().cacheHitRatio(); 39 | if(Double.isNaN(v)) { 40 | return getEhcache().getStatistics().cacheHitCount() == 0 ? 0f : 100f; 41 | } 42 | return (float) v * 100; 43 | } 44 | 45 | @Override 46 | public long getCacheMisses() { 47 | return getEhcache().getStatistics().cacheMissCount() - pCacheMisses; 48 | } 49 | 50 | @Override 51 | public float getCacheMissPercentage() { 52 | final double v = getEhcache().getStatistics().cacheHitRatio(); 53 | if(Double.isNaN(v)) { 54 | return 0f; 55 | } 56 | return (float) (1 - v) * 100; 57 | } 58 | 59 | @Override 60 | public long getCacheGets() { 61 | return getEhcache().getStatistics().cacheGetOperation().count().value() - pCacheGets; 62 | } 63 | 64 | @Override 65 | public long getCachePuts() { 66 | return getEhcache().getStatistics().cachePutCount() - pCachePuts; 67 | } 68 | 69 | @Override 70 | public long getCacheRemovals() { 71 | return getEhcache().getStatistics().cacheRemoveCount() - pCacheRemovals; 72 | } 73 | 74 | @Override 75 | public long getCacheEvictions() { 76 | return getEhcache().getStatistics().cacheEvictedCount() - pCacheEvictions; 77 | } 78 | 79 | @Override 80 | public float getAverageGetTime() { 81 | final float v = getEhcache().getStatistics().cacheGetOperation().latency().average().value().floatValue(); 82 | return Float.isNaN(v) ? 0f : v; 83 | } 84 | 85 | @Override 86 | public float getAveragePutTime() { 87 | final float v = getEhcache().getStatistics().cachePutOperation().latency().average().value().floatValue(); 88 | return Float.isNaN(v) ? 0f : v; 89 | } 90 | 91 | @Override 92 | public float getAverageRemoveTime() { 93 | final float v = getEhcache().getStatistics().cacheRemoveOperation().latency().average().value().floatValue(); 94 | return Float.isNaN(v) ? 0f : v; 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /ehcache-jcache/src/main/java/org/ehcache/jcache/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2003-2010 Terracotta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | /** 17 | * This package contains implementations of JCache (JSR107)interfaces for use with EHCache. 18 | * 19 | * This allows you to have EHCache act as a CachingProvider for applications that use JCache interfaces 20 | * 21 | * @author Ryan Gardner 22 | */ 23 | package org.ehcache.jcache; -------------------------------------------------------------------------------- /ehcache-jcache/src/main/java/org/ehcache/jcache/tck/TCKMBeanServerBuilder.java: -------------------------------------------------------------------------------- 1 | package org.ehcache.jcache.tck; 2 | 3 | import com.sun.jmx.mbeanserver.JmxMBeanServer; 4 | 5 | import javax.management.ListenerNotFoundException; 6 | import javax.management.MBeanNotificationInfo; 7 | import javax.management.MBeanServer; 8 | import javax.management.MBeanServerBuilder; 9 | import javax.management.MBeanServerDelegate; 10 | import javax.management.Notification; 11 | import javax.management.NotificationFilter; 12 | import javax.management.NotificationListener; 13 | 14 | /** 15 | * @author Alex Snaps 16 | */ 17 | public class TCKMBeanServerBuilder extends MBeanServerBuilder { 18 | 19 | /** 20 | * Empty public constructor as required 21 | */ 22 | public TCKMBeanServerBuilder() { 23 | super(); 24 | } 25 | 26 | @Override 27 | public MBeanServer newMBeanServer(String defaultDomain, MBeanServer outer, 28 | MBeanServerDelegate delegate) { 29 | MBeanServerDelegate decoratingDelegate = new RIMBeanServerDelegate(delegate); 30 | return JmxMBeanServer.newMBeanServer(defaultDomain, outer, 31 | decoratingDelegate, false); 32 | } 33 | 34 | /** 35 | * A decorator around the MBeanServerDelegate which sets the mBeanServerId 36 | * to the value of the org.jsr107.tck.management.agentId system 37 | * property so that the TCK can precisely identify the correct MBeanServer 38 | * when running tests. 39 | */ 40 | public class RIMBeanServerDelegate extends MBeanServerDelegate { 41 | 42 | private MBeanServerDelegate delegate; 43 | 44 | /** 45 | * Constructor 46 | * 47 | * @param delegate the provided delegate 48 | */ 49 | public RIMBeanServerDelegate(MBeanServerDelegate delegate) { 50 | this.delegate = delegate; 51 | } 52 | 53 | @Override 54 | public String getSpecificationName() { 55 | return delegate.getSpecificationName(); 56 | } 57 | 58 | @Override 59 | public String getSpecificationVersion() { 60 | return delegate.getSpecificationVersion(); 61 | } 62 | 63 | @Override 64 | public String getSpecificationVendor() { 65 | return delegate.getSpecificationVendor(); 66 | } 67 | 68 | @Override 69 | public String getImplementationName() { 70 | return delegate.getImplementationName(); 71 | } 72 | 73 | @Override 74 | public String getImplementationVersion() { 75 | return delegate.getImplementationVersion(); 76 | } 77 | 78 | @Override 79 | public String getImplementationVendor() { 80 | return delegate.getImplementationVendor(); 81 | } 82 | 83 | @Override 84 | public MBeanNotificationInfo[] getNotificationInfo() { 85 | return delegate.getNotificationInfo(); 86 | } 87 | 88 | @Override 89 | public synchronized void addNotificationListener(NotificationListener listener, 90 | NotificationFilter filter, 91 | Object handback) throws 92 | IllegalArgumentException { 93 | delegate.addNotificationListener(listener, filter, handback); 94 | } 95 | 96 | @Override 97 | public synchronized void removeNotificationListener(NotificationListener 98 | listener, 99 | NotificationFilter 100 | filter, 101 | Object handback) throws 102 | ListenerNotFoundException { 103 | delegate.removeNotificationListener(listener, filter, handback); 104 | } 105 | 106 | @Override 107 | public synchronized void removeNotificationListener(NotificationListener 108 | listener) throws 109 | ListenerNotFoundException { 110 | delegate.removeNotificationListener(listener); 111 | } 112 | 113 | @Override 114 | public void sendNotification(Notification notification) { 115 | delegate.sendNotification(notification); 116 | } 117 | 118 | @Override 119 | public synchronized String getMBeanServerId() { 120 | return System.getProperty("org.jsr107.tck.management.agentId"); 121 | } 122 | } 123 | 124 | 125 | } 126 | -------------------------------------------------------------------------------- /ehcache-jcache/src/main/resources/META-INF/services/javax.cache.spi.CachingProvider: -------------------------------------------------------------------------------- 1 | org.ehcache.jcache.JCacheCachingProvider -------------------------------------------------------------------------------- /ehcache-jcache/src/test/java/org/ehcache/jcache/JCacheAndEhcacheAccessTest.java: -------------------------------------------------------------------------------- 1 | package org.ehcache.jcache; 2 | 3 | import net.sf.ehcache.Ehcache; 4 | import org.ehcache.jcache.JCache; 5 | import org.ehcache.jcache.JCacheConfiguration; 6 | import org.junit.Test; 7 | 8 | import java.util.concurrent.TimeUnit; 9 | import java.util.concurrent.atomic.AtomicBoolean; 10 | 11 | import javax.cache.Cache; 12 | import javax.cache.CacheManager; 13 | import javax.cache.Caching; 14 | import javax.cache.configuration.MutableConfiguration; 15 | import javax.cache.expiry.Duration; 16 | import javax.cache.expiry.ModifiedExpiryPolicy; 17 | import javax.cache.processor.EntryProcessor; 18 | import javax.cache.processor.EntryProcessorException; 19 | import javax.cache.processor.MutableEntry; 20 | 21 | import static org.hamcrest.CoreMatchers.notNullValue; 22 | import static org.hamcrest.CoreMatchers.nullValue; 23 | import static org.hamcrest.core.Is.is; 24 | import static org.junit.Assert.assertThat; 25 | 26 | public class JCacheAndEhcacheAccessTest { 27 | 28 | @Test 29 | public void ehcacheIsBeingPickedAsCacheProvider() { 30 | final MutableConfiguration mutableConfiguration = new MutableConfiguration() 31 | .setExpiryPolicyFactory(ModifiedExpiryPolicy.factoryOf(new Duration(TimeUnit.MINUTES, 10))) 32 | .setStoreByValue(true); 33 | 34 | Cache foo = Caching.getCachingProvider().getCacheManager().createCache("foo", new JCacheConfiguration(mutableConfiguration)); 35 | assertThat(foo, is(notNullValue())); 36 | assertThat(foo, is(JCache.class)); 37 | } 38 | 39 | @Test 40 | public void namedEhcacheDotXMLReadWhenOneExists() { 41 | javax.cache.Cache jcache = Caching.getCachingProvider().getCacheManager().getCache("sampleCache"); 42 | assertThat(jcache, is(notNullValue())); 43 | assertThat((jcache.unwrap(Ehcache.class)), is(notNullValue())); 44 | } 45 | 46 | @Test 47 | public void namedEhcachePropertiesUsedWhenOneExists() { 48 | JCache jcache = (JCache) Caching.getCachingProvider().getCacheManager().getCache("sampleCache"); 49 | assertThat(jcache, is(notNullValue())); 50 | assertThat("Store by value is only true if copyOnRead and copyOnWrite are both configured in the xml config", 51 | jcache.getConfiguration(JCacheConfiguration.class).isStoreByValue(), is(false)); 52 | // assertThat(jcache.getConfiguration().getExpiry(CacheConfiguration.ExpiryType.ACCESSED).getTimeUnit(), 53 | // is(equalTo(TimeUnit.SECONDS))); 54 | // assertThat(jcache.getConfiguration().getExpiry(CacheConfiguration.ExpiryType.ACCESSED).getDurationAmount(), 55 | // is(360L)); 56 | // 57 | // assertThat(jcache.getConfiguration().getExpiry(CacheConfiguration.ExpiryType.MODIFIED).getTimeUnit(), 58 | // is(equalTo(TimeUnit.SECONDS))); 59 | // assertThat(jcache.getConfiguration().getExpiry(CacheConfiguration.ExpiryType.MODIFIED).getDurationAmount(), 60 | // is(1000L)); 61 | // assertThat(jcache.getConfiguration(JCacheConfiguration.class).getEhcacheConfiguration().isOverflowToDisk(), is(true)); 62 | } 63 | 64 | @Test 65 | public void nullCacheWhenNoCacheExists() { 66 | JCache jcache = (JCache) Caching.getCachingProvider().getCacheManager().getCache("nonexistent-cache"); 67 | assertThat(jcache, nullValue()); 68 | } 69 | 70 | @Test 71 | public void testUpdatesCacheWhenSettingMutableEntryValue() { 72 | final CacheManager cacheManager = Caching.getCachingProvider().getCacheManager(); 73 | Cache cache = cacheManager.createCache("testUpdatesCacheWhenSettingMutableEntryValue", new MutableConfiguration()); 74 | try { 75 | cache.put("key", new AtomicBoolean()); 76 | assertThat(cache.invoke("key", new EntryProcessor() { 77 | @Override 78 | public Boolean process(final MutableEntry entry, final Object... arguments) throws EntryProcessorException { 79 | final AtomicBoolean value = entry.getValue(); 80 | final boolean previous = value.getAndSet(true); 81 | entry.setValue(value); 82 | return previous; 83 | } 84 | }), is(false)); 85 | assertThat(cache.get("key").get(), is(true)); 86 | } finally { 87 | cacheManager.destroyCache(cache.getName()); 88 | } 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /ehcache-jcache/src/test/java/org/ehcache/jcache/JCacheCachingProviderTest.java: -------------------------------------------------------------------------------- 1 | package org.ehcache.jcache; 2 | 3 | import net.sf.ehcache.Ehcache; 4 | import net.sf.ehcache.Element; 5 | import org.junit.Test; 6 | 7 | import javax.cache.Cache; 8 | import javax.cache.CacheManager; 9 | import javax.cache.Caching; 10 | import javax.cache.configuration.Configuration; 11 | import javax.cache.configuration.MutableConfiguration; 12 | import javax.cache.spi.CachingProvider; 13 | 14 | import static org.hamcrest.CoreMatchers.is; 15 | import static org.junit.Assert.assertEquals; 16 | import static org.junit.Assert.assertNotNull; 17 | import static org.junit.Assert.assertNull; 18 | import static org.junit.Assert.assertThat; 19 | 20 | public class JCacheCachingProviderTest { 21 | 22 | @Test 23 | public void testLoadsXMLFile() { 24 | final CachingProvider cachingProvider = Caching.getCachingProvider(); 25 | final CacheManager cacheManager = cachingProvider.getCacheManager(); 26 | assertNull(cacheManager.getCache("foo")); 27 | final Cache sampleCache = cacheManager.getCache("sampleCache"); 28 | assertNotNull(sampleCache); 29 | sampleCache.put("key", "value"); 30 | final Ehcache unwrapped = sampleCache.unwrap(Ehcache.class); 31 | final Element element = unwrapped.get("key"); 32 | assertThat(element.isEternal(), is(false)); 33 | assertThat(element.getTimeToIdle(), is(360)); 34 | assertThat(element.getTimeToLive(), is(1000)); 35 | } 36 | 37 | @Test 38 | public void testCreatingCacheInRuntime() { 39 | final CachingProvider cachingProvider = Caching.getCachingProvider(); 40 | final CacheManager cacheManager = cachingProvider.getCacheManager(); 41 | String cacheName = "nonExistingCache"; 42 | assertNull(cacheManager.getCache(cacheName)); 43 | 44 | Configuration configuration = new JCacheConfiguration(new MutableConfiguration()); 45 | cacheManager.createCache(cacheName, configuration); 46 | 47 | final Cache sampleCache = cacheManager.getCache(cacheName); 48 | assertNotNull(sampleCache); 49 | sampleCache.put("key", "value"); 50 | final Ehcache unwrapped = sampleCache.unwrap(Ehcache.class); 51 | final Element element = unwrapped.get("key"); 52 | assertEquals("value", element.getObjectValue()); 53 | assertThat(element.isEternal(), is(true)); 54 | assertThat(element.getTimeToIdle(), is(0)); 55 | assertThat(element.getTimeToLive(), is(0)); 56 | } 57 | 58 | @Test 59 | public void testShuttingDownProviderWithManagerNotFoundByClassloader() { 60 | JCacheCachingProvider provider = new JCacheCachingProvider(); 61 | 62 | JCacheManager manager = new JCacheManager(null, new net.sf.ehcache.CacheManager(), null, null); 63 | provider.shutdown(manager); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /ehcache-jcache/src/test/java/org/ehcache/jcache/JCacheConfigurationTest.java: -------------------------------------------------------------------------------- 1 | package org.ehcache.jcache; 2 | 3 | 4 | import javax.cache.Cache; 5 | import javax.cache.expiry.Duration; 6 | import javax.cache.expiry.ExpiryPolicy; 7 | 8 | import net.sf.ehcache.CacheManager; 9 | import net.sf.ehcache.config.CacheConfiguration; 10 | import org.junit.Test; 11 | 12 | import static org.hamcrest.CoreMatchers.is; 13 | import static org.hamcrest.CoreMatchers.notNullValue; 14 | import static org.hamcrest.CoreMatchers.nullValue; 15 | import static org.junit.Assert.assertThat; 16 | 17 | 18 | public class JCacheConfigurationTest { 19 | 20 | @Test 21 | public void shouldCreateJCacheConfigurationFromOtherInstance() { 22 | //given 23 | CacheConfiguration ehCacheConfig = new CacheConfiguration("testCache", 1000); 24 | JCacheConfiguration originJCacheConfig = new JCacheConfiguration(ehCacheConfig); 25 | 26 | //when 27 | new JCacheConfiguration(originJCacheConfig); 28 | 29 | //then - no Exception 30 | } 31 | 32 | /** 33 | * Helper to assert that given duration is either null or eternal. 34 | */ 35 | private void assertDurationNullOrEternal(final Duration duration) { 36 | if (duration != null) { 37 | assertThat(duration.isEternal(), is(true)); 38 | } 39 | } 40 | 41 | /** 42 | * Verify that pre-configured cache (in ehcache.xml) with eternal=true actually gets an EternalExpiryPolicy 43 | * and does not remove keys after first retrieval. 44 | */ 45 | @Test 46 | public void preconfiguredEternalCache() { 47 | final CacheManager ehcache = CacheManager.getInstance(); 48 | String cacheName = "simpleEternalCache"; 49 | 50 | // sanity check configuration has eternal flag with ehcache native api 51 | assertThat(ehcache.getCache(cacheName).getCacheConfiguration().isEternal(), is(true)); 52 | 53 | // stand up jcache manager and verify with jcache api that preconfigured cache is eternal 54 | JCacheManager cacheManager = new JCacheManager(null, ehcache, null, null); 55 | try { 56 | Cache cache = cacheManager.getCache(cacheName, Object.class, Object.class); 57 | assertThat(cache, notNullValue()); 58 | 59 | // verify the jcache configuration impl has the right bits for expire policy 60 | JCacheConfiguration config = cache.getConfiguration(JCacheConfiguration.class); 61 | assertThat(config, notNullValue()); 62 | 63 | ExpiryPolicy expiryPolicy = config.getExpiryPolicy(); 64 | assertThat(expiryPolicy, notNullValue()); 65 | 66 | // for some reason creation returns a value (Duration.ETERNAL), but access/update return null 67 | assertDurationNullOrEternal(expiryPolicy.getExpiryForCreation()); 68 | assertDurationNullOrEternal(expiryPolicy.getExpiryForAccess()); 69 | assertDurationNullOrEternal(expiryPolicy.getExpiryForUpdate()); 70 | 71 | Object key = "foo"; 72 | Object value = "bar"; 73 | Object result = cache.getAndPut(key, value); 74 | assertThat(result, nullValue()); 75 | 76 | // get should return same value 77 | result = cache.get(key); 78 | assertThat(result, is(value)); 79 | 80 | // again, since its eternal, we get the same, if the policy was not eternal we'd get null here instead 81 | result = cache.get(key); 82 | assertThat(result, is(value)); 83 | 84 | // and for sanity 85 | result = cache.get(key); 86 | assertThat(result, is(value)); 87 | 88 | // remove it and its should be gone 89 | cache.remove(key); 90 | result = cache.get(key); 91 | assertThat(result, nullValue()); 92 | } finally { 93 | // NOTE: This will NPE due to configuration above allowing null provider, and expecting non-null in close 94 | //cacheManager.close(); 95 | ehcache.shutdown(); 96 | } 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /ehcache-jcache/src/test/java/org/ehcache/jcache/JCacheManagerTest.java: -------------------------------------------------------------------------------- 1 | package org.ehcache.jcache; 2 | 3 | import net.sf.ehcache.Cache; 4 | import net.sf.ehcache.CacheManager; 5 | import org.junit.Test; 6 | 7 | import static org.hamcrest.CoreMatchers.instanceOf; 8 | import static org.hamcrest.CoreMatchers.notNullValue; 9 | import static org.junit.Assert.assertThat; 10 | import static org.junit.Assert.fail; 11 | 12 | public class JCacheManagerTest { 13 | 14 | @Test 15 | public void testUnwrapReturnsCacheManagerType() { 16 | JCacheManager jCacheManager = new JCacheManager(null, CacheManager.getInstance(), null, null); 17 | final CacheManager unwrap = jCacheManager.unwrap(CacheManager.class); 18 | assertThat(unwrap, notNullValue()); 19 | assertThat(unwrap, instanceOf(CacheManager.class)); 20 | } 21 | 22 | @Test 23 | public void testUnwrapThrowsOnUnsupportedType() { 24 | JCacheManager jCacheManager = new JCacheManager(null, CacheManager.getInstance(), null, null); 25 | try { 26 | jCacheManager.unwrap(Cache.class); 27 | fail(); 28 | } catch (IllegalArgumentException e) { 29 | // Expected 30 | } 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /ehcache-jcache/src/test/resources/ehcache-basic.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /ehcache-jcache/src/test/resources/ehcache.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 14 | 15 | 16 | 17 | 23 | 24 | 25 | 26 | 32 | 33 | 34 | 39 | 40 | 41 | 45 | 46 | 47 | 54 | 55 | 58 | 67 | 68 | 69 | 70 | 75 | 81 | 82 | 83 | 87 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /jcache-tck-runner/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 6 | org.ehcache 7 | ehcache-jcache-parent 8 | 1.0.2-SNAPSHOT 9 | 10 | 11 | jcache-tck-runner 12 | jar 13 | 14 | Implementation Tester - Ehcache JCache Implementation 15 | 16 | Wires together TCK cache-tests with the Ehcache JCache implementation and runs them using JUnit. 17 | 18 | 19 | 20 | ${project.build.directory}/domainlib 21 | domain.jar 22 | org.ehcache.jcache.JCacheManager 23 | org.ehcache.jcache.JCache 24 | org.ehcache.jcache.JCacheEntry 25 | org.ehcache.jcache.tck.TCKMBeanServerBuilder 26 | org.ehcache.JCache-MBeanServer 27 | javax.cache.annotation.impl.cdi.CdiCacheKeyInvocationContextImpl 28 | 29 | 30 | 31 | 32 | org.ehcache 33 | jcache 34 | ${project.version} 35 | 36 | 37 | 38 | javax.cache 39 | cache-tests 40 | ${javax.cache.tck.version} 41 | 42 | 43 | 44 | javax.cache 45 | cache-tests 46 | tests 47 | ${javax.cache.tck.version} 48 | test 49 | 50 | 51 | 52 | 53 | org.hamcrest 54 | hamcrest-library 55 | 1.2 56 | test 57 | 58 | 59 | 60 | 61 | log4j 62 | log4j 63 | 1.2.16 64 | test 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | src/test/resources 73 | true 74 | 75 | 76 | 77 | 78 | org.apache.maven.plugins 79 | maven-dependency-plugin 80 | 2.8 81 | 82 | 83 | 84 | copy-cache-tests 85 | 86 | unpack-dependencies 87 | 88 | 89 | ${project.build.testOutputDirectory} 90 | 91 | cache-tests 92 | test 93 | 94 | 95 | 96 | copy-domain 97 | 98 | copy 99 | 100 | 101 | 102 | 103 | javax.cache 104 | app-domain 105 | ${javax.cache.tck.version} 106 | ${domain-lib-dir} 107 | 108 | ${domain-jar} 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | org.apache.maven.plugins 118 | maven-deploy-plugin 119 | 120 | true 121 | 122 | 123 | 124 | 125 | org.apache.maven.plugins 126 | maven-surefire-plugin 127 | 2.9 128 | 129 | 130 | ${domain-lib-dir}/${domain-jar} 131 | ${javax.management.builder.initial} 132 | ${org.jsr107.tck.management.agentId} 133 | ${CacheManagerImpl} 134 | ${CacheImpl} 135 | ${CacheEntryImpl} 136 | ${CacheInvocationContextImpl} 137 | 138 | 139 | **/annotation/*Test.java 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 153 | 154 | test-basic-cache 155 | 156 | 157 | 158 | org.apache.maven.plugins 159 | maven-surefire-plugin 160 | 161 | 162 | **/interceptor/*Test.java 163 | 164 | 165 | ${domain-lib-dir}/${domain-jar} 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 175 | 176 | test-optional-cache 177 | 178 | 179 | 180 | org.apache.maven.plugins 181 | maven-surefire-plugin 182 | 183 | 184 | **/interceptor/*Test.java 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | -------------------------------------------------------------------------------- /jcache-tck-runner/src/test/resources/ExcludeList: -------------------------------------------------------------------------------- 1 | #List tests to be excluded. 2 | #Lines beginning with a '#' are comments 3 | #Enter One method per line with syntax FULL_CLASS_NAME#METHOD_NAME as in the example below 4 | 5 | # This is a dummy test that fails if not in the exclude list. 6 | org.jsr107.tck.CachingTest#dummyTest 7 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | 7 | org.sonatype.oss 8 | oss-parent 9 | 7 10 | 11 | 12 | 13 | 14 | org.ehcache 15 | ehcache-jcache-parent 16 | 1.0.2-SNAPSHOT 17 | pom 18 | 19 | Ehcache JCache Parent Pom 20 | 21 | 22 | https://github.com/Terracotta-OSS/ehcache-jcache 23 | 24 | 25 | Terracotta 26 | http://terracotta.org 27 | 28 | 29 | 30 | 31 | The Apache Software License, Version 2.0 32 | http://www.apache.org/licenses/LICENSE-2.0.txt 33 | repo 34 | 35 | 36 | 37 | 38 | 2 39 | UTF-8 40 | UTF-8 41 | 1.0.0 42 | ${javax.cache.version} 43 | 44 | 45 | 46 | ehcache-jcache 47 | 48 | 49 | 50 | 51 | 52 | javax.cache 53 | cache-api 54 | ${javax.cache.version} 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | org.apache.maven.plugins 64 | maven-deploy-plugin 65 | 2.8.1 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | sign 74 | 75 | 76 | 77 | org.apache.maven.plugins 78 | maven-gpg-plugin 79 | 1.5 80 | 81 | 82 | sign-artifacts 83 | verify 84 | 85 | sign 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | run-tck 96 | 97 | true 98 | 99 | 100 | jcache-tck-runner 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | cloudbees-snapshots 109 | https://repository-jsr107.forge.cloudbees.com/snapshot 110 | 111 | false 112 | 113 | 114 | true 115 | 116 | 117 | 118 | 119 | 120 | 121 | alexsnaps 122 | Alex Snaps 123 | 124 | Project Lead 125 | 126 | Terracotta Inc., a wholly-owned subsidiary of Software AG USA, Inc. 127 | http://terracotta.org 128 | 129 | 130 | ljacomet 131 | Louis Jacomet 132 | 133 | Developer 134 | 135 | Terracotta Inc., a wholly-owned subsidiary of Software AG USA, Inc. 136 | http://terracotta.org 137 | 138 | 139 | 140 | 141 | https://github.com/Terracotta-OSS/ehcache-jcache 142 | scm:git:git@github.com:Terracotta-OSS/ehcache-jcache.git 143 | scm:git:git@github.com:Terracotta-OSS/ehcache-jcache.git 144 | 145 | 146 | 147 | --------------------------------------------------------------------------------