| /******************************************************************************* |
| * 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.io.File; |
| import java.io.IOException; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.concurrent.locks.Lock; |
| import java.util.concurrent.locks.ReentrantReadWriteLock; |
| |
| import org.eclipse.core.filesystem.EFS; |
| import org.eclipse.core.filesystem.IFileStore; |
| import org.eclipse.core.filesystem.provider.FileSystem; |
| import org.eclipse.core.internal.resources.semantic.model.SemanticResourceDB.ResourceTreeNode; |
| import org.eclipse.core.internal.resources.semantic.model.SemanticResourceDB.SemanticResourceDBFactory; |
| import org.eclipse.core.internal.resources.semantic.model.SemanticResourceDB.TreeNodeType; |
| import org.eclipse.core.internal.resources.semantic.model.SemanticResourceDB.TreeRoot; |
| import org.eclipse.core.internal.resources.semantic.util.ISemanticFileSystemLog; |
| import org.eclipse.core.resources.semantic.ISemanticFileSystem; |
| import org.eclipse.core.resources.semantic.ISemanticURILocatorService; |
| import org.eclipse.core.resources.semantic.SemanticResourceException; |
| import org.eclipse.core.resources.semantic.SemanticResourceStatusCode; |
| import org.eclipse.core.resources.semantic.spi.ISemanticContentProvider; |
| import org.eclipse.core.resources.semantic.spi.ISemanticContentProviderFederation; |
| import org.eclipse.core.resources.semantic.spi.ISemanticFileStore; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.common.util.TreeIterator; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.resource.Resource.Diagnostic; |
| |
| /** |
| * The Semantic File System. |
| * <p> |
| * In order to access specific methods, this may be cast to |
| * {@link ISemanticFileSystem}. |
| * |
| */ |
| public class SemanticFileSystem extends FileSystem implements ISemanticFileSystem { |
| |
| private static final String METADATA_FILENAME = "metadata.xmi"; //$NON-NLS-1$ |
| final static IPath EMPTY = new Path(""); //$NON-NLS-1$ |
| |
| private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); |
| private final Lock readLock = this.rwl.readLock(); |
| private final Lock writeLock = this.rwl.writeLock(); |
| private final ISemanticFileSystemLog log; |
| |
| SemanticMetadataPersistenceManager mgr; |
| private File metadataFolder; |
| |
| private SemanticURILocatorService uriLocator; |
| |
| /** |
| * No-argument constructor |
| */ |
| public SemanticFileSystem() { |
| |
| this.log = new SemanticFileSystemLog(); |
| |
| init(null); |
| } |
| |
| public SemanticFileSystem(File rootFolder) { |
| |
| this.log = new SemanticFileSystemLog(); |
| |
| init(rootFolder); |
| } |
| |
| public String[] getRootNames() throws CoreException { |
| |
| if (this.mgr.getSemanticDB() == null) { |
| throw new SemanticResourceException(SemanticResourceStatusCode.SFS_DB_NOT_INITIALIZED, SemanticFileSystem.EMPTY, |
| Messages.SemanticFileSystem_NotInitialized_XMSG); |
| } |
| |
| List<String> result = new ArrayList<String>(); |
| |
| try { |
| lockForRead(); |
| |
| EList<TreeRoot> roots = this.mgr.getSemanticDB().getRoots(); |
| |
| for (TreeRoot treeRoot : roots) { |
| result.add(treeRoot.getName()); |
| } |
| } finally { |
| unlockForRead(); |
| } |
| return result.toArray(new String[0]); |
| } |
| |
| /** |
| * Requests a database update. |
| * |
| * @param force |
| * <code>true</code> for immediate update |
| * @throws CoreException |
| * in case of failure |
| */ |
| public void requestFlush(boolean force, ResourceTreeNode node) throws CoreException { |
| node = getHighestParent(node); |
| |
| saveSemanticDB(node.getName()); |
| } |
| |
| public ResourceTreeNode getHighestParent(ResourceTreeNode node) { |
| ResourceTreeNode parent = node.getParent(); |
| while (parent != null) { |
| node = parent; |
| parent = node.getParent(); |
| } |
| return node; |
| } |
| |
| @Override |
| public IFileStore getStore(URI uri) { |
| if (ISemanticFileSystem.SCHEME.equals(uri.getScheme())) { |
| return getFileStoreImplementation(uri); |
| } |
| return EFS.getNullFileSystem().getStore(uri); |
| } |
| |
| IFileStore getFileStoreImplementation(String pathString, String queryString) { |
| IPath path; |
| |
| if (pathString != null) { |
| path = new Path(null, pathString); |
| } else { |
| path = Path.EMPTY; |
| } |
| |
| if (this.mgr.getSemanticDB() == null) { |
| return EFS.getNullFileSystem().getStore(path); |
| } |
| |
| ISemanticFileStore store; |
| // we do never return the virtual root node ("semanticfs:/") |
| if (path.segmentCount() > 0) { |
| try { |
| lockForWrite(); |
| |
| EList<TreeRoot> roots = this.mgr.getSemanticDB().getRoots(); |
| |
| TreeRoot treeRoot = null; |
| |
| for (TreeRoot root : roots) { |
| if (path.segment(0).equals(root.getName())) { |
| if (path.segmentCount() == 1) { |
| return getStore(root); |
| } |
| treeRoot = root; |
| break; |
| } |
| } |
| |
| if (treeRoot == null) { |
| if (path.segmentCount() == 1) { |
| treeRoot = createRootNode(path.segment(0), queryString); |
| return getStore(treeRoot); |
| } |
| treeRoot = createRootNode(path.segment(0)); |
| } |
| |
| store = (ISemanticFileStore) getFileStoreRecursive(path, treeRoot, queryString); |
| } finally { |
| unlockForWrite(); |
| } |
| |
| if (!store.isExists() && queryString != null) { |
| SemanticQueryParser parser = new SemanticQueryParser(queryString); |
| |
| if (parser.getShouldCreate()) { |
| try { |
| if (parser.getType().equals(TreeNodeType.FOLDER) || parser.getType().equals(TreeNodeType.PROJECT)) { |
| store.mkdir(EFS.NONE, new NullProgressMonitor()); |
| } else if (parser.getType().equals(TreeNodeType.FILE)) { |
| ISemanticFileStore parent = (ISemanticFileStore) store.getParent(); |
| |
| parent.mkdir(EFS.NONE, new NullProgressMonitor()); |
| |
| ((ISemanticFileStoreInternal) parent).addResource(path.lastSegment(), false, parser.getProviderID(), null, |
| new NullProgressMonitor()); |
| |
| ISemanticFileStoreInternal child = ((ISemanticFileStoreInternal) parent).getChildResource(path.lastSegment()); |
| |
| child.setRemoteURI(new URI(parser.getURI()), new NullProgressMonitor()); |
| } |
| |
| return store; |
| } catch (CoreException e) { |
| return EFS.getNullFileSystem().getStore(path); |
| } catch (URISyntaxException e) { |
| return EFS.getNullFileSystem().getStore(path); |
| } |
| } |
| } |
| return store; |
| } |
| |
| return EFS.getNullFileSystem().getStore(path); |
| } |
| |
| private IFileStore getFileStoreImplementation(URI uri) { |
| String pathString = uri.getPath(); |
| String queryString = uri.getQuery(); |
| return getFileStoreImplementation(pathString, queryString); |
| } |
| |
| private IFileStore getFileStoreRecursive(IPath path, ResourceTreeNode rootNode, String queryString) { |
| String[] segments = path.segments(); |
| ResourceTreeNode currentNode = rootNode; |
| boolean ready = true; |
| |
| for (int i = 1; i < segments.length; i++) { |
| String name = segments[i]; |
| EList<ResourceTreeNode> children = currentNode.getChildren(); |
| boolean found = false; |
| |
| for (ResourceTreeNode resourceTreeNode : children) { |
| if (resourceTreeNode.getName().equals(name)) { |
| currentNode = resourceTreeNode; |
| found = true; |
| break; |
| } |
| } |
| if (!found) { |
| ready = false; |
| break; |
| } |
| } |
| if (ready) { |
| return getStore(currentNode); |
| } |
| |
| ResourceTreeNode newNode = createNonExistingNode(path); |
| |
| if (queryString != null) { |
| SemanticQueryParser parser = new SemanticQueryParser(queryString); |
| |
| applyQueryParameters(newNode, parser); |
| } |
| |
| return getStore(newNode); |
| } |
| |
| ResourceTreeNode getParentNode(ResourceTreeNode childNode) { |
| try { |
| this.lockForRead(); |
| |
| if (childNode.isExists()) { |
| return childNode.getParent(); |
| } |
| |
| if (childNode.getPath() != null) { |
| int idx = childNode.getPath().lastIndexOf("/"); //$NON-NLS-1$ |
| if (idx >= 0) { |
| String parentPath = childNode.getPath().substring(0, idx); |
| return this.getNodeByPath(parentPath); |
| } |
| } |
| } finally { |
| this.unlockForRead(); |
| } |
| return null; |
| } |
| |
| public List<ResourceTreeNode> getNodesByPath(String pathString) { |
| ArrayList<ResourceTreeNode> nodes = new ArrayList<ResourceTreeNode>(); |
| IPath path = new Path(null, pathString); |
| |
| if (path.segmentCount() > 0) { |
| try { |
| lockForRead(); |
| |
| if (this.mgr.getSemanticDB() != null) { |
| EList<TreeRoot> roots = this.mgr.getSemanticDB().getRoots(); |
| |
| for (TreeRoot treeRoot : roots) { |
| if (path.segment(0).equals(treeRoot.getName())) { |
| nodes.add(treeRoot); |
| |
| if (path.segmentCount() == 1) { |
| return nodes; |
| } |
| |
| ResourceTreeNode currentNode = treeRoot; |
| boolean withinExistingTree = true; |
| |
| for (int i = 1; i < path.segmentCount(); i++) { |
| String name = path.segment(i); |
| |
| if (withinExistingTree) { |
| EList<ResourceTreeNode> children = currentNode.getChildren(); |
| boolean found = false; |
| for (ResourceTreeNode resourceTreeNode : children) { |
| if (resourceTreeNode.getName().equals(name)) { |
| currentNode = resourceTreeNode; |
| found = true; |
| break; |
| } |
| } |
| |
| if (!found) { |
| currentNode = createNonExistingNode(path.removeLastSegments(path.segmentCount() - i - 1)); |
| withinExistingTree = false; |
| } |
| } else { |
| currentNode = createNonExistingNode(path.removeLastSegments(path.segmentCount() - i - 1)); |
| } |
| |
| nodes.add(currentNode); |
| } |
| return nodes; |
| } |
| } |
| } |
| |
| // no root found, create new node hierarchy outside the tree |
| nodes.add(createRootNode(path.segment(0))); |
| |
| for (int i = 1; i < path.segmentCount(); i++) { |
| nodes.add(createNonExistingNode(path.removeLastSegments(path.segmentCount() - i - 1))); |
| } |
| } finally { |
| unlockForRead(); |
| } |
| } |
| |
| return nodes; |
| } |
| |
| ResourceTreeNode getNodeByPath(String pathString) { |
| IPath path = new Path(null, pathString); |
| |
| // we do never return the virtual root node ("semanticfs:/") |
| if (path.segmentCount() > 0) { |
| try { |
| lockForRead(); |
| |
| if (this.mgr.getSemanticDB() != null) { |
| EList<TreeRoot> roots = this.mgr.getSemanticDB().getRoots(); |
| |
| for (TreeRoot treeRoot : roots) { |
| if (path.segment(0).equals(treeRoot.getName())) { |
| if (path.segmentCount() == 1) { |
| return treeRoot; |
| } |
| |
| String[] segments = path.segments(); |
| ResourceTreeNode currentNode = treeRoot; |
| boolean ready = true; |
| |
| for (int i = 1; i < segments.length; i++) { |
| String name = segments[i]; |
| EList<ResourceTreeNode> children = currentNode.getChildren(); |
| boolean found = false; |
| |
| for (ResourceTreeNode resourceTreeNode : children) { |
| if (resourceTreeNode.getName().equals(name)) { |
| currentNode = resourceTreeNode; |
| found = true; |
| break; |
| } |
| } |
| if (!found) { |
| ready = false; |
| break; |
| } |
| } |
| if (ready) { |
| return currentNode; |
| } |
| return createNonExistingNode(path); |
| } |
| } |
| } |
| } finally { |
| unlockForRead(); |
| } |
| |
| // no root found, create new node outside the tree |
| if (path.segmentCount() == 1) { |
| return createRootNode(path.segment(0)); |
| } |
| |
| return createNonExistingNode(path); |
| } |
| |
| return null; |
| } |
| |
| ISemanticContentProvider mkdir(ResourceTreeNode actNode, ResourceTreeNode parent) throws CoreException { |
| ISemanticContentProvider parentProvider = null; |
| |
| if (parent != null && !parent.isExists()) { |
| ResourceTreeNode parentParent = this.getParentNode(parent); |
| parentProvider = mkdir(parent, parentParent); |
| } else if (parent != null) { // and exists |
| parentProvider = this.getStore(parent).getEffectiveContentProvider(); |
| } else { // parent == null |
| parentProvider = this.getStore(actNode).getEffectiveContentProvider(); |
| } |
| |
| return makeFolder(actNode, parent, parentProvider); |
| } |
| |
| ISemanticContentProvider makeFolder(ResourceTreeNode actNode, ResourceTreeNode parent, ISemanticContentProvider parentProvider) |
| throws CoreException { |
| ISemanticContentProvider effectiveProvider = parentProvider; |
| String federatedContentProviderId = null; |
| |
| if (actNode.getType() == TreeNodeType.FILE) { |
| // wrong type encountered |
| throw new SemanticResourceException(SemanticResourceStatusCode.RESOURCE_WITH_OTHER_TYPE_EXISTS, this.getStore(actNode) |
| .getPath(), Messages.SemanticFileStore_MkDirOnFile_XMSG); |
| } |
| |
| boolean bExistedBefore = actNode.isExists(); |
| |
| if (!actNode.isExists() && actNode.getTemplateID() == null) { |
| if (parentProvider instanceof ISemanticContentProviderFederation) { |
| federatedContentProviderId = ((ISemanticContentProviderFederation) parentProvider).getFederatedProviderIDForPath(new Path( |
| actNode.getPath())); |
| } |
| |
| actNode.setTemplateID(federatedContentProviderId); |
| |
| } |
| |
| // TODO 0.2: this should be intercepted by the content provider to |
| // avoid unwanted folder creation |
| this.switchToExists(actNode, parent); |
| |
| if (actNode.getType() != TreeNodeType.PROJECT) { |
| // set type folder if it is not already a project |
| actNode.setType(TreeNodeType.FOLDER); |
| } |
| |
| if (actNode.getTemplateID() != null) { |
| ISemanticFileStore newStore = this.getStore(actNode); |
| effectiveProvider = newStore.getEffectiveContentProvider(); |
| |
| if (!bExistedBefore) { |
| effectiveProvider.onRootStoreCreate(newStore); |
| } |
| } |
| return effectiveProvider; |
| } |
| |
| void switchToExists(ResourceTreeNode node, ResourceTreeNode parent) { |
| if (!node.isExists()) { |
| if (node instanceof TreeRoot) { |
| ((TreeRoot) node).setParentDB(this.mgr.getSemanticDB()); |
| } else { |
| |
| if (parent != null) { |
| node.setParent(parent); |
| } |
| } |
| |
| node.setPath(null); |
| node.setExists(true); |
| } |
| } |
| |
| private ResourceTreeNode createNonExistingNode(IPath childPath) { |
| // all callers have a lock, so we don't lock here |
| ResourceTreeNode child = SemanticResourceDBFactory.eINSTANCE.createResourceTreeNode(); |
| |
| child.setName(childPath.lastSegment()); |
| child.setType(TreeNodeType.UNKNOWN); |
| child.setExists(false); |
| child.setPath(childPath.toString()); |
| child.setLocalOnly(true); |
| |
| return child; |
| } |
| |
| public IPath getPathForNode(ResourceTreeNode node) { |
| try { |
| lockForRead(); |
| if (node.isExists()) { |
| StringBuilder sb = new StringBuilder(50); |
| sb.append('/'); |
| sb.append(node.getName()); |
| ResourceTreeNode parent = node.getParent(); |
| while (parent != null) { |
| sb.insert(0, parent.getName()); |
| sb.insert(0, '/'); |
| parent = parent.getParent(); |
| } |
| return new Path(sb.toString()); |
| } |
| if (node.getPath() != null) { |
| return new Path(node.getPath()); |
| } |
| |
| return EMPTY; |
| } finally { |
| unlockForRead(); |
| } |
| } |
| |
| protected ISemanticFileStore getStore(ResourceTreeNode node) { |
| return new SemanticFileStore(this, node); |
| } |
| |
| private void init(File rootFolder) { |
| if (rootFolder != null) { |
| this.metadataFolder = rootFolder; |
| } else { |
| this.metadataFolder = SemanticResourcesPlugin.getCacheLocation().toFile(); |
| } |
| |
| mgr = new SemanticMetadataPersistenceManager(metadataFolder); |
| |
| try { |
| mgr.init(); |
| } catch (IOException e) { |
| for (Diagnostic diagnostic : mgr.getMetadataResource().getErrors()) { |
| this.log.log(new SemanticResourceException(SemanticResourceStatusCode.SFS_INITIALIZATION_ERROR, SemanticFileSystem.EMPTY, |
| diagnostic.getMessage())); |
| } |
| this.log.log(new SemanticResourceException(SemanticResourceStatusCode.SFS_INITIALIZATION_ERROR, SemanticFileSystem.EMPTY, |
| Messages.SemanticFileSystem_SFSInitError_XMSG, e)); |
| |
| } |
| } |
| |
| private TreeRoot createRootNode(String name) { |
| TreeRoot root = SemanticResourceDBFactory.eINSTANCE.createTreeRoot(); |
| |
| root.setName(name); |
| root.setExists(false); |
| root.setPath("/" + name); //$NON-NLS-1$ |
| root.setType(TreeNodeType.PROJECT); |
| // root.setParentDB(this.db); |
| |
| return root; |
| } |
| |
| private TreeRoot createRootNode(String name, String queryString) { |
| TreeRoot root = SemanticResourceDBFactory.eINSTANCE.createTreeRoot(); |
| |
| root.setName(name); |
| root.setQueryPart(queryString); |
| root.setExists(false); |
| root.setPath("/" + name); //$NON-NLS-1$ |
| root.setType(TreeNodeType.PROJECT); |
| |
| if (queryString != null) { |
| SemanticQueryParser parser = new SemanticQueryParser(queryString); |
| |
| applyQueryParameters(root, parser); |
| |
| if (parser.getShouldCreate()) { |
| root.setExists(true); |
| root.setPath(null); |
| root.setParentDB(this.mgr.getSemanticDB()); |
| } |
| } |
| return root; |
| } |
| |
| private void applyQueryParameters(ResourceTreeNode node, SemanticQueryParser parser) { |
| node.setTemplateID(parser.getProviderID()); |
| node.setType(parser.getType()); |
| node.setRemoteURI(parser.getURI()); |
| } |
| |
| private void saveSemanticDB(String name) throws CoreException { |
| try { |
| if (SfsTraceLocation.CORE_DB.isActive()) { |
| SfsTraceLocation.getTrace().traceEntry(SfsTraceLocation.CORE_DB.getLocation()); |
| } |
| try { |
| this.lockForWrite(); |
| |
| this.mgr.saveSemanticDB(name); |
| } finally { |
| this.unlockForWrite(); |
| } |
| } catch (IOException e) { |
| SemanticResourceException ex = new SemanticResourceException(SemanticResourceStatusCode.SFS_ERROR_WRITING_METADATA, |
| SemanticFileSystem.EMPTY, Messages.SemanticFileSystem_SFSUpdateError_XMSG, e); |
| throw ex; |
| |
| } |
| } |
| |
| protected void lockForRead() { |
| this.readLock.lock(); |
| } |
| |
| protected void unlockForRead() { |
| this.readLock.unlock(); |
| } |
| |
| protected void lockForWrite() { |
| this.writeLock.lock(); |
| } |
| |
| protected void unlockForWrite() { |
| this.writeLock.unlock(); |
| } |
| |
| public String getPathToDb() { |
| File metadataFile = new File(metadataFolder, SemanticFileSystem.METADATA_FILENAME); |
| |
| String metadataLocation = metadataFile.getAbsolutePath(); |
| |
| return metadataLocation; |
| } |
| |
| public ISemanticFileSystemLog getLog() { |
| return this.log; |
| } |
| |
| static final class SemanticURILocatorService implements ISemanticURILocatorService { |
| private HashMap<String, ArrayList<IPath>> uri2pathMapping = new HashMap<String, ArrayList<IPath>>(); |
| final SemanticFileSystem fs; |
| boolean needsRebuild; |
| |
| /** |
| * @param fs |
| * |
| */ |
| public SemanticURILocatorService(SemanticFileSystem fs) { |
| this.fs = fs; |
| } |
| |
| /** |
| * @throws CoreException |
| */ |
| public IPath[] locateURI(URI uri) throws CoreException { |
| try { |
| this.fs.lockForWrite(); |
| |
| if (this.needsRebuild) { |
| this.rebuildMapping(null); |
| } |
| |
| ArrayList<IPath> paths = this.uri2pathMapping.get(uri.toString()); |
| if (paths != null) { |
| return paths.toArray(new IPath[paths.size()]); |
| } |
| return new IPath[0]; |
| } finally { |
| this.fs.unlockForWrite(); |
| } |
| } |
| |
| /** |
| * @throws CoreException |
| */ |
| public IPath[] locateURI(URI uri, IPath rootpath) throws CoreException { |
| try { |
| this.fs.lockForWrite(); |
| |
| if (this.needsRebuild) { |
| this.rebuildMapping(null); |
| } |
| |
| ArrayList<IPath> paths = this.uri2pathMapping.get(uri.toString()); |
| if (paths != null) { |
| ArrayList<IPath> filteredpaths = new ArrayList<IPath>(); |
| |
| for (IPath iPath : paths) { |
| if (rootpath.isPrefixOf(iPath)) { |
| filteredpaths.add(iPath); |
| } |
| } |
| |
| return filteredpaths.toArray(new IPath[filteredpaths.size()]); |
| } |
| return new IPath[0]; |
| } finally { |
| this.fs.unlockForWrite(); |
| } |
| } |
| |
| public IPath getPathForNode(ResourceTreeNode node) { |
| return this.fs.getPathForNode(node); |
| } |
| |
| public void rebuildMapping(IProgressMonitor monitor) { |
| this.uri2pathMapping.clear(); |
| |
| TreeIterator<EObject> contents = this.fs.mgr.getMetadataResource().getAllContents(); |
| |
| while (contents.hasNext()) { |
| EObject eObject = contents.next(); |
| if (eObject instanceof ResourceTreeNode) { |
| ResourceTreeNode node = (ResourceTreeNode) eObject; |
| |
| String uriString = node.getRemoteURI(); |
| |
| if (uriString != null) { |
| addURI(getPathForNode(node), uriString); |
| } |
| } |
| } |
| this.needsRebuild = false; |
| } |
| |
| public void addURI(IPath path, String uriString) { |
| ArrayList<IPath> paths = this.uri2pathMapping.get(uriString); |
| |
| if (paths != null) { |
| paths.add(path); |
| } else { |
| paths = new ArrayList<IPath>(); |
| |
| paths.add(path); |
| this.uri2pathMapping.put(uriString, paths); |
| } |
| } |
| |
| public void removeURI(IPath path, String uriString) { |
| ArrayList<IPath> paths = this.uri2pathMapping.get(uriString); |
| |
| paths.remove(path); |
| |
| if (paths.isEmpty()) { |
| this.uri2pathMapping.remove(uriString); |
| } |
| } |
| |
| public void requestRebuild() { |
| this.needsRebuild = true; |
| } |
| |
| } |
| |
| /** |
| * @throws CoreException |
| */ |
| public ISemanticURILocatorService getURILocatorService(IProgressMonitor monitor) throws CoreException { |
| try { |
| this.lockForWrite(); |
| if (this.uriLocator == null) { |
| this.uriLocator = new SemanticURILocatorService(this); |
| |
| this.uriLocator.rebuildMapping(monitor); |
| } |
| return this.uriLocator; |
| } finally { |
| this.unlockForWrite(); |
| } |
| } |
| |
| /** |
| * |
| */ |
| public void requestURILocatorRebuild() { |
| if (this.uriLocator != null) { |
| this.uriLocator.requestRebuild(); |
| } |
| } |
| |
| public SemanticURILocatorService getURILocator() { |
| return this.uriLocator; |
| } |
| } |