package org.eclipse.dltk.tcl.internal.core; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.LinkedList; import java.util.Queue; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.dltk.ast.parser.IASTCache; import org.eclipse.dltk.ast.parser.IModuleDeclaration; import org.eclipse.dltk.compiler.problem.IProblemReporter; import org.eclipse.dltk.compiler.problem.ProblemCollector; import org.eclipse.dltk.core.DLTKCore; import org.eclipse.dltk.core.ISourceModule; import org.eclipse.dltk.core.caching.IContentCache; import org.eclipse.dltk.core.environment.EnvironmentPathUtils; import org.eclipse.dltk.core.environment.IFileHandle; import org.eclipse.dltk.internal.core.ModelManager; import org.eclipse.dltk.tcl.ast.TclModule; import org.eclipse.dltk.tcl.ast.TclModuleDeclaration; import org.eclipse.dltk.tcl.internal.core.serialization.TclASTLoader; import org.eclipse.dltk.tcl.internal.core.serialization.TclASTSaver; import org.eclipse.dltk.tcl.internal.parser.NewTclSourceParser; @SuppressWarnings("restriction") public class TclASTCache implements IASTCache { public static final String TCL_AST_ATTRIBUTE = "_ast"; public static final String TCL_PKG_INFO = "_pinf"; public static final String TCL_STRUCTURE_INDEX = IContentCache.STRUCTURE_INDEX; public static final String TCL_MIXIN_INDEX = IContentCache.MIXIN_INDEX; private static class StoreEntry { ProblemCollector problems; IFileHandle handle; TclModule module; } private static class TclCacheSaver extends Job { final Queue<StoreEntry> queue = new LinkedList<StoreEntry>(); public TclCacheSaver() { super("Tcl Cache Saver"); setSystem(true); setPriority(SHORT); } @Override protected IStatus run(IProgressMonitor monitor) { for (;;) { final StoreEntry entry; synchronized (queue) { entry = queue.poll(); } if (entry == null) { break; } IContentCache cache = ModelManager.getModelManager() .getCoreCache(); OutputStream stream = cache.getCacheEntryAttributeOutputStream( entry.handle, TCL_AST_ATTRIBUTE); storeTclEntryInCache(entry.problems, entry.module, stream); try { stream.close(); } catch (IOException e) { } } return Status.OK_STATUS; } @Override public boolean shouldRun() { synchronized (queue) { return !queue.isEmpty(); } } void addToQueue(StoreEntry entry) { final int prevSize; synchronized (queue) { prevSize = queue.size(); if (prevSize <= 256) { queue.add(entry); } } if ((prevSize & 0x0F) == 0) { schedule(); } } } private final TclCacheSaver cacheSaverJob = new TclCacheSaver(); public ASTCacheEntry restoreModule(ISourceModule module) { IFileHandle handle = EnvironmentPathUtils.getFile(module); if (handle == null) { return null; } IContentCache cache = ModelManager.getModelManager().getCoreCache(); ProblemCollector collector = new ProblemCollector(); TclModule tclModule = null; tclModule = restoreTclModuleFromCache(handle, cache, collector); if (tclModule != null) { ASTCacheEntry entry = new ASTCacheEntry(); NewTclSourceParser parser = new NewTclSourceParser(); entry.problems = collector; entry.module = parser.parse(null, tclModule, null); if (entry.problems.isEmpty()) { entry.problems = null; } return entry; } return null; } public static TclModule restoreTclModuleFromCache(IFileHandle handle, IContentCache cache, IProblemReporter collector) { InputStream stream = cache.getCacheEntryAttribute(handle, TCL_AST_ATTRIBUTE); if (stream != null) { try { TclASTLoader loader = new TclASTLoader(stream); TclModule tclModule = loader.getModule(collector); if (tclModule != null) { return tclModule; } } catch (Exception e) { if (DLTKCore.DEBUG) { e.printStackTrace(); } } finally { try { stream.close(); } catch (IOException e) { } } } return null; } public void storeModule(ISourceModule module, IModuleDeclaration moduleDeclaration, ProblemCollector problems) { IFileHandle handle = EnvironmentPathUtils.getFile(module, false); if (handle == null) { return; } if (moduleDeclaration instanceof TclModuleDeclaration) { TclModuleDeclaration decl = (TclModuleDeclaration) moduleDeclaration; TclModule tclModule = decl.getTclModule(); if (tclModule != null) { StoreEntry entry = new StoreEntry(); entry.handle = handle; entry.module = tclModule; if (problems != null) { entry.problems = new ProblemCollector(); problems.copyTo(entry.problems); } cacheSaverJob.addToQueue(entry); } } } public static void storeTclEntryInCache(ProblemCollector problems, TclModule tclModule, OutputStream stream) { TclASTSaver saver; try { saver = new TclASTSaver(); saver.save(tclModule, problems, stream); } catch (IOException e) { if (DLTKCore.DEBUG) { e.printStackTrace(); } } } }