org.ogema.resourcemanager.impl.transaction.actions.DeletionAction Maven / Gradle / Ivy
The newest version!
/**
* Copyright 2011-2018 Fraunhofer-Gesellschaft zur Förderung der angewandten Wissenschaften e.V.
*
* 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 org.ogema.resourcemanager.impl.transaction.actions;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import java.util.Objects;
import java.util.Queue;
import org.ogema.core.model.Resource;
import org.ogema.core.model.ValueResource;
import org.ogema.core.resourcemanager.AccessMode;
import org.ogema.core.resourcemanager.AccessPriority;
import org.ogema.core.resourcemanager.ResourceManagement;
import org.ogema.core.resourcemanager.ResourceOperationException.Type;
import org.ogema.resourcemanager.impl.transaction.AtomicAction;
import org.ogema.tools.resource.util.ValueResourceUtils;
// TODO restore access mode and priorities for other apps in rollback
public class DeletionAction implements AtomicAction {
private final ResourceManagement rm;
private final boolean isTopLevel;
private final Resource target;
private final String path; // only set if isTopLevel == true; for rollback
private final Class extends Resource> type; // only set if isTopLevel == true; for rollback
private boolean existed = false; // for rollback
private Resource oldReferenceTarget = null; // for rollback
private List oldReferences = null; // for rollback
private AccessMode oldMode = null; // for rollback -> TODO restore the access mode for all apps
private AccessPriority oldPriority = null; // for rollback -> TODO restore the access priority for all apps
private boolean wasActive = false;
private Object oldValue = null;
private boolean done;
private boolean setBack;
private final Queue subactions = new ArrayDeque<>();
private final Deque subactionsDone = new ArrayDeque<>();
public DeletionAction(Resource target, ResourceManagement rm) {
Objects.requireNonNull(target);
this.target = target;
this.rm = rm;
this.isTopLevel = target.isTopLevel();
if (isTopLevel) {
path = target.getPath();
type = target.getResourceType();
}
else {
path = null;
type = null;
}
}
private void buildActionsTree() {
// subresources of references must no be deleted
if (!target.isReference(false)) {
List subresources = target.getSubResources(false);
// subresources
for (Resource sub: subresources) {
subactions.add(new DeletionAction(sub,null));
}
}
List refs = target.getReferencingNodes(false);
for (Resource ref :refs) {
subactions.add(new DeletionAction(ref, null));
}
}
private void executeSubActions() throws Exception {
AtomicAction action;
while ((action = subactions.poll()) != null) {
subactionsDone.add(action); // add this immediately, so we'll try to rollback this action even if it fails
action.execute();
}
}
private void rollbackSubactions() throws IllegalStateException {
AtomicAction action;
while ((action = subactionsDone.pollLast()) != null) {
try {
action.rollback();
} catch (Exception e) {
continue;
}
}
}
@Override
public void execute() throws Exception {
if (done || setBack)
throw new IllegalStateException("Transaction has been executed already");
done = true;
buildActionsTree(); // we cannot do this earlier, e.g. in the constructor, since at that time no resource lock is held
executeSubActions();
existed = target.exists();
if (!existed)
return;
wasActive = target.isActive();
if (target.isReference(false))
oldReferenceTarget = target.getLocationResource();
else if (target instanceof ValueResource)
oldValue = ValueResourceUtils.getValue((ValueResource) target);
oldReferences = target.getReferencingResources(Resource.class);
oldMode = target.getAccessMode();
oldPriority = target.getAccessPriority();
target.delete();
}
@Override
public void rollback() throws IllegalStateException {
if (!done)
throw new IllegalStateException("Transaction has not been executed yet, cannot set back");
if (setBack)
throw new IllegalStateException("Transaction has been rolled back already");
setBack =true;
// if (!existed) {
// target.delete();
// return;
// }
if (!existed)
return;
// it may be that the reference target was deleted in the same transaction, and has not been recreated yet
// in this case, the reference will be restored when the referenceTarget deletion action is rolled back (see below)
if (oldReferenceTarget != null && oldReferenceTarget.exists())
target.setAsReference(oldReferenceTarget);
else {
if (isTopLevel)
rm.createResource(path, type);
else
target.create();
try { // we probably still want to execute the sub-rollbacks
if (wasActive)
target.activate(false);
if (oldValue != null && target instanceof ValueResource) {
ValueResourceUtils.setValue((ValueResource) target, oldValue);
}
} catch (Exception e) {
// TODO
}
}
target.requestAccessMode(oldMode, oldPriority);
if (oldReferences != null) {
for (Resource res: oldReferences) {
try {
if (res.getParent().exists())
res.setAsReference(target);
} catch (Exception e) {
// ignore:
// it may be that the referencing resource has been deleted in the same transaction, and its parent has not been recreated yet
// in this case, the reference will be restored when the respective delete action for res is rolled back (see above)
}
}
}
rollbackSubactions();
}
@Override
public boolean requiresStructureWriteLock() {
return true;
}
@Override
public boolean requiresCommitWriteLock() {
return false; // XXX?
}
@Override
public Type getType() {
return Type.DELETE;
}
@Override
public Resource getSource() {
return target;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy