| /******************************************************************************* |
| * Copyright (c) 2009 SAP AG. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Eduard Bartsch (SAP AG) - initial API and implementation |
| * Mathias Kinzler (SAP AG) - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.core.internal.resources.semantic; |
| |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| |
| import org.eclipse.core.filesystem.provider.FileStore; |
| import org.eclipse.core.internal.resources.semantic.model.SemanticResourceDB.ResourceTreeNode; |
| import org.eclipse.core.resources.semantic.ISemanticProperties; |
| import org.eclipse.core.resources.semantic.SemanticResourceException; |
| import org.eclipse.core.resources.semantic.SemanticResourceStatusCode; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.QualifiedName; |
| |
| /** |
| * The {@link ISemanticProperties} implementation. |
| * |
| */ |
| public abstract class SemanticProperties extends FileStore implements ISemanticProperties { |
| |
| protected ResourceTreeNode node; |
| protected final SemanticFileSystem fs; |
| |
| SemanticProperties(SemanticFileSystem fs, ResourceTreeNode node) { |
| this.fs = fs; |
| this.node = node; |
| } |
| |
| private IPath getPathForTrace() { |
| try { |
| return this.fs.getPathForNode(this.node); |
| } catch (RuntimeException rte) { |
| // $JL-EXC$ |
| return new Path(this.node.getName()); |
| } |
| } |
| |
| /** |
| * @throws CoreException |
| */ |
| public Map<QualifiedName, String> getPersistentProperties() throws CoreException { |
| |
| if (SfsTraceLocation.CORE_VERBOSE.isActive()) { |
| SfsTraceLocation.getTrace().traceEntry(SfsTraceLocation.CORE_VERBOSE.getLocation(), getPathForTrace().toString()); |
| } |
| |
| checkAccessible(); |
| |
| Map<QualifiedName, String> result = new HashMap<QualifiedName, String>(); |
| try { |
| this.fs.lockForRead(); |
| HashMap<String, String> atts = this.node.getPersistentProperties(); |
| if (atts == null) { |
| return result; |
| } |
| for (Map.Entry<String, String> entry : atts.entrySet()) { |
| String qualifier; |
| String localName; |
| int index = entry.getKey().indexOf('^'); |
| if (index > 0) { |
| qualifier = entry.getKey().substring(0, index); |
| localName = entry.getKey().substring(index + 1); |
| } else { |
| qualifier = null; |
| localName = entry.getKey(); |
| } |
| result.put(new QualifiedName(qualifier, localName), entry.getValue()); |
| } |
| |
| return result; |
| } finally { |
| this.fs.unlockForRead(); |
| if (SfsTraceLocation.CORE_VERBOSE.isActive()) { |
| SfsTraceLocation.getTrace().traceExit(SfsTraceLocation.CORE_VERBOSE.getLocation(), result); |
| } |
| } |
| |
| } |
| |
| /** |
| * @throws CoreException |
| */ |
| public String getPersistentProperty(QualifiedName key) throws CoreException { |
| |
| if (SfsTraceLocation.CORE_VERBOSE.isActive()) { |
| SfsTraceLocation.getTrace().traceEntry(SfsTraceLocation.CORE_VERBOSE.getLocation(), |
| new Object[] {getPathForTrace().toString(), key}); |
| } |
| |
| String result = null; |
| try { |
| this.fs.lockForRead(); |
| HashMap<String, String> nodeProps = this.node.getPersistentProperties(); |
| if (nodeProps == null) { |
| return result; |
| } |
| String keyString = Util.qualifiedNameToString(key); |
| result = nodeProps.get(keyString); |
| |
| return result; |
| } finally { |
| this.fs.unlockForRead(); |
| if (SfsTraceLocation.CORE_VERBOSE.isActive()) { |
| SfsTraceLocation.getTrace().traceExit(SfsTraceLocation.CORE_VERBOSE.getLocation(), result); |
| } |
| } |
| |
| } |
| |
| public void setPersistentProperty(QualifiedName key, String value) throws CoreException { |
| |
| if (SfsTraceLocation.CORE_VERBOSE.isActive()) { |
| SfsTraceLocation.getTrace().traceEntry(SfsTraceLocation.CORE_VERBOSE.getLocation(), getPathForTrace().toString()); |
| } |
| |
| checkAccessible(); |
| |
| Util.assertQualifiedNameValid(key); |
| |
| String keyString = Util.qualifiedNameToString(key); |
| try { |
| this.fs.lockForWrite(); |
| |
| String oldValue = null; |
| |
| HashMap<String, String> map = this.node.getPersistentProperties(); |
| if (map == null) { |
| map = new HashMap<String, String>(); |
| } else { |
| oldValue = map.get(keyString); |
| } |
| |
| if (!isEqualValue(value, oldValue)) { |
| if (value != null) { |
| map.put(keyString, value); |
| } else { |
| map.remove(keyString); |
| } |
| this.node.setPersistentProperties(map); |
| |
| this.notifyPersistentPropertySet(keyString, oldValue, value); |
| |
| this.fs.requestFlush(false, this.node); |
| } |
| } finally { |
| this.fs.unlockForWrite(); |
| } |
| |
| } |
| |
| public void updatePersistentProperties(Map<QualifiedName, String> propertiesToBeAddedOrUpdated, |
| List<QualifiedName> propertiesToBeDeleted) throws CoreException { |
| if (SfsTraceLocation.CORE_VERBOSE.isActive()) { |
| SfsTraceLocation.getTrace().traceEntry(SfsTraceLocation.CORE_VERBOSE.getLocation(), getPathForTrace().toString()); |
| } |
| |
| checkAccessible(); |
| |
| // check all keys to be added/updated |
| if (propertiesToBeAddedOrUpdated != null) { |
| for (QualifiedName key : propertiesToBeAddedOrUpdated.keySet()) { |
| Util.assertQualifiedNameValid(key); |
| } |
| } |
| |
| try { |
| this.fs.lockForWrite(); |
| |
| boolean needsFlush = false; |
| |
| HashMap<String, String> map = this.node.getPersistentProperties(); |
| if (map == null) { |
| map = new HashMap<String, String>(); |
| } |
| |
| if (propertiesToBeDeleted != null) { |
| for (QualifiedName key : propertiesToBeDeleted) { |
| String keyString = Util.qualifiedNameToString(key); |
| if (map.get(keyString) != null) { |
| map.remove(keyString); |
| needsFlush = true; |
| } |
| } |
| } |
| |
| if (propertiesToBeAddedOrUpdated != null) { |
| for (Entry<QualifiedName, String> entry : propertiesToBeAddedOrUpdated.entrySet()) { |
| String keyString = Util.qualifiedNameToString(entry.getKey()); |
| String oldValue = null; |
| |
| oldValue = map.get(keyString); |
| |
| if (!isEqualValue(entry.getValue(), oldValue) && entry.getValue() != null) { |
| map.put(keyString, entry.getValue()); |
| |
| this.notifyPersistentPropertySet(keyString, oldValue, entry.getValue()); |
| |
| needsFlush = true; |
| } |
| } |
| } |
| if (needsFlush) { |
| this.node.setPersistentProperties(map); |
| |
| this.fs.requestFlush(false, node); |
| } |
| } finally { |
| this.fs.unlockForWrite(); |
| } |
| } |
| |
| protected abstract void notifyPersistentPropertySet(String keyString, String oldValue, String newValue) throws CoreException; |
| |
| /** |
| * @throws CoreException |
| */ |
| public void setSessionProperty(QualifiedName key, Object value) throws CoreException { |
| |
| if (SfsTraceLocation.CORE_VERBOSE.isActive()) { |
| SfsTraceLocation.getTrace().traceEntry(SfsTraceLocation.CORE_VERBOSE.getLocation(), getPathForTrace().toString()); |
| } |
| |
| checkAccessible(); |
| |
| Util.assertQualifiedNameValid(key); |
| |
| try { |
| this.fs.lockForWrite(); |
| |
| HashMap<QualifiedName, Object> map = this.node.getSessionProperties(); |
| if (map == null) { |
| map = new HashMap<QualifiedName, Object>(); |
| this.node.setSessionProperties(map); |
| } |
| if (value != null) { |
| map.put(key, value); |
| } else { |
| map.remove(key); |
| } |
| |
| } finally { |
| this.fs.unlockForWrite(); |
| } |
| |
| } |
| |
| /** |
| * @throws CoreException |
| */ |
| public Map<QualifiedName, Object> getSessionProperties() throws CoreException { |
| |
| if (SfsTraceLocation.CORE_VERBOSE.isActive()) { |
| SfsTraceLocation.getTrace().traceEntry(SfsTraceLocation.CORE_VERBOSE.getLocation(), getPathForTrace().toString()); |
| } |
| |
| checkAccessible(); |
| |
| Map<QualifiedName, Object> result = new HashMap<QualifiedName, Object>(); |
| |
| try { |
| this.fs.lockForRead(); |
| HashMap<QualifiedName, Object> atts = this.node.getSessionProperties(); |
| if (atts == null) { |
| return result; |
| } |
| // we copy the map here (QualifiedName is immutable) |
| for (Map.Entry<QualifiedName, Object> entry : atts.entrySet()) { |
| result.put(entry.getKey(), entry.getValue()); |
| } |
| |
| return result; |
| } finally { |
| this.fs.unlockForRead(); |
| if (SfsTraceLocation.CORE_VERBOSE.isActive()) { |
| SfsTraceLocation.getTrace().traceExit(SfsTraceLocation.CORE_VERBOSE.getLocation(), result); |
| } |
| } |
| } |
| |
| /** |
| * @throws CoreException |
| */ |
| public Object getSessionProperty(QualifiedName key) throws CoreException { |
| |
| if (SfsTraceLocation.CORE_VERBOSE.isActive()) { |
| SfsTraceLocation.getTrace().traceEntry(SfsTraceLocation.CORE_VERBOSE.getLocation(), |
| new Object[] {getPathForTrace().toString(), key}); |
| } |
| |
| Object result = null; |
| try { |
| this.fs.lockForRead(); |
| HashMap<QualifiedName, Object> nodeProps = this.node.getSessionProperties(); |
| if (nodeProps == null) { |
| return result; |
| } |
| result = nodeProps.get(key); |
| return result; |
| } finally { |
| this.fs.unlockForRead(); |
| if (SfsTraceLocation.CORE_VERBOSE.isActive()) { |
| SfsTraceLocation.getTrace().traceExit(SfsTraceLocation.CORE_VERBOSE.getLocation(), result); |
| } |
| } |
| } |
| |
| /** |
| * Similar to |
| * <code>org.eclipse.core.internal.resources.Resource#checkAccessible(int)</code> |
| * <p> |
| * The corresponding Resource method is called on: |
| * <ul> |
| * <li>Container.memebers()</li> |
| * <li>Container.setDefaultCharset()</li> |
| * <li>File.appendContents()</li> |
| * <li>File.create() (on the parent)</li> |
| * <li>File.getContentDescription()</li> |
| * <li>File.getContents()</li> |
| * <li>File.getEncoding()</li> |
| * <li>File.setCharset()</li> |
| * <li>File.setContents()</li> |
| * <li>Folder.create() (on the parent)</li> |
| * <li>Project.checkAccessible()</li> |
| * <li>Project.getDescription()</li> |
| * <li>Project.getNature()</li> |
| * <li>Project.getReferencedProjects()</li> |
| * <li>Project.hasNature</li> |
| * <li>Project.isNatureEnabled()</li> |
| * <li>Project.setDescription()</li> |
| * <li>Resource.accept()</li> |
| * <li>Resource.createLink()</li> |
| * <li>Resource.copy()</li> |
| * <li>Resource.move()</li> |
| * <li>Resource.createMarker()</li> |
| * <li>Resource.deleteMarkers()</li> |
| * <li>Resource.findMarkers()</li> |
| * <li>Resource.findMaxProblemSeverity()</li> |
| * <li>Resource.setDerived()</li> |
| * <li>Resource.setHidden()</li> |
| * <li>Resource.setTeamPrivateMember()</li> |
| * </ul> |
| * |
| * @throws CoreException |
| */ |
| protected void checkAccessible() throws CoreException { |
| checkAndJoinTreeIfAnotherEntryExists(); |
| |
| if (!this.node.isExists()) { |
| throw new SemanticResourceException(SemanticResourceStatusCode.NOT_ACCESSIBLE, getPathForTrace(), |
| Messages.SemanticProperties_StoreNotAccessible_XMSG); |
| } |
| } |
| |
| protected void checkAndJoinTreeIfAnotherEntryExists() { |
| try { |
| this.fs.lockForRead(); |
| if (!this.node.isExists()) { |
| ResourceTreeNode other = this.fs.getNodeByPath(this.node.getPath()); |
| |
| if (other.isExists()) { |
| this.node = other; |
| } |
| } |
| } finally { |
| this.fs.unlockForRead(); |
| if (SfsTraceLocation.CORE_VERBOSE.isActive()) { |
| SfsTraceLocation.getTrace().traceExit(SfsTraceLocation.CORE_VERBOSE.getLocation()); |
| } |
| } |
| } |
| |
| private boolean isEqualValue(String value, String oldValue) { |
| if (value == null && oldValue == null) { |
| return true; |
| } else if (value != null && oldValue == null) { |
| return false; |
| } else if (value == null && oldValue != null) { |
| return false; |
| } |
| return value.equals(oldValue); |
| } |
| |
| } |