blob: c8ec6ab43605b2fae3cb317348000e5c01447fda [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015, 2019 1C-Soft LLC.
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Vladimir Piskarev (1C) - initial API and implementation
*******************************************************************************/
package org.eclipse.handly.internal.examples.jmodel;
import static org.eclipse.handly.context.Contexts.EMPTY_CONTEXT;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.handly.context.Context;
import org.eclipse.handly.context.IContext;
import org.eclipse.handly.examples.jmodel.IJavaElement;
import org.eclipse.handly.model.ElementDeltas;
import org.eclipse.handly.model.IElementDelta;
import org.eclipse.handly.model.IElementHandleFactory;
import org.eclipse.handly.model.impl.support.ElementChangeEvent;
import org.eclipse.handly.model.impl.support.ElementDelta;
import org.eclipse.handly.model.impl.support.ElementManager;
import org.eclipse.handly.model.impl.support.IModelManager;
import org.eclipse.handly.model.impl.support.INotificationManager;
import org.eclipse.handly.model.impl.support.NotificationManager;
import org.eclipse.handly.util.SavedStateJob;
/**
* The manager for the Java model.
*
* @threadsafe This class is intended to be thread-safe
*/
public class JavaModelManager
implements IModelManager, IResourceChangeListener
{
/**
* The sole instance of the manager.
*/
public static final JavaModelManager INSTANCE = new JavaModelManager();
private JavaModel javaModel;
private ElementManager elementManager;
private NotificationManager notificationManager;
private DeltaProcessingState deltaState;
private Context modelContext;
private Map<IProject, PerProjectInfo> perProjectInfo =
new HashMap<IProject, PerProjectInfo>(5); // NOTE: this object itself is used as a lock to synchronize creation/removal of per project info
public void startup() throws Exception
{
try
{
IWorkspace workspace = ResourcesPlugin.getWorkspace();
javaModel = new JavaModel(workspace);
elementManager = new ElementManager(new JavaModelCache());
notificationManager = new NotificationManager();
deltaState = new DeltaProcessingState();
deltaState.initialize();
modelContext = new Context();
modelContext.bind(INotificationManager.class).to(
notificationManager);
modelContext.bind(ElementDelta.Factory.class).to(
element -> new JavaElementDelta((IJavaElement)element));
modelContext.bind(IElementHandleFactory.class).to(
new JavaElementHandleFactory());
workspace.addResourceChangeListener(this,
IResourceChangeEvent.POST_CHANGE);
new SavedStateJob(Activator.PLUGIN_ID, this).schedule();
}
catch (Exception e)
{
shutdown();
throw e;
}
}
public void shutdown() throws Exception
{
ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
modelContext = null;
deltaState = null;
notificationManager = null;
elementManager = null;
javaModel = null;
}
@Override
public void resourceChanged(IResourceChangeEvent event)
{
DeltaProcessor deltaProcessor = new DeltaProcessor(deltaState);
try
{
event.getDelta().accept(deltaProcessor);
}
catch (CoreException e)
{
Activator.logError(e);
}
finally
{
deltaState.reset();
}
IElementDelta delta = deltaProcessor.getDelta();
if (!ElementDeltas.isEmpty(delta))
{
getNotificationManager().fireElementChangeEvent(
new ElementChangeEvent(ElementChangeEvent.POST_CHANGE, delta));
}
}
@Override
public JavaModel getModel()
{
if (javaModel == null)
throw new IllegalStateException();
return javaModel;
}
@Override
public ElementManager getElementManager()
{
if (elementManager == null)
throw new IllegalStateException();
return elementManager;
}
public NotificationManager getNotificationManager()
{
if (notificationManager == null)
throw new IllegalStateException();
return notificationManager;
}
public IContext getModelContext()
{
if (modelContext == null)
throw new IllegalStateException();
return modelContext;
}
/**
* Returns the per-project info for the given project.
* If specified, create the info if the info doesn't exist.
* <p>
* Note that no check is done at this time on the existence
* or the nature of this project.
* </p>
*
* @param project the given project
* @param create indicates whether to create the info if it doesn't exist
* @return the per-project info for the given project, or <code>null</code>
* if the info doesn't exist and <code>create == false</code>
*/
public PerProjectInfo getPerProjectInfo(IProject project, boolean create)
{
synchronized (perProjectInfo)
{
PerProjectInfo info = perProjectInfo.get(project);
if (info == null && create)
{
info = new PerProjectInfo(project);
perProjectInfo.put(project, info);
}
return info;
}
}
/**
* Returns the per-project info for the given project. If the info
* doesn't exist, check for the project existence and create the info.
*
* @param project the given project
* @return the per-project info for the given project (never <code>null</code>)
* @throws CoreException if the Java project doesn't exist
*/
public PerProjectInfo getPerProjectInfoCheckExistence(IProject project)
throws CoreException
{
PerProjectInfo info = getPerProjectInfo(project, false);
if (info == null)
{
new JavaProject(javaModel, project).validateExistence_(
EMPTY_CONTEXT);
info = getPerProjectInfo(project, true);
}
return info;
}
public void removePerProjectInfo(IProject project)
{
synchronized (perProjectInfo)
{
perProjectInfo.remove(project);
}
}
private JavaModelManager()
{
}
}