Example usage for java.util.concurrent.atomic AtomicReference set

List of usage examples for java.util.concurrent.atomic AtomicReference set

Introduction

In this page you can find the example usage for java.util.concurrent.atomic AtomicReference set.

Prototype

public final void set(V newValue) 

Source Link

Document

Sets the value to newValue , with memory effects as specified by VarHandle#setVolatile .

Usage

From source file:org.geotools.jdbc.JoiningJDBCFeatureSource.java

/**
 * Generates a 'SELECT p1, p2, ... FROM ... WHERE ...' prepared statement.
 * /*w w  w. j  a  v  a  2  s.  co m*/
 * @param featureType
 *            the feature type that the query must return (may contain less attributes than the
 *            native one)
 * @param attributes
 *            the properties queried, or {@link Query#ALL_NAMES} to gather all of them
 * @param query
 *            the query to be run. The type name and property will be ignored, as they are
 *            supposed to have been already embedded into the provided feature type
 * @param cx
 *            The database connection to be used to create the prepared statement
 * @throws SQLException 
 * @throws IOException 
 * @throws FilterToSQLException
 */
protected String selectSQL(SimpleFeatureType featureType, JoiningQuery query,
        AtomicReference<PreparedFilterToSQL> toSQLref) throws IOException, SQLException, FilterToSQLException {

    // first we create from clause, for aliases

    StringBuffer fromclause = new StringBuffer();
    getDataStore().encodeTableName(featureType.getTypeName(), fromclause, query.getHints());

    //joining
    Set<String> tableNames = new HashSet<String>();

    String lastTypeName = featureType.getTypeName();
    String curTypeName = lastTypeName;

    String[] aliases = null;

    if (query.getQueryJoins() != null) {

        aliases = new String[query.getQueryJoins().size()];

        for (int i = 0; i < query.getQueryJoins().size(); i++) {
            JoiningQuery.QueryJoin join = query.getQueryJoins().get(i);

            fromclause.append(" INNER JOIN ");
            String alias = null;

            FilterToSQL toSQL1 = createFilterToSQL(getDataStore().getSchema(lastTypeName));
            FilterToSQL toSQL2 = createFilterToSQL(getDataStore().getSchema(join.getJoiningTypeName()));

            String last_alias = createAlias(lastTypeName, tableNames);
            tableNames.add(last_alias);
            curTypeName = last_alias;
            if (tableNames.contains(join.getJoiningTypeName())) {
                alias = createAlias(join.getJoiningTypeName(), tableNames);

                aliases[i] = alias;

                getDataStore().encodeTableName(join.getJoiningTypeName(), fromclause, query.getHints());
                fromclause.append(" ");
                getDataStore().dialect.encodeTableName(alias, fromclause);
                fromclause.append(" ON ( ");

                toSQL2.setFieldEncoder(new JoiningFieldEncoder(alias));
                fromclause.append(toSQL2.encodeToString(join.getForeignKeyName()));

            } else {
                aliases[i] = null;
                getDataStore().encodeTableName(join.getJoiningTypeName(), fromclause, query.getHints());
                fromclause.append(" ON ( ");
                toSQL2.setFieldEncoder(new JoiningFieldEncoder(join.getJoiningTypeName()));
                fromclause.append(toSQL2.encodeToString(join.getForeignKeyName()));
            }
            fromclause.append(" = ");
            toSQL1.setFieldEncoder(new JoiningFieldEncoder(curTypeName));
            fromclause.append(toSQL1.encodeToString(join.getJoiningKeyName()));
            fromclause.append(") ");
            lastTypeName = join.getJoiningTypeName();
            curTypeName = alias == null ? lastTypeName : alias;
        }
    }

    //begin sql
    StringBuffer sql = new StringBuffer();
    sql.append("SELECT ");

    // primary key
    PrimaryKey key = null;

    try {
        key = getDataStore().getPrimaryKey(featureType);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    Set<String> pkColumnNames = new HashSet<String>();
    String colName;
    for (PrimaryKeyColumn col : key.getColumns()) {
        colName = col.getName();
        encodeColumnName(colName, featureType.getTypeName(), sql, query.getHints());
        sql.append(",");
        pkColumnNames.add(colName);
    }

    //other columns
    for (AttributeDescriptor att : featureType.getAttributeDescriptors()) {
        // skip the eventually exposed pk column values
        String columnName = att.getLocalName();
        if (pkColumnNames.contains(columnName))
            continue;

        if (att instanceof GeometryDescriptor) {
            //encode as geometry
            encodeGeometryColumn((GeometryDescriptor) att, featureType.getTypeName(), sql, query.getHints());

            //alias it to be the name of the original geometry
            getDataStore().dialect.encodeColumnAlias(columnName, sql);
        } else {
            encodeColumnName(columnName, featureType.getTypeName(), sql, query.getHints());

        }

        sql.append(",");
    }

    if (query.getQueryJoins() != null && query.getQueryJoins().size() > 0) {
        for (int i = 0; i < query.getQueryJoins().size(); i++) {
            for (int j = 0; j < query.getQueryJoins().get(i).getSortBy().length; j++) {
                if (aliases[i] != null) {
                    getDataStore().dialect.encodeColumnName(aliases[i],
                            query.getQueryJoins().get(i).getSortBy()[j].getPropertyName().getPropertyName(),
                            sql);
                } else {
                    encodeColumnName(
                            query.getQueryJoins().get(i).getSortBy()[j].getPropertyName().getPropertyName(),
                            query.getQueryJoins().get(i).getJoiningTypeName(), sql, query.getHints());

                }
                sql.append(" ").append(FOREIGN_ID + "_" + i + "_" + j).append(",");
            }
        }
    }

    sql.setLength(sql.length() - 1);

    sql.append(" FROM ");

    sql.append(fromclause);

    //filtering
    FilterToSQL toSQL = null;
    Filter filter = query.getFilter();
    if (filter != null && !Filter.INCLUDE.equals(filter)) {
        //encode filter
        try {
            SortBy[] lastSortBy = null;
            // leave it as null if it's asking for a subset, since we don't want to join to get
            // other rows of same id
            // since we don't want a full feature, but a subset only
            if (!query.isSubset()) {
                // grab the full feature type, as we might be encoding a filter
                // that uses attributes that aren't returned in the results
                lastSortBy = query.getQueryJoins() == null || query.getQueryJoins().size() == 0
                        ? query.getSortBy()
                        : query.getQueryJoins().get(query.getQueryJoins().size() - 1).getSortBy();
            }
            String lastTableName = query.getQueryJoins() == null || query.getQueryJoins().size() == 0
                    ? query.getTypeName()
                    : query.getQueryJoins().get(query.getQueryJoins().size() - 1).getJoiningTypeName();
            String lastTableAlias = query.getQueryJoins() == null || query.getQueryJoins().size() == 0
                    ? query.getTypeName()
                    : aliases[query.getQueryJoins().size() - 1] == null ? lastTableName
                            : aliases[query.getQueryJoins().size() - 1];

            toSQL = createFilterToSQL(getDataStore().getSchema(lastTableName));

            if (lastSortBy != null) {
                //we will use another join for the filter
                //assuming that the last sort by specifies the ID of the parent feature                   
                //this way we will ensure that if the table is denormalized, that all rows
                //with the same ID are included (for multi-valued features)

                sql.append(" INNER JOIN ( SELECT DISTINCT ");
                for (int i = 0; i < lastSortBy.length; i++) {
                    getDataStore().dialect.encodeColumnName(null,
                            lastSortBy[i].getPropertyName().getPropertyName(), sql);
                    if (i < lastSortBy.length - 1)
                        sql.append(",");
                }
                sql.append(" FROM ");
                getDataStore().encodeTableName(lastTableName, sql, query.getHints());
                sql.append(" ").append(toSQL.encodeToString(filter));
                sql.append(" ) " + TEMP_FILTER_ALIAS);
                sql.append(" ON ( ");
                for (int i = 0; i < lastSortBy.length; i++) {
                    encodeColumnName2(lastSortBy[i].getPropertyName().getPropertyName(), lastTableAlias, sql,
                            null);
                    sql.append(" = ");
                    encodeColumnName2(lastSortBy[i].getPropertyName().getPropertyName(), TEMP_FILTER_ALIAS, sql,
                            null);
                    if (i < lastSortBy.length - 1)
                        sql.append(" AND ");
                }
                sql.append(" ) ");
            } else {
                toSQL.setFieldEncoder(new JoiningFieldEncoder(curTypeName));
                sql.append(" ").append(toSQL.encodeToString(filter));
            }
        } catch (FilterToSQLException e) {
            throw new RuntimeException(e);
        }
    }

    //sorting
    sort(query, sql, aliases, pkColumnNames);

    // finally encode limit/offset, if necessary
    getDataStore().applyLimitOffset(sql, query);

    if (toSQLref != null && toSQL instanceof PreparedFilterToSQL) {
        toSQLref.set((PreparedFilterToSQL) toSQL);
    }

    return sql.toString();
}

From source file:io.warp10.continuum.egress.EgressFetchHandler.java

private void packedDump(PrintWriter pw, GTSDecoderIterator iter, long now, long timespan, boolean dedup,
        boolean signed, AtomicReference<Metadata> lastMeta, AtomicLong lastCount, int maxDecoderLen,
        String classSuffix, long chunksize, boolean sortMeta) throws IOException {

    String name = null;//from   w w  w. ja v a  2  s .  co m
    Map<String, String> labels = null;

    StringBuilder sb = new StringBuilder();

    Metadata lastMetadata = lastMeta.get();
    long currentCount = lastCount.get();

    List<GTSEncoder> encoders = new ArrayList<GTSEncoder>();

    while (iter.hasNext()) {
        GTSDecoder decoder = iter.next();

        if (dedup) {
            decoder = decoder.dedup();
        }

        if (!decoder.next()) {
            continue;
        }

        long toDecodeCount = Long.MAX_VALUE;

        if (timespan < 0) {
            Metadata meta = decoder.getMetadata();
            if (!meta.equals(lastMetadata)) {
                lastMetadata = meta;
                currentCount = 0;
            }
            toDecodeCount = Math.max(0, -timespan - currentCount);
        }

        GTSEncoder encoder = decoder.getEncoder(true);

        //
        // Only display the class + labels if they have changed since the previous GTS
        //

        Map<String, String> lbls = decoder.getLabels();

        //
        // Compute the name
        //

        name = decoder.getName();
        labels = lbls;
        sb.setLength(0);
        GTSHelper.encodeName(sb, name + classSuffix);
        sb.append("{");
        boolean first = true;

        if (sortMeta) {
            lbls = new TreeMap<String, String>(lbls);
        }

        for (Entry<String, String> entry : lbls.entrySet()) {
            //
            // Skip owner/producer labels and any other 'private' labels
            //
            if (!signed) {
                if (Constants.PRODUCER_LABEL.equals(entry.getKey())) {
                    continue;
                }
                if (Constants.OWNER_LABEL.equals(entry.getKey())) {
                    continue;
                }
            }

            if (!first) {
                sb.append(",");
            }
            GTSHelper.encodeName(sb, entry.getKey());
            sb.append("=");
            GTSHelper.encodeName(sb, entry.getValue());
            first = false;
        }
        sb.append("}");

        // We treat the case where encoder.getCount() is 0 in a special way
        // as this may be because the encoder was generated from a partly
        // consumed decoder and thus its count was reset to 0
        if (0 == encoder.getCount() || encoder.getCount() > toDecodeCount) {
            // We have too much data, shrink the encoder
            GTSEncoder enc = new GTSEncoder();
            enc.safeSetMetadata(decoder.getMetadata());
            while (decoder.next() && toDecodeCount > 0) {
                enc.addValue(decoder.getTimestamp(), decoder.getLocation(), decoder.getElevation(),
                        decoder.getValue());
                toDecodeCount--;
            }
            encoder = enc;
        }

        if (timespan < 0) {
            currentCount += encoder.getCount();
        }

        encoders.clear();

        //
        // Add encoders per chunk
        //

        GTSDecoder chunkdec = encoder.getDecoder(true);

        GTSEncoder chunkenc = null;

        Long lastchunk = null;

        if (Long.MAX_VALUE == chunksize) {
            encoders.add(encoder);
        } else {
            while (chunkdec.next()) {
                long ts = chunkdec.getTimestamp();
                long chunk = ts >= 0 ? ts / chunksize : ((ts + 1) / chunksize) - 1;

                //
                // If it is the first chunk or we changed chunk, create a new encoder
                //

                if (null == chunkenc || (null != lastchunk && chunk != lastchunk)) {
                    chunkenc = new GTSEncoder(0L);
                    chunkenc.setMetadata(encoder.getMetadata());
                    encoders.add(chunkenc);
                }

                lastchunk = chunk;

                chunkenc.addValue(ts, chunkdec.getLocation(), chunkdec.getElevation(), chunkdec.getValue());
            }
        }

        while (!encoders.isEmpty()) {
            encoder = encoders.remove(0);

            if (encoder.size() > 0) {
                //
                // Determine most recent timestamp
                //

                GTSDecoder dec = encoder.getDecoder(true);

                dec.next();

                long timestamp = dec.getTimestamp();

                //
                // Build GTSWrapper
                //

                encoder.setMetadata(new Metadata());
                // Clear labels
                encoder.setName("");
                encoder.setLabels(new HashMap<String, String>());
                encoder.getMetadata().setAttributes(new HashMap<String, String>());

                GTSWrapper wrapper = GTSWrapperHelper.fromGTSEncoderToGTSWrapper(encoder, true);

                TSerializer ser = new TSerializer(new TCompactProtocol.Factory());
                byte[] serialized;

                try {
                    serialized = ser.serialize(wrapper);
                } catch (TException te) {
                    throw new IOException(te);
                }

                //
                // Check the size of the generatd wrapper. If it is over 75% of maxDecoderLen,
                // split the original encoder in two
                //

                if (serialized.length >= Math.floor(0.75D * maxDecoderLen) && encoder.getCount() > 2) {
                    GTSEncoder split = new GTSEncoder(0L);
                    split.setMetadata(encoder.getMetadata());

                    List<GTSEncoder> splits = new ArrayList<GTSEncoder>();

                    splits.add(split);

                    int threshold = encoder.size() / 2;

                    GTSDecoder deco = encoder.getDecoder(true);

                    while (deco.next()) {
                        split.addValue(deco.getTimestamp(), deco.getLocation(), deco.getElevation(),
                                deco.getValue());
                        if (split.size() > threshold) {
                            split = new GTSEncoder(0L);
                            splits.add(split);
                        }
                    }

                    //
                    // Now insert the splits at the beginning of 'encoders'
                    //

                    for (int i = splits.size() - 1; i >= 0; i--) {
                        encoders.add(0, splits.get(i));
                    }
                    continue;
                }

                if (serialized.length > Math.ceil(0.75D * maxDecoderLen)) {
                    throw new IOException(
                            "Encountered a value whose length is above the configured threshold of "
                                    + maxDecoderLen);
                }

                pw.print(timestamp);
                pw.print("//");
                pw.print(encoder.getCount());
                pw.print(" ");
                pw.print(sb.toString());
                pw.print(" '");

                OrderPreservingBase64.encodeToWriter(serialized, pw);

                pw.print("'");
                pw.write('\r');
                pw.write('\n');
            }
        }
    }

    lastMeta.set(lastMetadata);
    lastCount.set(currentCount);
}

From source file:com.microsoft.tfs.core.clients.versioncontrol.internal.localworkspace.LocalDataAccessLayer.java

/**
 *
 *
 *
 * @param workspace/*from  w  w  w . j  a v  a2s  . c  om*/
 * @param lv
 * @param pc
 * @param changeRequests
 * @param silent
 * @param failures
 * @return
 */
public static GetOperation[] pendAdd(final Workspace workspace, final LocalWorkspaceProperties wp,
        final WorkspaceVersionTable lv, final LocalPendingChangesTable pc, final ChangeRequest[] changeRequests,
        final boolean silent, final AtomicReference<Failure[]> failures, final String[] itemPropertyFilters) {
    Check.notNull(workspace, "workspace"); //$NON-NLS-1$
    Check.notNullOrEmpty(changeRequests, "changeRequests"); //$NON-NLS-1$

    final List<Failure> failureList = new ArrayList<Failure>();
    final List<GetOperation> getOps = new ArrayList<GetOperation>();

    // Most duplicates filters are by WorkspaceLocalItem instance; but since
    // we are creating local version entries ourselves, we have to filter by
    // target server item.
    final Set<String> duplicatesFilter = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);

    for (final ChangeRequest changeRequest : changeRequests) {
        if (null == changeRequest) {
            continue;
        }

        // It is not legal to modify the state of a lock through a local
        // call.
        Check.isTrue(
                changeRequest.getLockLevel() == LockLevel.UNCHANGED
                        || changeRequest.getLockLevel() == LockLevel.NONE,
                "changeRequest.getLockLevel() == LockLevel.UNCHANGED || changeRequest.getLockLevel() == LockLevel.NONE"); //$NON-NLS-1$

        // The paths for PendAdd must be local items with no recursion.
        if (ServerPath.isServerPath(changeRequest.getItemSpec().getItem())
                || RecursionType.NONE != changeRequest.getItemSpec().getRecursionType()) {
            throw new IllegalArgumentException(MessageFormat.format(
                    Messages.getString("LocalDataAccessLayer.ChangeRequestMustBeLocalNonRecursiveFormat"), //$NON-NLS-1$
                    changeRequest.getItemSpec()));
        }

        LocalPath.checkLocalItem(changeRequest.getItemSpec().getItem(), "item", false, false, false, true); //$NON-NLS-1$

        // The local item includes all pending renames of parents so we
        // treat it as a target server item.
        final String targetServerItem = WorkingFolder
                .getServerItemForLocalItem(changeRequest.getItemSpec().getItem(), wp.getWorkingFolders());

        if (null == targetServerItem) {
            // We should have already validated that the path is mapped; so
            // if the server item is null, the item must be cloaked.
            failureList.add(createItemCloakedFailure(changeRequest.getItemSpec().getItem()));
            continue;
        }

        // Verify the length of the resultant target server item meets our
        // constraints.
        if (targetServerItem.length() > VersionControlConstants.MAX_SERVER_PATH_SIZE) {
            failureList.add(createPathTooLongFailure(targetServerItem));
            continue;
        }

        WorkspaceLocalItem lvEntry = lv.getByLocalItem(changeRequest.getItemSpec().getItem());
        LocalPendingChange pcEntry = pc.getByTargetServerItem(targetServerItem);

        final Failure teamProjectValidationFailure = TeamProject.validateChange(targetServerItem,
                changeRequest.getItemType());

        // if we have a committed local version row, fall back to the error
        // below.
        if (teamProjectValidationFailure != null && (lvEntry == null || lvEntry.getVersion() == 0)) {
            failureList.add(teamProjectValidationFailure);
            continue;
        } else if (pcEntry != null && pcEntry.isAdd()) {
            // Existing pending add. Skip other validators and re-use the
            // existing pending change.

            // No change will be made to the existing pending change -- for
            // example the encoding will *not* be changed to respect the
            // encoding supplied on this ChangeRequest.
        } else if (pcEntry != null) {
            failureList
                    .add(new Failure(
                            MessageFormat.format(
                                    Messages.getString(
                                            "LocalDataAccessLayer.ChangeAlreadyPendingExceptionFormat"), //$NON-NLS-1$
                                    targetServerItem),
                            FailureCodes.CHANGE_ALREADY_PENDING_EXCEPTION, SeverityType.ERROR,
                            changeRequest.getItemSpec().getItem()));

            continue;
        } else if (lvEntry != null && lvEntry.getVersion() != 0) {
            failureList.add(new Failure(
                    MessageFormat.format(Messages.getString("LocalDataAccessLayer.ItemExistsExceptionFormat"), //$NON-NLS-1$
                            targetServerItem),
                    FailureCodes.ITEM_EXISTS_EXCEPTION, SeverityType.ERROR,
                    changeRequest.getItemSpec().getItem()));

            continue;
        } else if (pc.getRecursiveChangeTypeForTargetServerItem(targetServerItem).contains(ChangeType.DELETE)) {
            final String changedItem = changeRequest.getItemSpec().getItem();
            failureList.add(createPendingParentDeleteFailure(targetServerItem, changedItem));
            continue;
        }

        if (null == lvEntry) {
            lvEntry = new WorkspaceLocalItem();
            lvEntry.setServerItem(targetServerItem);
            lvEntry.setVersion(0);
            lvEntry.setLocalItem(changeRequest.getItemSpec().getItem());
            lvEntry.setEncoding((ItemType.FILE == changeRequest.getItemType()) ? changeRequest.getEncoding()
                    : VersionControlConstants.ENCODING_FOLDER);
            lvEntry.setPendingReconcile(true);

            lv.add(lvEntry);
        }

        lvEntry.setPropertyValues(changeRequest.getProperties());
        if (null == pcEntry) {
            pcEntry = new LocalPendingChange(lvEntry, targetServerItem, ChangeType.ADD_ENCODING);
            pcEntry.setEncoding(lvEntry.getEncoding());
            pcEntry.setTargetServerItem(targetServerItem);
            pcEntry.setCommittedServerItem(null);

            if (ItemType.FILE == changeRequest.getItemType()) {
                pcEntry.setChangeType(pcEntry.getChangeType().combine(ChangeType.EDIT));
            }

            if (changeRequest.getProperties() != null && changeRequest.getProperties().length > 0) {
                pcEntry.setChangeType(pcEntry.getChangeType().combine(ChangeType.PROPERTY));
                pcEntry.setPropertyValues(changeRequest.getProperties());
            }

            pc.pendChange(pcEntry);
            pc.removeCandidateByTargetServerItem(targetServerItem);
        }

        // Create the GetOperation for this pending change.
        if (!silent) {
            if (!duplicatesFilter.add(lvEntry.getServerItem())) {
                continue;
            }

            getOps.add(lvEntry.toGetOperation(pcEntry, itemPropertyFilters));
        }
    }

    for (final Failure failure : failureList) {
        failure.setRequestType(RequestType.ADD);
    }

    failures.set(failureList.toArray(new Failure[failureList.size()]));

    return getOps.toArray(new GetOperation[getOps.size()]);
}

From source file:com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace.java

/**
 * Merge changes made between two versions to items in a given source path
 * into a given target path. The result of this method is that one or more
 * merge items are pended./*from   www. j a v  a  2 s  .c om*/
 * <p>
 * <!-- Event Origination Info -->
 * <p>
 * This method is an <b>core event origination point</b>. The
 * {@link EventSource} object that accompanies each event fired by this
 * method describes the execution context (current thread, etc.) when and
 * where this method was invoked.
 *
 * @param sourceSpec
 *        the local or server path of the source of the merge; where the
 *        changes are copied from, and the recursion type to match the given
 *        source path with (must not be <code>null</code>, path must not be
 *        <code>null</code> or empty)
 * @param targetPath
 *        the local or server path of the target of the merge; where the
 *        changes will end up (must not be <code>null</code> or empty).
 * @param sourceVersionFrom
 *        the version (inclusive) of the source item to start including
 *        changes from for this merge operation. null indicates all versions
 *        beginning with version 1.
 * @param sourceVersionTo
 *        the version (inclusive) of the source item to stop including
 *        changes from for this merge operation. null indicates all versions
 *        up to and including tip version.
 * @param lockLevel
 *        the lock level to apply to the pended changes (must not be
 *        <code>null</code>)
 * @param mergeFlags
 *        any merge options to apply during this merge (must not be
 *        <code>null</code>)
 * @param itemPropertyFilters
 *        a list of versioned item properties to return with each get
 *        operation (may be <code>null</code>)
 * @return a GetStatus instance with the results of the merge operation.
 */
public GetStatus merge(final ItemSpec sourceSpec, final String targetPath, final VersionSpec sourceVersionFrom,
        final VersionSpec sourceVersionTo, final LockLevel lockLevel, final MergeFlags mergeFlags,
        String[] itemPropertyFilters) {
    Check.notNull(sourceSpec, "sourceSpec"); //$NON-NLS-1$
    Check.notNullOrEmpty(sourceSpec.getItem(), "sourceSpec.item"); //$NON-NLS-1$
    Check.notNull(sourceSpec.getRecursionType(), "sourceSpec.recursion"); //$NON-NLS-1$
    Check.notNullOrEmpty(targetPath, "targetPath"); //$NON-NLS-1$
    Check.notNull(lockLevel, "lockLevel"); //$NON-NLS-1$
    Check.notNull(mergeFlags, "mergeFlags"); //$NON-NLS-1$

    // Using web service directly so merge filters configured on client
    itemPropertyFilters = client.mergeWithDefaultItemPropertyFilters(itemPropertyFilters);

    final ItemSpec targetSpec = new ItemSpec(targetPath, RecursionType.NONE);

    int nonResolvedConflicts = 0;
    int resolvedConflicts = 0;

    client.getEventEngine()
            .fireOperationStarted(new MergeOperationStartedEvent(EventSource.newFromHere(), this));

    final AtomicReference<Failure[]> failures = new AtomicReference<Failure[]>();
    final AtomicReference<Conflict[]> conflicts = new AtomicReference<Conflict[]>();
    final AtomicReference<ChangePendedFlags> changePendedFlags = new AtomicReference<ChangePendedFlags>();

    try {
        final GetOperation[] getOps = client.getWebServiceLayer().merge(getName(), getOwnerName(), sourceSpec,
                targetSpec, sourceVersionFrom, sourceVersionTo, lockLevel, mergeFlags, failures, conflicts,
                null, itemPropertyFilters, changePendedFlags);

        final boolean discard = mergeFlags.contains(MergeFlags.ALWAYS_ACCEPT_MINE);

        // Match up these getOps and merge details (returned as Conflict
        // objects). The conflicts with matching getOps have already been
        // resolved.
        final Map<String, Conflict> pathConflictDict = new TreeMap<String, Conflict>(
                ServerPath.TOP_DOWN_COMPARATOR);
        final Map<Integer, Conflict> itemIdConflictDict = new HashMap<Integer, Conflict>();
        for (final Conflict conflict : conflicts.get()) {
            if (conflict.isResolved()) {
                // if it is a branch, and the user asked for preview, we do
                // not assign ItemIds
                // so we need to lookup by path
                if (conflict.getBaseChangeType().contains(ChangeType.BRANCH) && conflict.getYourItemID() == 0) {
                    pathConflictDict.put(conflict.getYourServerItem(), conflict);
                } else {
                    itemIdConflictDict.put(conflict.getYourItemID(), conflict);
                }
            }
        }
        for (final GetOperation getOp : getOps) {
            if (getOp.getChangeType().contains(ChangeType.BRANCH) && getOp.getItemID() == 0) {
                final Conflict conflict = pathConflictDict.get(getOp.getTargetServerItem());
                if (conflict != null) {
                    getOp.setMergeDetails(conflict);
                }
            } else {
                final Conflict conflict = itemIdConflictDict.get(getOp.getItemID());
                if (conflict != null) {
                    getOp.setMergeDetails(conflict);
                }
            }
        }

        GetStatus getStatus = null;

        if (isLocal()) {
            /*
             * We want to auto resolve conflicts if the option is set to do
             * so and we are not discarding
             */
            if (!discard && !mergeFlags.contains(MergeFlags.NO_AUTO_RESOLVE)
                    && !mergeFlags.contains(MergeFlags.NO_MERGE)) {
                if (getClient().getWebServiceLayer().getServiceLevel().getValue() < WebServiceLevel.TFS_2012_1
                        .getValue()) {
                    /*
                     * The download urls for base files were not populated
                     * on conflicts in pre 2012 servers. Let's call
                     * QueryConflicts now so that we have that information.
                     * We use sourceSpec.RecursionType here because that
                     * corresponds to what the user passed in.
                     */
                    conflicts.set(queryConflicts(new String[] { targetSpec.getItem() },
                            sourceSpec.getRecursionType() != RecursionType.NONE));
                }

                final Conflict[] remainingConflicts = getClient().autoResolveValidConflicts(this,
                        conflicts.get(), AutoResolveOptions.ALL_SILENT);

                resolvedConflicts = conflicts.get().length - remainingConflicts.length;
                conflicts.set(remainingConflicts);
            }

            // Fire events for merges that did not get resolved by the
            // server.
            // The others will get fired in get.cs as they are processed.
            for (final Conflict conflict : conflicts.get()) {
                if (conflict.getResolution() == Resolution.NONE) {
                    log.trace("Firing event on conflict: " + conflict); //$NON-NLS-1$

                    // The pending change arg is null because of the
                    // conflict.
                    client.getEventEngine()
                            .fireMerging(new MergingEvent(EventSource.newFromHere(), new Conflict(conflict),
                                    this, false, null, OperationStatus.CONFLICT, ChangeType.NONE, true,
                                    new PropertyValue[0]));

                    nonResolvedConflicts++;
                }
            }

            // When we are discarding source changes, we simply call
            // ResolveConflict.
            if (discard) {
                for (final Conflict conflict : conflicts.get()) {
                    // There is nothing to do when the resolution is
                    // AcceptYours.
                    client.getEventEngine().fireConflictResolved(new ConflictResolvedEvent(
                            EventSource.newFromHere(), this, conflict, changePendedFlags.get()));
                }

                getStatus = new GetStatus();
                getStatus.setNumOperations(conflicts.get().length);
                return getStatus;
            }

            final GetOptions options = mergeFlags.contains(MergeFlags.NO_MERGE) ? GetOptions.PREVIEW
                    : GetOptions.NONE;

            final GetEngine getEngine = new GetEngine(client);
            getStatus = getEngine.processGetOperations(this, ProcessType.MERGE, getOps, options,
                    changePendedFlags.get());

            getStatus.setNumConflicts(getStatus.getNumConflicts() + nonResolvedConflicts);
            getStatus.setNumResolvedConflicts(resolvedConflicts);
        } else if (getOps.length > 0) {
            client.getEventEngine()
                    .fireNonFatalError(new NonFatalErrorEvent(EventSource.newFromHere(), this,
                            new VersionControlException(MessageFormat.format(
                                    Messages.getString("Workspace.NoLocalChangesRemoteWorkspaceFormat"), //$NON-NLS-1$
                                    getDisplayName()))));
        }

        if (getStatus == null) {
            getStatus = new GetStatus();
            getStatus.setNumOperations(getOps.length);
        }

        if (changePendedFlags.get().contains(ChangePendedFlags.WORKING_FOLDER_MAPPINGS_UPDATED)) {
            invalidateMappings();
        }

        client.reportFailures(this, failures.get());

        for (final Failure failure : failures.get()) {
            getStatus.addFailure(failure);
        }

        return getStatus;
    } finally {
        client.getEventEngine()
                .fireOperationCompleted(new MergeOperationCompletedEvent(EventSource.newFromHere(), this));

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

From source file:com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace.java

/**
 * Pend these changes for this workspace on the server.
 *
 * @param requests//from   ww  w  . j  a va  2s . c om
 *        the requested changes to pend (must not be <code>null</code>)
 * @param getOptions
 *        options that affect how files on disk are treated during
 *        processing (must not be <code>null</code>)
 * @param pendOptions
 *        options that affect how items are pended (must not be
 *        <code>null</code>)
 * @param itemPropertyFilters
 *        a list of versioned item properties to return with each get
 *        operation (may be <code>null</code>)
 * @return the number of changes that were successfully processed by the
 *         server.
 */
private int pendChanges(final ChangeRequest[] requests, final GetOptions getOptions,
        final PendChangesOptions pendOptions, String[] itemPropertyFilters) {
    Check.notNull(requests, "requests"); //$NON-NLS-1$
    Check.notNull(getOptions, "getOptions"); //$NON-NLS-1$
    Check.notNull(pendOptions, "pendOptions"); //$NON-NLS-1$

    // Using web service directly so merge filters configured on client
    itemPropertyFilters = client.mergeWithDefaultItemPropertyFilters(itemPropertyFilters);

    client.getEventEngine()
            .fireOperationStarted(new PendOperationStartedEvent(EventSource.newFromHere(), this, requests));

    if (getClient().getServiceLevel().getValue() < WebServiceLevel.TFS_2012.getValue()) {
        if (hasPropertyChange(requests)) {
            client.getEventEngine().fireNonFatalError(new NonFatalErrorEvent(EventSource.newFromHere(), this,
                    new VersionControlException(Messages.getString("Workspace.PropertyNotSupportedText")))); //$NON-NLS-1$
        }
    }

    int ret = 0;
    try {
        SupportedFeatures features = SupportedFeatures.ALL;

        /*
         * If the get operation "Force Checkout Local Version" is set, we do
         * not advertise to the server that we support get latest on
         * checkout. Presumably, there may be a state where the server
         * wishes to update us to the local version and this explicitly
         * stops that.
         */
        if (pendOptions.contains(PendChangesOptions.FORCE_CHECK_OUT_LOCAL_VERSION)) {
            features = features.remove(SupportedFeatures.GET_LATEST_ON_CHECKOUT);
        }

        final AtomicReference<Failure[]> failures = new AtomicReference<Failure[]>();
        final AtomicBoolean onlineOperation = new AtomicBoolean();
        final AtomicReference<ChangePendedFlags> changePendedFlags = new AtomicReference<ChangePendedFlags>();

        final GetOperation[] operations = client.getWebServiceLayer().pendChanges(getName(), getOwnerName(),
                requests, pendOptions, features, failures, itemPropertyFilters, null, true, onlineOperation,
                changePendedFlags);

        // Get any required files.
        if (operations.length > 0) {

            /*
             * The TFS server (as of TFS 2013 QU1) provides in the response
             * only properties saved in the server's database, i.e. already
             * checked in. Thus, to process the executable bit and symlinks
             * using properties mechanism correctly in the client file
             * system, we have to merge properties received in the response
             * with those submitted in the change request.
             *
             * Note that for the local workspaces it's already done in the
             * LocalDataAccessLayer class.
             */
            if (WorkspaceLocation.SERVER == this.getLocation()
                    && getClient().getServiceLevel().getValue() >= WebServiceLevel.TFS_2012.getValue()) {
                for (final ChangeRequest request : requests) {
                    final PropertyValue[] requestProperties = request.getProperties();
                    if (requestProperties != null) {
                        final GetOperation operation = findMatchingOperation(operations, request);

                        if (operation != null) {
                            final PropertyValue[] operationProperties = operation.getPropertyValues();

                            if (operationProperties != null) {
                                operation.setPropertyValues(PropertyUtils
                                        .mergePendingValues(operationProperties, requestProperties));
                            }
                        }
                    }
                }
            }

            final GetEngine getEngine = new GetEngine(client);

            getEngine.processGetOperations(this, ProcessType.PEND, requests[0].getRequestType(),
                    new GetOperation[][] { operations }, getOptions, false, onlineOperation.get(),
                    changePendedFlags.get());

            // Return the number of operations that were successful.
            ret = operations.length;
        }

        if (changePendedFlags.get().contains(ChangePendedFlags.WORKING_FOLDER_MAPPINGS_UPDATED)) {
            invalidateMappings();
        }

        /*
         * If it was requested by the caller, strip out any Failure objects
         * from the failure set which are of type ItemNotFoundException.
         */
        if (failures.get() != null && failures.get().length > 0
                && pendOptions.contains(PendChangesOptions.SUPPRESS_ITEM_NOT_FOUND_FAILURES)) {
            final List<Failure> otherFailures = new ArrayList<Failure>();

            for (final Failure f : failures.get()) {
                if (f.getCode() == null || !f.getCode().equals(FailureCodes.ITEM_EXISTS_EXCEPTION)) {
                    otherFailures.add(f);
                }
            }

            failures.set(otherFailures.toArray(new Failure[otherFailures.size()]));
        }

        client.reportFailures(this, failures.get());

    } finally {
        client.getEventEngine().fireOperationCompleted(
                new PendOperationCompletedEvent(EventSource.newFromHere(), this, requests));

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

    return ret;
}

From source file:io.warp10.continuum.egress.EgressFetchHandler.java

/**
 * Output a tab separated version of fetched data. Deduplication is done on the fly so we don't decode twice.
 * /*  w w w  .jav a  2  s .com*/
 */
private static void tsvDump(PrintWriter pw, GTSDecoderIterator iter, long now, long timespan, boolean raw,
        boolean dedup, boolean signed, AtomicReference<Metadata> lastMeta, AtomicLong lastCount,
        boolean sortMeta) throws IOException {

    String name = null;
    Map<String, String> labels = null;

    StringBuilder classSB = new StringBuilder();
    StringBuilder labelsSB = new StringBuilder();
    StringBuilder attributesSB = new StringBuilder();
    StringBuilder valueSB = new StringBuilder();

    Metadata lastMetadata = lastMeta.get();
    long currentCount = lastCount.get();

    while (iter.hasNext()) {
        GTSDecoder decoder = iter.next();

        if (!decoder.next()) {
            continue;
        }

        long toDecodeCount = Long.MAX_VALUE;

        if (timespan < 0) {
            Metadata meta = decoder.getMetadata();
            if (!meta.equals(lastMetadata)) {
                lastMetadata = meta;
                currentCount = 0;
            }
            toDecodeCount = Math.max(0, -timespan - currentCount);
        }

        //
        // Only display the class + labels if they have changed since the previous GTS
        //

        Map<String, String> lbls = decoder.getLabels();

        //
        // Compute the new name
        //

        boolean displayName = false;

        if (null == name || (!name.equals(decoder.getName()) || !labels.equals(lbls))) {
            displayName = true;
            name = decoder.getName();
            labels = lbls;
            classSB.setLength(0);
            GTSHelper.encodeName(classSB, name);
            labelsSB.setLength(0);
            attributesSB.setLength(0);
            boolean first = true;

            if (sortMeta) {
                lbls = new TreeMap<String, String>(lbls);
            }
            for (Entry<String, String> entry : lbls.entrySet()) {
                //
                // Skip owner/producer labels and any other 'private' labels
                //
                if (!signed) {
                    if (Constants.PRODUCER_LABEL.equals(entry.getKey())) {
                        continue;
                    }
                    if (Constants.OWNER_LABEL.equals(entry.getKey())) {
                        continue;
                    }
                }

                if (!first) {
                    labelsSB.append(",");
                }
                GTSHelper.encodeName(labelsSB, entry.getKey());
                labelsSB.append("=");
                GTSHelper.encodeName(labelsSB, entry.getValue());
                first = false;
            }

            first = true;
            if (decoder.getMetadata().getAttributesSize() > 0) {

                if (sortMeta) {
                    decoder.getMetadata()
                            .setAttributes(new TreeMap<String, String>(decoder.getMetadata().getAttributes()));
                }

                for (Entry<String, String> entry : decoder.getMetadata().getAttributes().entrySet()) {
                    if (!first) {
                        attributesSB.append(",");
                    }
                    GTSHelper.encodeName(attributesSB, entry.getKey());
                    attributesSB.append("=");
                    GTSHelper.encodeName(attributesSB, entry.getValue());
                    first = false;
                }
            }

        }

        long timestamp = 0L;
        long location = GeoTimeSerie.NO_LOCATION;
        long elevation = GeoTimeSerie.NO_ELEVATION;
        Object value = null;

        boolean dup = true;

        long decoded = 0;

        do {

            if (toDecodeCount == decoded) {
                break;
            }

            //
            // Filter out any value not in the time range
            //

            long newTimestamp = decoder.getTimestamp();

            if (newTimestamp > now || (timespan >= 0 && newTimestamp <= (now - timespan))) {
                continue;
            }

            //
            // TODO(hbs): filter out values with no location or outside the selected geozone when a geozone was set
            //

            long newLocation = decoder.getLocation();
            long newElevation = decoder.getElevation();
            Object newValue = decoder.getValue();

            dup = true;

            if (dedup) {
                if (location != newLocation || elevation != newElevation) {
                    dup = false;
                } else {
                    if (null == newValue) {
                        // Consider nulls as duplicates (can't happen!)
                        dup = false;
                    } else if (newValue instanceof Number) {
                        if (!((Number) newValue).equals(value)) {
                            dup = false;
                        }
                    } else if (newValue instanceof String) {
                        if (!((String) newValue).equals(value)) {
                            dup = false;
                        }
                    } else if (newValue instanceof Boolean) {
                        if (!((Boolean) newValue).equals(value)) {
                            dup = false;
                        }
                    }
                }
            }

            decoded++;

            location = newLocation;
            elevation = newElevation;
            timestamp = newTimestamp;
            value = newValue;

            if (raw) {
                if (!dedup || !dup) {
                    pw.print(classSB);
                    pw.print('\t');
                    pw.print(labelsSB);
                    pw.print('\t');
                    pw.print(attributesSB);
                    pw.print('\t');

                    pw.print(timestamp);
                    pw.print('\t');

                    if (GeoTimeSerie.NO_LOCATION != location) {
                        double[] latlon = GeoXPLib.fromGeoXPPoint(location);
                        pw.print(latlon[0]);
                        pw.print('\t');
                        pw.print(latlon[1]);
                    } else {
                        pw.print('\t');
                    }

                    pw.print('\t');

                    if (GeoTimeSerie.NO_ELEVATION != elevation) {
                        pw.print(elevation);
                    }
                    pw.print('\t');

                    valueSB.setLength(0);
                    GTSHelper.encodeValue(valueSB, value);
                    pw.println(valueSB);
                }
            } else {
                // Display the name only if we have at least one value to display
                // We force 'dup' to be false when we must show the name
                if (displayName) {
                    pw.print("# ");
                    pw.print(classSB);
                    pw.print("{");
                    pw.print(labelsSB);
                    pw.print("}");
                    pw.print("{");
                    pw.print(attributesSB);
                    pw.println("}");
                    displayName = false;
                    dup = false;
                }

                if (!dedup || !dup) {
                    pw.print(timestamp);
                    pw.print('\t');
                    if (GeoTimeSerie.NO_LOCATION != location) {
                        double[] latlon = GeoXPLib.fromGeoXPPoint(location);
                        pw.print(latlon[0]);
                        pw.print('\t');
                        pw.print(latlon[1]);
                    } else {
                        pw.print('\t');
                    }

                    pw.print('\t');

                    if (GeoTimeSerie.NO_ELEVATION != elevation) {
                        pw.print(elevation);
                    }
                    pw.print('\t');

                    valueSB.setLength(0);
                    GTSHelper.encodeValue(valueSB, value);
                    pw.println(valueSB);
                }
            }
        } while (decoder.next());

        // Update currentcount
        if (timespan < 0) {
            currentCount += decoded;
        }

        // Print any remaining value
        if (dedup && dup) {
            if (raw) {
                pw.print(classSB);
                pw.print('\t');
                pw.print(labelsSB);
                pw.print('\t');
                pw.print(attributesSB);
                pw.print('\t');

                pw.print(timestamp);
                pw.print('\t');

                if (GeoTimeSerie.NO_LOCATION != location) {
                    double[] latlon = GeoXPLib.fromGeoXPPoint(location);
                    pw.print(latlon[0]);
                    pw.print('\t');
                    pw.print(latlon[1]);
                } else {
                    pw.print('\t');
                }

                pw.print('\t');

                if (GeoTimeSerie.NO_ELEVATION != elevation) {
                    pw.print(elevation);
                }
                pw.print('\t');

                valueSB.setLength(0);
                GTSHelper.encodeValue(valueSB, value);
                pw.println(valueSB);
            } else {
                pw.print(timestamp);
                pw.print('\t');
                if (GeoTimeSerie.NO_LOCATION != location) {
                    double[] latlon = GeoXPLib.fromGeoXPPoint(location);
                    pw.print(latlon[0]);
                    pw.print('\t');
                    pw.print(latlon[1]);
                } else {
                    pw.print('\t');
                }

                pw.print('\t');

                if (GeoTimeSerie.NO_ELEVATION != elevation) {
                    pw.print(elevation);
                }
                pw.print('\t');

                valueSB.setLength(0);
                GTSHelper.encodeValue(valueSB, value);
                pw.println(valueSB);
            }

        }

        //
        // If displayName is still true it means we should have displayed the name but no value matched,
        // so set name to null so we correctly display the name for the next decoder if it has values
        //

        if (displayName) {
            name = null;
        }
    }

    lastMeta.set(lastMetadata);
    lastCount.set(currentCount);
}

From source file:com.microsoft.tfs.core.clients.versioncontrol.internal.localworkspace.LocalDataAccessLayer.java

/**
 *
 *
 *
 * @param workspace//from  ww w  .j  a v a 2s  .  c  o  m
 * @param lv
 * @param pc
 * @param changeRequests
 * @param silent
 * @param failures
 * @return
 */
public static GetOperation[] pendDelete(final Workspace workspace, final LocalWorkspaceProperties wp,
        final WorkspaceVersionTable lv, final LocalPendingChangesTable pc, final ChangeRequest[] changeRequests,
        final boolean silent, final AtomicReference<Failure[]> failures, final String[] itemPropertyFilters) {
    Check.notNull(workspace, "workspace"); //$NON-NLS-1$
    Check.notNullOrEmpty(changeRequests, "changeRequests"); //$NON-NLS-1$

    workspace.getWorkspaceWatcher().scan(wp, lv, pc);

    final List<Failure> failureList = new ArrayList<Failure>();
    final List<GetOperation> getOps = new ArrayList<GetOperation>();
    final Set<WorkspaceLocalItem> duplicatesFilter = new HashSet<WorkspaceLocalItem>();

    for (final ChangeRequest changeRequest : changeRequests) {
        if (null == changeRequest) {
            continue;
        }

        // It is not legal to modify the state of a lock through a local
        // call.
        Check.isTrue(changeRequest.getLockLevel() == LockLevel.UNCHANGED,
                "changeRequest.getLockLevel() == LockLevel.UNCHANGED"); //$NON-NLS-1$

        if (ServerPath.isRootFolder(changeRequest.getItemSpec().getItem())) {
            failureList.add(new Failure(Messages.getString("TeamProject.CanNotChangeRootFolderException"), //$NON-NLS-1$
                    FailureCodes.CANNOT_CHANGE_ROOT_FOLDER_EXCEPTION, SeverityType.ERROR,
                    changeRequest.getItemSpec().getItem()));

            continue;
        }

        final ParsedItemSpec parsedItemSpec = ParsedItemSpec.fromItemSpec(changeRequest.getItemSpec(), wp, lv,
                pc, ParsedItemSpecOptions.INCLUDE_DELETED, failureList);

        if (null == parsedItemSpec) {
            continue;
        }

        // Check up front to see if the item provided is deleted. Emit the
        // appropriate errors if so.
        final String rootTargetServerItem;
        if (parsedItemSpec.isServerItem()) {
            rootTargetServerItem = parsedItemSpec.getTargetItem();
        } else {
            rootTargetServerItem = WorkingFolder.getServerItemForLocalItem(parsedItemSpec.getTargetItem(),
                    wp.getWorkingFolders());
        }

        if (null != rootTargetServerItem) {
            if (rootTargetServerItem.length() > VersionControlConstants.MAX_SERVER_PATH_SIZE) {
                failureList.add(createPathTooLongFailure(rootTargetServerItem));
                continue;
            }

            final LocalPendingChange pcEntry = pc.getByTargetServerItem(rootTargetServerItem);

            if (null != pcEntry && pcEntry.isDelete()) {
                failureList.add(createPendingDeleteConflictChangeFailure(rootTargetServerItem));
                continue;
            } else if (pc.getRecursiveChangeTypeForTargetServerItem(rootTargetServerItem)
                    .contains(ChangeType.DELETE)) {
                failureList.add(createPendingParentDeleteFailure(rootTargetServerItem));
                continue;
            }
        }

        for (final WorkspaceLocalItem lvEntry : parsedItemSpec.expandRootsFrom(lv, pc, failureList)) {
            if (!duplicatesFilter.add(lvEntry)) {
                continue;
            }

            final String targetServerItem = pc.getTargetServerItemForLocalVersion(lvEntry);
            final Failure failure = TeamProject.validateChange(targetServerItem, changeRequest.getItemType());

            if (failure != null) {
                failureList.add(failure);
                continue;
            }

            LocalPendingChange pcEntry = pc.getByLocalVersion(lvEntry);

            // Permit the lock, property and branch bits. If the branch bit
            // is specified, permit the encoding and merge bits, too.
            // Additionally permit PendDelete to stomp on pending edits if
            // the item is missing from disk.
            if (null != pcEntry) {
                ChangeType remainingChangeType = pcEntry.getChangeType().remove(ChangeType.LOCK)
                        .remove(ChangeType.BRANCH).remove(ChangeType.PROPERTY);

                if (pcEntry.isBranch()) {
                    remainingChangeType = remainingChangeType.remove(ChangeType.ENCODING)
                            .remove(ChangeType.MERGE);
                }

                if (pcEntry.isEdit() && lvEntry.isMissingOnDisk()) {
                    remainingChangeType = remainingChangeType.remove(ChangeType.EDIT);
                }

                if (!remainingChangeType.equals(ChangeType.NONE)) {
                    failureList.add(createPendingDeleteConflictChangeFailure(targetServerItem));
                    continue;
                }
            }

            if (lvEntry.isDirectory()) {
                boolean okayToDelete = true;

                for (final LocalPendingChange pcChildEntry : pc.queryByTargetServerItem(targetServerItem,
                        RecursionType.FULL, null)) {
                    if (pcChildEntry.getChangeType().containsAny(PEND_DELETE_CONFLICTING_CHANGE_TYPES)) {
                        failureList.add(createPendingDeleteConflictChangeFailure(targetServerItem));
                        okayToDelete = false;
                        break;
                    }
                }

                if (!okayToDelete) {
                    continue;
                }

                for (final LocalPendingChange pcRenamedOut : pc
                        .queryByCommittedServerItem(lvEntry.getServerItem(), RecursionType.FULL, null)) {
                    if (pcRenamedOut.isRename()) {
                        final String format = Messages
                                .getString("LocalDataAccessLayer.PendingChildExceptionFormat"); //$NON-NLS-1$
                        failureList.add(new Failure(MessageFormat.format(format, targetServerItem),
                                FailureCodes.PENDING_CHILD_EXCEPTION, SeverityType.ERROR, targetServerItem));

                        okayToDelete = false;
                        break;
                    }
                }

                if (!okayToDelete) {
                    continue;
                }
            }

            if (pc.getRecursiveChangeTypeForTargetServerItem(targetServerItem).contains(ChangeType.DELETE)) {
                failureList.add(createPendingParentDeleteFailure(targetServerItem));
                continue;
            }

            if (null == pcEntry) {
                pcEntry = new LocalPendingChange(lvEntry, targetServerItem, ChangeType.DELETE);
            } else {
                pcEntry.setChangeType(pcEntry.getChangeType().combine(ChangeType.DELETE));

                // It's possible to pend a delete on an item whose local
                // version entry is marked as MissingFromDisk. In this case,
                // we want to strip the edit bit -- it's not a pending edit
                // any longer.
                pcEntry.setChangeType(pcEntry.getChangeType().remove(ChangeType.EDIT));
            }

            pc.pendChange(pcEntry);
            pc.removeCandidateByTargetServerItem(targetServerItem, true);

            if (lvEntry.isDirectory()) {
                final List<String> childDeletesToRemove = new ArrayList<String>();

                for (final LocalPendingChange pcChildEntry : pc.queryByTargetServerItem(targetServerItem,
                        RecursionType.FULL, "*")) //$NON-NLS-1$
                {
                    if (pcChildEntry.getChangeType().equals(ChangeType.DELETE)) {
                        childDeletesToRemove.add(pcChildEntry.getTargetServerItem());
                    } else {
                        pcChildEntry.setChangeType(pcChildEntry.getChangeType().combine(ChangeType.DELETE));
                    }
                }

                for (final String toRemove : childDeletesToRemove) {
                    pc.removeByTargetServerItem(toRemove);
                }
            }

            // Generate GetOperations for this pending change.
            if (!silent) {
                final GetOperation rootGetOp = lvEntry.toGetOperation(pcEntry, itemPropertyFilters);
                rootGetOp.setTargetLocalItem(null);
                getOps.add(rootGetOp);

                if (lvEntry.isDirectory()) {
                    final Iterable<WorkspaceLocalItem> lvChildEntries = lv
                            .queryByServerItem(lvEntry.getServerItem(), RecursionType.FULL, "*"); //$NON-NLS-1$

                    for (final WorkspaceLocalItem lvChildEntry : lvChildEntries) {
                        if (!duplicatesFilter.add(lvChildEntry)) {
                            continue;
                        }

                        final GetOperation childGetOp = lvChildEntry.toGetOperation(itemPropertyFilters);
                        childGetOp.setBaselineFileGUID(null);
                        childGetOp.setTargetLocalItem(null);
                        childGetOp.setPendingChangeID(0);
                        childGetOp.setChangeType(pc.getRecursiveChangeTypeForLocalVersion(lvChildEntry));
                        childGetOp.setProcessType(ProcessType.PEND);

                        getOps.add(childGetOp);
                    }
                }
            }
        }
    }

    for (final Failure failure : failureList) {
        failure.setRequestType(RequestType.DELETE);
    }

    failures.set(failureList.toArray(new Failure[failureList.size()]));
    return getOps.toArray(new GetOperation[getOps.size()]);
}

From source file:com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace.java

/**
 * Update the given items for the given workspace.
 * <p>/*from   w  w w. j a v a 2 s .co m*/
 * <!-- Event Origination Info -->
 * <p>
 * This method is an <b>core event origination point</b>. The
 * {@link EventSource} object that accompanies each event fired by this
 * method describes the execution context (current thread, etc.) when and
 * where this method was invoked.
 *
 * @param requests
 *        the request items to process (must not be null; items in array
 *        must not be null). To update all items in this workspace, pass a
 *        single {@link GetRequest} with a null itemSpec.
 * @param options
 *        options for the get operation (must not be <code>null</code>)
 * @param itemPropertyFilters
 *        a list of versioned item properties to return with each get
 *        operation (may be <code>null</code>)
 * @param alwaysQueryConflicts
 *        true to always query conflicts, false if we may omit this step
 * @param conflicts
 *        a reference to a list of conflicts to return (must not be
 *        <code>null</code>)
 * @return a GetStatus instance with the results of the get operation.
 */
public GetStatus get(final GetRequest[] requests, final GetOptions options, String[] itemPropertyFilters,
        final boolean alwaysQueryConflicts, final AtomicReference<Conflict[]> conflicts) {
    Check.notNull(requests, "requests"); //$NON-NLS-1$
    Check.notNull(options, "options"); //$NON-NLS-1$
    Check.notNull(conflicts, "conflicts"); //$NON-NLS-1$

    // Using web service directly so merge filters configured on client
    itemPropertyFilters = client.mergeWithDefaultItemPropertyFilters(itemPropertyFilters);

    client.getEventEngine()
            .fireOperationStarted(new GetOperationStartedEvent(EventSource.newFromHere(), this, requests));

    /*
     * Always work toward 100 work units. The progress indicator will only
     * be accurate for gets that fit in one page (result set). If we have to
     * process more than one set we'll fill up the task monitor prematurely,
     * which is not an error. Pages are huge so almost all requests will fit
     * inside one.
     */
    final TaskMonitor taskMonitor = TaskMonitorService.getTaskMonitor();
    taskMonitor.begin("", 100); //$NON-NLS-1$
    taskMonitor.setCurrentWorkDescription(
            Messages.getString("Workspace.ContactingServertoGetListOfItemsToUpdate")); //$NON-NLS-1$

    /*
     * Specify a limit to number of Get operation results that server may
     * return from a single call. This is to guard against client running
     * out of memory, and also to guard against Http runtime timeout on
     * server when streaming a large result set back to the client. This
     * "paging" technique relies on the page advancing once we process the
     * results from the previous call. This is incompatible with force
     * option.
     */

    final boolean getAll = options.contains(GetOptions.GET_ALL);
    final int maxResults = getAll ? 0 : VersionControlConstants.MAX_GET_RESULTS;

    final GetStatus getStatus = new GetStatus();

    try {
        String[] sourceWritableConflicts;
        final WritableConflictOnSourcePathListener conflictListener = new WritableConflictOnSourcePathListener();

        try {
            client.getEventEngine().addGetListener(conflictListener);

            GetStatus latestStatus = null;
            final GetEngine getEngine = new GetEngine(client);

            int resultCount;

            /*
             * Call the server. If we specify a page limit, call repeatedly
             * as long as we keep getting a full page back.
             *
             * Paging like this makes progress monitoring hard, because we
             * don't know the total amount of work up front.
             */
            do {
                log.debug("Call server for GetOperations."); //$NON-NLS-1$

                final GetOperation[][] results = client.getWebServiceLayer().get(getName(), getOwnerName(),
                        requests, maxResults, options, null, itemPropertyFilters, false);

                // Web service call always gets 5
                taskMonitor.worked(5);

                // How many results were returned? Is it a full page (see
                // loop
                // terminating condition)?
                resultCount = 0;
                for (final GetOperation[] result : results) {
                    resultCount += result.length;
                }

                log.debug("Process GetOperations"); //$NON-NLS-1$
                // Use 95 for the processing.
                TaskMonitorService.pushTaskMonitor(taskMonitor.newSubTaskMonitor(95));
                try {
                    latestStatus = getEngine.processGetOperations(this, ProcessType.GET, RequestType.NONE,
                            results, options, false, true, ChangePendedFlags.UNKNOWN);
                } catch (final Exception e) {
                    log.error("Error processing GET operations", e); //$NON-NLS-1$
                    if (e instanceof VersionControlException) {
                        throw (VersionControlException) e;
                    } else {
                        throw new VersionControlException(e);
                    }
                } finally {
                    TaskMonitorService.popTaskMonitor(true);
                }

                log.debug("Latest GetOperations status:"); //$NON-NLS-1$
                log.debug("    NumOperations        = " + latestStatus.getNumOperations()); //$NON-NLS-1$
                log.debug("    NumUpdated           = " + latestStatus.getNumUpdated()); //$NON-NLS-1$
                log.debug("    NumWarnings          = " + latestStatus.getNumWarnings()); //$NON-NLS-1$
                log.debug("    NumFailures          = " + latestStatus.getNumFailures()); //$NON-NLS-1$
                log.debug("    NumConflicts         = " + latestStatus.getNumConflicts()); //$NON-NLS-1$
                log.debug("    NumResolvedConflicts = " + latestStatus.getNumResolvedConflicts()); //$NON-NLS-1$

                getStatus.combine(latestStatus);
            } while (VersionControlConstants.MAX_GET_RESULTS > 0
                    && resultCount == VersionControlConstants.MAX_GET_RESULTS
                    && latestStatus.getNumUpdated() >= 1);

            sourceWritableConflicts = conflictListener.getMovedPaths();
        } finally {
            client.getEventEngine().removeGetListener(conflictListener);
        }

        final boolean attemptAutoResolve = (!options.contains(GetOptions.NO_AUTO_RESOLVE));

        if (getStatus.getNumConflicts() > 0
                || getStatus.haveResolvableWarnings() && (alwaysQueryConflicts || attemptAutoResolve)) {
            log.debug("Querying conflicts."); //$NON-NLS-1$
            taskMonitor.setCurrentWorkDescription(Messages.getString("Workspace.QueryingConflicts")); //$NON-NLS-1$

            final AtomicBoolean recursive = new AtomicBoolean();
            final String[] conflictScope = calculateConflictScope(requests, sourceWritableConflicts, recursive);
            Conflict[] unresolvedConflicts = queryConflicts(conflictScope, recursive.get());

            if (attemptAutoResolve) {
                log.debug("Resolving conflicts."); //$NON-NLS-1$
                taskMonitor.setCurrentWorkDescription(Messages.getString("Workspace.ResolvingConflicts")); //$NON-NLS-1$

                /* Auto resolve the conflicts */
                unresolvedConflicts = client.autoResolveValidConflicts(this, unresolvedConflicts,
                        AutoResolveOptions.ALL_SILENT);

                /*
                 * Update the get status information about conflicts. We
                 * don't change the value of HaveResolvableWarnings because
                 * we won't auto resolve local conflicts.
                 */
                getStatus.setNumConflicts(unresolvedConflicts.length);
            }

            log.debug("Unresolved conflicts: " + unresolvedConflicts.length); //$NON-NLS-1$
            conflicts.set(unresolvedConflicts);
        }
    } finally {
        /*
         * Event handlers may run a while but not update the work
         * description, so set a generic message so the user knows things
         * are wrapping up.
         */
        taskMonitor.setCurrentWorkDescription(Messages.getString("Workspace.FinishingGetOperation")); //$NON-NLS-1$

        client.getEventEngine().fireOperationCompleted(
                new GetOperationCompletedEvent(EventSource.newFromHere(), this, requests, getStatus));

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

        taskMonitor.done();
    }

    return getStatus;
}

From source file:com.microsoft.tfs.core.clients.versioncontrol.internal.localworkspace.LocalDataAccessLayer.java

public static GetOperation[] undoPendingChanges(final Workspace workspace, final LocalWorkspaceProperties wp,
        final WorkspaceVersionTable lv, final LocalPendingChangesTable pc,
        final Iterable<LocalPendingChange> pendingChanges, final ChangeType selectiveUndo,
        final AtomicReference<Failure[]> failures, final AtomicBoolean onlineOperationRequired) {
    // Our collection of GetOperations that we will return. There will be
    // one GetOperation for every undone pending change and for every item
    // affected by an undone recursive pending change. The dictionary is
    // keyed by (SourceServerItem, IsCommitted) just like the local version
    // table.//from   ww  w  . j  ava  2 s .c o  m
    final Map<ServerItemIsCommittedTuple, GetOperation> getOps = new HashMap<ServerItemIsCommittedTuple, GetOperation>();

    // The UndoneChange structure encapsulates a pending change and its
    // destination server item in pending space (RevertToServerItem).
    final List<UndoneChange> undoneChanges = new ArrayList<UndoneChange>();

    // A hash table where we can check quickly to see if a server path has a
    // pending change being undone (by target server item)
    final Map<String, UndoneChange> undoneChangesMap = new HashMap<String, UndoneChange>();

    // When a recursive pending change is undone, there may be affected
    // child pending changes that are not undone. We store in this queue a
    // list of updates that need to be processed (atomically!).
    final List<RenamedPendingChange> renamedPendingChanges = new ArrayList<RenamedPendingChange>();

    // When undoing a rename, we need to make sure that the current target
    // server item isn't at or below a workspace mapping.
    List<String> workingFolderServerItems = null;

    // Failures generated by undo
    final List<Failure> failureList = new ArrayList<Failure>();

    int undoRenameCount = 0;

    // The RevertToServerItem starts out with the CommittedServerItem of the
    // pending change.
    for (final LocalPendingChange pcEntry : pendingChanges) {
        final ChangeType changeType = pcEntry.getChangeType().retain(selectiveUndo);
        final UndoneChange undoneChange = new UndoneChange(pcEntry, pcEntry.getServerItem(), changeType);

        // Add this item to our data structures
        undoneChanges.add(undoneChange);
        undoneChangesMap.put(undoneChange.getPendingChange().getTargetServerItem(), undoneChange);

        // We can't undo a checkin lock without going to the server. If we
        // match one, the entire undo operation needs to go to the server.
        if (undoneChange.isUndoingLock()
                || (undoneChange.isUndoingRename() && undoneChange.getPendingChange().isLock())) {
            return sendToServer(failures, onlineOperationRequired);
        }

        // Count how many renames we are undoing and make sure the rename is
        // not at or under a workspace mapping
        if (undoneChange.isUndoingRename()) {
            undoRenameCount++;

            // The first rename will initialize our list of working folders
            // and sort it
            if (null == workingFolderServerItems) {
                final WorkingFolder[] workingFolders = wp.getWorkingFolders();
                workingFolderServerItems = new ArrayList<String>(workingFolders.length);

                for (final WorkingFolder workingFolder : workingFolders) {
                    workingFolderServerItems.add(workingFolder.getServerItem());
                }

                Collections.sort(workingFolderServerItems, new Comparator<String>() {
                    @Override
                    public int compare(final String x, final String y) {
                        return ServerPath.compareTopDown(x, y);
                    }
                });
            }

            // Check to see if undoing this rename would modify the
            // workspace mappings
            final int index = Collections.binarySearch(workingFolderServerItems, pcEntry.getTargetServerItem(),
                    ServerPath.TOP_DOWN_COMPARATOR);

            if (index >= 0 || (~index < workingFolderServerItems.size() && ServerPath
                    .isChild(pcEntry.getTargetServerItem(), workingFolderServerItems.get(~index)))) {
                return sendToServer(failures, onlineOperationRequired);
            }
        }
    }

    // Sort by target server item descending
    Collections.sort(undoneChanges, new Comparator<UndoneChange>() {
        @Override
        public int compare(final UndoneChange x, final UndoneChange y) {
            return ServerPath.compareTopDown(y.getPendingChange().getTargetServerItem(),
                    x.getPendingChange().getTargetServerItem());
        }
    });

    // Pass 1: Calculate the RevertToServerItem for each undone pending
    // change.
    if (undoRenameCount > 0) {
        // We should come up with a faster way of figuring out whether the
        // user is undoing all renames in the workspace.
        int totalRenameCount = 0;
        final List<LocalPendingChange> remainingFolderRenames = new ArrayList<LocalPendingChange>();

        for (final LocalPendingChange pcEntry : pc.queryByTargetServerItem(ServerPath.ROOT, RecursionType.FULL,
                null)) {
            if (pcEntry.isRename()) {
                totalRenameCount++;

                if (pcEntry.isRecursiveChange()) {
                    final UndoneChange undoneChange = undoneChangesMap.get(pcEntry.getTargetServerItem());

                    if (undoneChange == null || !undoneChange.isUndoingRename()) {
                        remainingFolderRenames.add(pcEntry);
                    }
                }
            }
        }

        if (undoneChanges.size() != pc.getCount()) {
            // We are not undoing all the changes in the workspace, so we
            // need to make sure that we do not have any pending changes
            // that are not being undone that have a target server item that
            // is at or underneath the source of a pending rename. Otherwise
            // there will be a collision when we undo the rename and it goes
            // back to the source.

            for (final UndoneChange undoneChange : undoneChanges) {
                final LocalPendingChange lpc = undoneChange.getPendingChange();

                // TODO: What kinds of bad situations can we end up with
                // when you have a merge of a deleted item under a rename --
                // a pending merge on a deleted item
                if (0 == lpc.getDeletionID() && lpc.isCommitted() && undoneChange.isUndoingRename()
                        && !ServerPath.equals(lpc.getCommittedServerItem(), lpc.getTargetServerItem())) {
                    // Check to see if there is a namespace-additive pending
                    // change blocking this item from reverting to its
                    // committed server item
                    for (final LocalPendingChange pcEntry : pc.queryByTargetServerItem(
                            undoneChange.getPendingChange().getCommittedServerItem(), RecursionType.FULL,
                            null)) {
                        if (pcEntry.isAdd() || pcEntry.isBranch() || pcEntry.isRename()) {
                            final UndoneChange collision = undoneChangesMap.get(pcEntry.getTargetServerItem());

                            if (collision == null || !collision.getUndoneChangeType()
                                    .containsAny(ChangeType.ADD_BRANCH_OR_RENAME)) {
                                final String format = Messages
                                        .getString("LocalDataAccessLayer.PartialRenameConflictExceptionFormat"); //$NON-NLS-1$
                                throw new PartialRenameConflictException(
                                        MessageFormat.format(format, pcEntry.getTargetServerItem()));
                            }
                        }
                    }
                }
            }
        }

        if (undoRenameCount != totalRenameCount) {
            // Only some of the renames in the workspace are being undone

            // Find a pending folder rename (PARENT\a->PARENT\b) that is
            // NOT being undone which is affecting a pending folder rename
            // (PARENT\A\SUB -> OUTSIDE) that IS being undone Where the
            // depth of the target name for the rename being undone
            // (OUTSIDE) is less than the depth of the target name that is
            // NOT being undone (PARENT\B).
            for (final LocalPendingChange remainingFolderRename : remainingFolderRenames) {
                for (final LocalPendingChange pcEntry : pc.queryByCommittedServerItem(
                        remainingFolderRename.getCommittedServerItem(), RecursionType.FULL, null)) {
                    if (pcEntry.isRename() && pcEntry.isRecursiveChange()) {
                        final UndoneChange undoneChange = undoneChangesMap.get(pcEntry.getTargetServerItem());
                        final int targetFolderDepth = ServerPath.getFolderDepth(pcEntry.getTargetServerItem());
                        final int remainFolderDepth = ServerPath
                                .getFolderDepth(remainingFolderRename.getTargetServerItem());

                        if (undoneChange != null && undoneChange.isUndoingRename()
                                && targetFolderDepth < remainFolderDepth) {
                            final String format = Messages
                                    .getString("LocalDataAccessLayer.PartialRenameConflictExceptionFormat"); //$NON-NLS-1$
                            throw new PartialRenameConflictException(
                                    MessageFormat.format(format, pcEntry.getCommittedServerItem()));
                        }
                    }
                }
            }

            // Calculate new names for all namespace-changing pending
            // changes.

            // Map of key server item (current target server item) to the
            // data structure used for the name calculation. We'll use this
            // later to sub in the new names.
            final Map<String, RenameCalculationEntry> newNames = new HashMap<String, RenameCalculationEntry>();

            // Our algorithm wants to walk the set of pending renames only.
            final List<RenameCalculationEntry> pendingRenamesOnly = new ArrayList<RenameCalculationEntry>(
                    totalRenameCount);

            for (final UndoneChange undoneChange : undoneChanges) {
                final RenameCalculationEntry rcEntry = new RenameCalculationEntry(
                        undoneChange.getPendingChange().getTargetServerItem(),
                        undoneChange.getPendingChange().getServerItem(), undoneChange.getPendingChange(),
                        undoneChange.isUndoingRename());

                newNames.put(undoneChange.getPendingChange().getTargetServerItem(), rcEntry);

                if (undoneChange.getPendingChange().isRename()) {
                    pendingRenamesOnly.add(rcEntry);
                }
            }

            for (final LocalPendingChange pcEntry : pc.queryByTargetServerItem(ServerPath.ROOT,
                    RecursionType.FULL, null)) {
                if ((pcEntry.isRename() || pcEntry.isAdd() || pcEntry.isBranch())
                        && !undoneChangesMap.containsKey(pcEntry.getTargetServerItem())) {
                    final RenameCalculationEntry rcEntry = new RenameCalculationEntry(
                            pcEntry.getTargetServerItem(), pcEntry.getServerItem(), pcEntry, false);

                    newNames.put(pcEntry.getTargetServerItem(), rcEntry);

                    if (pcEntry.isRename()) {
                        pendingRenamesOnly.add(rcEntry);
                    }
                }
            }

            // Our algorithm wants to walk the set of pending renames only,
            // by source server item ascending.
            Collections.sort(pendingRenamesOnly, new Comparator<RenameCalculationEntry>() {
                @Override
                public int compare(final RenameCalculationEntry x, final RenameCalculationEntry y) {
                    return ServerPath.compareTopDown(x.getPendingChange().getCommittedServerItem(),
                            y.getPendingChange().getCommittedServerItem());
                }
            });

            for (final RenameCalculationEntry newName : pendingRenamesOnly) {
                // Capture the data from newName into local variables, since
                // we will be checking/editing values on the very same
                // instance of RenameCalculationEntry in our up coming
                // for each loops
                final String sourceServerItem = newName.getSourceServerItem();
                final String targetServerItem = newName.getTargetServerItem();

                if (!newName.isUndoingChange()) {
                    for (final RenameCalculationEntry rcEntry : newNames.values()) {
                        final String entrySourceServerItem = rcEntry.getSourceServerItem();
                        if (ServerPath.isChild(sourceServerItem, entrySourceServerItem)) {
                            final String entryTargetServerItem = rcEntry.getTargetServerItem();
                            final String pendingTargetServerItem = rcEntry.getPendingChange()
                                    .getTargetServerItem();

                            if (!ServerPath.equals(entrySourceServerItem, entryTargetServerItem)
                                    || ServerPath.equals(pendingTargetServerItem, entrySourceServerItem)) {
                                rcEntry.setSourceServerItem(targetServerItem
                                        + entrySourceServerItem.substring(sourceServerItem.length()));
                            }
                        }
                    }
                } else {
                    for (final RenameCalculationEntry rcEntry : newNames.values()) {
                        final String entryTargetServerItem = rcEntry.getTargetServerItem();
                        if (ServerPath.isChild(targetServerItem, entryTargetServerItem)) {
                            final String entrySourceServerItem = rcEntry.getSourceServerItem();
                            final String pendingTargetServerItem = rcEntry.getPendingChange()
                                    .getTargetServerItem();

                            if (!ServerPath.equals(entrySourceServerItem, entryTargetServerItem)
                                    || ServerPath.equals(pendingTargetServerItem, entrySourceServerItem)) {
                                rcEntry.setTargetServerItem(sourceServerItem
                                        + entryTargetServerItem.substring(targetServerItem.length()));
                            }
                        }
                    }
                }
            }

            // If there are duplicate TargetServerItem values in the set of
            // RenameCalculationEntry objects, that indicates we have a
            // collision and cannot perform the undo. Sort by target server
            // item so that duplicates will be adjacent.
            final RenameCalculationEntry[] rcEntries = newNames.values()
                    .toArray(new RenameCalculationEntry[newNames.size()]);

            Arrays.sort(rcEntries, new Comparator<RenameCalculationEntry>() {
                @Override
                public int compare(final RenameCalculationEntry x, final RenameCalculationEntry y) {
                    return ServerPath.compareTopDown(x.getTargetServerItem(), y.getTargetServerItem());
                }
            });

            // The loop is complicated because we need to exclude pending
            // renames on deleted items from consideration.
            int duplicateCheckIndex = -1;

            for (int i = 1; i < rcEntries.length; i++) {
                // Only allow rcEntries[duplicateCheckIndex] to point to a
                // pending change which meets our criteria
                if (rcEntries[i - 1].getPendingChange().getDeletionID() == 0
                        || !rcEntries[i - 1].getPendingChange().isRename()) {
                    duplicateCheckIndex = i - 1;
                }

                // This pending change must also meet the criteria, we must
                // have something to compare it against, and the target
                // server items need to be the same.
                if (duplicateCheckIndex >= 0
                        && (rcEntries[i].getPendingChange().getDeletionID() == 0
                                || !rcEntries[i].getPendingChange().isRename())
                        && ServerPath.equals(rcEntries[i].getTargetServerItem(),
                                rcEntries[duplicateCheckIndex].getTargetServerItem())) {
                    throw new PartialRenameConflictException(MessageFormat.format(
                            Messages.getString("LocalDataAccessLayer.PartialRenameConflictExceptionFormat"), //$NON-NLS-1$ ,
                            rcEntries[i].getTargetServerItem()));
                }
            }

            for (final UndoneChange undoneChange : undoneChanges) {
                final RenameCalculationEntry rcEntry = newNames
                        .get(undoneChange.getPendingChange().getTargetServerItem());

                if (rcEntry != null) {
                    undoneChange.setRevertToServerItem(rcEntry.getTargetServerItem());
                }
            }
        } else {
            // All renames in the workspace are being undone.
            for (final UndoneChange undoneChange : undoneChanges) {
                if (undoneChange.getPendingChange().isCommitted()) {
                    // Committed changes have their revert to server item
                    // already calculated.
                    undoneChange
                            .setRevertToServerItem(undoneChange.getPendingChange().getCommittedServerItem());
                } else {
                    // Find the closest rename that affects this uncommitted
                    // item and unrename it.
                    undoneChange.setRevertToServerItem(pc.getCommittedServerItemForTargetServerItem(
                            undoneChange.getPendingChange().getTargetServerItem()));
                }
            }
        }
    } else {
        // Even though we are not undoing a rename, there could be a
        // parental rename. So set the revert to server item based upon
        // existing parental renames.
        for (final UndoneChange undoneChange : undoneChanges) {
            undoneChange.setRevertToServerItem(undoneChange.getPendingChange().getTargetServerItem());
        }
    }

    // Pass 1: One GetOperation for every LocalPendingChange being undone
    for (final UndoneChange undoneChange : undoneChanges) {
        if (undoneChange.getRevertToServerItem().length() > VersionControlConstants.MAX_SERVER_PATH_SIZE) {
            throw createPathTooLongException(undoneChange.getRevertToServerItem());
        }

        final LocalPendingChange pcEntry = undoneChange.getPendingChange();
        final WorkspaceLocalItem lvEntry = lv.getByPendingChange(undoneChange.getPendingChange());

        final GetOperation getOp = new GetOperation();

        getOp.setTargetServerItem(undoneChange.getRevertToServerItem());
        getOp.setSourceServerItem(
                pcEntry.isCommitted() ? pcEntry.getCommittedServerItem() : pcEntry.getTargetServerItem());

        if (null != lvEntry && !lvEntry.isDeleted()) {
            getOp.setSourceLocalItem(lvEntry.getLocalItem());

            // If we're undoing a pending add, mark the path as changed in
            // the scanner. This is because when the pending change is
            // undone, the item in question will not actually be touched on
            // disk. But we want to have it marked, so that we re-detect the
            // item as a candidate add.
            if (undoneChange.isUndoingAdd()) {
                workspace.getWorkspaceWatcher().markPathChanged(lvEntry.getLocalItem());
                LocalWorkspaceTransaction.getCurrent().setRaisePendingChangeCandidatesChanged(true);
            }
        }

        if ((0 == pcEntry.getDeletionID()
                || undoneChange.getRemainingChangeType().contains(ChangeType.UNDELETE))
                && !undoneChange.isUndoingBranch()) {
            final String targetLocalItem = WorkingFolder
                    .getLocalItemForServerItem(undoneChange.getRevertToServerItem(), wp.getWorkingFolders());

            if (null != lvEntry) {
                getOp.setTargetLocalItem(targetLocalItem);

                // We never want the client to delete adds -- even if the
                // target is cloaked.
                if (pcEntry.isAdd() && null == getOp.getTargetLocalItem()) {
                    getOp.setTargetLocalItem(getOp.getSourceLocalItem());
                }
            } else {
                // We don't have a local version entry for this pending
                // change, so we can't restore the content.
                getOp.setTargetLocalItem(null);

                if (null != targetLocalItem) {
                    final String format = "OfflineUndoNoLocalVersionEntry"; //$NON-NLS-1$
                    failureList
                            .add(new Failure(MessageFormat.format(format, undoneChange.getRevertToServerItem()),
                                    FailureCodes.BASELINE_UNAVAILABLE_EXCEPTION, SeverityType.WARNING,
                                    undoneChange.getRevertToServerItem()));
                }
            }

            if (null != getOp.getTargetLocalItem()) {
                getOp.setLocalVersionEntry(lv.getByLocalItem(getOp.getTargetLocalItem()));
            }
        }

        // This is the current encoding on the pending change -- we need the
        // committed encoding, which is on the local version entry if we
        // have one, but if we don't, we're in trouble and need to go to the
        // server.
        if (!pcEntry.getChangeType().contains(ChangeType.ENCODING)) {
            // If we aren't changing the encoding, then the local pending
            // change row's encoding is the encoding for the item.

            getOp.setEncoding(pcEntry.getEncoding());
        } else if (null != lvEntry) {
            getOp.setEncoding(lvEntry.getEncoding());
        } else {
            // We don't have the committed encoding for this item stored
            // locally. We need to process this undo operation on the
            // server.

            // TODO: Issue a warning and not download the change? The user
            // can go to the server and get it later, we don't want to
            // completely block them while they're offline
            return sendToServer(failures, onlineOperationRequired);
        }

        getOp.setChangeType(undoneChange.getUndoneChangeType());

        // If we are undoing an uncommitted pending change then do not add
        // in parent recursive changetypes
        if (!undoneChange.isUndoingAdd() && !undoneChange.isUndoingBranch()) {
            ChangeType inheritedChangeType = ChangeType.NONE;

            // The ChangeType on the item being undone is equal to the
            // ChangeType on the item itself, plus the recursive ChangeType
            // on its parent pending changes which are also being undone.
            for (final LocalPendingChange parentPcEntry : pc
                    .queryParentsOfTargetServerItem(pcEntry.getTargetServerItem())) {
                final UndoneChange checkChange = undoneChangesMap.get(parentPcEntry.getTargetServerItem());

                if (!parentPcEntry.isRecursiveChange() || checkChange == null) {
                    continue;
                }

                if (checkChange.getUndoneChangeType().contains(ChangeType.RENAME)) {
                    inheritedChangeType = inheritedChangeType.combine(ChangeType.RENAME);
                }
                if (checkChange.getUndoneChangeType().contains(ChangeType.DELETE)) {
                    inheritedChangeType = inheritedChangeType.combine(ChangeType.DELETE);
                }
            }

            getOp.setChangeType(inheritedChangeType.combine(getOp.getChangeType()));
        }

        getOp.setDeletionID(pcEntry.getDeletionID());
        getOp.setItemType(pcEntry.getItemType());
        getOp.setPendingChangeID(LocalPendingChange.LOCAL_PENDING_CHANGE_ID);
        getOp.setItemID(pcEntry.getItemID());

        if (null != lvEntry) {
            if (lvEntry.isCommitted() && !lvEntry.isDirectory()) {
                getOp.setBaselineFileGUID(
                        lvEntry.hasBaselineFileGUID() ? lvEntry.getBaselineFileGUID() : new byte[16]);
            }

            getOp.setHashValue(lvEntry.getHashValue());
            getOp.setVersionLocal(lvEntry.isDeleted() ? 0 : lvEntry.getVersion());
            getOp.setVersionServer(lvEntry.getVersion());
            getOp.setVersionServerDate((-1 == lvEntry.getCheckinDate()) ? DotNETDate.MIN_CALENDAR
                    : DotNETDate.fromWindowsFileTimeUTC(lvEntry.getCheckinDate()));
            getOp.setPropertyValues(pcEntry.getPropertyValues());
        } else {
            getOp.setVersionServer(pcEntry.getVersion());
        }

        getOps.put(new ServerItemIsCommittedTuple(getOp.getSourceServerItem(), pcEntry.isCommitted()), getOp);

        // Remove local version rows for adds, branches where the item is an
        // add, or we are syncing an item on top of an undone branch.
        if (undoneChange.isUndoingAdd()
                || (undoneChange.isUndoingBranch() && getOp.getTargetLocalItem() != null)) {
            if (null != lvEntry) {
                lv.removeByServerItem(lvEntry.getServerItem(), lvEntry.isCommitted(), true);
            }
        }
    }

    // Pass 2: Affected items underneath undone recursive changes
    for (final UndoneChange undoneChange : undoneChanges) {
        if (!undoneChange.isUndoingRecursiveChange()) {
            continue;
        }

        // The sort order means that undoneChange is always the closest
        // recursive operation affecting the item
        for (final WorkspaceLocalItem lvEntry : ParsedItemSpec.queryLocalVersionsByTargetServerItem(lv, pc,
                undoneChange.getPendingChange().getTargetServerItem(), RecursionType.FULL, null,
                ParsedItemSpecOptions.INCLUDE_DELETED)) {
            if (getOps.containsKey(
                    new ServerItemIsCommittedTuple(lvEntry.getServerItem(), lvEntry.isCommitted()))) {
                continue;
            }

            final String currentServerItem = lvEntry.isCommitted()
                    ? pc.getTargetServerItemForCommittedServerItem(lvEntry.getServerItem())
                    : lvEntry.getServerItem();

            final GetOperation getOp = new GetOperation();

            getOp.setSourceLocalItem(lvEntry.isDeleted() ? null : lvEntry.getLocalItem());

            getOp.setTargetServerItem(undoneChange.getRevertToServerItem() + currentServerItem
                    .substring(undoneChange.getPendingChange().getTargetServerItem().length()));

            if (getOp.getTargetServerItem().length() > VersionControlConstants.MAX_SERVER_PATH_SIZE) {
                throw createPathTooLongException(getOp.getTargetServerItem());
            }

            getOp.setSourceServerItem(
                    lvEntry.isCommitted() ? lvEntry.getServerItem() : getOp.getTargetServerItem());

            getOp.setTargetLocalItem(WorkingFolder.getLocalItemForServerItem(getOp.getTargetServerItem(),
                    wp.getWorkingFolders()));

            if (null != getOp.getTargetLocalItem()) {
                getOp.setLocalVersionEntry(lv.getByLocalItem(getOp.getTargetLocalItem()));
            }

            getOp.setDeletionID(0);
            getOp.setEncoding(lvEntry.getEncoding());
            getOp.setItemType(lvEntry.isDirectory() ? ItemType.FOLDER : ItemType.FILE);
            getOp.setPropertyValues(lvEntry.getPropertyValues());

            // Even if this item has a pending change which is not being
            // undone -- we return 0 here
            getOp.setPendingChangeID(0);
            getOp.setItemID(lvEntry.getItemID());

            if (!ServerPath.equals(currentServerItem, getOp.getTargetServerItem())) {
                if (!lvEntry.isCommitted()
                        && !ServerPath.equals(currentServerItem, getOp.getTargetServerItem())) {
                    // Uncommitted items have the itemid of the target
                    // server item, and we're changing paths, so set the
                    // item id to 0 because we have no idea what the item id
                    // of the target server item is
                    getOp.setItemID(0);
                }

                final LocalPendingChange pcEntry = pc.getByTargetServerItem(currentServerItem);

                if (null != pcEntry) {
                    if (pcEntry.isLock()) {
                        // We cannot change the path of an item with a
                        // pending lock locally.
                        return sendToServer(failures, onlineOperationRequired);
                    }

                    if (pcEntry.hasMergeConflict()) {
                        throw new CannotRenameDueToChildConflictException(
                                undoneChange.getPendingChange().getTargetServerItem(),
                                pcEntry.getTargetServerItem());
                    }

                    // Queue this pending change for a later update of its
                    // target path and itemid (if it still exists after
                    // removing those pending changes that are being undone)
                    renamedPendingChanges
                            .add(new RenamedPendingChange(currentServerItem, getOp.getTargetServerItem()));
                }
            }

            if (lvEntry.isCommitted() && !lvEntry.isDirectory()) {
                getOp.setBaselineFileGUID(
                        lvEntry.hasBaselineFileGUID() ? lvEntry.getBaselineFileGUID() : new byte[16]);
            }

            getOp.setHashValue(lvEntry.getHashValue());
            getOp.setVersionLocal(lvEntry.isDeleted() ? 0 : lvEntry.getVersion());
            getOp.setVersionServer(lvEntry.getVersion());
            getOp.setVersionServerDate((-1 == lvEntry.getCheckinDate()) ? DotNETDate.MIN_CALENDAR
                    : DotNETDate.fromWindowsFileTimeUTC(lvEntry.getCheckinDate()));
            getOp.setChangeType(ChangeType.NONE);

            // We'll take a quick look at the parents of this target server
            // item to determine if the item is still deleted. On this same
            // pass, we'll compute the ChangeType of the GetOperation to
            // generate. Since there was no pending change being undone on
            // this item, the ChangeType is equal to the union of the
            // recursive changetype bits on parent pending changes which are
            // being undone.
            boolean stillDeleted = false;

            for (final LocalPendingChange parentPcEntry : pc
                    .queryParentsOfTargetServerItem(currentServerItem)) {
                final UndoneChange checkChange = undoneChangesMap.get(parentPcEntry.getTargetServerItem());

                if (checkChange == null) {
                    if (parentPcEntry.isDelete()) {
                        stillDeleted = true;

                        // Who cares what the ChangeType on the GetOperation
                        // is, if we're not going to emit it?
                        break;
                    }
                } else {
                    ChangeType changeType = getOp.getChangeType();
                    changeType = changeType.combine(checkChange.getUndoneChangeType());
                    changeType = changeType.combine(ChangeType.RENAME_OR_DELETE);
                    getOp.setChangeType(changeType);
                }
            }

            if (!lvEntry.isDeleted() || !stillDeleted) {
                if (null != getOp.getTargetLocalItem() || null != getOp.getSourceLocalItem()) {
                    getOps.put(new ServerItemIsCommittedTuple(lvEntry.getServerItem(), lvEntry.isCommitted()),
                            getOp);
                }
            }
        }
    }

    // Remove the pending change rows, putting back modified changes for
    // those entries which were selective undoes. Do this in two loops so
    // the changes are atomic.
    final List<LocalPendingChange> selectiveUndoChanges = new ArrayList<LocalPendingChange>();

    for (final UndoneChange undoneChange : undoneChanges) {
        pc.remove(undoneChange.getPendingChange());

        // If this was a selective undo, add an entry to the table
        if (!undoneChange.getUndoneChangeType().equals(undoneChange.getPendingChange().getChangeType())) {
            final LocalPendingChange newChange = undoneChange.getPendingChange().clone();
            newChange.setChangeType(
                    undoneChange.getPendingChange().getChangeType().remove(undoneChange.getUndoneChangeType()));
            newChange.setTargetServerItem(undoneChange.getRevertToServerItem());

            selectiveUndoChanges.add(newChange);
        }
    }

    // Second loop -- pend the selective undo changes.
    for (final LocalPendingChange pcEntry : selectiveUndoChanges) {
        pc.pendChange(pcEntry);
    }

    // Update the pending changes that were not undone but were affected by
    // parental renames.
    // Do this in two loops (remove+capture, modify+apply) so the changes
    // are atomic.
    for (final RenamedPendingChange renamedPendingChange : renamedPendingChanges) {
        final LocalPendingChange pcEntry = pc
                .getByTargetServerItem(renamedPendingChange.getOldTargetServerItem());

        if (null != pcEntry) {
            pc.remove(pcEntry);
            renamedPendingChange.setPendingChange(pcEntry);

            if (!pcEntry.isCommitted()) {
                final WorkspaceLocalItem lvEntry = lv
                        .getByServerItem(renamedPendingChange.getOldTargetServerItem(), false);

                if (null != lvEntry) {
                    renamedPendingChange.setLocalVersion(lvEntry);
                    lv.removeByServerItem(lvEntry.getServerItem(), lvEntry.isCommitted(), true);
                }
            }
        }
    }

    // Second loop -- apply the data to the tables after modifying it
    for (final RenamedPendingChange renamedPendingChange : renamedPendingChanges) {
        final LocalPendingChange pcEntry = renamedPendingChange.getPendingChange();
        final WorkspaceLocalItem lvEntry = renamedPendingChange.getLocalVersion();

        if (null != pcEntry) {
            pcEntry.setTargetServerItem(renamedPendingChange.getTargetServerItem());

            if (!pcEntry.isCommitted()) {
                pcEntry.setItemID(0);
            }

            pc.pendChange(pcEntry);
        }

        if (null != lvEntry) {
            lvEntry.setServerItem(renamedPendingChange.getTargetServerItem());
            lvEntry.setItemID(0);
            lv.add(lvEntry);
        }
    }

    failures.set(failureList.toArray(new Failure[failureList.size()]));
    onlineOperationRequired.set(false);

    return getOps.values().toArray(new GetOperation[getOps.size()]);
}