blob: 0741acd92640a94bc6d27223c1afb4f27d98b7fc [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2019 Xored Software 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
* https://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Xored Software Inc - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.rcptt.internal.core.model.deltas;
import java.util.HashMap;
import java.util.HashSet;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.rcptt.core.model.IElementChangedListener;
import org.eclipse.rcptt.core.model.IQ7Project;
import org.eclipse.rcptt.core.model.ModelException;
import org.eclipse.rcptt.internal.core.model.ModelManager;
public class DeltaProcessingState implements IResourceChangeListener {
public IElementChangedListener[] elementChangedListeners = new IElementChangedListener[5];
public int[] elementChangedListenerMasks = new int[5];
public int elementChangedListenerCount = 0;
public IResourceChangeListener[] preResourceChangeListeners = new IResourceChangeListener[1];
public int[] preResourceChangeEventMasks = new int[1];
public int preResourceChangeListenerCount = 0;
private ThreadLocal<DeltaProcessor> deltaProcessors = new ThreadLocal<DeltaProcessor>();
@SuppressWarnings("rawtypes")
public HashMap projectDependencies = new HashMap();
// private Set initializingThreads = Collections
// .synchronizedSet(new HashSet());
private HashSet<String> scriptProjectNamesCache;
public synchronized void addElementChangedListener(
IElementChangedListener listener, int eventMask) {
for (int i = 0; i < this.elementChangedListenerCount; i++) {
if (this.elementChangedListeners[i].equals(listener)) {
// only clone the masks, since we could be in the middle of
// notifications and one listener decide to change
// any event mask of another listeners (yet not notified).
int cloneLength = this.elementChangedListenerMasks.length;
System.arraycopy(
this.elementChangedListenerMasks,
0,
this.elementChangedListenerMasks = new int[cloneLength],
0, cloneLength);
this.elementChangedListenerMasks[i] = eventMask; // could be
// different
return;
}
}
// may need to grow, no need to clone, since iterators will have cached
// original arrays and max boundary and we only add to the end.
int length;
if ((length = this.elementChangedListeners.length) == this.elementChangedListenerCount) {
System.arraycopy(
this.elementChangedListeners,
0,
this.elementChangedListeners = new IElementChangedListener[length * 2],
0, length);
System.arraycopy(this.elementChangedListenerMasks, 0,
this.elementChangedListenerMasks = new int[length * 2], 0,
length);
}
this.elementChangedListeners[this.elementChangedListenerCount] = listener;
this.elementChangedListenerMasks[this.elementChangedListenerCount] = eventMask;
this.elementChangedListenerCount++;
}
public void addPreResourceChangedListener(IResourceChangeListener listener,
int eventMask) {
for (int i = 0; i < this.preResourceChangeListenerCount; i++) {
if (this.preResourceChangeListeners[i].equals(listener)) {
this.preResourceChangeEventMasks[i] |= eventMask;
return;
}
}
// may need to grow, no need to clone, since iterators will have cached
// original arrays and max boundary and we only add to the end.
int length;
if ((length = this.preResourceChangeListeners.length) == this.preResourceChangeListenerCount) {
System.arraycopy(
this.preResourceChangeListeners,
0,
this.preResourceChangeListeners = new IResourceChangeListener[length * 2],
0, length);
System.arraycopy(this.preResourceChangeEventMasks, 0,
this.preResourceChangeEventMasks = new int[length * 2], 0,
length);
}
this.preResourceChangeListeners[this.preResourceChangeListenerCount] = listener;
this.preResourceChangeEventMasks[this.preResourceChangeListenerCount] = eventMask;
this.preResourceChangeListenerCount++;
}
public DeltaProcessor getDeltaProcessor() {
DeltaProcessor deltaProcessor = (DeltaProcessor) this.deltaProcessors
.get();
if (deltaProcessor != null)
return deltaProcessor;
deltaProcessor = new DeltaProcessor(this,
ModelManager.getModelManager());
this.deltaProcessors.set(deltaProcessor);
return deltaProcessor;
}
public synchronized void removeElementChangedListener(
IElementChangedListener listener) {
for (int i = 0; i < this.elementChangedListenerCount; i++) {
if (this.elementChangedListeners[i].equals(listener)) {
// need to clone defensively since we might be in the middle of
// listener notifications (#fire)
int length = this.elementChangedListeners.length;
IElementChangedListener[] newListeners = new IElementChangedListener[length];
System.arraycopy(this.elementChangedListeners, 0, newListeners,
0, i);
int[] newMasks = new int[length];
System.arraycopy(this.elementChangedListenerMasks, 0, newMasks,
0, i);
// copy trailing listeners
int trailingLength = this.elementChangedListenerCount - i - 1;
if (trailingLength > 0) {
System.arraycopy(this.elementChangedListeners, i + 1,
newListeners, i, trailingLength);
System.arraycopy(this.elementChangedListenerMasks, i + 1,
newMasks, i, trailingLength);
}
// update manager listener state (#fire need to iterate over
// original listeners through a local variable to hold onto
// the original ones)
this.elementChangedListeners = newListeners;
this.elementChangedListenerMasks = newMasks;
this.elementChangedListenerCount--;
return;
}
}
}
public void removePreResourceChangedListener(
IResourceChangeListener listener) {
for (int i = 0; i < this.preResourceChangeListenerCount; i++) {
if (this.preResourceChangeListeners[i].equals(listener)) {
// need to clone defensively since we might be in the middle of
// listener notifications (#fire)
int length = this.preResourceChangeListeners.length;
IResourceChangeListener[] newListeners = new IResourceChangeListener[length];
int[] newEventMasks = new int[length];
System.arraycopy(this.preResourceChangeListeners, 0,
newListeners, 0, i);
System.arraycopy(this.preResourceChangeEventMasks, 0,
newEventMasks, 0, i);
// copy trailing listeners
int trailingLength = this.preResourceChangeListenerCount - i
- 1;
if (trailingLength > 0) {
System.arraycopy(this.preResourceChangeListeners, i + 1,
newListeners, i, trailingLength);
System.arraycopy(this.preResourceChangeEventMasks, i + 1,
newEventMasks, i, trailingLength);
}
// update manager listener state (#fire need to iterate over
// original listeners through a local variable to hold onto
// the original ones)
this.preResourceChangeListeners = newListeners;
this.preResourceChangeEventMasks = newEventMasks;
this.preResourceChangeListenerCount--;
return;
}
}
}
public void resourceChanged(final IResourceChangeEvent event) {
for (int i = 0; i < this.preResourceChangeListenerCount; i++) {
// wrap callbacks with Safe runnable for subsequent listeners to be
// called when some are causing grief
final IResourceChangeListener listener = this.preResourceChangeListeners[i];
if ((this.preResourceChangeEventMasks[i] & event.getType()) != 0)
SafeRunner.run(new ISafeRunnable() {
public void handleException(Throwable exception) {
exception.printStackTrace();
}
public void run() throws Exception {
listener.resourceChanged(event);
}
});
}
try {
getDeltaProcessor().resourceChanged(event);
} finally {
// TODO (jerome) see 47631, may want to get rid of following so as
// to reuse delta processor ?
if (event.getType() == IResourceChangeEvent.POST_CHANGE) {
this.deltaProcessors.set(null);
}
}
}
public IQ7Project findProject(String name) {
if (getOldProjectNames().contains(name))
return ModelManager.getModelManager().getModel().getProject(name);
return null;
}
public synchronized HashSet<String> getOldProjectNames() {
if (this.scriptProjectNamesCache == null) {
HashSet<String> result = new HashSet<String>();
IQ7Project[] projects;
try {
projects = ModelManager.getModelManager().getModel()
.getProjects();
} catch (ModelException e) {
return this.scriptProjectNamesCache;
}
for (int i = 0, length = projects.length; i < length; i++) {
IQ7Project project = projects[i];
result.add(project.getName());
}
return this.scriptProjectNamesCache = result;
}
return this.scriptProjectNamesCache;
}
public synchronized void resetOldProjectNames() {
this.scriptProjectNamesCache = null;
}
}