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

org.eclipse.core.internal.resources.Synchronizer Maven / Gradle / Ivy

Go to download

AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based @AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step. This library is a superset of AspectJ weaver and hence also of AspectJ runtime.

There is a newer version: 1.9.22.1
Show newest version
/*******************************************************************************
 * Copyright (c) 2000, 2015 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     James Blackburn (Broadcom Corp.) - ongoing development
 *     Lars Vogel  - Bug 473427
 *******************************************************************************/
package org.eclipse.core.internal.resources;

import java.io.*;
import java.util.*;
import org.eclipse.core.internal.localstore.SafeChunkyInputStream;
import org.eclipse.core.internal.localstore.SafeFileInputStream;
import org.eclipse.core.internal.utils.Messages;
import org.eclipse.core.internal.utils.Policy;
import org.eclipse.core.internal.watson.IPathRequestor;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.osgi.util.NLS;

//
public class Synchronizer implements ISynchronizer {
	protected Workspace workspace;
	protected SyncInfoWriter writer;

	// Registry of sync partners. Set of qualified names.
	protected Set registry = new HashSet<>(5);

	public Synchronizer(Workspace workspace) {
		super();
		this.workspace = workspace;
		this.writer = new SyncInfoWriter(workspace, this);
	}

	/**
	 * @see ISynchronizer#accept(QualifiedName, IResource, IResourceVisitor, int)
	 */
	@Override
	public void accept(QualifiedName partner, IResource resource, IResourceVisitor visitor, int depth)
			throws CoreException {
		Assert.isLegal(partner != null);
		Assert.isLegal(resource != null);
		Assert.isLegal(visitor != null);

		// if we don't have sync info for the given identifier, then skip it
		if (getSyncInfo(partner, resource) != null) {
			// visit the resource and if the visitor says to stop the recursion then return
			if (!visitor.visit(resource))
				return;
		}

		// adjust depth if necessary
		if (depth == IResource.DEPTH_ZERO || resource.getType() == IResource.FILE)
			return;
		if (depth == IResource.DEPTH_ONE)
			depth = IResource.DEPTH_ZERO;

		// otherwise recurse over the children
		IResource[] children = ((IContainer) resource).members();
		for (IResource element : children)
			accept(partner, element, visitor, depth);
	}

	/**
	 * @see ISynchronizer#add(QualifiedName)
	 */
	@Override
	public void add(QualifiedName partner) {
		Assert.isLegal(partner != null);
		registry.add(partner);
	}

	/**
	 * @see ISynchronizer#flushSyncInfo(QualifiedName, IResource, int)
	 */
	@Override
	public void flushSyncInfo(final QualifiedName partner, final IResource root, final int depth) throws CoreException {
		Assert.isLegal(partner != null);
		Assert.isLegal(root != null);

		ICoreRunnable body = monitor -> {
			IResourceVisitor visitor = resource -> {
				// only need to flush sync info if there is sync info
				if (getSyncInfo(partner, resource) != null)
					setSyncInfo(partner, resource, null);
				return true;
			};
			root.accept(visitor, depth, true);
		};
		workspace.run(body, root, IResource.NONE, null);
	}

	/**
	 * @see ISynchronizer#getPartners()
	 */
	@Override
	public QualifiedName[] getPartners() {
		return registry.toArray(new QualifiedName[registry.size()]);
	}

	/**
	 * For use by the serialization code.
	 */
	protected Set getRegistry() {
		return registry;
	}

	/**
	 * @see ISynchronizer#getSyncInfo(QualifiedName, IResource)
	 */
	@Override
	public byte[] getSyncInfo(QualifiedName partner, IResource resource) throws CoreException {
		Assert.isLegal(partner != null);
		Assert.isLegal(resource != null);

		if (!isRegistered(partner)) {
			String message = NLS.bind(Messages.synchronizer_partnerNotRegistered, partner);
			throw new ResourceException(new ResourceStatus(IResourceStatus.PARTNER_NOT_REGISTERED, message));
		}

		// namespace check, if the resource doesn't exist then return null
		ResourceInfo info = workspace.getResourceInfo(resource.getFullPath(), true, false);
		return (info == null) ? null : info.getSyncInfo(partner, true);
	}

	protected boolean isRegistered(QualifiedName partner) {
		Assert.isLegal(partner != null);
		return registry.contains(partner);
	}

	/**
	 * @see #savePartners(DataOutputStream)
	 */
	public void readPartners(DataInputStream input) throws CoreException {
		SyncInfoReader reader = new SyncInfoReader(workspace, this);
		reader.readPartners(input);
	}

	public void restore(IResource resource, IProgressMonitor monitor) throws CoreException {
		// first restore from the last save and then apply any snapshots
		restoreFromSave(resource);
		restoreFromSnap(resource);
	}

