Copyright (c) 2004, 2016 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 Lars Vogel - Bug 473427 Mickael Istria (Red Hat Inc.) - Bug 488937
/******************************************************************************* * Copyright (c) 2004, 2016 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 * Lars Vogel <Lars.Vogel@vogella.com> - Bug 473427 * Mickael Istria (Red Hat Inc.) - Bug 488937 *******************************************************************************/
package org.eclipse.core.internal.properties; import java.io.File; import java.util.*; import org.eclipse.core.internal.localstore.Bucket; import org.eclipse.core.internal.localstore.Bucket.Entry; import org.eclipse.core.internal.localstore.BucketTree; import org.eclipse.core.internal.properties.PropertyBucket.PropertyEntry; import org.eclipse.core.internal.resources.*; import org.eclipse.core.internal.utils.Messages; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceStatus; import org.eclipse.core.runtime.*; import org.eclipse.osgi.util.NLS;
See Also:
  • IPropertyManager
/** * @see org.eclipse.core.internal.properties.IPropertyManager */
public class PropertyManager2 implements IPropertyManager { private static final int MAX_VALUE_SIZE = 2 * 1024; class PropertyCopyVisitor extends Bucket.Visitor { private List<PropertyEntry> changes = new ArrayList<>(); private IPath destination; private IPath source; public PropertyCopyVisitor(IPath source, IPath destination) { this.source = source; this.destination = destination; } @Override public void afterSaving(Bucket bucket) throws CoreException { saveChanges((PropertyBucket) bucket); changes.clear(); } private void saveChanges(PropertyBucket bucket) throws CoreException { if (changes.isEmpty()) return; // make effective all changes collected Iterator<PropertyEntry> i = changes.iterator(); PropertyEntry entry = i.next(); tree.loadBucketFor(entry.getPath()); bucket.setProperties(entry); while (i.hasNext()) bucket.setProperties(i.next()); bucket.save(); } @Override public int visit(Entry entry) { PropertyEntry sourceEntry = (PropertyEntry) entry; IPath destinationPath = destination.append(sourceEntry.getPath().removeFirstSegments(source.segmentCount())); PropertyEntry destinationEntry = new PropertyEntry(destinationPath, sourceEntry); changes.add(destinationEntry); return CONTINUE; } } BucketTree tree; public PropertyManager2(Workspace workspace) { this.tree = new BucketTree(workspace, new PropertyBucket()); } @Override public void closePropertyStore(IResource target) throws CoreException { // ensure any uncommitted are written to disk tree.getCurrent().save(); // flush in-memory state to avoid confusion if another project is later // created with the same name tree.getCurrent().flush(); } @Override public synchronized void copy(IResource source, IResource destination, int depth) throws CoreException { copyProperties(source.getFullPath(), destination.getFullPath(), depth); }
Copies all properties from the source path to the target path, to the given depth.
/** * Copies all properties from the source path to the target path, to the given depth. */
private void copyProperties(final IPath source, final IPath destination, int depth) throws CoreException { Assert.isLegal(source.segmentCount() > 0); Assert.isLegal(destination.segmentCount() > 0); Assert.isLegal(source.segmentCount() > 1 || destination.segmentCount() == 1); // copy history by visiting the source tree PropertyCopyVisitor copyVisitor = new PropertyCopyVisitor(source, destination); tree.accept(copyVisitor, source, BucketTree.DEPTH_INFINITE); } @Override public synchronized void deleteProperties(IResource target, int depth) throws CoreException { tree.accept(new PropertyBucket.Visitor() { @Override public int visit(Entry entry) { entry.delete(); return CONTINUE; } }, target.getFullPath(), depth == IResource.DEPTH_INFINITE ? BucketTree.DEPTH_INFINITE : depth); } @Override public void deleteResource(IResource target) throws CoreException { deleteProperties(target, IResource.DEPTH_INFINITE); } @Override public synchronized Map<QualifiedName, String> getProperties(IResource target) throws CoreException { final Map<QualifiedName, String> result = new HashMap<>(); tree.accept(new PropertyBucket.Visitor() { @Override public int visit(Entry entry) { PropertyEntry propertyEntry = (PropertyEntry) entry; int propertyCount = propertyEntry.getOccurrences(); for (int i = 0; i < propertyCount; i++) result.put(propertyEntry.getPropertyName(i), propertyEntry.getPropertyValue(i)); return CONTINUE; } }, target.getFullPath(), BucketTree.DEPTH_ZERO); return result; } @Override public synchronized String getProperty(IResource target, QualifiedName name) throws CoreException { if (name.getQualifier() == null) { String message = Messages.properties_qualifierIsNull; throw new ResourceException(IResourceStatus.FAILED_READ_METADATA, target.getFullPath(), message, null); } IPath resourcePath = target.getFullPath(); PropertyBucket current = (PropertyBucket) tree.getCurrent(); tree.loadBucketFor(resourcePath); return current.getProperty(resourcePath, name); } public BucketTree getTree() { return tree; } public File getVersionFile() { return tree.getVersionFile(); } @Override public synchronized void setProperty(IResource target, QualifiedName name, String value) throws CoreException { //resource may have been deleted concurrently //must check for existence within synchronized method Resource resource = (Resource) target; ResourceInfo info = resource.getResourceInfo(false, false); int flags = resource.getFlags(info); resource.checkAccessible(flags); // enforce the limit stated by the spec if (value != null && value.length() > MAX_VALUE_SIZE) { String message = NLS.bind(Messages.properties_valueTooLong, new Object[] {name.getQualifier(), name.getLocalName(), Integer.toString(MAX_VALUE_SIZE)}); throw new ResourceException(IResourceStatus.FAILED_WRITE_METADATA, target.getFullPath(), message, null); } if (name.getQualifier() == null) { String message = Messages.properties_qualifierIsNull; throw new ResourceException(IResourceStatus.FAILED_WRITE_METADATA, target.getFullPath(), message, null); } IPath resourcePath = target.getFullPath(); tree.loadBucketFor(resourcePath); PropertyBucket current = (PropertyBucket) tree.getCurrent(); current.setProperty(resourcePath, name, value); current.save(); } @Override public void shutdown(IProgressMonitor monitor) throws CoreException { tree.close(); } @Override public void startup(IProgressMonitor monitor) { // nothing to do } }