blob: 43ea14e3c2b51c7bcd02bb8d188681e99da03503 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2002, 2007 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
* Jens Lukowski/Innoopract - initial renaming/restructuring
*
*******************************************************************************/
package org.eclipse.wst.xml.core.internal.contentmodel.util;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.Platform;
import org.eclipse.wst.xml.core.internal.contentmodel.CMDocument;
/**
* A singleton cache of CMDocuments. Because of the CM
*/
public class CMDocumentCache {
class CacheEntry {
String uri;
int status = STATUS_NOT_LOADED;
float progress;
private SoftReference cmDocumentReference;
CacheEntry(String uri) {
this.uri = uri;
}
CacheEntry(String uri, int status, CMDocument document) {
this.uri = uri;
this.status = status;
this.cmDocumentReference = new SoftReference(document);
}
CMDocument getCMDocument() {
if (cmDocumentReference == null)
return null;
return (CMDocument) cmDocumentReference.get();
}
public void setCMDocument(CMDocument document) {
cmDocumentReference = new SoftReference(document);
}
}
public static final int STATUS_NOT_LOADED = 0;
public static final int STATUS_LOADING = 2;
public static final int STATUS_LOADED = 3;
public static final int STATUS_ERROR = 4;
static final boolean DEBUG_CACHE = Boolean.valueOf(Platform.getDebugOption("org.eclipse.wst.xml.core/debug/cmdocumentcache")).booleanValue(); //$NON-NLS-1$
private static CMDocumentCache SHARED_INSTANCE = new CMDocumentCache();
public static CMDocumentCache getInstance() {
return SHARED_INSTANCE;
}
Map fSavedDocuments = new HashMap();
protected Hashtable fCachetable;
protected List listenerList = new ArrayList();
private CMDocumentCache() {
fCachetable = new Hashtable();
}
public void addListener(CMDocumentCacheListener listener) {
listenerList.add(listener);
}
/**
*
*/
public void clear() {
synchronized (fCachetable) {
fCachetable.clear();
}
notifyCacheCleared();
}
/**
*
*/
public CMDocument getCMDocument(String grammarURI) {
CMDocument result = null;
boolean cachedDocumentWasRemoved = false;
if (grammarURI != null) {
CacheEntry entry = null;
synchronized (fCachetable) {
entry = (CacheEntry) fCachetable.get(grammarURI);
if (entry != null) {
result = entry.getCMDocument();
cachedDocumentWasRemoved = ((entry.status == STATUS_LOADED) && (result == null));
}
}
if (cachedDocumentWasRemoved) {
if (DEBUG_CACHE)
System.out.println("CMDocumentCache hit on reclaimed document " + grammarURI);
/* a previously loaded document has been reclaimed, */
notifyCacheUpdated(grammarURI, entry.status, STATUS_NOT_LOADED, result);
/* wait until after notification to actually remove the entry */
synchronized (fCachetable) {
fCachetable.remove(grammarURI);
}
}
else if (DEBUG_CACHE && entry != null) {
System.out.println("CMDocumentCache hit on " + grammarURI);
}
}
else if (DEBUG_CACHE) {
System.out.println("CMDocumentCache miss on " + grammarURI);
}
return result;
}
public synchronized List getCMDocuments() {
List list = new ArrayList();
for (Iterator i = fCachetable.values().iterator(); i.hasNext();) {
CacheEntry entry = (CacheEntry) i.next();
CMDocument document = entry.getCMDocument();
if (document != null) {
list.add(document);
}
}
return list;
}
/**
*
*/
public int getStatus(String grammarURI) {
int result = STATUS_NOT_LOADED;
boolean cacheDocumentWasRemoved = false;
if (grammarURI != null) {
CacheEntry entry = null;
synchronized (fCachetable) {
entry = (CacheEntry) fCachetable.get(grammarURI);
if (entry != null) {
cacheDocumentWasRemoved = ((entry.status == STATUS_LOADED) && (entry.getCMDocument() == null));
}
}
if (cacheDocumentWasRemoved) {
/* a previously loaded document has been reclaimed, */
notifyCacheUpdated(grammarURI, entry.status, STATUS_NOT_LOADED, null);
/* wait until after notification to actually update the entry */
entry.status = STATUS_NOT_LOADED;
}
if (entry != null) {
result = entry.status;
}
}
return result;
}
/**
* Gets a corresponding CacheEntry for the given grammarURI, creating one
* if needed. Assumes that fCachetable is locked.
*
* @param grammarURI
* @return
*/
CacheEntry lookupOrCreate(String grammarURI) {
CacheEntry entry = null;
entry = (CacheEntry) fCachetable.get(grammarURI);
if (entry == null) {
entry = new CacheEntry(grammarURI);
fCachetable.put(grammarURI, entry);
}
return entry;
}
/**
*
*/
protected void notifyCacheCleared() {
CMDocumentCacheListener[] listeners = (CMDocumentCacheListener[]) listenerList.toArray(new CMDocumentCacheListener[0]);
for (int i = 0; i < listeners.length; i++) {
listeners[i].cacheCleared(this);
}
}
/**
*
*/
protected void notifyCacheUpdated(String uri, int oldStatus, int newStatus, CMDocument cmDocument) {
CMDocumentCacheListener[] listeners = (CMDocumentCacheListener[]) listenerList.toArray(new CMDocumentCacheListener[0]);
for (int i = 0; i < listeners.length; i++) {
listeners[i].cacheUpdated(this, uri, oldStatus, newStatus, cmDocument);
}
}
/**
*
*/
public void putCMDocument(String grammarURI, CMDocument cmDocument) {
if (grammarURI != null && cmDocument != null) {
CacheEntry entry = null;
int oldStatus = STATUS_NOT_LOADED;
synchronized (fCachetable) {
entry = lookupOrCreate(grammarURI);
oldStatus = entry.status;
entry.status = STATUS_LOADED;
entry.setCMDocument(cmDocument);
}
notifyCacheUpdated(grammarURI, oldStatus, entry.status, cmDocument);
}
}
public void removeListener(CMDocumentCacheListener listener) {
listenerList.remove(listener);
}
/**
*
*/
public void setStatus(String grammarURI, int status) {
if (grammarURI != null) {
CacheEntry entry = lookupOrCreate(grammarURI);
int oldStatus = entry.status;
entry.status = status;
notifyCacheUpdated(grammarURI, oldStatus, entry.status, entry.getCMDocument());
}
}
}