	protected void restoreFromSave(IResource resource) throws CoreException {
		IPath sourceLocation = workspace.getMetaArea().getSyncInfoLocationFor(resource);
		IPath tempLocation = workspace.getMetaArea().getBackupLocationFor(sourceLocation);
		if (!sourceLocation.toFile().exists() && !tempLocation.toFile().exists())
			return;
		try (DataInputStream input = new DataInputStream(
				new SafeFileInputStream(sourceLocation.toOSString(), tempLocation.toOSString()))) {
			SyncInfoReader reader = new SyncInfoReader(workspace, this);
			reader.readSyncInfo(input);
		} catch (Exception e) {
			// don't let runtime exceptions such as ArrayIndexOutOfBounds prevent startup
			String msg = NLS.bind(Messages.resources_readMeta, sourceLocation);
			throw new ResourceException(IResourceStatus.FAILED_READ_METADATA, sourceLocation, msg, e);
		}
	}

	protected void restoreFromSnap(IResource resource) {
		IPath sourceLocation = workspace.getMetaArea().getSyncInfoSnapshotLocationFor(resource);
		if (!sourceLocation.toFile().exists())
			return;
		try (DataInputStream input = new DataInputStream(new SafeChunkyInputStream(sourceLocation.toFile()))) {
			SyncInfoSnapReader reader = new SyncInfoSnapReader(workspace, this);
			while (true)
				reader.readSyncInfo(input);
		} catch (EOFException eof) {
			// ignore end of file -- proceed with what we successfully read
		} catch (Exception e) {
			// only log the exception, we should not fail restoring the snapshot
			String msg = NLS.bind(Messages.resources_readMeta, sourceLocation);
			Policy.log(new ResourceStatus(IResourceStatus.FAILED_READ_METADATA, sourceLocation, msg, e));
		}
	}

	/**
	 * @see ISynchronizer#remove(QualifiedName)
	 */
	@Override
	public void remove(QualifiedName partner) {
		Assert.isLegal(partner != null);
		if (isRegistered(partner)) {
			// remove all sync info for this partner
			try {
				flushSyncInfo(partner, workspace.getRoot(), IResource.DEPTH_INFINITE);
				registry.remove(partner);
			} catch (CoreException e) {
				// XXX: flush needs to be more resilient and not throw exceptions all the time
				Policy.log(e);
			}
		}
	}

	public void savePartners(DataOutputStream output) throws IOException {
		writer.savePartners(output);
	}

	public void saveSyncInfo(ResourceInfo info, IPathRequestor requestor, DataOutputStream output,
			List writtenPartners) throws IOException {
		writer.saveSyncInfo(info, requestor, output, writtenPartners);
	}

	protected void setRegistry(Set registry) {
		this.registry = registry;
	}

	/**
	 * @see ISynchronizer#setSyncInfo(QualifiedName, IResource, byte[])
	 */
	@Override
	public void setSyncInfo(QualifiedName partner, IResource resource, byte[] info) throws CoreException {
		Assert.isLegal(partner != null);
		Assert.isLegal(resource != null);
		try {
			workspace.prepareOperation(resource, null);
			workspace.beginOperation(true);
			if (!isRegistered(partner)) {
				String message = NLS.bind(Messages.synchronizer_partnerNotRegistered, partner);
				throw new ResourceException(new ResourceStatus(IResourceStatus.PARTNER_NOT_REGISTERED, message));
			}
			// we do not store sync info on the workspace root
			if (resource.getType() == IResource.ROOT)
				return;
			// if the resource doesn't yet exist then create a phantom so we can set the
			// sync info on it
			Resource target = (Resource) resource;
			ResourceInfo resourceInfo = workspace.getResourceInfo(target.getFullPath(), true, false);
			int flags = target.getFlags(resourceInfo);
			if (!target.exists(flags, false)) {
				if (info == null)
					return;
				// ensure it is possible to create this resource
				target.checkValidPath(target.getFullPath(), target.getType(), false);
				Container parent = (Container) target.getParent();
				parent.checkAccessible(parent.getFlags(parent.getResourceInfo(true, false)));
				workspace.createResource(target, true);
			}
			resourceInfo = target.getResourceInfo(true, true);
			resourceInfo.setSyncInfo(partner, info);
			resourceInfo.incrementSyncInfoGenerationCount();
			resourceInfo.set(ICoreConstants.M_SYNCINFO_SNAP_DIRTY);
			flags = target.getFlags(resourceInfo);
			if (target.isPhantom(flags) && resourceInfo.getSyncInfo(false) == null) {
				MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.INTERNAL_ERROR,
						Messages.resources_deleteProblem, null);
				((Resource) resource).deleteResource(false, status);
				if (!status.isOK())
					throw new ResourceException(status);
			}
		} finally {
			workspace.endOperation(resource, false);
		}
	}

	public void snapSyncInfo(ResourceInfo info, IPathRequestor requestor, DataOutputStream output) throws IOException {
		writer.snapSyncInfo(info, requestor, output);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy