~hjd/ubuntu/wily/xmlgraphics-commons/debian-merged

« back to all changes in this revision

Viewing changes to src/java/org/apache/xmlgraphics/image/loader/cache/ImageCache.java

  • Committer: Bazaar Package Importer
  • Author(s): Vincent Fourmond
  • Date: 2011-02-11 14:15:14 UTC
  • mfrom: (8.1.2 experimental)
  • Revision ID: james.westby@ubuntu.com-20110211141514-h67achft6x31gju1
Tags: 1.4.dfsg-3
Uploading to unstable, hoping we won't break too many things ;-)...

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
6
 * (the "License"); you may not use this file except in compliance with
7
7
 * the License.  You may obtain a copy of the License at
8
 
 * 
 
8
 *
9
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 
 * 
 
10
 *
11
11
 * Unless required by applicable law or agreed to in writing, software
12
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
15
 * limitations under the License.
16
16
 */
17
17
 
18
 
/* $Id: ImageCache.java 606580 2007-12-23 17:45:02Z jeremias $ */
19
 
 
 
18
/* $Id: ImageCache.java 816640 2009-09-18 14:14:55Z maxberger $ */
 
19
 
20
20
package org.apache.xmlgraphics.image.loader.cache;
21
21
 
22
22
import java.io.FileNotFoundException;
23
23
import java.io.IOException;
24
24
import java.util.Collections;
 
25
import java.util.HashSet;
 
26
import java.util.Iterator;
 
27
import java.util.Map;
25
28
import java.util.Set;
26
29
 
27
30
import javax.xml.transform.Source;
44
47
 * <p>
45
48
 * Don't use one ImageCache instance in the context of multiple base URIs because relative URIs
46
49
 * would not work correctly anymore.
 
50
 * <p>
 
51
 * By default, the URIs of inaccessible images are remembered but these entries are discarded
 
52
 * after 60 seconds (which causes a retry next time the same URI is requested). This allows
 
53
 * to counteract performance loss when accessing invalid or temporarily unavailable images
 
54
 * over slow connections.
47
55
 */
48
56
public class ImageCache {
49
57
 
50
58
    /** logger */
51
59
    protected static Log log = LogFactory.getLog(ImageCache.class);
52
 
    
53
 
    private Set invalidURIs = Collections.synchronizedSet(new java.util.HashSet());
54
 
    
 
60
 
 
61
    //Handling of invalid URIs
 
62
    private Map invalidURIs = Collections.synchronizedMap(new java.util.HashMap());
 
63
    private ExpirationPolicy invalidURIExpirationPolicy;
 
64
 
 
65
    //Actual image cache
55
66
    private SoftMapCache imageInfos = new SoftMapCache(true);
56
67
    private SoftMapCache images = new SoftMapCache(true);
57
 
    
 
68
 
58
69
    private ImageCacheListener cacheListener;
 
70
    private TimeStampProvider timeStampProvider;
 
71
    private long lastHouseKeeping;
 
72
 
 
73
    /**
 
74
     * Default constructor with default settings.
 
75
     */
 
76
    public ImageCache() {
 
77
        this(new TimeStampProvider(), new DefaultExpirationPolicy());
 
78
    }
 
79
 
 
80
    /**
 
81
     * Constructor for customized behaviour and testing.
 
82
     * @param timeStampProvider the time stamp provider to use
 
83
     * @param invalidURIExpirationPolicy the expiration policy for invalid URIs
 
84
     */
 
85
    public ImageCache(TimeStampProvider timeStampProvider,
 
86
            ExpirationPolicy invalidURIExpirationPolicy) {
 
87
        this.timeStampProvider = timeStampProvider;
 
88
        this.invalidURIExpirationPolicy = invalidURIExpirationPolicy;
 
89
        this.lastHouseKeeping = this.timeStampProvider.getTimeStamp();
 
90
    }
59
91
 
60
92
    /**
61
93
     * Sets an ImageCacheListener instance so the events in the image cache can be observed.
64
96
    public void setCacheListener(ImageCacheListener listener) {
65
97
        this.cacheListener = listener;
66
98
    }
67
 
    
 
99
 
68
100
    /**
69
101
     * Returns an ImageInfo instance for a given URI.
70
102
     * @param uri the image's URI
107
139
            return info;
108
140
        }
109
141
    }
110
 
    
 
142
 
111
143
    /**
112
144
     * Indicates whether a URI has previously been identified as an invalid URI.
113
145
     * @param uri the image's URI
114
146
     * @return true if the URI is invalid
115
147
     */
116
148
    public boolean isInvalidURI(String uri) {
117
 
        if (invalidURIs.contains(uri)) {
 
149
        boolean expired = removeInvalidURIIfExpired(uri);
 
150
        if (expired) {
 
151
            return false;
 
152
        } else {
118
153
            if (cacheListener != null) {
119
154
                cacheListener.invalidHit(uri);
120
155
            }
121
156
            return true;
122
157
        }
123
 
        return false;
124
 
    }
125
 
    
 
158
    }
 
159
 
 
160
    private boolean removeInvalidURIIfExpired(String uri) {
 
161
        Long timestamp = (Long) invalidURIs.get(uri);
 
162
        boolean expired = (timestamp == null)
 
163
                || this.invalidURIExpirationPolicy.isExpired(
 
164
                        this.timeStampProvider, timestamp.longValue());
 
165
        if (expired) {
 
166
            this.invalidURIs.remove(uri);
 
167
        }
 
168
        return expired;
 
169
    }
 
170
 
126
171
    /**
127
172
     * Returns an ImageInfo instance from the cache or null if none is found.
128
173
     * @param uri the image's URI
141
186
        }
142
187
        return info;
143
188
    }
144
 
    
 
189
 
145
190
    /**
146
191
     * Registers an ImageInfo instance with the cache.
147
192
     * @param info the ImageInfo instance
150
195
        //An already existing ImageInfo is replaced.
151
196
        imageInfos.put(info.getOriginalURI(), info);
152
197
    }
153
 
    
 
198
 
 
199
    private static final long ONE_HOUR = 60 * 60 * 1000;
 
200
 
154
201
    /**
155
202
     * Registers a URI as invalid so getImageInfo can indicate that quickly with no I/O access.
156
203
     * @param uri the URI of the invalid image
157
204
     */
158
 
