private void setWorkspaceLocation()

in source/com.microsoft.tfs.core/src/com/microsoft/tfs/core/clients/versioncontrol/VersionControlClient.java [1540:1871]


    private void setWorkspaceLocation(final Workspace workspace, final WorkspaceLocation newLocation)
        throws CoreCancelException {
        Check.notNull(workspace, "workspace"); //$NON-NLS-1$
        Check.notNull(newLocation, "newLocation"); //$NON-NLS-1$

        if (newLocation == workspace.getLocation()) {
            // No work to do.
            return;
        }

        // Using UpdateWorkspace to set the location of a workspace was not
        // supported prior to revision Tfs2012_2.
        if (getWebServiceLayer().getServiceLevel().getValue() < WebServiceLevel.TFS_2012_2.getValue()) {
            throw new FeatureNotSupportedException(Messages.getString("Workspace.LocalWorkspacesNotSupported")); //$NON-NLS-1$
        }

        final TaskMonitor taskMonitor = TaskMonitorService.getTaskMonitor();
        try {
            // 100 total work units, make sure they all add up below
            taskMonitor.begin(Messages.getString("VersionControlClient.ChangingWorkspaceLocation"), 100); //$NON-NLS-1$

            if (WorkspaceLocation.SERVER == newLocation) {
                // Local -> server
                final WorkspaceLock wLock = workspace.lock();
                try {
                    if (taskMonitor.isCanceled()) {
                        throw new CoreCancelException();
                    }

                    // 1. Reconcile
                    taskMonitor.setCurrentWorkDescription(
                        Messages.getString("VersionControlClient.ReconcilingLocalWorkspaceToServer")); //$NON-NLS-1$
                    final AtomicBoolean pendingChangesUpdatedByServer = new AtomicBoolean();
                    workspace.reconcile(false, pendingChangesUpdatedByServer);
                    taskMonitor.worked(20);

                    // Last cancellation point
                    if (taskMonitor.isCanceled()) {
                        throw new CoreCancelException();
                    }

                    // 2. Mark all items without a pending edit as read-only on
                    // disk, since
                    // this is now a server workspace.
                    taskMonitor.setCurrentWorkDescription(
                        Messages.getString("VersionControlClient.MarkingUneditedReadOnly")); //$NON-NLS-1$
                    LocalDataAccessLayer.markReadOnlyBit(workspace, true, taskMonitor.newSubTaskMonitor(30));

                    // 3. Ask the server to make this a server workspace. Before
                    // we do,
                    // grab a couple of pieces of information we won't be able
                    // to get afterward.
                    taskMonitor.setCurrentWorkDescription(
                        Messages.getString("VersionControlClient.ChangingWorkspaceLocationOnServer")); //$NON-NLS-1$
                    final String localMetadataDirectory = workspace.getLocalMetadataDirectory();
                    final String[] baselineFolders = LocalDataAccessLayer.getBaselineFolders(workspace);

                    getWebServiceLayer().updateWorkspace(
                        workspace.getName(),
                        workspace.getOwnerName(),
                        new Workspace(
                            this,
                            workspace.getName(),
                            workspace.getOwnerName(),
                            workspace.getOwnerDisplayName(),
                            workspace.getOwnerAliases(),
                            workspace.getComment(),
                            workspace.getSecurityToken(),
                            workspace.getFolders(),
                            workspace.getComputer(),
                            WorkspaceLocation.SERVER,
                            workspace.getPermissions(),
                            null,
                            workspace.getOptions()),
                        SupportedFeatures.ALL);
                    taskMonitor.worked(10);

                    // 4. Refresh the Workspace object in this instance of the
                    // client object model.
                    // This has the additional effect of updating the local
                    // workspace cache (VersionControl.config).
                    taskMonitor.setCurrentWorkDescription(
                        Messages.getString("VersionControlClient.RefreshingWorkspace")); //$NON-NLS-1$
                    workspace.refresh();
                    taskMonitor.worked(10);

                    // 5. Get rid of the baseline folders and local metadata
                    // directory for this workspace.
                    // (Past the point of cancellation)
                    taskMonitor.setCurrentWorkDescription(
                        MessageFormat.format(
                            Messages.getString("VersionControlClient.DeletingUnusedBaselineFormat"), //$NON-NLS-1$
                            localMetadataDirectory));
                    FileHelpers.deleteDirectory(localMetadataDirectory);
                    taskMonitor.worked(10);

                    final TaskMonitor deleteBaselineMonitor = taskMonitor.newSubTaskMonitor(20);
                    deleteBaselineMonitor.begin("", baselineFolders.length); //$NON-NLS-1$
                    for (final String baselineFolder : baselineFolders) {
                        taskMonitor.setCurrentWorkDescription(
                            MessageFormat.format(
                                Messages.getString("VersionControlClient.DeletingUnusedBaselineFormat"), //$NON-NLS-1$
                                baselineFolder));

                        FileHelpers.deleteDirectory(baselineFolder);
                        deleteBaselineMonitor.worked(1);
                    }
                    deleteBaselineMonitor.done();
                } finally {
                    if (wLock != null) {
                        wLock.close();
                    }
                }

                // 6. Fire a cross-process notification indicating that the
                // workspace object changed.
                Workstation.getCurrent(getConnection().getPersistenceStoreProvider()).notifyForWorkspace(
                    workspace,
                    Notification.VERSION_CONTROL_WORKSPACE_CHANGED);
            } else if (WorkspaceLocation.LOCAL == newLocation) {
                // Server -> local

                /*
                 * Create a clone of the workspace object which is marked as a
                 * local workspace. We'll use this object for local work before
                 * we convert the workspace on the server. This Workspace object
                 * must not escape this method.
                 */
                final Workspace localWorkspace = new Workspace(
                    this,
                    workspace.getName(),
                    workspace.getOwnerName(),
                    workspace.getOwnerDisplayName(),
                    workspace.getOwnerAliases(),
                    workspace.getComment(),
                    workspace.getSecurityToken(),
                    workspace.getFolders(),
                    workspace.getComputer(),
                    WorkspaceLocation.LOCAL,
                    workspace.getPermissions(),
                    null,
                    workspace.getOptions());

                final WorkspaceLock wLock = workspace.lock();
                try {
                    boolean workspacePropertiesCreated = false;

                    try {
                        if (taskMonitor.isCanceled()) {
                            throw new CoreCancelException();
                        }

                        // Delete any existing local metadata for this
                        // workspace.
                        taskMonitor.setCurrentWorkDescription(
                            Messages.getString("VersionControlClient.RemovingMetadataForLocalWorkspace")); //$NON-NLS-1$
                        FileHelpers.deleteDirectory(localWorkspace.getLocalMetadataDirectory());
                        taskMonitor.worked(10);

                        if (taskMonitor.isCanceled()) {
                            throw new CoreCancelException();
                        }

                        // 1. Set up the workspace properties table for this
                        // workspace.
                        taskMonitor.setCurrentWorkDescription(
                            Messages.getString("VersionControlClient.CreatingPropertiesTable")); //$NON-NLS-1$

                        final LocalWorkspaceTransaction propsTransaction =
                            new LocalWorkspaceTransaction(localWorkspace);

                        // We're explicitly creating a new workspace properties
                        // table here. We don't
                        // want autorecovery to ever run in this scenario.
                        propsTransaction.setAutoRecover(false);

                        try {
                            propsTransaction.execute(new WorkspacePropertiesTransaction() {
                                @Override
                                public void invoke(final LocalWorkspaceProperties wp) {
                                    // Set the working folders for the workspace
                                    // (initial population).
                                    wp.setWorkingFolders(workspace.getFolders());
                                    wp.doBaselineFolderMaintenance();
                                }
                            });
                        } finally {
                            try {
                                propsTransaction.close();
                            } catch (final IOException e) {
                                throw new VersionControlException(e);
                            }
                        }

                        workspacePropertiesCreated = true;
                        taskMonitor.worked(10);

                        if (taskMonitor.isCanceled()) {
                            throw new CoreCancelException();
                        }

                        // 2. Set the pending changes for the local workspace.
                        taskMonitor.setCurrentWorkDescription(
                            Messages.getString("VersionControlClient.CreatingPendingChangesTable")); //$NON-NLS-1$

                        final LocalWorkspaceTransaction pcTransaction = new LocalWorkspaceTransaction(localWorkspace);

                        try {
                            pcTransaction.execute(new LocalVersionPendingChangesTransaction() {
                                @Override
                                public void invoke(final WorkspaceVersionTable lv, final LocalPendingChangesTable pc) {
                                    final PendingSet set = workspace.getPendingChanges();

                                    if (set != null && set.getPendingChanges() != null) {
                                        pc.replacePendingChanges(set.getPendingChanges());
                                    }
                                }
                            });
                        } finally {
                            try {
                                pcTransaction.close();
                            } catch (final IOException e) {
                                throw new VersionControlException(e);
                            }
                        }

                        taskMonitor.worked(10);

                        if (taskMonitor.isCanceled()) {
                            throw new CoreCancelException();
                        }

                        // 3. Get the data we need to populate the local version
                        // table for the workspace.
                        taskMonitor.setCurrentWorkDescription(
                            Messages.getString("VersionControlClient.CreatingLocalVersionTable")); //$NON-NLS-1$

                        final WorkspaceItemSet[] workspaceItemSets = workspace.getItems(new ItemSpec[] {
                            new ItemSpec(ServerPath.ROOT, RecursionType.FULL)
                        }, DeletedState.ANY, ItemType.ANY, true, GetItemsOptions.INCLUDE_RECURSIVE_DELETES);

                        if (null != workspaceItemSets && 1 == workspaceItemSets.length) {
                            if (taskMonitor.isCanceled()) {
                                throw new CoreCancelException();
                            }

                            // 4. Populate the local version table for the
                            // workspace.

                            final BaselineRequest[] baselineRequests = LocalDataAccessLayer.populateLocalVersionTable(
                                localWorkspace,
                                workspaceItemSets[0].getItems(),
                                taskMonitor.newSubTaskMonitor(10));

                            if (null != baselineRequests) {
                                if (taskMonitor.isCanceled()) {
                                    throw new CoreCancelException();
                                }

                                // 5. Put the baselines in place (either by
                                // gzip+hash of existing local content,
                                // or by downloading content from the server).
                                taskMonitor.setCurrentWorkDescription(
                                    Messages.getString("VersionControlClient.CompressingAndDownloadingBaselines")); //$NON-NLS-1$
                                LocalDataAccessLayer.processConversionBaselineRequests(
                                    localWorkspace,
                                    Arrays.asList(baselineRequests));
                            }

                            taskMonitor.worked(20);
                        } else {
                            taskMonitor.worked(30);
                        }

                        // Last cancellation point
                        if (taskMonitor.isCanceled()) {
                            throw new CoreCancelException();
                        }
                    } catch (final CoreCancelException e) {
                        // If we were canceled and we have a workspace
                        // properties table in place, go ahead and take the time
                        // to clean up the $tf folders we created.
                        if (workspacePropertiesCreated) {
                            final String[] baselineFolders = LocalDataAccessLayer.getBaselineFolders(localWorkspace);

                            for (final String baselineFolder : baselineFolders) {
                                FileHelpers.deleteDirectory(baselineFolder);
                            }
                        }

                        throw e;
                    }

                    // 5. Mark all items in the workspace as writable.
                    taskMonitor.setCurrentWorkDescription(
                        Messages.getString("VersionControlClient.RemovingReadOnlyFromUneditedItems")); //$NON-NLS-1$
                    LocalDataAccessLayer.markReadOnlyBit(localWorkspace, false, taskMonitor.newSubTaskMonitor(20));

                    // 6. Mark this workspace as a local workspace.
                    taskMonitor.setCurrentWorkDescription(
                        Messages.getString("VersionControlClient.ChangingWorkspaceLocationOnServer")); //$NON-NLS-1$
                    getWebServiceLayer().updateWorkspace(
                        workspace.getName(),
                        workspace.getOwnerName(),
                        localWorkspace,
                        SupportedFeatures.ALL);
                    taskMonitor.worked(10);

                } finally {
                    if (wLock != null) {
                        wLock.close();
                    }
                }

                // 7. Refresh this Workspace instance in the client object
                // model. This has the additional effect of updating the local
                // workspace cache (VersionControl.config).
                taskMonitor.setCurrentWorkDescription(Messages.getString("VersionControlClient.RefreshingWorkspace")); //$NON-NLS-1$
                workspace.refresh();
                workspace.getWorkspaceWatcher().workingFoldersChanged(workspace.getFolders());
                taskMonitor.worked(10);

                // 8. Fire a cross-process notification indicating that the
                // workspace object changed.
                Workstation.getCurrent(getConnection().getPersistenceStoreProvider()).notifyForWorkspace(
                    workspace,
                    Notification.VERSION_CONTROL_WORKSPACE_CHANGED);
            }
        } finally {
            taskMonitor.done();
        }
    }