All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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 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