KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > team > core > variants > CachedResourceVariant


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.team.core.variants;
12
13 import java.io.IOException JavaDoc;
14 import java.io.InputStream JavaDoc;
15
16 import org.eclipse.core.resources.*;
17 import org.eclipse.core.runtime.*;
18 import org.eclipse.osgi.util.NLS;
19 import org.eclipse.team.core.TeamException;
20 import org.eclipse.team.internal.core.*;
21
22 /**
23  * A resource variant is a partial implementation of a remote resource
24  * whose contents and handle are cached locally. It is assumed that a
25  * resource variant is an immutable version or revision of a resource.
26  * Therefore, once the contents are cached they cannot be replaced.
27  * However, the cached handle can be replaced to allow clients to
28  * cache addition state or properties for a resource variant.
29  * <p>
30  * Overriding subclasses need to provide a cache Id for all their resource variants
31  * and a cache path for each resource variant that uniquely identifies it. In addition,
32  * they must implement <code>fetchContents</code> to retrieve the contents of the
33  * resource variant and then call <code>setContents</code> to place these contents in the cache.
34  * Subclasses may also call <code>cacheHandle</code> in order to place the handle in the
35  * cache so that it can be retrieved later by calling <code>getCachedHandle</code> on any
36  * resource variant whose cache path is the same as the cached handle. This allows subclasses to
37  * cache additional resource variant properties such as author, comment, etc.
38  * </p>
39  * <p>
40  * The <code>IStorage</code> instance returned by this class will be
41  * an {@link org.eclipse.core.resources.IEncodedStorage}.
42  * <p>
43  * The cache in which the resource variants reside will occasionally clear
44  * cached entries if they have not been accessed for a certain amount of time.
45  * </p>
46  *
47  * @since 3.0
48  */

49 public abstract class CachedResourceVariant extends PlatformObject implements IResourceVariant {
50     
51     // holds the storage instance for this resource variant
52
private IStorage storage;
53     
54     /*
55      * Internal class which provides access to the cached contents
56      * of this resource variant
57      */

58     class ResourceVariantStorage implements IEncodedStorage {
59         public InputStream JavaDoc getContents() throws CoreException {
60             if (!isContentsCached()) {
61                 // The cache may have been cleared if someone held
62
// on to the storage too long
63
throw new TeamException(NLS.bind(Messages.CachedResourceVariant_0, new String JavaDoc[] { getCachePath() }));
64             }
65             return getCachedContents();
66         }
67         public IPath getFullPath() {
68             return getDisplayPath();
69         }
70         public String JavaDoc getName() {
71             return CachedResourceVariant.this.getName();
72         }
73         public boolean isReadOnly() {
74             return true;
75         }
76         public Object JavaDoc getAdapter(Class JavaDoc adapter) {
77             return CachedResourceVariant.this.getAdapter(adapter);
78         }
79         public String JavaDoc getCharset() throws CoreException {
80             InputStream JavaDoc contents = getContents();
81             try {
82                 String JavaDoc charSet = TeamPlugin.getCharset(getName(), contents);
83                 return charSet;
84             } catch (IOException JavaDoc e) {
85                 throw new TeamException(new Status(IStatus.ERROR, TeamPlugin.ID, IResourceStatus.FAILED_DESCRIBING_CONTENTS, NLS.bind(Messages.CachedResourceVariant_1, new String JavaDoc[] { getFullPath().toString() }), e));
86             } finally {
87                 try {
88                     contents.close();
89                 } catch (IOException JavaDoc e1) {
90                     // Ignore
91
}
92             }
93         }
94     }
95     
96     /* (non-Javadoc)
97      * @see org.eclipse.team.core.variants.IResourceVariant#getStorage(org.eclipse.core.runtime.IProgressMonitor)
98      */

99     public IStorage getStorage(IProgressMonitor monitor) throws TeamException {
100         if (isContainer()) return null;
101         ensureContentsCached(monitor);
102         if (storage == null) {
103             storage = new ResourceVariantStorage();
104         }
105         return storage;
106     }
107     
108     private void ensureContentsCached(IProgressMonitor monitor) throws TeamException {
109         // Ensure that the contents are cached from the server
110
if (!isContentsCached()) {
111             fetchContents(monitor);
112         }
113     }
114     
115     /**
116      * Method that is invoked when the contents of the resource variant need to
117      * be fetched. This method will only be invoked for files (i.e.
118      * <code>isContainer()</code> returns <code>false</code>.
119      * Subclasses should override this method and invoke <code>setContents</code>
120      * with a stream containing the fetched contents.
121      * @param monitor a progress monitor
122      */

123     protected abstract void fetchContents(IProgressMonitor monitor) throws TeamException;
124
125     /**
126      * This method should be invoked by subclasses from within their <code>fetchContents</code>
127      * method in order to cache the contents for this resource variant.
128      * <p>
129      * This method is not intended to be overridden by clients.
130      * @param stream the stream containing the contents of the resource variant
131      * @param monitor a progress monitor
132      * @throws TeamException
133      */

134     protected void setContents(InputStream JavaDoc stream, IProgressMonitor monitor) throws TeamException {
135         // Ensure that there is a cache entry to receive the contents
136
Assert.isTrue(!isContainer());
137         if (!isHandleCached()) cacheHandle();
138         getCacheEntry().setContents(stream, monitor);
139     }
140     
141     private ResourceVariantCacheEntry getCacheEntry() {
142         return getCache().getCacheEntry(this.getCachePath());
143     }
144     
145     /**
146      * Return whether there are already contents cached for this resource variant.
147      * This method will return <code>false</code> even if the contents are currently
148      * being cached by another thread. The consequence of this is that the contents
149      * may be fetched twice in the rare case where two threads request the same contents
150      * concurrently. For containers, this method will always return <code>false</code>.
151      * <p>
152      * This method is not intended to be overridden by clients.
153      * @return whether there are contents cached for this resource variant
154      */

155     public boolean isContentsCached() {
156         if (isContainer() || !isHandleCached()) {
157             return false;
158         }
159         ResourceVariantCacheEntry entry = getCache().getCacheEntry(getCachePath());
160         return entry.getState() == ResourceVariantCacheEntry.READY;
161     }
162     
163     /**
164      * Return the cached contents for this resource variant or <code>null</code>
165      * if the contents have not been cached.
166      * For containers, this method will always return <code>null</code>.
167      * <p>
168      * This method is not intended to be overridden by clients.
169      * @return the cached contents or <code>null</code>
170      * @throws TeamException
171      */

172     protected InputStream JavaDoc getCachedContents() throws TeamException {
173         if (isContainer() || !isContentsCached()) return null;
174         return getCache().getCacheEntry(getCachePath()).getContents();
175     }
176     
177     /**
178      * Return <code>true</code> if the cache contains an entry for this resource
179      * variant. It is possible that another instance of this variant is cached.
180      * To get the cached instance, call <code>getCachedHandle()</code>. Note that
181      * cached contents can be retrieved from any handle to a resource variant whose
182      * cache path (as returned by <code>getCachePath()</code>) match but other
183      * state information may only be accessible from the cached copy.
184      * <p>
185      * This method is not intended to be overridden by clients.
186      * @return whether the variant is cached
187      */

188     protected boolean isHandleCached() {
189         return (getCache().hasEntry(getCachePath()));
190     }
191
192     /**
193      * Get the path that uniquely identifies the remote resource
194      * variant. This path describes the remote location where
195      * the remote resource is stored and also uniquely identifies
196      * each resource variant. It is used to uniquely identify this
197      * resource variant when it is stored in the resource variant cache.
198      * This path is also returned as the full path of the <code>IStorage</code>
199      * returned from this variant so the path could be converted to an
200      * <code>IPath</code> and displayed to the user.
201      * @return the full path of the remote resource variant
202      */

203     protected abstract String JavaDoc getCachePath();
204     
205     /**
206      * Return the size (in bytes) of the contents of this resource variant.
207      * The method will return 0 if the contents have not yet been cached
208      * locally.
209      * For containers, this method will always return 0.
210      * @return the size (in bytes) of the contents of this resource variant
211      */

212     public long getSize() {
213         if (isContainer() || !isContentsCached()) return 0;
214         ResourceVariantCacheEntry entry = getCacheEntry();
215         if (entry == null || entry.getState() != ResourceVariantCacheEntry.READY) {
216             return 0;
217         }
218         return entry.getSize();
219     }
220     
221     /*
222      * Return the cache that is used to cache this resource variant and its contents.
223      * @return Returns the cache.
224      */

225     private ResourceVariantCache getCache() {
226         ResourceVariantCache.enableCaching(getCacheId());
227         return ResourceVariantCache.getCache(getCacheId());
228     }
229     
230     /**
231      * Return the ID that uniquely identifies the cache in which this resource variant
232      * is to be cache. The ID of the plugin that provides the resource variant subclass
233      * is a good candidate for this ID. The creation, management and disposal of the cache
234      * is managed by Team.
235      * @return the cache ID
236      */

237     protected abstract String JavaDoc getCacheId();
238
239     /**
240      * Return the cached handle for this resource variant if there is
241      * one. If there isn't one, then <code>null</code> is returned.
242      * If there is no cached handle and one is desired, then <code>cacheHandle()</code>
243      * should be called.
244      * <p>
245      * This method is not intended to be overridden by clients.
246      * @return a cached copy of this resource variant or <code>null</code>
247      */

248     protected CachedResourceVariant getCachedHandle() {
249         ResourceVariantCacheEntry entry = getCacheEntry();
250         if (entry == null) return null;
251         return entry.getResourceVariant();
252     }
253     
254     /**
255      * Cache this handle in the cache, replacing any previously cached handle.
256      * Note that caching this handle will replace any state associated with a
257      * previously cached handle, if there is one, but the contents will remain.
258      * The reason for this is the assumption that the cache path for a resource
259      * variant (as returned by <code>getCachePath()</code> identifies an immutable
260      * resource version (or revision). The ability to replace the handle itself
261      * is provided so that additional state may be cached before or after the contents
262      * are fetched.
263      * <p>
264      * This method is not intended to be overridden by clients.
265      */

266     protected void cacheHandle() {
267         getCache().add(getCachePath(), this);
268     }
269     
270     /**
271      * Return the full path of this resource that should be displayed to the
272      * user. This path is also used as the path of the <code>IStorage</code> that
273      * is returned by this instance.
274      * Subclasses may override.
275      * @return the full path of this resource that should be displayed to the
276      * user
277      *
278      * @since 3.1
279      */

280     public IPath getDisplayPath() {
281         return new Path(null, getCachePath());
282     }
283     
284 }
285
Popular Tags