public int checkIn()

in source/com.microsoft.tfs.core/src/com/microsoft/tfs/core/clients/versioncontrol/soapextensions/Workspace.java [1084:1444]


    public int checkIn(
        PendingChange[] changes,
        final String committer,
        final String committerDisplayName,
        String author,
        String authorDisplayName,
        final String comment,
        final CheckinNote checkinNote,
        WorkItemCheckinInfo[] associatedWorkItems,
        final PolicyOverrideInfo policyOverrideInfo,
        final CheckinFlags flags) throws CheckinException {
        Check.isTrue(
            changes == null || changes.length > 0,
            "changes must be null for server-side change selection or non-empty"); //$NON-NLS-1$
        Check.notNull(flags, "flags"); //$NON-NLS-1$

        /**
         * TFS 2010 behaves strangely with gated check-ins if we send null for
         * associated work items (a non-standard subcode comes back in the
         * ActionDeniedBySubscriberException. Always send at least an empty
         * list.
         */
        if (associatedWorkItems == null) {
            associatedWorkItems = new WorkItemCheckinInfo[0];
        }

        final TaskMonitor monitor = TaskMonitorService.getTaskMonitor();

        /*
         * The total work for our progress monitor is set to 100, and subtasks
         * are allocated as percentages. For example, checkin for conflicts is
         * quick, so it takes only 2 percent. Uploading files usually takes
         * longer, so it's 80 percent. Make sure all the work done in this
         * method adds to 100.
         */
        monitor.begin("", 100); //$NON-NLS-1$

        /*
         * We sort the changes by server path so they appear in the correct
         * order when giving status information to the user.
         */
        String[] serverItems = null;
        if (changes != null) {
            changes = changes.clone();
            Arrays.sort(changes, new PendingChangeComparator(PendingChangeComparatorType.SERVER_ITEM));
            serverItems = PendingChange.toServerItems(changes);
        }

        // Lets us detect all abnormal exits (Throwable, Exception, Gated
        // checkin exception) for saved checkin reset
        boolean success = false;

        try {
            TaskMonitorService.pushTaskMonitor(monitor.newSubTaskMonitor(75));
            try {
                // Upload contents
                if (changes != null) {
                    final CheckinEngine ci = new CheckinEngine(client, this);

                    final long start = System.currentTimeMillis();
                    ci.uploadChanges(changes, false, getLocation() == WorkspaceLocation.LOCAL);
                    log.debug(MessageFormat.format(
                        "total time for upload of {0} was {1} ms", //$NON-NLS-1$
                        changes.length,
                        (System.currentTimeMillis() - start)));
                } else {
                    log.debug("null changes (server side change selection), skipped upload"); //$NON-NLS-1$
                }
            } finally {
                TaskMonitorService.popTaskMonitor(true);
            }

            if (author == null) {
                author = VersionControlConstants.AUTHENTICATED_USER;
            }
            if (authorDisplayName == null) {
                authorDisplayName = UserNameUtil.getCurrentUserName();
                final String domainName = UserNameUtil.getCurrentUserDomain();
                if (!StringUtil.isNullOrEmpty(domainName)) {
                    authorDisplayName = UserNameUtil.format(authorDisplayName, domainName);
                }
            }

            /*
             * Finally, create a Changeset and send it to the server to be
             * committed. It's important to pass "null" for the date so TFS 2010
             * and later do not require CheckinOther permissions (required to
             * set a specific date on a new changeset).
             */
            final Changeset changeset = new Changeset(
                null,
                comment,
                checkinNote,
                policyOverrideInfo,
                committer,
                committerDisplayName,
                null,
                -1,
                author,
                authorDisplayName,
                null);

            /*
             * Test one final time before the change set is fully committed.
             */
            if (monitor.isCanceled()) {
                // Caught in this method below.
                throw new CoreCancelException();
            }

            monitor.setCurrentWorkDescription(Messages.getString("Workspace.CheckinInNewChangeset")); //$NON-NLS-1$

            final AtomicReference<Failure[]> failures = new AtomicReference<Failure[]>();
            final AtomicReference<Failure[]> conflicts = new AtomicReference<Failure[]>();
            final boolean noAutoResolve = flags.contains(CheckinFlags.NO_AUTO_RESOLVE);

            final CheckinResult result;
            try {
                /*
                 * If changes was null when this method was called, serverItems
                 * will be null here, which causes the server to check in all
                 * workspace changes.
                 */
                result = getClient().getWebServiceLayer().checkIn(
                    getName(),
                    getOwnerName(),
                    serverItems,
                    changeset,
                    makeCheckinNotificationInfo(associatedWorkItems),
                    flags,
                    null,
                    conflicts,
                    failures,
                    false,
                    0,
                    client.mergeWithDefaultItemPropertyFilters(null));
            } catch (final ActionDeniedBySubscriberException e) {
                if (e.getSubscriberType().equals(BUILD_CHECKIN_SUBSCRIBER) && e.getStatusCode() == 1) {
                    /*
                     * For ease of use, convert the
                     * ActionDeniedBySubscriberException into a stronger type,
                     * GatedCheckinException. This exception has helper
                     * properties and is typed in a way that customers expect.
                     * It is still an ActionDeniedBySubscriberException.
                     */
                    throw new GatedCheckinException(e);
                } else {
                    /*
                     * Some other subscriber has denied the decision point.
                     * Throw the ActionDeniedBySubscriberException verbatim.
                     */
                    throw e;
                }
            }

            monitor.worked(10);

            changeset.setChangesetID(result.getChangeset());

            // Report any failures.
            reportCheckinConflictsAndThrow(result, conflicts.get(), failures.get(), noAutoResolve);

            /*
             * When the SetFileTimeToCheckin workspace option is set, then the
             * full checkin manifest is returned to the client in the form of
             * GetOperations, even in a server workspace. (In a server
             * workspace, the local version updates are still performed by the
             * server at the end of the CheckIn call.) We use this manifest to
             * set the check-in date on each item in the changeset, even
             * implicitly included missing parents and affected items of
             * recursive changes.
             */
            final TaskMonitor setFileTimeMonitor = monitor.newSubTaskMonitor(5);
            try {
                if (getOptions().contains(WorkspaceOptions.SET_FILE_TO_CHECKIN)) {
                    final GetOperation[] updates = result.getLocalVersionUpdates();

                    if (updates != null && updates.length > 0) {
                        setFileTimeMonitor.begin(Messages.getString("Workspace.SettingFileTime"), updates.length); //$NON-NLS-1$

                        for (final GetOperation getOp : updates) {
                            if (ItemType.FILE == getOp.getItemType()
                                && null != getOp.getTargetLocalItem()
                                && new File(getOp.getTargetLocalItem()).exists()) {
                                setFileTimeMonitor.setCurrentWorkDescription(getOp.getTargetLocalItem());

                                try {
                                    final FileSystemAttributes attributes =
                                        FileSystemUtils.getInstance().getAttributes(getOp.getTargetLocalItem());
                                    boolean restoreReadOnly = false;

                                    /*
                                     * Temporarily remove the read-only flag so
                                     * we can modify the time (Windows requires
                                     * this).
                                     */
                                    if (attributes.isReadOnly()) {
                                        attributes.setReadOnly(false);
                                        FileSystemUtils.getInstance().setAttributes(
                                            getOp.getTargetLocalItem(),
                                            attributes);
                                        restoreReadOnly = true;
                                    }

                                    new File(getOp.getTargetLocalItem()).setLastModified(
                                        result.getCreationDate().getTimeInMillis());

                                    if (restoreReadOnly) {
                                        attributes.setReadOnly(true);
                                        FileSystemUtils.getInstance().setAttributes(
                                            getOp.getTargetLocalItem(),
                                            attributes);
                                    }
                                } catch (final Exception e) {
                                    client.getEventEngine().fireNonFatalError(
                                        new NonFatalErrorEvent(EventSource.newFromHere(), this, e));
                                }
                            }
                        }
                    }
                }
            } finally {
                setFileTimeMonitor.done();
            }

            /*
             * If this is a server workspace, set files read-only.
             */
            final TaskMonitor makeReadOnlyMonitor = monitor.newSubTaskMonitor(5);
            try {
                if (changes != null && getLocation() == WorkspaceLocation.SERVER) {
                    makeReadOnlyMonitor.begin(Messages.getString("Workspace.SettingReadOnly"), changes.length); //$NON-NLS-1$

                    for (final PendingChange change : changes) {
                        if (change.getChangeType().contains(ChangeType.EDIT)
                            && change.getLocalItem() != null
                            && new File(change.getLocalItem()).exists()) {
                            makeReadOnlyMonitor.setCurrentWorkDescription(change.getLocalItem());

                            try {
                                final FileSystemAttributes attributes =
                                    FileSystemUtils.getInstance().getAttributes(change.getLocalItem());
                                if (!attributes.isSymbolicLink() && !attributes.isDirectory()) {
                                    attributes.setReadOnly(true);
                                    FileSystemUtils.getInstance().setAttributes(change.getLocalItem(), attributes);
                                }
                            } catch (final Exception e) {
                                client.getEventEngine().fireNonFatalError(
                                    new NonFatalErrorEvent(EventSource.newFromHere(), this, e));
                            }
                        } else {
                            // Skipping this one.
                            makeReadOnlyMonitor.setCurrentWorkDescription(""); //$NON-NLS-1$
                        }

                        makeReadOnlyMonitor.worked(1);
                    }
                }
            } finally {
                makeReadOnlyMonitor.done();
            }

            monitor.setCurrentWorkDescription(Messages.getString("Workspace.NotifyingListeners")); //$NON-NLS-1$

            /*
             * Determine which pending changes were committed and which were
             * undone. Preserve the sorted order in the sublists.
             */

            PendingChange[] committedChangesArray = new PendingChange[0];
            PendingChange[] undoneChangesArray = new PendingChange[0];

            if (changes != null && changes.length > 0) {
                final Set<String> undoneServerItems = new TreeSet<String>(ServerPath.TOP_DOWN_COMPARATOR);

                for (final String undoneServerItem : result.getUndoneServerItems()) {
                    undoneServerItems.add(undoneServerItem);
                }

                final List<PendingChange> undonePendingChanges = new ArrayList<PendingChange>(undoneServerItems.size());
                final List<PendingChange> committedPendingChanges = new ArrayList<PendingChange>();

                for (final PendingChange change : changes) {
                    if (undoneServerItems.contains(change.getServerItem())) {
                        undonePendingChanges.add(change);
                    } else {
                        committedPendingChanges.add(change);
                    }
                }

                committedChangesArray =
                    committedPendingChanges.toArray(new PendingChange[committedPendingChanges.size()]);
                undoneChangesArray = undonePendingChanges.toArray(new PendingChange[undonePendingChanges.size()]);
            }

            // Notify the user that the checkin iCheckinEvents complete.
            client.getEventEngine().fireCheckin(
                new CheckinEvent(
                    EventSource.newFromHere(),
                    this,
                    result.getChangeset(),
                    committedChangesArray,
                    undoneChangesArray));

            Workstation.getCurrent(getClient().getConnection().getPersistenceStoreProvider()).notifyForWorkspace(
                this,
                Notification.VERSION_CONTROL_PENDING_CHANGES_CHANGED);

            monitor.worked(1);

            final int cset = changeset.getChangesetID();

            TaskMonitorService.pushTaskMonitor(monitor.newSubTaskMonitor(4));
            try {
                /*
                 * Only update work items if we have a valid (non-0) changeset.
                 * Changeset 0 indicates all the pending changes were undone on
                 * the server.
                 */
                if (cset != 0) {
                    updateWorkItems(associatedWorkItems, cset, comment);
                }
            } finally {
                TaskMonitorService.popTaskMonitor(true);
            }

            // Remove any saved attempted checkin info.
            setLastSavedCheckin(buildEmptyLastSavedCheckin());

            success = true;
            return cset;
        } catch (final CanceledException e) {
            // Fire as non-fatal
            client.getEventEngine().fireNonFatalError(
                new NonFatalErrorEvent(
                    EventSource.newFromHere(),
                    this,
                    new CoreCancelException(Messages.getString("Workspace.CheckinCancelled")))); //$NON-NLS-1$
            return 0;
        } catch (final CoreCancelException e) {
            // Convert to CanceledException and fire as non-fatal
            client.getEventEngine().fireNonFatalError(
                new NonFatalErrorEvent(
                    EventSource.newFromHere(),
                    this,
                    new CanceledException(Messages.getString("Workspace.CheckinCancelled")))); //$NON-NLS-1$
            return 0;
        } finally {
            /*
             * If the checkin didn't succeed, save the info for the next
             * attempt. success will be false for expected things like gated
             * checkin and cancelation exceptions, and also for unexpected
             * exceptions.
             */
            if (!success) {
                updateLastSavedCheckin(comment, checkinNote, associatedWorkItems, policyOverrideInfo);
            }

            monitor.done();
        }
    }