    private void registerInvalidURI(String uri) {
159
 
        synchronized (invalidURIs) {
160
 
            // cap size of invalid list
161
 
            if (invalidURIs.size() > 100) {
162
 
                invalidURIs.clear();
163
 
            }
164
 
            invalidURIs.add(uri);
165
 
        }
 
205
    void registerInvalidURI(String uri) {
 
206
        invalidURIs.put(uri, new Long(timeStampProvider.getTimeStamp()));
 
207
 
 
208
        considerHouseKeeping();
166
209
    }
167
 
    
 
210
 
168
211
    /**
169
212
     * Returns an image from the cache or null if it wasn't found.
170
213
     * @param info the ImageInfo instance representing the image
174
217
    public Image getImage(ImageInfo info, ImageFlavor flavor) {
175
218
        return getImage(info.getOriginalURI(), flavor);
176
219
    }
177
 
    
 
220
 
178
221
    /**
179
222
     * Returns an image from the cache or null if it wasn't found.
180
223
     * @param uri the image's URI
196
239
        }
197
240
        return img;
198
241
    }
199
 
    
 
242
 
200
243
    /**
201
244
     * Registers an image with the cache.
202
245
     * @param img the image
224
267
        images.clear();
225
268
        doHouseKeeping();
226
269
    }
227
 
    
 
270
 
 
271
    private void considerHouseKeeping() {
 
272
        long ts = timeStampProvider.getTimeStamp();
 
273
        if (this.lastHouseKeeping + ONE_HOUR > ts) {
 
274
            //Housekeeping is only triggered through registration of an invalid URI at the moment.
 
275
            //Depending on the environment this could be triggered next to never.
 
276
            //Doing this check for every image access could be relatively costly.
 
277
            //The only alternative is a cleanup thread which is rather heavy-weight.
 
278
            this.lastHouseKeeping = ts;
 
279
            doHouseKeeping();
 
280
        }
 
281
    }
 
282
 
228
283
    /**
229
284
     * Triggers some house-keeping, i.e. removes stale entries.
230
285
     */
231
286
    public void doHouseKeeping() {
232
287
        imageInfos.doHouseKeeping();
233
288
        images.doHouseKeeping();
234
 
    }
235
 
    
 
289
        doInvalidURIHouseKeeping();
 
290
    }
 
291
 
 
292
    private void doInvalidURIHouseKeeping() {
 
293
        final Set currentEntries = new HashSet(this.invalidURIs.keySet());
 
294
        final Iterator iter = currentEntries.iterator();
 
295
        while (iter.hasNext()) {
 
296
            final String key = (String) iter.next();
 
297
            removeInvalidURIIfExpired(key);
 
298
        }
 
299
    }
 
300
 
236
301
}