com.confighub.api.repository.user.editor.CompareResolver.java Source code

Java tutorial

Introduction

Here is the source code for com.confighub.api.repository.user.editor.CompareResolver.java

Source

/*
 * This file is part of ConfigHub.
 *
 * ConfigHub is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ConfigHub is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ConfigHub.If not, see <http://www.gnu.org/licenses/>.
 */

package com.confighub.api.repository.user.editor;

import com.confighub.api.repository.user.AUserAccessValidation;
import com.confighub.api.util.GsonHelper;
import com.confighub.core.error.ConfigException;
import com.confighub.core.error.Error;
import com.confighub.core.repository.*;
import com.confighub.core.resolver.Context;
import com.confighub.core.rules.AccessRuleWrapper;
import com.confighub.core.security.SecurityProfile;
import com.confighub.core.store.Store;
import com.confighub.core.utils.ContextParser;
import com.confighub.core.utils.DateTimeUtils;
import com.confighub.core.utils.Utils;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.*;

@Path("/compareResolver")
public class CompareResolver extends AUserAccessValidation {
    private static final Logger log = LogManager.getLogger(EditorResolver.class);

    @GET
    @Path("/{account}/{repository}")
    @Produces("application/json")
    public Response get(@PathParam("account") String account, @PathParam("repository") String repositoryName,
            @QueryParam("aContext") String aContextString, @QueryParam("aTag") String aTagLabel,
            @QueryParam("aTs") Long aTs,

            @QueryParam("bContext") String bContextString, @QueryParam("bTag") String bTagLabel,
            @QueryParam("bTs") Long bTs,

            @QueryParam("all") boolean allKeys, @QueryParam("diffOnly") boolean diffOnly,
            @QueryParam("allValues") boolean allValues, @QueryParam("key") String keyString,
            @QueryParam("aPass") String aPass, @QueryParam("bPass") String bPass, @QueryParam("json") boolean json,
            @HeaderParam("Authorization") String token) {
        JsonObject data = new JsonObject();
        Store store = new Store();

        try {
            int status = validate(account, repositoryName, token, store);
            if (0 != status)
                return Response.status(status).build();

            if (diffOnly)
                allKeys = false;

            Tag aTag = Utils.isBlank(aTagLabel) ? null : store.getTag(repository.getId(), aTagLabel);

            Date aDateObj = DateTimeUtils.dateFromTsOrTag(aTag, aTs, repository.getCreateDate());

            Tag bTag = Utils.isBlank(bTagLabel) ? null : store.getTag(repository.getId(), bTagLabel);
            Date bDateObj = DateTimeUtils.dateFromTsOrTag(bTag, bTs, repository.getCreateDate());

            Repository aRepo = repository, bRepo = repository;
            if (null != aDateObj)
                aRepo = store.getRepository(repository.getId(), aDateObj);
            if (null != bDateObj)
                bRepo = store.getRepository(repository.getId(), bDateObj);

            Collection<CtxLevel> aContextCtxLevels = ContextParser.parseAndCreate(aContextString, aRepo, store,
                    user, aDateObj, true);
            Collection<CtxLevel> bContextCtxLevels = ContextParser.parseAndCreate(bContextString, bRepo, store,
                    user, bDateObj, true);

            AccessRuleWrapper accessRuleWrapper = repository.getRulesWrapper(user);

            Context aContext = new Context(store, aRepo, aContextCtxLevels, aDateObj, allKeys);
            Context bContext = new Context(store, bRepo, bContextCtxLevels, bDateObj, allKeys);

            Map<PropertyKey, Collection<Property>> aResolved;
            Map<PropertyKey, Collection<Property>> bResolved;

            Map<String, SecurityProfile> aSecurityProfiles = new HashMap<>();
            Map<String, SecurityProfile> bSecurityProfiles = new HashMap<>();

            if (!Utils.isBlank(keyString)) {
                aResolved = new HashMap<>();
                bResolved = new HashMap<>();
                Collection<Property> aProps;
                Collection<Property> bProps;

                if (!Utils.isBlank(aPass)) {
                    PropertyKey aKey = store.getKey(aRepo, keyString, aDateObj);
                    if (null != aKey && aKey.isEncrypted()) {
                        SecurityProfile aSp = aKey.getSecurityProfile();
                        boolean validSK = false;
                        try {
                            validSK = !Utils.isBlank(aPass) && aSp.isSecretValid(aPass);
                        } catch (Exception ignore) {
                        }

                        if (validSK) {
                            aSp.sk = aPass;
                            aSecurityProfiles.put(keyString, aSp);
                            data.addProperty("aDecrypted", true);
                        }
                    }
                }

                if (!Utils.isBlank(bPass)) {
                    PropertyKey bKey = store.getKey(bRepo, keyString, bDateObj);
                    if (null != bKey && bKey.isEncrypted()) {
                        SecurityProfile bSp = bKey.getSecurityProfile();
                        boolean validSK = false;
                        try {
                            validSK = !Utils.isBlank(bPass) && bSp.isSecretValid(bPass);
                        } catch (Exception ignore) {
                        }

                        if (validSK) {
                            bSp.sk = bPass;
                            bSecurityProfiles.put(keyString, bSp);
                            data.addProperty("bDecrypted", true);
                        }
                    }
                }

                if (allValues)
                    aProps = aContext.contextualSplitKeyResolver(keyString);
                else
                    aProps = aContext.keyResolver(keyString);

                if (null != aProps && aProps.size() > 0)
                    aResolved.put(aProps.iterator().next().getPropertyKey(), aProps);

                if (allValues)
                    bProps = bContext.contextualSplitKeyResolver(keyString);
                else
                    bProps = bContext.keyResolver(keyString);

                if (null != bProps && bProps.size() > 0)
                    bResolved.put(bProps.iterator().next().getPropertyKey(), bProps);

            } else {
                aResolved = aContext.resolve();
                bResolved = bContext.resolve();
            }

            List<Cmp> organized = organize(aResolved, bResolved, aSecurityProfiles, bSecurityProfiles);

            JsonArray config = new JsonArray();

            long start = System.currentTimeMillis();
            for (Cmp comparisonEntry : organized) {
                JsonObject entryJson = comparisonEntry.toJson(aRepo, bRepo, accessRuleWrapper, diffOnly, allValues);
                if (null != entryJson)
                    config.add(entryJson);
            }
            log.info(String.format("Json gen: %d/ms;", (System.currentTimeMillis() - start)));

            if (null != aDateObj && null != bDateObj)
                data.addProperty("date", aDateObj.compareTo(bDateObj));
            else if (null == aDateObj && null != bDateObj)
                data.addProperty("date", -1);
            else if (null == bDateObj && null != aDateObj)
                data.addProperty("date", 1);
            else
                data.addProperty("date", 0);

            data.add("diff", config);

        } catch (ConfigException e) {
            data.addProperty("error", e.getMessage());
            if (e.getErrorCode().equals(Error.Code.CONTEXT_SCOPE_MISMATCH))
                data.addProperty("resetContext", true);

            log.error("Compare error: " + e.getMessage());

            e.printStackTrace();
        } finally {
            store.close();
        }

        Gson gson = new Gson();
        return Response.ok(gson.toJson(data), MediaType.APPLICATION_JSON).build();
    }

    /**
     * @param aResolved
     * @param bResolved
     * @return
     */
    private List<Cmp> organize(Map<PropertyKey, Collection<Property>> aResolved,
            Map<PropertyKey, Collection<Property>> bResolved, Map<String, SecurityProfile> aSecurityProfiles,
            Map<String, SecurityProfile> bSecurityProfiles) {
        List<Cmp> data = new ArrayList<>();

        Map<String, PropertyKey> aKeys = new HashMap<>();
        Map<String, PropertyKey> bKeys = new HashMap<>();

        for (PropertyKey key : aResolved.keySet())
            aKeys.put(key.getKey(), key);

        for (PropertyKey key : bResolved.keySet())
            bKeys.put(key.getKey(), key);

        for (String keyString : aKeys.keySet()) {
            PropertyKey aKey, bKey;
            Collection<Property> aProps = null, bProps = null;

            aKey = aKeys.get(keyString);
            bKey = bKeys.remove(keyString);

            if (null != aKey)
                aProps = aResolved.get(aKey);
            if (null != bKey)
                bProps = bResolved.get(bKey);

            data.add(new Cmp(keyString, aKey, bKey, aProps, bProps, aSecurityProfiles.get(keyString),
                    bSecurityProfiles.get(keyString)));
        }

        for (String keyString : bKeys.keySet()) {
            PropertyKey bKey = bKeys.get(keyString);
            data.add(new Cmp(keyString, null, bKey, null, bResolved.get(bKey), aSecurityProfiles.get(keyString),
                    bSecurityProfiles.get(keyString)));
        }

        return data;
    }

    /**
     *
     */
    private class Cmp {
        private final PropertyKey aKey, bKey;
        private final Collection<Property> aProps, bProps;
        private final String keyString;
        private final SecurityProfile aSp;
        private final SecurityProfile bSp;

