/*
* Copyright 2003-2017 JetBrains s.r.o.
*
* 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 jetbrains.mps.smodel;
import jetbrains.mps.project.Project;
import jetbrains.mps.util.Computable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.mps.openapi.repository.CommandListener;
import javax.swing.SwingUtilities;
import java.util.HashMap;
import java.util.Map;
/**
* Evgeny Gryaznov, Sep 3, 2010
*/
class DefaultModelAccess extends ModelAccess {
/**
* write action is the same as command; storing a map from command listener clients to the actual write action listeners
*/
private final Map<CommandListener, CommandWriteActionAdapter> myAdaptersMap = new HashMap<>();
DefaultModelAccess() {
}
@Override
public void runReadAction(final Runnable r) {
if (canRead()) {
r.run();
return;
}
getReadLock().lock();
try {
r.run();
} finally {
getReadLock().unlock();
}
}
@Override
public void runWriteAction(final Runnable r) {
if (canWrite()) {
r.run();
return;
}
assertNotWriteFromRead();
getWriteLock().lock();
try {
clearRepositoryStateCaches();
myWriteActionDispatcher.run(r);
} finally {
getWriteLock().unlock();
}
}
private void assertNotWriteFromRead() {
assert !canRead() : "Deadlock: Write action should not be executed from within read.";
}
@Override
public <T> T runReadAction(final Computable<T> c) {
if (canRead()) {
return c.compute();
}
getReadLock().lock();
try {
return c.compute();
} finally {
getReadLock().unlock();
}
}
@Override
public <T> T runWriteAction(final Computable<T> c) {
if (canWrite()) {
return c.compute();
}
getWriteLock().lock();
try {
clearRepositoryStateCaches();
return myWriteActionDispatcher.compute(c);
} finally {
getWriteLock().unlock();
}
}
@Override
public void flushEventQueue() {
}
@Override
public void runReadInEDT(final Runnable r) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
runReadAction(r);
}
});
}
@Override
public void runWriteInEDT(final Runnable r) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
runWriteAction(r);
}
});
}
@Override
public void runCommandInEDT(@NotNull Runnable r, @NotNull Project p) {
runWriteInEDT(r);
}
@Override
public boolean isInEDT() {
return canWrite();
}
@Override
public <T> T tryRead(final Computable<T> c) {
if (getReadLock().tryLock()) {
try {
return c.compute();
} finally {
getReadLock().unlock();
}
} else {
return null;
}
}
@Override
public boolean tryRead(Runnable r) {
if (getReadLock().tryLock()) {
try {
r.run();
} finally {
getReadLock().unlock();
}
return true;
} else {
return false;
}
}
@Override
public void executeCommand(Runnable r, Project project) {
runWriteAction(r);
}
@Override
public void runUndoTransparentCommand(Runnable r, Project project) {
r.run();
}
@Override
public void runUndoTransparentCommand(Runnable r) {
r.run();
}
@Override
public boolean isInsideCommand() {
return canWrite();
}
@Override
public void addCommandListener(@NotNull CommandListener listener) {
LOG.warn("Adding command listener to DefaultModelAccess: a command is the same as a write action");
CommandWriteActionAdapter adapter = new CommandWriteActionAdapter(listener);
myAdaptersMap.put(listener, adapter);
addWriteActionListener(adapter);
}
@Override
public void removeCommandListener(@NotNull CommandListener listener) {
@NotNull CommandWriteActionAdapter adapter = myAdaptersMap.remove(listener);
removeWriteActionListener(adapter);
}
}