/*******************************************************************************
* Copyright (c) 2014, 2015 Cisco Systems, Inc. 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
*
*******************************************************************************/
package com.cisco.yangide.core.model;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.ISaveContext;
import org.eclipse.core.resources.ISaveParticipant;
import org.eclipse.core.resources.ISavedState;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
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.jdt.core.JavaCore;
import com.cisco.yangide.core.IOpenable;
import com.cisco.yangide.core.OpenableElementCache;
import com.cisco.yangide.core.OpenableElementInfo;
import com.cisco.yangide.core.YangCorePlugin;
import com.cisco.yangide.core.YangModelException;
import com.cisco.yangide.core.indexing.DeltaProcessor;
import com.cisco.yangide.core.indexing.ElementIndexInfo;
import com.cisco.yangide.core.indexing.ElementIndexType;
import com.cisco.yangide.core.indexing.IJob;
import com.cisco.yangide.core.indexing.IndexManager;
import com.cisco.yangide.core.indexing.JobAdapter;
/**
* @author Konstantin Zaitsev
* @date Jun 24, 2014
*/
public final class YangModelManager implements ISaveParticipant {
/** Singleton instance. */
private static final YangModelManager MANAGER = new YangModelManager();
/**
* Infos cache.
*/
private OpenableElementCache cache;
private YangModel yangModel = new YangModel();
public IndexManager indexManager = null;
public DeltaProcessor deltaProcessor = null;
protected HashSet<IOpenable> elementsOutOfSynchWithBuffers = new HashSet<IOpenable>(11);
/**
* @return singleton instance
*/
public static YangModelManager getYangModelManager() {
return MANAGER;
}
public void startup() throws CoreException {
try {
// initialize Yang model cache, 5000 is default value for JDT openable cache
this.cache = new OpenableElementCache(5000);
this.indexManager = new IndexManager();
this.deltaProcessor = new DeltaProcessor(this);
final IWorkspace workspace = ResourcesPlugin.getWorkspace();
workspace.addResourceChangeListener(deltaProcessor,
/*
* update spec in JavaCore#addPreProcessingResourceChangedListener(...) if adding more
* event types
*/
IResourceChangeEvent.PRE_BUILD | IResourceChangeEvent.POST_BUILD | IResourceChangeEvent.POST_CHANGE
| IResourceChangeEvent.PRE_DELETE | IResourceChangeEvent.PRE_CLOSE
| IResourceChangeEvent.PRE_REFRESH);
// Register for JDT Class path changes.
JavaCore.addElementChangedListener(deltaProcessor);
// start indexing
if (this.indexManager != null) {
this.indexManager.reset();
}
// init projects
yangModel.getYangProjects();
Job processSavedState = new Job("Processing Yang changes since last activation") {
@Override
protected IStatus run(IProgressMonitor monitor) {
try {
workspace.run(new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor progress) throws CoreException {
ISavedState savedState = workspace.addSaveParticipant(YangCorePlugin.PLUGIN_ID,
YangModelManager.this);
if (savedState != null) {
// the event type coming from the saved state is always
// POST_AUTO_BUILD
// force it to be POST_CHANGE so that the delta processor can
// handle it
YangModelManager.this.deltaProcessor.overridenEventType = IResourceChangeEvent.POST_CHANGE;
savedState.processResourceChangeEvents(YangModelManager.this.deltaProcessor);
}
}
}, monitor);
} catch (CoreException e) {
return e.getStatus();
}
return Status.OK_STATUS;
}
};
processSavedState.setSystem(true);
processSavedState.setPriority(Job.SHORT); // process asap
processSavedState.schedule();
} catch (RuntimeException e) {
e.printStackTrace();
shutdown();
throw e;
}
}
public void shutdown() {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
workspace.removeResourceChangeListener(this.deltaProcessor);
workspace.removeSaveParticipant(YangCorePlugin.PLUGIN_ID);
// Stop indexing
if (this.indexManager != null) {
this.indexManager.shutdown();
}
// wait for the initialization job to finish
try {
Job.getJobManager().join(YangCorePlugin.PLUGIN_ID, null);
} catch (InterruptedException e) {
// ignore
}
}
/**
* @param element
* @return
*/
public synchronized Object getInfo(IOpenable element) {
return cache.get(element);
}
/*
* Puts the infos in the given map (keys are IJavaElements and values are JavaElementInfos) in
* the Java model cache in an atomic way.
*/
protected synchronized void putInfos(IOpenable openedElement, Map<IOpenable, OpenableElementInfo> newElements) {
Object existingInfo = this.cache.get(openedElement);
closeChildren(existingInfo);
Iterator<Entry<IOpenable, OpenableElementInfo>> iterator = newElements.entrySet().iterator();
while (iterator.hasNext()) {
Entry<IOpenable, OpenableElementInfo> entry = iterator.next();
this.cache.put(entry.getKey(), entry.getValue());
}
}
private void closeChildren(Object info) {
// if (info instanceof JavaElementInfo) {
// IJavaElement[] children = ((JavaElementInfo)info).getChildren();
// for (int i = 0, size = children.length; i < size; ++i) {
// JavaElement child = (JavaElement) children[i];
// try {
// child.close();
// } catch (JavaModelException e) {
// // ignore
// }
// }
// }
}
/*
* Removes all cached info for the given element (including all children) from the cache.
* Returns the info for the given element, or null if it was closed.
*/
public synchronized Object removeInfoAndChildren(IOpenable element) throws YangModelException {
Object info = this.cache.get(element);
if (info != null) {
closeChildren(info);
this.cache.remove(element);
return info;
}
return null;
}
/**
* @return the yangModel
*/
public YangModel getYangModel() {
return yangModel;
}
/**
* @return index manager
*/
public static IndexManager getIndexManager() {
return MANAGER.indexManager;
}
public static ElementIndexInfo[] search(final String module, final String revision, final String name,
final ElementIndexType type, final IProject project, final IPath scope) {
final AtomicReference<ElementIndexInfo[]> search = new AtomicReference<>();
YangModelManager.getIndexManager().performConcurrentJob(new JobAdapter() {
@Override
public boolean execute(IProgressMonitor progress) {
search.set(MANAGER.indexManager.search(module, revision, name, type, project, scope));
return false;
}
}, IJob.WaitUntilReady, null);
return search.get();
}
protected HashSet<IOpenable> getElementsOutOfSynchWithBuffers() {
return this.elementsOutOfSynchWithBuffers;
}
// / methods from ISaveParticipant
@Override
public void doneSaving(ISaveContext context) {
}
@Override
public void prepareToSave(ISaveContext context) throws CoreException {
}
@Override
public void rollback(ISaveContext context) {
}
@Override
public void saving(ISaveContext context) throws CoreException {
}
// / end of methods from ISaveParticipant
}