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

com.marklogic.mgmt.api.security.RoleObjectNodesSorter Maven / Gradle / Ivy

Go to download

Java client for the MarkLogic REST Management API and for deploying applications to MarkLogic

There is a newer version: 5.0.0
Show newest version
/*
 * Copyright (c) 2023 MarkLogic Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.marklogic.mgmt.api.security;

import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.marklogic.mgmt.util.ObjectMapperFactory;
import com.marklogic.mgmt.util.ObjectNodesSorter;
import com.marklogic.mgmt.util.TopologicalSorter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class RoleObjectNodesSorter implements ObjectNodesSorter {

	/**
	 * Return a new list of object nodes, sorted based on the dependencies of each role.
	 *
	 * @param objectNodes
	 * @return
	 */
	@Override
	public List sortObjectNodes(List objectNodes) {
		// Construct a list of roles so they can be sorted
		List roles = new ArrayList<>();

		// Construct a map of roles to object nodes so that the original object nodes can be added to the list.
		// This is to resolve bug #441, where capability-query's are being dropped because the Role class doesn't
		// support them. It may be better to refactor this to not deserialize into Role instances so that ObjectNodes
		// are used the entire time, even though we'd lose some of the convenience methods provided by the Role class.
		final Map roleMap = new HashMap();

		ObjectReader reader = ObjectMapperFactory.getObjectMapper().readerFor(Role.class);
		for (ObjectNode objectNode : objectNodes) {
			try {
				Role role = reader.readValue(objectNode);
				roles.add(role);
				roleMap.put(role.getRoleName(), objectNode);
			} catch (IOException e) {
				throw new RuntimeException("Unable to read ObjectNode into Role; JSON: " + objectNode, e);
			}
		}

		roles = sortRoles(roles);

		List sortedNodes = new ArrayList<>();
		roles.forEach(role -> {
			// Sanity check; we don't ever expect to get back a role in the sorted list that isn't in the roleMap
			if (roleMap.containsKey(role.getRoleName())) {
				sortedNodes.add(roleMap.get(role.getRoleName()));
			}
		});
		return sortedNodes;
	}


	/**
	 * Performs a topological sort to sort the list of roles. Ignores two kinds of dependencies - a dependency on a
	 * role that's not in the list (such a role is assumed to exist in MarkLogic already), and a dependency on the
	 * role itself. The latter is assumed to be addressed by creating the role without any dependencies first.
	 * 

* Public so that a client can use it when they have a list of Role objects instead of ObjectNode objects. * * @param roles * @return */ public List sortRoles(List roles) { final int count = roles.size(); final TopologicalSorter sorter = new TopologicalSorter(count); final List roleNames = new ArrayList<>(); final Map map = new HashMap<>(); roles.forEach(role -> { sorter.addVertex(role.getRoleName()); roleNames.add(role.getRoleName()); map.put(role.getRoleName(), role); }); for (int i = 0; i < count; i++) { for (String dependency : roles.get(i).getDependentRoleNames()) { int index = roleNames.indexOf(dependency); // If the role has a dependency on itself, ignore it. It is assumed that the role will first be // created without any roles or permissions. if (index == i) { continue; } // If it's not in the list of roles to create, it must already exist, and thus we don't need to // worry about it else if (index > -1) { sorter.addEdge(index, i); } } } String[] sortedRoleNames; try { sortedRoleNames = sorter.sort(); } catch (IllegalStateException ex) { throw new IllegalArgumentException("Unable to deploy roles due to circular dependencies " + "between two or more roles; please remove these circular dependencies in order to deploy" + " your roles"); } roles = new ArrayList<>(); for (String name : sortedRoleNames) { roles.add(map.get(name)); } return roles; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy