All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ionic.sdk.agent.key.merge.KeyAttributesMapMergerDefault Maven / Gradle / Ivy

Go to download

The Ionic Java SDK provides an easy-to-use interface to the Ionic Platform.

There is a newer version: 2.9.0
Show newest version
package com.ionic.sdk.agent.key.merge;

import com.ionic.sdk.agent.key.KeyAttributesMap;
import com.ionic.sdk.error.SdkError;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.logging.Logger;

/**
 * This is the default SDK-provided implementation of key attribute merging logic that can be used
 * in the event that a merge is needed during a protection key update operation (Agent::updateKeys()).
 */
public class KeyAttributesMapMergerDefault implements KeyAttributesMapMerger {

    /**
     * Class scoped logger.
     */
    private final Logger logger = Logger.getLogger(getClass().getName());

    /**
     * Perform key attribute merge operation.
     *
     * @param attributesAreMutable     Specifies if the attributes being merged are mutable or not.
     * @param originalServerAttributes The attributes originally received from the server during a past
     *                                 key create, fetch, or update operation.
     * @param currentServerAttributes  The attributes as they are currently known to the server.
     * @param clientAttributes         The attributes known to the client.
     * @return The output attributes resulting from the merge operation.
     */
    public final KeyAttributesMap mergeKeyAttributeMaps(final boolean attributesAreMutable,
                                                        final KeyAttributesMap originalServerAttributes,
                                                        final KeyAttributesMap currentServerAttributes,
                                                        final KeyAttributesMap clientAttributes) {
        final KeyAttributesMap mergedAttributes = new KeyAttributesMap(currentServerAttributes);
        mergeKeyAttributeMapsInternal(attributesAreMutable, originalServerAttributes,
                currentServerAttributes, clientAttributes, mergedAttributes);
        return mergedAttributes;
    }

    /**
     * Perform key attribute merge operation.
     *
     * @param attributesAreMutable     Specifies if the attributes being merged are mutable or not.
     * @param originalServerAttributes The attributes originally received from the server during a past
     *                                 key create, fetch, or update operation.
     * @param currentServerAttributes  The attributes as they are currently known to the server.
     * @param clientAttributes         The attributes known to the client.
     * @param mergedAttributes         The output attributes resulting from the merge operation.
     * @return An error code indicating the status of the operation.
     */
    @Override
    public final int mergeKeyAttributeMaps(final boolean attributesAreMutable,
                                           final KeyAttributesMap originalServerAttributes,
                                           final KeyAttributesMap currentServerAttributes,
                                           final KeyAttributesMap clientAttributes,
                                           final KeyAttributesMap mergedAttributes) {
        return mergeKeyAttributeMapsInternal(attributesAreMutable,
                originalServerAttributes, currentServerAttributes, clientAttributes, mergedAttributes);
    }

    /**
     * Perform key attribute merge operation.
     *
     * @param attributesAreMutable     Specifies if the attributes being merged are mutable or not.
     * @param originalServerAttributes The attributes originally received from the server during a past
     *                                 key create, fetch, or update operation.
     * @param currentServerAttributes  The attributes as they are currently known to the server.
     * @param clientAttributes         The attributes known to the client.
     * @param mergedAttributes         The output attributes resulting from the merge operation.
     * @return An error code indicating the status of the operation.
     */
    private int mergeKeyAttributeMapsInternal(final boolean attributesAreMutable,
                                              final KeyAttributesMap originalServerAttributes,
                                              final KeyAttributesMap currentServerAttributes,
                                              final KeyAttributesMap clientAttributes,
                                              final KeyAttributesMap mergedAttributes) {
        // Trying to model as closely as possible the existing C++ implementation.  One gotcha was that the C++
        // algorithm depended on the ability to examine the collection element at the iterator cursor.  Using
        // ListIterator and adjusting the logic as needed.  Also changed KeyAttributesMap to derive from TreeMap, so
        // we get the same ordering implied by std::map.
        final KeyAttributesMap finalAttributes = new KeyAttributesMap(currentServerAttributes);
        final ListIterator origIter = new ArrayList(originalServerAttributes.keySet()).listIterator();
        final ListIterator clientIter = new ArrayList(clientAttributes.keySet()).listIterator();
        while (origIter.hasNext() || clientIter.hasNext()) {
            if (!origIter.hasNext()) {
                // there are no more items in the original server attributes, so we are iterating
                // on client attributes. this means we need to merge our client attribute values
                // with the current server attribute values (which FYI are available in mapFinalAttributes).
                final String clientKey = clientIter.next();
                final List clientValues = clientAttributes.get(clientKey);
                final List mergedValues = new ArrayList();
                mergeKeyAttributeValues(new ArrayList(),
                        finalAttributes.get(clientKey), clientValues, mergedValues);
                finalAttributes.put(clientKey, mergedValues);
            } else if (!clientIter.hasNext()) {
                // there are no more items in the client attributes, so we are iterating on
                // original server attributes. this means we need to remove the original server
                // attribute altogether since our client has intentionally deleted it.
                final String origKey = origIter.next();
                finalAttributes.remove(origKey);
            } else {
                // Java does not implement ability to "peek" through the Iterator interface, but ListIterator works
                final String origKey = origIter.next();
                final String clientKey = clientIter.next();
                origIter.previous();
                clientIter.previous();
                if (clientKey.compareTo(origKey) < 0) {
                    // we found a client attribute that does not exist in the original server attributes.
                    // this means we need to merge our client attribute values with the current server
                    // attribute values (which FYI are available in mapFinalAttributes).
                    final List clientValues = clientAttributes.get(clientKey);
                    final List mergedValues = new ArrayList();
                    mergeKeyAttributeValues(new ArrayList(),
                            finalAttributes.get(clientKey), clientValues, mergedValues);
                    finalAttributes.put(clientKey, mergedValues);
                    clientIter.next();
                } else if (origKey.compareTo(clientKey) < 0) {
                    // we found an original server attribute that does not exist in the client attributes.
                    // this means we need to remove the original server attribute altogether since our
                    // client has intentionally deleted it.
                    finalAttributes.remove(origKey);
                    origIter.next();
                } else {
                    // we found an original server attribute that also exists in the client attributes.
                    // this means we need to merge both of their value vectors together into the current
                    // server attribute values (which FYI are available in mapFinalAttributes).
                    if (finalAttributes.containsKey(clientKey)) {
                        final List clientValues = clientAttributes.get(clientKey);
                        final List mergedValues = new ArrayList();
                        mergeKeyAttributeValues(originalServerAttributes.get(origKey),
                                finalAttributes.get(clientKey), clientValues, mergedValues);
                        finalAttributes.put(clientKey, mergedValues);
                    }
                    origIter.next();
                    clientIter.next();
                }
            }
        }
        mergedAttributes.clear();
        mergedAttributes.putAll(finalAttributes);
        logger.finest(String.format("mergedAttributes = %s", mergedAttributes.toString()));
        return SdkError.ISAGENT_OK;
    }

    /**
     * Merge sets of values for a (mutable) attribute key.
     *
     * @param originalServerValues The attribute values originally received from the server during a past
     *                             key create, fetch, or update operation.
     * @param currentServerValues  The attribute values as they are currently known to the server.
     * @param currentClientValues  The attribute values known to the client.
     * @param mergedValues         The output attribute values resulting from the merge operation.
     */
    private void mergeKeyAttributeValues(final List originalServerValues,
                                         final List currentServerValues,
                                         final List currentClientValues,
                                         final List mergedValues) {
        final List currentServerValuesNN = (currentServerValues == null)
                ? new ArrayList() : currentServerValues;
        final List finalValues = new ArrayList(currentServerValuesNN);
        // detect which values were removed by the client and remove them from the final
        // values vector. this is done by seeing which values inside of vecOriginalServerValuesIn
        // do not exist inside of vecClientValuesInOut
        for (String originalServerValue : originalServerValues) {
            if (!currentClientValues.contains(originalServerValue)) {
                finalValues.remove(originalServerValue);
            }
        }
        // detect which values were added by the client and add them to the final
        // values vector. this is done by seeing which values inside of vecClientValuesInOut
        // do not exist inside of vecOriginalServerValuesIn
        for (String currentClientValue : currentClientValues) {
            if (!originalServerValues.contains(currentClientValue)
                    && !finalValues.contains(currentClientValue)) {
                finalValues.add(currentClientValue);
            }
        }
        mergedValues.clear();
        mergedValues.addAll(finalValues);
        logger.finest(String.format("mergedValues = %s", mergedValues.toString()));
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy