Skip to main content
aboutsummaryrefslogblamecommitdiffstats
blob: ff8be693949f1da293c8a81d6910d058b1a62544 (plain) (tree)
1
2
3
4
5
6
                                                                                
                                                       

                                                                        
                                                           
                                            











                                                                                 
                                                            












                                                             




























































                                                                                                                                         
                                     


                               
                                       





















































































































                                                                                                                                                 
/*******************************************************************************
 * Copyright (c) 2000, 2004 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.team.internal.core;

import java.io.*;
import java.util.Date;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.jobs.ILock;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.core.variants.CachedResourceVariant;

/**
 * This class provides the implementation for the ICacheEntry
 */
public class ResourceVariantCacheEntry {
	
	public static final int UNINITIALIZED = 0;
	public static final int READY = 1;
	public static final int DISPOSED = 2;
	
	private String id;
	private String filePath;
	private ResourceVariantCache cache;
	private int state = UNINITIALIZED;
	private long lastAccess;
	private CachedResourceVariant resourceVariant;
	private ILock lock;

	public ResourceVariantCacheEntry(ResourceVariantCache cache, ILock lock, String id, String filePath) {
		this.lock = lock;
		state = UNINITIALIZED;
		this.cache = cache;
		this.id = id;
		this.filePath = filePath;
		registerHit();
	}

	/* (non-Javadoc)
	 * @see org.eclipse.team.core.sync.ICacheEntry#getContents()
	 */
	public InputStream getContents() throws TeamException {
		if (state != READY) return null;
		registerHit();
		File ioFile = getFile();
		try {
			try {
				if (ioFile.exists()) {
					return new FileInputStream(ioFile);
				}
			} catch (IOException e) {
				// Try to purge the cache and continue
				cache.purgeFromCache(this);
				throw e;
			}
		} catch (IOException e) {
			// We will end up here if we couldn't read or delete the cache file
			throw new TeamException(Policy.bind("RemoteContentsCache.fileError", ioFile.getAbsolutePath()), e); //$NON-NLS-1$
		}
		// This can occur when there is no remote contents
		return new ByteArrayInputStream(new byte[0]);
	}

	protected File getFile() {
		return new File(cache.getCachePath().toFile(), filePath);
	}

	/**
	 * Set the contents of for this cache entry. This method supports concurrency by only allowing
	 * one cache entry to be written at a time. In the case of two concurrent writes to the same cache entry,
	 * the contents from the first write is used and the content from subsequent writes is ignored.
	 * @param stream an InputStream that provides the contents to be cached
	 * @param monitor a progress monitor
	 * @throws TeamException if the entry is DISPOSED or an I/O error occurres
	 */
	public void setContents(InputStream stream, IProgressMonitor monitor) throws TeamException {
		// Use a lock to only allow one write at a time
		beginOperation();
		try {
			internalSetContents(stream, monitor);
		} finally {
			endOperation();
		}
	}
	
	private void endOperation() {
		lock.release();
	}

	private void beginOperation() {
		lock.acquire();
	}

	private void internalSetContents(InputStream stream, IProgressMonitor monitor) throws TeamException {
		// if the state is DISPOSED then there is a problem
		if (state == DISPOSED) {
			throw new TeamException(Policy.bind("RemoteContentsCacheEntry.3", cache.getName(), id)); //$NON-NLS-1$
		}
		// Otherwise, the state is UNINITIALIZED or READY so we can proceed
		registerHit();
		File ioFile = getFile();
		try {
			
			// Open the cache file for writing
			OutputStream out;
			try {
				if (state == UNINITIALIZED) {
					out = new BufferedOutputStream(new FileOutputStream(ioFile));
				} else {
					// If the entry is READY, the contents must have been read in another thread.
					// We still need to red the contents but they can be ignored since presumably they are the same
					out = new ByteArrayOutputStream();
				}
			} catch (FileNotFoundException e) {
				throw new TeamException(Policy.bind("RemoteContentsCache.fileError", ioFile.getAbsolutePath()), e); //$NON-NLS-1$
			}
			
			// Transfer the contents
			try {
				try {
					byte[] buffer = new byte[1024];
					int read;
					while ((read = stream.read(buffer)) >= 0) {
						Policy.checkCanceled(monitor);
						out.write(buffer, 0, read);
					}
				} finally {
					out.close();
				}
			} catch (IOException e) {
				// Make sure we don't leave the cache file around as it may not have the right contents
				cache.purgeFromCache(this);
				throw e;
			}
			
			// Mark the cache entry as ready
			state = READY;
		} catch (IOException e) {
			throw new TeamException(Policy.bind("RemoteContentsCache.fileError", ioFile.getAbsolutePath()), e); //$NON-NLS-1$
		} finally {
			try {
				stream.close();
			} catch (IOException e1) {
				// Ignore close errors
			}
		}

	}

	/* (non-Javadoc)
	 * @see org.eclipse.team.core.sync.ICacheEntry#getState()
	 */
	public int getState() {
		return state;
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.team.core.sync.ICacheEntry#getSize()
	 */
	public long getSize() {
		if (state != READY) return 0;
		File ioFile = getFile();
		if (ioFile.exists()) {
			return ioFile.length();
		}
		return 0;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.team.core.sync.ICacheEntry#getLastAccessTimeStamp()
	 */
	public long getLastAccessTimeStamp() {
		return lastAccess;
	}

	/**
	 * Registers a hit on this cache entry. This updates the last access timestamp.
	 * Thsi method is intended to only be invokded from inside this class or the cahce itself.
	 * Other clients should not use it.
	 */
	protected void registerHit() {
		lastAccess = new Date().getTime();
	}

	public void dispose() {
		// Use a lock to avoid changing state while another thread may be writting
		beginOperation();
		try {
			state = DISPOSED;
			cache.purgeFromCache(this);
		} finally {
			endOperation();
		}
	}

	
	public String getId() {
		return id;
	}
	
	public CachedResourceVariant getResourceVariant() {
		return resourceVariant;
	}
	
	public void setResourceVariant(CachedResourceVariant resourceVariant) {
		this.resourceVariant = resourceVariant;
	}
}

Back to the top