Skip to content
This repository was archived by the owner on Sep 16, 2024. It is now read-only.

Commit 5389668

Browse files
committed
#172 Fixed issue with sorting roles
1 parent c0a66f6 commit 5389668

File tree

10 files changed

+139
-43
lines changed

10 files changed

+139
-43
lines changed

src/main/java/com/marklogic/appdeployer/command/AbstractCommand.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,9 @@ protected void storeTokenForResourceId(SaveReceipt receipt, CommandContext conte
142142

143143
protected File[] listFilesInDirectory(File dir) {
144144
File[] files = dir.listFiles(resourceFilenameFilter);
145-
Arrays.sort(files);
145+
if (files != null && files.length > 1) {
146+
Arrays.sort(files);
147+
}
146148
return files;
147149
}
148150

src/main/java/com/marklogic/appdeployer/command/security/DeployRolesCommand.java

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public DeployRolesCommand() {
3131
protected File[] listFilesInDirectory(File dir, CommandContext context) {
3232
File[] files = super.listFilesInDirectory(dir);
3333

34-
if (context.getAppConfig().isSortRolesByDependencies()) {
34+
if (context.getAppConfig().isSortRolesByDependencies() && files != null && files.length > 0) {
3535
if (logger.isInfoEnabled()) {
3636
logger.info("Sorting role files by role dependencies");
3737
}
@@ -47,6 +47,9 @@ protected File[] listFilesInDirectory(File dir, CommandContext context) {
4747

4848
protected List<RoleFile> sortFilesBasedOnRoleDependencies(File[] files, CommandContext context) {
4949
List<RoleFile> roleFiles = new ArrayList<>();
50+
if (files == null || files.length < 1) {
51+
return roleFiles;
52+
}
5053
PayloadParser parser = new PayloadParser();
5154
for (File f : files) {
5255
RoleFile rf = new RoleFile(f);
@@ -69,7 +72,12 @@ protected List<RoleFile> sortFilesBasedOnRoleDependencies(File[] files, CommandC
6972
roleFiles.add(rf);
7073
}
7174

72-
Collections.sort(roleFiles);
75+
return sortRoleFiles(roleFiles);
76+
}
77+
78+
protected List<RoleFile> sortRoleFiles(List<RoleFile> roleFiles) {
79+
RoleFileComparator comparator = new RoleFileComparator(roleFiles);
80+
Collections.sort(roleFiles, comparator);
7381
return roleFiles;
7482
}
7583

@@ -84,7 +92,7 @@ protected ResourceManager getResourceManager(CommandContext context) {
8492

8593
}
8694

87-
class RoleFile implements Comparable<RoleFile> {
95+
class RoleFile {
8896

8997
File file;
9098
Role role;
@@ -95,8 +103,77 @@ public RoleFile(File file) {
95103
this.role.setRole(new ArrayList<String>());
96104
}
97105

106+
}
107+
108+
/**
109+
* This comparator is designed to handle a scenario where two roles are next to each other, but they don't have any
110+
* dependencies in common, nor does one depend on the other. In this scenario, we need to know which role has a
111+
* dependency on a role furthest to the end of the list of roles. In order to know that, we first build up a data
112+
* structure that tracks the highest position of a dependency in the list of roles for each role.
113+
*/
114+
class RoleFileComparator implements Comparator<RoleFile> {
115+
116+
private Map<String, Integer> highestDependencyPositionMap;
117+
118+
public RoleFileComparator(List<RoleFile> roleFiles) {
119+
Map<String, Integer> rolePositions = new HashMap<>();
120+
for (int i = 0; i < roleFiles.size(); i++) {
121+
rolePositions.put(roleFiles.get(i).role.getRoleName(), i);
122+
}
123+
124+
highestDependencyPositionMap = new HashMap<>();
125+
for (RoleFile rf : roleFiles) {
126+
String roleName = rf.role.getRoleName();
127+
int highest = -1;
128+
for (String role : rf.role.getRole()) {
129+
if (rolePositions.containsKey(role)) {
130+
int pos = rolePositions.get(role);
131+
if (pos > highest) {
132+
highest = pos;
133+
}
134+
}
135+
}
136+
highestDependencyPositionMap.put(roleName, highest);
137+
}
138+
}
139+
98140
@Override
99-
public int compareTo(RoleFile o) {
100-
return this.role.compareTo(o.role);
141+
public int compare(RoleFile o1, RoleFile o2) {
142+
if (o1 == null && o2 != null) {
143+
return 1;
144+
}
145+
if (o2 == null) {
146+
return -1;
147+
}
148+
if (o1.role.getRole() == null || o1.role.getRole().isEmpty()) {
149+
return -1;
150+
}
151+
if (o2.role.getRole() == null || o2.role.getRole().isEmpty()) {
152+
return 1;
153+
}
154+
if (o2.role.getRole().contains(o1.role.getRoleName())) {
155+
return -1;
156+
}
157+
if (o1.role.getRole().contains(o2.role.getRoleName())) {
158+
return 1;
159+
}
160+
161+
/**
162+
* If the roles aren't dependent on each other, then we want to base this on which role has a dependency further
163+
* to the right.
164+
*/
165+
int o1Pos = highestDependencyPositionMap.get(o1.role.getRoleName());
166+
int o2Pos = highestDependencyPositionMap.get(o2.role.getRoleName());
167+
if (o1Pos > o2Pos) {
168+
return 1;
169+
}
170+
if (o2Pos > o1Pos) {
171+
return -1;
172+
}
173+
174+
/**
175+
* This would be for two roles that depend on the same other role.
176+
*/
177+
return 0;
101178
}
102179
}

src/main/java/com/marklogic/appdeployer/export/AbstractNamedResourceExporter.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,16 @@ protected AbstractNamedResourceExporter(ManageClient manageClient, String... res
3232

3333
@Override
3434
public ExportedResources exportResources(File baseDir) {
35-
ResourceManager mgr = newResourceManager(getManageClient());
36-
File resourceDir = getResourceDirectory(baseDir);
37-
resourceDir.mkdirs();
3835
List<File> files = new ArrayList<>();
39-
for (String resourceName : resourceNames) {
40-
File f = exportToFile(mgr, resourceName, resourceDir);
41-
if (f != null) {
42-
files.add(f);
36+
if (resourceNames != null && resourceNames.length > 0) {
37+
ResourceManager mgr = newResourceManager(getManageClient());
38+
File resourceDir = getResourceDirectory(baseDir);
39+
resourceDir.mkdirs();
40+
for (String resourceName : resourceNames) {
41+
File f = exportToFile(mgr, resourceName, resourceDir);
42+
if (f != null) {
43+
files.add(f);
44+
}
4345
}
4446
}
4547
return new ExportedResources(files, getExportMessages());

src/main/java/com/marklogic/appdeployer/export/security/RoleExporter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,6 @@ protected File getResourceDirectory(File baseDir) {
2626

2727
@Override
2828
protected String[] getExportMessages() {
29-
return new String[] {"The exported role files may need to be renamed to guarantee they are deployed in an order that respects the dependencies between them."};
29+
return new String[] {"The exported role files may have circular dependencies between them that must be resolved before they can be deployed."};
3030
}
3131
}

src/main/java/com/marklogic/mgmt/api/security/Role.java

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package com.marklogic.mgmt.api.security;
22

3-
import java.util.ArrayList;
4-
import java.util.List;
5-
63
import com.marklogic.mgmt.ResourceManager;
74
import com.marklogic.mgmt.api.API;
85
import com.marklogic.mgmt.api.Resource;
96
import com.marklogic.mgmt.security.RoleManager;
107

11-
public class Role extends Resource implements Comparable<Role> {
8+
import java.util.ArrayList;
9+
import java.util.List;
10+
11+
public class Role extends Resource {
1212

1313
private String roleName;
1414
private String description;
@@ -27,26 +27,6 @@ public Role(API api, String roleName) {
2727
this.roleName = roleName;
2828
}
2929

30-
@Override
31-
public int compareTo(Role other) {
32-
if (other == null) {
33-
return 0;
34-
}
35-
if (this.role == null || this.role.isEmpty()) {
36-
return -1;
37-
}
38-
if (other.role == null || other.role.isEmpty()) {
39-
return 1;
40-
}
41-
if (other.role.contains(this.roleName)) {
42-
return -1;
43-
}
44-
if (this.role.contains(other.roleName)) {
45-
return 1;
46-
}
47-
return -1;
48-
}
49-
5030
public void addExternalName(String name) {
5131
if (externalName == null) {
5232
externalName = new ArrayList<>();

src/test/java/com/marklogic/appdeployer/command/security/DeployRolesWithDependenciesTest.java

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010

1111
public class DeployRolesWithDependenciesTest extends AbstractAppDeployerTest {
1212

13-
@Before
14-
public void setup() {
15-
appConfig.getConfigDir().setBaseDir(new File("src/test/resources/sample-app/roles-with-dependencies"));
16-
}
17-
13+
/**
14+
* This scenario has a mix of XML/JSON files (to verify that we parse each correctly) and a big jumble of roles.
15+
*/
1816
@Test
1917
public void testSorting() {
18+
appConfig.getConfigDir().setBaseDir(new File("src/test/resources/sample-app/roles-with-dependencies"));
19+
2020
DeployRolesCommand command = new DeployRolesCommand();
2121
File[] files = command.listFilesInDirectory(appConfig.getConfigDir().getRolesDir(),
2222
new CommandContext(appConfig, manageClient, null));
@@ -29,8 +29,27 @@ public void testSorting() {
2929
assertEquals("role0.json", files[5].getName());
3030
}
3131

32+
/**
33+
* This scenario tests that when two roles are next to each other with different dependencies - role1 and role2 -
34+
* that we figure out that role1 has a dependency on a role closest to the end of the current list of files.
35+
*/
36+
@Test
37+
public void anotherSortingTest() {
38+
appConfig.getConfigDir().setBaseDir(new File("src/test/resources/sample-app/more-roles-with-dependencies"));
39+
40+
DeployRolesCommand command = new DeployRolesCommand();
41+
File[] files = command.listFilesInDirectory(appConfig.getConfigDir().getRolesDir(),
42+
new CommandContext(appConfig, manageClient, null));
43+
44+
assertEquals("role0.json", files[0].getName());
45+
assertEquals("role2.json", files[1].getName());
46+
assertEquals("role3.json", files[2].getName());
47+
assertEquals("role1.json", files[3].getName());
48+
}
49+
3250
@Test
3351
public void test() {
52+
appConfig.getConfigDir().setBaseDir(new File("src/test/resources/sample-app/roles-with-dependencies"));
3453
initializeAppDeployer(new DeployRolesCommand());
3554

3655
try {
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"role-name" : "more-roles-role0",
3+
"role" : [ "app-user" ]
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"role-name" : "more-roles-role1",
3+
"role" : [ "more-roles-role3" ]
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"role-name" : "more-roles-role2",
3+
"role" : [ "more-roles-role0"]
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"role-name" : "more-roles-role3",
3+
"role" : [ "more-roles-role0" ]
4+
}

0 commit comments

Comments
 (0)