View Javadoc
1   package ca.uhn.fhir.jpa.util;
2   
3   /*-
4    * #%L
5    * HAPI FHIR JPA Server
6    * %%
7    * Copyright (C) 2014 - 2018 University Health Network
8    * %%
9    * Licensed under the Apache License, Version 2.0 (the "License");
10   * you may not use this file except in compliance with the License.
11   * You may obtain a copy of the License at
12   * 
13   *      http://www.apache.org/licenses/LICENSE-2.0
14   * 
15   * Unless required by applicable law or agreed to in writing, software
16   * distributed under the License is distributed on an "AS IS" BASIS,
17   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18   * See the License for the specific language governing permissions and
19   * limitations under the License.
20   * #L%
21   */
22  
23  import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
24  import com.google.common.annotations.VisibleForTesting;
25  import org.slf4j.Logger;
26  import org.slf4j.LoggerFactory;
27  import org.springframework.scheduling.annotation.Scheduled;
28  
29  import java.util.concurrent.Callable;
30  import java.util.concurrent.atomic.AtomicReference;
31  
32  /**
33   * This is a simple cache for CapabilityStatement resources to
34   * be returned as server metadata.
35   */
36  public class SingleItemLoadingCache<T> {
37  	private static final Logger ourLog = LoggerFactory.getLogger(SingleItemLoadingCache.class);
38  	private static Long ourNowForUnitTest;
39  	private final Callable<T> myFetcher;
40  	private volatile long myCacheMillis;
41  	private AtomicReference<T> myCapabilityStatement = new AtomicReference<>();
42  	private long myLastFetched;
43  
44  	/**
45  	 * Constructor
46  	 */
47  	public SingleItemLoadingCache(Callable<T> theFetcher) {
48  		myFetcher = theFetcher;
49  	}
50  
51  	public synchronized void clear() {
52  		ourLog.info("Clearning cache");
53  		myCapabilityStatement.set(null);
54  		myLastFetched = 0;
55  	}
56  
57  	public synchronized T get() {
58  		return myCapabilityStatement.get();
59  	}
60  
61  	private T refresh() {
62  		T retVal;
63  		try {
64  			retVal = myFetcher.call();
65  		} catch (Exception e) {
66  			throw new InternalErrorException(e);
67  		}
68  
69  		myCapabilityStatement.set(retVal);
70  		myLastFetched = now();
71  		return retVal;
72  	}
73  
74  	public void setCacheMillis(long theCacheMillis) {
75  		myCacheMillis = theCacheMillis;
76  	}
77  
78  	@Scheduled(fixedDelay = 60000)
79  	public void update() {
80  		if (myCacheMillis > 0) {
81  			long now = now();
82  			long expiry = now - myCacheMillis;
83  			if (myLastFetched < expiry) {
84  				refresh();
85  			}
86  		}
87  	}
88  
89  	private static long now() {
90  		if (ourNowForUnitTest != null) {
91  			return ourNowForUnitTest;
92  		}
93  		return System.currentTimeMillis();
94  	}
95  
96  	@VisibleForTesting
97  	static void setNowForUnitTest(Long theNowForUnitTest) {
98  		ourNowForUnitTest = theNowForUnitTest;
99  	}
100 
101 }