        public Cmp(String keyString, PropertyKey aKey, PropertyKey bKey, Collection<Property> aProps,
                Collection<Property> bProps, SecurityProfile aSp, SecurityProfile bSp) {
            this.keyString = keyString;
            this.aKey = aKey;
            this.bKey = bKey;
            this.aProps = aProps;
            this.bProps = bProps;
            this.aSp = aSp;
            this.bSp = bSp;
        }

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append("--------\n");
            sb.append("aKey: " + aKey + "\n");
            sb.append("bKey: " + bKey + "\n");
            sb.append("-- props --\n");
            if (null != aProps) {
                for (Property p : aProps)
                    sb.append(" ap: " + p + "\n");
            }

            if (null != bProps) {
                for (Property p : bProps)
                    sb.append(" bp: " + p + "\n");
            }

            return sb.toString();
        }

        public JsonObject toJson(final Repository aRepo, final Repository bRepo,
                final AccessRuleWrapper accessRuleWrapper, boolean diffOnly, boolean allValues) {
            JsonObject json = new JsonObject();

            JsonArray propertiesJson = new JsonArray();
            boolean hasDiff = false;

            // ToDo, if two properties' contexts are only different in the
            // depth that is different as per specified search contexts, then
            // show these on the same line, highlighted
            //
            // i.e.
            // Searching for:
            // A: foo, DEV,  bar
            // B: foo, PROD, bar
            //
            // properties with these contexts should be on the same line

            // Define property pairs
            if (null == aProps) {
                for (Property bProp : bProps) {
                    JsonObject pairJson = new JsonObject();

                    pairJson.addProperty("score", bProp.getContextWeight());
                    pairJson.add("2", GsonHelper.propertyToGSON(bRepo, bProp, accessRuleWrapper,
                            bSp /* SecurityProfile*/, null, null)); // ep
                    pairJson.addProperty("diff", -1);
                    hasDiff = true;
                    propertiesJson.add(pairJson);
                }
            } else if (null == bProps) {
                for (Property aProp : aProps) {
                    JsonObject pairJson = new JsonObject();

                    pairJson.addProperty("score", aProp.getContextWeight());
                    pairJson.add("0", GsonHelper.propertyToGSON(aRepo, aProp, accessRuleWrapper,
                            aSp /* SecurityProfile*/, null, null)); // ep
                    pairJson.addProperty("diff", -1);
                    hasDiff = true;
                    propertiesJson.add(pairJson);
                }
            } else {
                for (Property aProp : aProps) {
                    JsonObject pairJson = new JsonObject();

                    pairJson.addProperty("score", aProp.getContextWeight());
                    pairJson.add("0", GsonHelper.propertyToGSON(aRepo, aProp, accessRuleWrapper,
                            aSp /* SecurityProfile*/, null, null)); // ep

                    Iterator<Property> bPropsI = bProps.iterator();
                    int diff = -1;
                    while (bPropsI.hasNext()) {
                        Property bProp = bPropsI.next();
                        if (Utils.equal(aProp.getContextJson(), bProp.getContextJson())) {
                            // ToDo if same, just add one

                            boolean equal;

                            if (allValues)
                                equal = Utils.same(aProp.getValue(), bProp.getValue())
                                        && aProp.isActive() == bProp.isActive()
                                        && Utils.equal(aProp.type, bProp.type);
                            else
                                equal = Utils.same(aProp.getValue(), bProp.getValue())
                                        && aProp.isActive() == bProp.isActive();

                            if (equal)
                                diff = 0;
                            else {
                                hasDiff = true;
                                diff = 1;
                            }

                            pairJson.add("2", GsonHelper.propertyToGSON(bRepo, bProp, accessRuleWrapper,
                                    bSp /* SecurityProfile*/, null, null));
                            bPropsI.remove();
                            break;
                        }
                    }

                    pairJson.addProperty("diff", diff);
                    propertiesJson.add(pairJson);
                }

                for (Property bProp : bProps) {
                    JsonObject pairJson = new JsonObject();

                    pairJson.addProperty("score", bProp.getContextWeight());
                    pairJson.add("2", GsonHelper.propertyToGSON(bRepo, bProp, accessRuleWrapper, bSp, null, null));
                    pairJson.addProperty("diff", -1);
                    hasDiff = true;
                    propertiesJson.add(pairJson);
                }
            }

            if (!allValues && (!hasDiff && diffOnly))
                return null;

            json.add("properties", propertiesJson);
            json.addProperty("key", keyString);

            if (null != aKey)
                json.add("0", GsonHelper.keyAttributesToGSON(aKey));

            if (null != bKey)
                json.add("2", GsonHelper.keyAttributesToGSON(bKey));

            return json;
        }
    }
}