Merge remote-tracking branch 'origin/GP-3979_ghidragon_program_caching--SQUASHED'

This commit is contained in:
ghidra1 2023-11-27 12:10:07 -05:00
commit 2e5b4fc22a
34 changed files with 2198 additions and 948 deletions

View file

@ -18,7 +18,6 @@ package ghidra.framework.data;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
@ -28,6 +27,7 @@ import ghidra.framework.store.FileSystem;
import ghidra.framework.store.LockException;
import ghidra.util.Lock;
import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.datastruct.ListenerSet;
/**
* An abstract class that provides default behavior for DomainObject(s), specifically it handles
@ -54,7 +54,11 @@ public abstract class DomainObjectAdapter implements DomainObject {
protected Map<EventQueueID, DomainObjectChangeSupport> changeSupportMap =
new ConcurrentHashMap<EventQueueID, DomainObjectChangeSupport>();
private volatile boolean eventsEnabled = true;
private Set<DomainObjectClosedListener> closeListeners = new CopyOnWriteArraySet<>();
private ListenerSet<DomainObjectClosedListener> closeListeners =
new ListenerSet<>(DomainObjectClosedListener.class, false);
private ListenerSet<DomainObjectFileListener> fileChangeListeners =
new ListenerSet<>(DomainObjectFileListener.class, false);
private ArrayList<Object> consumers;
protected Map<String, String> metadata = new LinkedHashMap<String, String>();
@ -185,10 +189,15 @@ public abstract class DomainObjectAdapter implements DomainObject {
if (df == null) {
throw new IllegalArgumentException("DomainFile must not be null");
}
if (df == domainFile) {
return;
}
clearDomainObj();
DomainFile oldDf = domainFile;
domainFile = df;
fireEvent(new DomainObjectChangeRecord(DO_DOMAIN_FILE_CHANGED, oldDf, df));
fileChangeListeners.invoke().domainFileChanged(this);
}
protected void close() {
@ -204,13 +213,7 @@ public abstract class DomainObjectAdapter implements DomainObject {
queue.dispose();
}
notifyCloseListeners();
}
private void notifyCloseListeners() {
for (DomainObjectClosedListener listener : closeListeners) {
listener.domainObjectClosed(this);
}
closeListeners.invoke().domainObjectClosed(this);
closeListeners.clear();
}
@ -251,6 +254,16 @@ public abstract class DomainObjectAdapter implements DomainObject {
closeListeners.remove(listener);
}
@Override
public void addDomainFileListener(DomainObjectFileListener listener) {
fileChangeListeners.add(listener);
}
@Override
public void removeDomainFileListener(DomainObjectFileListener listener) {
fileChangeListeners.remove(listener);
}
@Override
public EventQueueID createPrivateEventQueue(DomainObjectListener listener, int maxDelay) {
EventQueueID eventQueueID = new EventQueueID();

View file

@ -0,0 +1,32 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.framework.data;
import ghidra.framework.model.DomainFile;
import ghidra.framework.model.DomainObject;
/**
* Listener for when the {@link DomainFile} associated with a {@link DomainObject} changes, such
* as when a 'Save As' action occurs. Unlike DomainObject events, these callbacks are not buffered
* and happen immediately when the DomainFile is changed.
*/
public interface DomainObjectFileListener {
/**
* Notification that the DomainFile for the given DomainObject has changed
* @param domainObject the DomainObject whose DomainFile changed
*/
public void domainFileChanged(DomainObject domainObject);
}

View file

@ -20,6 +20,7 @@ import java.io.IOException;
import java.util.List;
import java.util.Map;
import ghidra.framework.data.DomainObjectFileListener;
import ghidra.framework.options.Options;
import ghidra.util.ReadOnlyException;
import ghidra.util.exception.CancelledException;
@ -165,6 +166,22 @@ public interface DomainObject {
*/
public void removeCloseListener(DomainObjectClosedListener listener);
/**
* Adds a listener that will be notified when this DomainFile associated with this
* DomainObject changes, such as when a 'Save As' action occurs. Unlike DomainObject events,
* these notifications are not buffered and happen immediately when the DomainFile is changed.
*
* @param listener the listener to be notified when the associated DomainFile changes
*/
public void addDomainFileListener(DomainObjectFileListener listener);
/**
* Removes the given DomainObjectFileListener listener.
*
* @param listener the listener to remove.
*/
public void removeDomainFileListener(DomainObjectFileListener listener);
/**
* Creates a private event queue that can be flushed independently from the main event queue.
* @param listener the listener to be notified of domain object events.

View file

@ -74,6 +74,15 @@ public class GhidraURL {
return str != null && str.startsWith(PROTOCOL_URL_START);
}
/**
* Tests if the given url is using the Ghidra protocol
* @param url the url to test
* @return true if the url is using the Ghidra protocol
*/
public static boolean isGhidraURL(URL url) {
return url != null && url.getProtocol().equals(PROTOCOL);
}
/**
* Determine if URL string uses a local format (e.g., {@code ghidra:/path...}).
* Extensive validation is not performed. This method is intended to differentiate