| /******************************************************************************* |
| * 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.resources.semantic.examples.providers; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| |
| import org.eclipse.core.filesystem.EFS; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IStorage; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.resources.semantic.ISemanticFileSystem; |
| import org.eclipse.core.resources.semantic.SemanticResourceException; |
| import org.eclipse.core.resources.semantic.SemanticResourceStatusCode; |
| import org.eclipse.core.resources.semantic.SyncDirection; |
| import org.eclipse.core.resources.semantic.examples.remote.RemoteFile; |
| import org.eclipse.core.resources.semantic.examples.remote.RemoteFolder; |
| import org.eclipse.core.resources.semantic.examples.remote.RemoteItem; |
| import org.eclipse.core.resources.semantic.examples.remote.RemoteItem.Type; |
| import org.eclipse.core.resources.semantic.examples.remote.RemoteStore; |
| import org.eclipse.core.resources.semantic.examples.remote.SemanticResourcesPluginExamplesCore; |
| import org.eclipse.core.resources.semantic.spi.CachingContentProvider; |
| import org.eclipse.core.resources.semantic.spi.FileCacheServiceFactory; |
| import org.eclipse.core.resources.semantic.spi.ICacheService; |
| import org.eclipse.core.resources.semantic.spi.ICacheServiceFactory; |
| import org.eclipse.core.resources.semantic.spi.ISemanticContentProviderRemote; |
| import org.eclipse.core.resources.semantic.spi.ISemanticFileHistoryProvider; |
| import org.eclipse.core.resources.semantic.spi.ISemanticFileStore; |
| import org.eclipse.core.resources.semantic.spi.ISemanticFileStore.ResourceType; |
| import org.eclipse.core.resources.semantic.spi.ISemanticResourceRuleFactory; |
| import org.eclipse.core.resources.semantic.spi.ISemanticSpiResourceInfo; |
| import org.eclipse.core.resources.semantic.spi.ISemanticTreeDeepFirstVisitor; |
| import org.eclipse.core.resources.semantic.spi.SemanticRevisionStorage; |
| import org.eclipse.core.resources.semantic.spi.SemanticSpiResourceInfo; |
| import org.eclipse.core.resources.semantic.spi.SemanticTreeWalker; |
| import org.eclipse.core.resources.semantic.spi.Util; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.MultiStatus; |
| import org.eclipse.core.runtime.QualifiedName; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.team.core.history.IFileHistory; |
| import org.eclipse.team.core.history.IFileRevision; |
| import org.eclipse.team.core.history.provider.FileRevision; |
| |
| /** |
| * Keeps the remote data in a XML file |
| * |
| */ |
| public class RemoteStoreContentProvider extends CachingContentProvider implements ISemanticContentProviderRemote { |
| |
| private static final IStatus OKSTATUS = new Status(IStatus.OK, SemanticResourcesPluginExamplesCore.PLUGIN_ID, ""); //$NON-NLS-1$ |
| |
| private static final QualifiedName ATTR_READONLY = new QualifiedName(SemanticResourcesPluginExamplesCore.PLUGIN_ID, "ReadOnly"); //$NON-NLS-1$ |
| |
| @Override |
| @SuppressWarnings({"rawtypes"}) |
| public Object getAdapter(Class adapter) { |
| |
| if (adapter == ISemanticFileHistoryProvider.class) { |
| |
| return new ISemanticFileHistoryProvider() { |
| |
| /** |
| * @throws CoreException |
| */ |
| public IFileRevision getWorkspaceFileRevision(ISemanticFileStore store) throws CoreException { |
| RemoteItem item = getRemoteItem(getStore(), store.getPath()); |
| if (item instanceof RemoteFile) { |
| return ((RemoteFile) item).getCurrentRevision(store); |
| } |
| return null; |
| } |
| |
| /** |
| * @throws CoreException |
| */ |
| public IFileHistory getHistoryFor(ISemanticFileStore store, int options, IProgressMonitor monitor) throws CoreException { |
| RemoteItem item = getRemoteItem(getStore(), store.getPath()); |
| if (item instanceof RemoteFile) { |
| return ((RemoteFile) item).getHistory(store); |
| } |
| return null; |
| } |
| |
| public IFileRevision[] getResourceVariants(final ISemanticFileStore semanticFileStore, IProgressMonitor monitor) { |
| |
| RemoteItem item = getStore().getItemByPath(semanticFileStore.getPath().removeFirstSegments(2)); |
| |
| if (!(item instanceof RemoteFile)) { |
| return null; |
| } |
| |
| final RemoteFile file = (RemoteFile) item; |
| |
| IFileRevision remote = new FileRevision() { |
| |
| /** |
| * @throws CoreException |
| */ |
| public IFileRevision withAllProperties(IProgressMonitor actmonitor) throws CoreException { |
| return this; |
| } |
| |
| public boolean isPropertyMissing() { |
| return false; |
| } |
| |
| @Override |
| public URI getURI() { |
| try { |
| return new URI(file.getPath().toString()); |
| } catch (URISyntaxException e) { |
| // $JL-EXC$ |
| throw new RuntimeException(Messages.RemoteStoreContentProvider_URIError_XMSG); |
| } |
| } |
| |
| @Override |
| public long getTimestamp() { |
| return file.getTimestamp(); |
| } |
| |
| public IStorage getStorage(IProgressMonitor actmonitor) throws CoreException { |
| SemanticRevisionStorage storage = new SemanticRevisionStorage(semanticFileStore); |
| storage.setContents(new ByteArrayInputStream(file.getContent()), actmonitor); |
| return storage; |
| } |
| |
| public String getName() { |
| return file.getName(); |
| } |
| |
| @Override |
| public String getContentIdentifier() { |
| return Long.toString(file.getTimestamp()); |
| } |
| |
| @Override |
| public String getComment() { |
| return null; |
| } |
| |
| @Override |
| public String getAuthor() { |
| return null; |
| } |
| |
| @Override |
| public boolean exists() { |
| return true; |
| } |
| |
| }; |
| |
| return new IFileRevision[] {null, remote}; |
| } |
| }; |
| } |
| return super.getAdapter(adapter); |
| } |
| |
| public void synchronizeContentWithRemote(ISemanticFileStore semanticFileStore, SyncDirection direction, IProgressMonitor monitor, |
| MultiStatus status) { |
| |
| monitor.setTaskName(NLS.bind(Messages.RemoteStoreContentProvider_Syncing_XMSG, semanticFileStore.getPath().toString())); |
| |
| RemoteStore store; |
| RemoteItem item; |
| try { |
| store = getStore(); |
| item = getRemoteItem(store, semanticFileStore.getPath()); |
| if (item == null) { |
| throw new SemanticResourceException(SemanticResourceStatusCode.REMOTE_RESOURCE_NOT_FOUND, semanticFileStore.getPath(), |
| Messages.RemoteStoreContentProvider_RemoteItemNotFound_XMSG); |
| } |
| |
| } catch (CoreException e) { |
| status.add(e.getStatus()); |
| return; |
| } |
| |
| if (item.getType() == Type.FOLDER) { |
| |
| RemoteFolder folder = (RemoteFolder) item; |
| |
| // check for deleted folders |
| try { |
| String[] childNames = semanticFileStore.childNames(EFS.NONE, monitor); |
| for (String name : childNames) { |
| if (!folder.hasChild(name)) { |
| ((ISemanticFileStore) semanticFileStore.getChild(name)).remove(monitor); |
| } |
| } |
| } catch (CoreException e) { |
| status.add(e.getStatus()); |
| return; |
| } |
| |
| for (RemoteItem childItem : folder.getChildren()) { |
| ISemanticFileStore fileStore = (ISemanticFileStore) semanticFileStore.getChild(childItem.getName()); |
| if (!fileStore.fetchInfo().exists()) { |
| try { |
| if (childItem.getType() == Type.FOLDER) { |
| semanticFileStore.addChildFolder(childItem.getName()); |
| } else if (childItem.getType() == Type.FILE) { |
| semanticFileStore.addChildFile(childItem.getName()); |
| setReadOnly((ISemanticFileStore) semanticFileStore.getChild(childItem.getName()), true, monitor); |
| } |
| |
| } catch (CoreException e) { |
| status.add(e.getStatus()); |
| return; |
| } |
| } |
| |
| try { |
| store.serialize(monitor); |
| } catch (CoreException e) { |
| status.add(e.getStatus()); |
| } |
| |
| synchronizeContentWithRemote(fileStore, direction, monitor, status); |
| } |
| |
| } else if (item.getType() == Type.FILE) { |
| try { |
| RemoteFile file = (RemoteFile) item; |
| long remoteTime = file.getTimestamp(); |
| long localTime = getResourceTimestamp(semanticFileStore, monitor); |
| ICacheService srv = getCacheService(); |
| |
| if (direction == SyncDirection.OUTGOING || localTime > remoteTime) { |
| // outgoing |
| OutputStream os = file.getOutputStream(false); |
| Util.transferStreams(srv.getContent(semanticFileStore.getPath()), os, monitor); |
| file.setTimestamp(localTime); |
| store.serialize(monitor); |
| } else if (direction == SyncDirection.INCOMING || remoteTime > localTime) { |
| // incoming |
| srv.addContent(semanticFileStore.getPath(), new ByteArrayInputStream(file.getContent()), ISemanticFileSystem.NONE, |
| monitor); |
| setResourceTimestamp(semanticFileStore, remoteTime, monitor); |
| } |
| |
| } catch (CoreException e) { |
| status.add(e.getStatus()); |
| } |
| } |
| |
| } |
| |
| public void addResource(ISemanticFileStore parentStore, String name, ResourceType resourceType, IProgressMonitor monitor) |
| throws CoreException { |
| switch (resourceType) { |
| case UNKNOWN_TYPE : |
| this.addResourceFromRemote(parentStore, name, monitor); |
| break; |
| case FILE_TYPE : |
| this.addFileFromRemote(parentStore, name, monitor); |
| break; |
| case FOLDER_TYPE : |
| this.addFolderFromRemote(parentStore, name, monitor); |
| break; |
| case PROJECT_TYPE : |
| throw new CoreException(new Status(IStatus.ERROR, SemanticResourcesPluginExamplesCore.PLUGIN_ID, |
| Messages.RemoteStoreContentProvider_CannotCreateProject_XMSG)); |
| } |
| } |
| |
| private void addFileFromRemote(ISemanticFileStore parentStore, String name, IProgressMonitor monitor) throws CoreException { |
| |
| RemoteItem item = getRemoteItem(getStore(), parentStore.getPath().append(name)); |
| |
| if (item == null) { |
| throw new SemanticResourceException(SemanticResourceStatusCode.REMOTE_RESOURCE_NOT_FOUND, parentStore.getPath(), |
| Messages.RemoteStoreContentProvider_RemoteItemNotFound_XMSG); |
| } |
| if (item.getType() != Type.FILE) { |
| IStatus error = new Status(IStatus.ERROR, SemanticResourcesPluginExamplesCore.PLUGIN_ID, |
| Messages.RemoteStoreContentProvider_RemoteNotFile_XMSG); |
| throw new CoreException(error); |
| } |
| |
| parentStore.addChildFile(name); |
| |
| ISemanticFileStore newChild = (ISemanticFileStore) parentStore.getChild(name); |
| setReadOnly(newChild, true, monitor); |
| |
| } |
| |
| private void addFolderFromRemote(ISemanticFileStore parentStore, String name, IProgressMonitor monitor) throws CoreException { |
| parentStore.addChildFolder(name); |
| |
| } |
| |
| private void addResourceFromRemote(ISemanticFileStore parentStore, String name, IProgressMonitor monitor) throws CoreException { |
| RemoteItem item = getRemoteItem(getStore(), parentStore.getPath().append(name)); |
| if (item == null) { |
| throw new SemanticResourceException(SemanticResourceStatusCode.REMOTE_RESOURCE_NOT_FOUND, parentStore.getPath(), |
| Messages.RemoteStoreContentProvider_RemoteNotFound_XMSG); |
| } |
| if (item.getType() == Type.FOLDER) { |
| addFolderFromRemote(parentStore, name, monitor); |
| } else { |
| addFileFromRemote(parentStore, name, monitor); |
| } |
| |
| } |
| |
| public void createResourceRemotely(ISemanticFileStore parentStore, String name, Object context, IProgressMonitor monitor) |
| throws CoreException { |
| // let's simply assume that a folder is wanted |
| RemoteStore store = getStore(); |
| RemoteItem item = getRemoteItem(store, parentStore.getPath()); |
| if (item.getType() == Type.FILE) { |
| throw new SemanticResourceException(SemanticResourceStatusCode.RESOURCE_WITH_OTHER_TYPE_EXISTS, parentStore.getPath(), |
| Messages.RemoteStoreContentProvider_ParentIsFile_XMSG); |
| } |
| ((RemoteFolder) item).addFolder(name); |
| store.serialize(monitor); |
| // need to store before add |
| addFolderFromRemote(parentStore, name, monitor); |
| } |
| |
| public void deleteRemotely(ISemanticFileStore semanticFileStore, IProgressMonitor monitor) throws CoreException { |
| |
| RemoteStore store = getStore(); |
| RemoteItem item = getRemoteItem(store, semanticFileStore.getPath()); |
| |
| item.getParent().deleteChild(item.getName()); |
| store.serialize(monitor); |
| // need to store before update |
| removeResource(semanticFileStore, monitor); |
| |
| } |
| |
| public void revertChanges(ISemanticFileStore semanticFileStore, IProgressMonitor monitor) throws CoreException { |
| |
| RemoteStore store = getStore(); |
| RemoteItem item = getRemoteItem(store, semanticFileStore.getPath()); |
| if (item.getType() != Type.FILE) { |
| throw new SemanticResourceException(SemanticResourceStatusCode.RESOURCE_WITH_OTHER_TYPE_EXISTS, semanticFileStore.getPath(), |
| Messages.RemoteStoreContentProvider_FoldersNoRevert_XMSG); |
| } |
| |
| RemoteFile file = ((RemoteFile) item); |
| |
| getCacheService().addContent(semanticFileStore.getPath(), new ByteArrayInputStream(file.getContent()), ISemanticFileSystem.NONE, |
| monitor); |
| setResourceTimestamp(semanticFileStore, file.getTimestamp(), monitor); |
| setReadOnly(semanticFileStore, true, monitor); |
| |
| } |
| |
| public IStatus validateRemoteCreate(ISemanticFileStore parentStore, String childName, final Object shell) { |
| return OKSTATUS; |
| } |
| |
| public IStatus validateRemoteDelete(ISemanticFileStore semanticFileStore, final Object shell) { |
| |
| return OKSTATUS; |
| } |
| |
| public IStatus validateEdit(ISemanticFileStore[] stores, final Object shell) { |
| |
| if (shell != null) { |
| |
| MultiStatus multi = new MultiStatus(SemanticResourcesPluginExamplesCore.PLUGIN_ID, IStatus.OK, |
| Messages.RemoteStoreContentProvider_ValidateEdit_XGRP, null); |
| |
| for (ISemanticFileStore store : stores) { |
| |
| try { |
| this.setReadOnly(store, false, null); |
| continue; |
| } catch (CoreException e) { |
| SemanticResourcesPluginExamplesCore.getDefault().getLog().log(e.getStatus()); |
| multi.add(e.getStatus()); |
| } |
| |
| } |
| return multi; |
| |
| } |
| // UI-less mode |
| for (ISemanticFileStore store : stores) { |
| try { |
| setReadOnly(store, false, null); |
| } catch (CoreException e) { |
| return e.getStatus(); |
| } |
| } |
| |
| return OKSTATUS; |
| |
| } |
| |
| RemoteItem getRemoteItem(RemoteStore remoteStore, IPath path) { |
| |
| if (remoteStore == null) { |
| return null; |
| } |
| IPath relPath = path.removeFirstSegments(getRootStore().getPath().segmentCount()); |
| |
| return remoteStore.getItemByPath(relPath); |
| |
| } |
| |
| RemoteStore getStore() { |
| |
| IProject ownProject = ResourcesPlugin.getWorkspace().getRoot().findMember(getRootStore().getPath()).getProject(); |
| RemoteStore store = (RemoteStore) ownProject.getAdapter(RemoteStore.class); |
| return store; |
| |
| } |
| |
| /** |
| * @throws CoreException |
| */ |
| @Override |
| public ICacheServiceFactory getCacheServiceFactory() throws CoreException { |
| return new FileCacheServiceFactory(); |
| } |
| |
| @Override |
| public InputStream openInputStreamInternal(ISemanticFileStore store, IProgressMonitor monitor, ICacheTimestampSetter timeStampSetter) |
| throws CoreException { |
| RemoteFile file = (RemoteFile) getRemoteItem(getStore(), store.getPath()); |
| if (file == null) { |
| throw new SemanticResourceException(SemanticResourceStatusCode.REMOTE_RESOURCE_NOT_FOUND, store.getPath(), |
| Messages.RemoteStoreContentProvider_RemoteItemNotFound_XMSG); |
| } |
| timeStampSetter.setTimestamp(file.getTimestamp()); |
| return new ByteArrayInputStream(file.getContent()); |
| } |
| |
| public void createFileRemotely(ISemanticFileStore parentStore, String name, InputStream source, Object context, IProgressMonitor monitor) |
| throws CoreException { |
| |
| RemoteStore store = getStore(); |
| RemoteItem item = getRemoteItem(store, parentStore.getPath()); |
| if (item.getType() == Type.FILE) { |
| throw new SemanticResourceException(SemanticResourceStatusCode.RESOURCE_WITH_OTHER_TYPE_EXISTS, parentStore.getPath(), |
| Messages.RemoteStoreContentProvider_CannotCreateFileChild_XMSG); |
| } |
| RemoteFile file = ((RemoteFolder) item).addFile(name, new byte[0], System.currentTimeMillis()); |
| if (source != null) { |
| Util.transferStreams(source, file.getOutputStream(false), monitor); |
| } |
| store.serialize(monitor); |
| // need to store before add |
| addFileFromRemote(parentStore, name, monitor); |
| } |
| |
| public ISemanticSpiResourceInfo fetchResourceInfo(ISemanticFileStore semanticFileStore, int options, IProgressMonitor monitor) |
| throws CoreException { |
| |
| String uriString = null; |
| |
| boolean readOnly; |
| if (SemanticSpiResourceInfo.isOptionRequested(ISemanticFileSystem.RESOURCE_INFO_READ_ONLY, options)) { |
| readOnly = isReadOnly(semanticFileStore); |
| } else { |
| readOnly = false; |
| } |
| |
| boolean existsRemotely = false; |
| if (SemanticSpiResourceInfo.isOptionRequested(ISemanticFileSystem.RESOURCE_INFO_EXISTS_REMOTELY, options)) { |
| |
| existsRemotely = getRemoteItem(getStore(), semanticFileStore.getPath()) != null; |
| |
| } |
| return new SemanticSpiResourceInfo(options, false, false, readOnly, existsRemotely, uriString, null); |
| } |
| |
| private boolean isReadOnly(ISemanticFileStore semanticFileStore) throws CoreException { |
| return semanticFileStore.getPersistentProperty(ATTR_READONLY) != null; |
| } |
| |
| public void removeResource(ISemanticFileStore semanticFileStore, IProgressMonitor monitor) throws CoreException { |
| |
| ISemanticTreeDeepFirstVisitor visitor = new ISemanticTreeDeepFirstVisitor() { |
| |
| @SuppressWarnings("synthetic-access") |
| public void visit(ISemanticFileStore store, IProgressMonitor actMonitor) throws CoreException { |
| if (store.getContentProviderID() == null || store.getPath().equals(getRootStore().getPath())) { |
| try { |
| deleteCache(store, actMonitor); |
| } catch (CoreException ce) { |
| // $JL-EXC$ TODO trace? we simply hope to delete this |
| // upon |
| // re-create |
| } |
| store.remove(actMonitor); |
| } else { |
| store.getEffectiveContentProvider().removeResource(store, actMonitor); |
| } |
| } |
| |
| /** |
| * @throws CoreException |
| */ |
| public boolean shouldVisitChildren(ISemanticFileStore store, IProgressMonitor actMonitor) throws CoreException { |
| return store.getContentProviderID() == null; |
| } |
| }; |
| |
| SemanticTreeWalker.accept(semanticFileStore, visitor, monitor); |
| |
| } |
| |
| public void setReadOnly(ISemanticFileStore semanticFileStore, boolean readonly, IProgressMonitor monitor) throws CoreException { |
| semanticFileStore.setPersistentProperty(ATTR_READONLY, readonly ? "" : null); //$NON-NLS-1$ |
| |
| } |
| |
| public IStatus validateSave(ISemanticFileStore semanticFileStore) { |
| return validateEdit(new ISemanticFileStore[] {semanticFileStore}, null); |
| } |
| |
| @Override |
| public ISemanticResourceRuleFactory getRuleFactory() { |
| // we always return the project, as the RemoteStore may need |
| // to update the xml file in the project |
| return new ISemanticResourceRuleFactory() { |
| |
| public ISemanticFileStore validateEditRule(ISemanticFileStore[] stores) { |
| return (ISemanticFileStore) getRootStore().getParent(); |
| } |
| |
| public ISemanticFileStore refreshRule(ISemanticFileStore store) { |
| return (ISemanticFileStore) getRootStore().getParent(); |
| } |
| |
| public ISemanticFileStore moveRule(ISemanticFileStore source, ISemanticFileStore destination) { |
| return (ISemanticFileStore) getRootStore().getParent(); |
| } |
| |
| public ISemanticFileStore modifyRule(ISemanticFileStore store) { |
| return (ISemanticFileStore) getRootStore().getParent(); |
| } |
| |
| public ISemanticFileStore deleteRule(ISemanticFileStore store) { |
| return (ISemanticFileStore) getRootStore().getParent(); |
| } |
| |
| public ISemanticFileStore createRule(ISemanticFileStore store) { |
| return (ISemanticFileStore) getRootStore().getParent(); |
| } |
| |
| public ISemanticFileStore copyRule(ISemanticFileStore source, ISemanticFileStore destination) { |
| return (ISemanticFileStore) getRootStore().getParent(); |
| } |
| |
| public ISemanticFileStore charsetRule(ISemanticFileStore store) { |
| return (ISemanticFileStore) getRootStore().getParent(); |
| } |
| }; |
| } |
| |
| } |