/******************************************************************************* * Copyright (c) 2015 Bruno Medeiros and other Contributors. * 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: * Bruno Medeiros - initial API and implementation *******************************************************************************/ package melnorme.lang.ide.core.project_model; import static melnorme.utilbox.core.Assert.AssertNamespace.assertNotNull; import java.util.HashSet; import org.eclipse.core.resources.IProject; import melnorme.lang.ide.core.utils.CoreExecutors; import melnorme.lang.tooling.bundle.BundleInfo; import melnorme.utilbox.concurrency.ITaskAgent; import melnorme.utilbox.concurrency.LatchRunnable; import melnorme.utilbox.misc.SimpleLogger; import melnorme.utilbox.ownership.Disposable; public abstract class BundleModelManager<BUNDLE_MODEL extends LangBundleModel> extends ProjectBasedModelManager implements IBundleModelManager { /* ----------------------------------- */ protected final BUNDLE_MODEL model; protected final SimpleLogger log; protected final ITaskAgent modelAgent = CoreExecutors.newExecutorTaskAgent(getClass()); protected final LatchRunnable startLatch = new LatchRunnable(); public BundleModelManager(BUNDLE_MODEL model) { this.model = assertNotNull(model); this.log = model.getLog(); initializeModelManagerWithModelAgent(); } public ITaskAgent getModelAgent() { return modelAgent; } protected void initializeModelManagerWithModelAgent() { // Put a latch runnable to prevent model from actually starting // This is because typically we want model to start only after UI code is fully loaded modelAgent.submitBasicRunnable(startLatch); // Run heavyweight initialization in executor thread. // This is necessary so that we avoid running the initialization during plugin initialization. // Otherwise there could be problems because initialization is heavyweight code: // it requests workspace locks (which may not be available) and issues workspace deltas modelAgent.submitBasicRunnable(new Runnable() { @Override public void run() { initializeModelManager(); } }); } @Override public void startManager() { log.println("==> Starting: " + getClass().getSimpleName()); startLatch.releaseAll(); } @Override protected void dispose_pre() { modelAgent.shutdownNowAndCancelAll(); } /* ----------------- ----------------- */ @Override public BUNDLE_MODEL getModel() { return model; } @Override public BundleInfo getProjectInfo(IProject project) { return model.getProjectInfo(project); } @Override protected void bundleProjectRemoved(IProject project) { model.removeProjectInfo(project); } @Override protected void bundleManifestFileChanged(IProject project) { bundleProjectAdded(project); } @Override protected final void bundleProjectAdded(IProject project) { if(ignoredProjects.contains(project)) { return; } handleBundleProjectAdded(project); } protected void handleBundleProjectAdded(IProject project) { model.setProjectInfo(project, createNewInfo(project)); } protected abstract BundleInfo createNewInfo(IProject project); /* ----------------- ----------------- */ protected final HashSet<IProject> ignoredProjects = new HashSet<>(); /** Ignore all manifest updates for given project. * This is intended to be used only for debugging or testing code. */ public Disposable enableIgnoreProject(IProject project) { ignoredProjects.add(project); return new Disposable() { @Override public void dispose() { ignoredProjects.remove(project); } }; } }