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

Commit aae28c5

Browse files
committed
#65 Now processing all database files
1 parent acd3642 commit aae28c5

23 files changed

+377
-74
lines changed

src/main/java/com/marklogic/appdeployer/AppConfig.java

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public class AppConfig {
5757

5858
private String name = DEFAULT_APP_NAME;
5959
private String host = DEFAULT_HOST;
60-
60+
6161
// Username/password combo for using the client REST API - e.g. to load modules
6262
private String restAdminUsername = DEFAULT_USERNAME;
6363
private String restAdminPassword = DEFAULT_PASSWORD;
@@ -105,14 +105,16 @@ public class AppConfig {
105105
// Path to use for DeployFlexrepCommand
106106
private String flexrepPath;
107107

108-
public AppConfig() {
108+
private Map<String, Integer> forestCounts = new HashMap<>();
109+
110+
public AppConfig() {
109111
this(DEFAULT_MODULES_PATH, DEFAULT_SCHEMAS_PATH);
110112
}
111113

112-
public AppConfig(String defaultModulePath) {
113-
this(defaultModulePath, DEFAULT_SCHEMAS_PATH);
114-
}
115-
114+
public AppConfig(String defaultModulePath) {
115+
this(defaultModulePath, DEFAULT_SCHEMAS_PATH);
116+
}
117+
116118
public AppConfig(String defaultModulePath, String defaultSchemasPath) {
117119
modulePaths = new ArrayList<String>();
118120
modulePaths.add(defaultModulePath);
@@ -145,18 +147,17 @@ public DatabaseClient newTestDatabaseClient() {
145147
return DatabaseClientFactory.newClient(getHost(), getTestRestPort(), getRestAdminUsername(),
146148
getRestAdminPassword(), getRestAuthentication(), getRestSslContext(), getRestSslHostnameVerifier());
147149
}
148-
150+
149151
/**
150152
* Like newDatabaseClient, but connects to schemas database.
151153
*
152154
* @return
153155
*/
154-
public DatabaseClient newSchemasDatabaseClient() {
155-
return DatabaseClientFactory.newClient(getHost(), getRestPort(), getSchemasDatabaseName(),
156-
getRestAdminUsername(), getRestAdminPassword(), getRestAuthentication(),
157-
getRestSslContext(), getRestSslHostnameVerifier());
158-
}
159-
156+
public DatabaseClient newSchemasDatabaseClient() {
157+
return DatabaseClientFactory.newClient(getHost(), getRestPort(), getSchemasDatabaseName(),
158+
getRestAdminUsername(), getRestAdminPassword(), getRestAuthentication(), getRestSslContext(),
159+
getRestSslHostnameVerifier());
160+
}
160161

161162
/**
162163
* @return an XccAssetLoader based on the configuration properties in this class
@@ -247,7 +248,7 @@ public String getTriggersDatabaseName() {
247248
public String getSchemasDatabaseName() {
248249
return schemasDatabaseName != null ? schemasDatabaseName : name + "-schemas";
249250
}
250-
251+
251252
/**
252253
* @return the name of the application, which is then used to generate app server and database names unless those
253254
* are set via their respective properties
@@ -499,4 +500,12 @@ public String getFlexrepPath() {
499500
public void setFlexrepPath(String flexrepPath) {
500501
this.flexrepPath = flexrepPath;
501502
}
503+
504+
public Map<String, Integer> getForestCounts() {
505+
return forestCounts;
506+
}
507+
508+
public void setForestCounts(Map<String, Integer> forestCounts) {
509+
this.forestCounts = forestCounts;
510+
}
502511
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ public ResourceFilenameFilter(Set<String> filenamesToIgnore) {
3131
@Override
3232
public boolean accept(File dir, String name) {
3333
if (filenamesToIgnore != null && filenamesToIgnore.contains(name)) {
34-
if (logger.isInfoEnabled()) {
35-
logger.info("Ignoring filename: " + name);
34+
if (logger.isDebugEnabled()) {
35+
logger.debug("Ignoring filename: " + name);
3636
}
3737
return false;
3838
}

src/main/java/com/marklogic/appdeployer/command/databases/DeployContentDatabasesCommand.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public void execute(CommandContext context) {
5151
DatabaseManager dbMgr = new DatabaseManager(context.getManageClient());
5252
String json = tokenReplacer.replaceTokens(payload, appConfig, true);
5353
SaveReceipt receipt = dbMgr.save(json);
54-
buildDeployForestsCommand(receipt, context).execute(context);
54+
buildDeployForestsCommand(payload, receipt, context).execute(context);
5555
}
5656
}
5757
}

src/main/java/com/marklogic/appdeployer/command/databases/DeployDatabaseCommand.java

Lines changed: 65 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
package com.marklogic.appdeployer.command.databases;
22

33
import java.io.File;
4+
import java.util.Map;
45

5-
import com.marklogic.appdeployer.AppConfig;
66
import com.marklogic.appdeployer.command.AbstractCommand;
77
import com.marklogic.appdeployer.command.CommandContext;
88
import com.marklogic.appdeployer.command.SortOrderConstants;
99
import com.marklogic.appdeployer.command.UndoableCommand;
1010
import com.marklogic.appdeployer.command.forests.DeployForestsCommand;
11+
import com.marklogic.mgmt.PayloadParser;
1112
import com.marklogic.mgmt.SaveReceipt;
1213
import com.marklogic.mgmt.databases.DatabaseManager;
1314

@@ -29,8 +30,8 @@ public class DeployDatabaseCommand extends AbstractCommand implements UndoableCo
2930
private boolean createDatabaseWithoutFile = false;
3031

3132
/**
32-
* The name of the database to be deployed; used for constructing forest names, and thus required if you're creating
33-
* forests.
33+
* The name of the database to be deployed; only needs to be set if the database payload is automatically generated
34+
* instead of being loaded from a file.
3435
*/
3536
private String databaseName;
3637

@@ -67,36 +68,55 @@ public DeployDatabaseCommand(String databaseFilename) {
6768
this();
6869
this.databaseFilename = databaseFilename;
6970
}
70-
71+
72+
@Override
73+
public String toString() {
74+
return databaseFilename;
75+
}
76+
7177
@Override
7278
public Integer getUndoSortOrder() {
7379
return undoSortOrder;
7480
}
7581

7682
@Override
7783
public void execute(CommandContext context) {
78-
AppConfig appConfig = context.getAppConfig();
79-
String payload = getPayload(context);
84+
String payload = buildPayload(context);
8085
if (payload != null) {
81-
String json = tokenReplacer.replaceTokens(payload, appConfig, false);
8286
DatabaseManager dbMgr = new DatabaseManager(context.getManageClient());
83-
SaveReceipt receipt = dbMgr.save(json);
84-
buildDeployForestsCommand(receipt, context).execute(context);
87+
SaveReceipt receipt = dbMgr.save(payload);
88+
buildDeployForestsCommand(payload, receipt, context).execute(context);
8589
}
8690
}
8791

8892
@Override
8993
public void undo(CommandContext context) {
90-
AppConfig appConfig = context.getAppConfig();
91-
String payload = getPayload(context);
94+
String payload = buildPayload(context);
9295
if (payload != null) {
93-
String json = tokenReplacer.replaceTokens(payload, appConfig, false);
9496
DatabaseManager dbMgr = new DatabaseManager(context.getManageClient());
9597
dbMgr.setForestDelete(forestDelete);
96-
dbMgr.delete(json);
98+
dbMgr.delete(payload);
9799
}
98100
}
99101

102+
/**
103+
* Builds the XML or JSON payload for this command, based on the given CommandContext.
104+
*
105+
* @param context
106+
* @return
107+
*/
108+
public String buildPayload(CommandContext context) {
109+
String payload = getPayload(context);
110+
return payload != null ? tokenReplacer.replaceTokens(payload, context.getAppConfig(), false) : null;
111+
}
112+
113+
/**
114+
* Get the payload based on the given CommandContext. Only loads the payload, does not replace any tokens in it.
115+
* Call buildPayload to construct a payload with all tokens replaced.
116+
*
117+
* @param context
118+
* @return
119+
*/
100120
protected String getPayload(CommandContext context) {
101121
File f = null;
102122
if (databaseFilename != null) {
@@ -117,20 +137,50 @@ protected String getPayload(CommandContext context) {
117137
/**
118138
* Allows for how an instance of DeployForestsCommand is built to be overridden by a subclass.
119139
*
140+
* @param dbPayload
141+
* Needed so we can look up forest counts based on the database name
120142
* @param receipt
121143
* @param context
122144
* @return
123145
*/
124-
protected DeployForestsCommand buildDeployForestsCommand(SaveReceipt receipt, CommandContext context) {
146+
protected DeployForestsCommand buildDeployForestsCommand(String dbPayload, SaveReceipt receipt,
147+
CommandContext context) {
125148
DeployForestsCommand c = new DeployForestsCommand();
126149
c.setCreateForestsOnEachHost(createForestsOnEachHost);
127-
c.setForestsPerHost(forestsPerHost);
150+
c.setForestsPerHost(determineForestCountPerHost(dbPayload, context));
128151
c.setForestFilename(forestFilename);
129152
c.setDatabaseName(receipt.getResourceId());
130153
c.setForestPayload(DeployForestsCommand.DEFAULT_FOREST_PAYLOAD);
131154
return c;
132155
}
133156

157+
/**
158+
* Checks the forestCounts map in AppConfig to see if the client has specified a number of forests per host for this
159+
* database.
160+
*
161+
* @param dbPayload
162+
* @param context
163+
* @return
164+
*/
165+
protected int determineForestCountPerHost(String dbPayload, CommandContext context) {
166+
int forestCount = forestsPerHost;
167+
if (dbPayload != null) {
168+
try {
169+
String dbName = new PayloadParser().getPayloadFieldValue(dbPayload, "database-name");
170+
Map<String, Integer> forestCounts = context.getAppConfig().getForestCounts();
171+
if (forestCounts != null && forestCounts.containsKey(dbName)) {
172+
Integer i = forestCounts.get(dbName);
173+
if (i != null) {
174+
forestCount = i;
175+
}
176+
}
177+
} catch (Exception ex) {
178+
logger.warn("Unable to determine forest counts, cause: " + ex.getMessage(), ex);
179+
}
180+
}
181+
return forestCount;
182+
}
183+
134184
protected String buildDefaultDatabasePayload(CommandContext context) {
135185
return format("{\"database-name\": \"%s\"}", databaseName);
136186
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.marklogic.appdeployer.command.databases;
2+
3+
import java.util.Comparator;
4+
5+
import com.marklogic.appdeployer.command.CommandContext;
6+
import com.marklogic.client.helper.LoggingObject;
7+
8+
/**
9+
* Used for sorting instances of DeployDatabaseCommand so that databases are created in a correct order - i.e. an order
10+
* in which we don't get errors from databases being created before their dependent databases are created.
11+
*/
12+
public class DeployDatabaseCommandComparator extends LoggingObject implements Comparator<DeployDatabaseCommand> {
13+
14+
private CommandContext context;
15+
private boolean reverseOrder = false;
16+
17+
public DeployDatabaseCommandComparator(CommandContext context, boolean reverseOrder) {
18+
this.context = context;
19+
this.reverseOrder = reverseOrder;
20+
}
21+
22+
@Override
23+
public int compare(DeployDatabaseCommand o1, DeployDatabaseCommand o2) {
24+
String p1 = o1.buildPayload(context);
25+
String p2 = o2.buildPayload(context);
26+
if (p1 == null || p2 == null) {
27+
return 0;
28+
}
29+
30+
boolean b1 = payloadDependsOnOtherDatabase(p1);
31+
boolean b2 = payloadDependsOnOtherDatabase(p2);
32+
if (b1 && !b2) {
33+
return reverseOrder ? -1 : 1;
34+
}
35+
if (b2 && !b1) {
36+
return reverseOrder ? 1 : -1;
37+
}
38+
return 0;
39+
}
40+
41+
/**
42+
* If the payload has a triggers-database or schemas-database, we consider it to depend on some other database. We
43+
* don't check for a security database yet, as it's very rare to use a custom security database.
44+
*
45+
* @param payload
46+
* @return
47+
*/
48+
protected boolean payloadDependsOnOtherDatabase(String payload) {
49+
return payload.contains("triggers-database") || payload.contains("schema-database");
50+
}
51+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package com.marklogic.appdeployer.command.databases;
2+
3+
import java.io.File;
4+
import java.util.ArrayList;
5+
import java.util.Collections;
6+
import java.util.HashSet;
7+
import java.util.List;
8+
import java.util.Set;
9+
10+
import com.marklogic.appdeployer.ConfigDir;
11+
import com.marklogic.appdeployer.command.AbstractUndoableCommand;
12+
import com.marklogic.appdeployer.command.CommandContext;
13+
import com.marklogic.appdeployer.command.ResourceFilenameFilter;
14+
import com.marklogic.appdeployer.command.SortOrderConstants;
15+
16+
/**
17+
* This commands handles deploying/undeploying every database file except the "default" ones of content-database.json,
18+
* triggers-database.json, and schemas-database.json. Those default ones are supported for ease-of-use, but it's not
19+
* uncommon to need to create additional databases (and perhaps REST API servers to go with them).
20+
* <p>
21+
* A key aspect of this class is its attempt to deploy/undeploy databases in the correct order. For each database file
22+
* that it finds that's not one of the default ones, a DeployDatabaseCommand will be created. All of those commands will
23+
* then be sorted based on the presence of "triggers-database" or "schema-database" within the payload for the command.
24+
* <p>
25+
* If the above strategy doesn't work for you, you can always resort to naming your database files to control the order
26+
* that they're processed in.
27+
* </p>
28+
*/
29+
public class DeployOtherDatabasesCommand extends AbstractUndoableCommand {
30+
31+
public DeployOtherDatabasesCommand() {
32+
setExecuteSortOrder(SortOrderConstants.DEPLOY_OTHER_DATABASES);
33+
setUndoSortOrder(SortOrderConstants.DELETE_OTHER_DATABASES);
34+
}
35+
36+
@Override
37+
public void execute(CommandContext context) {
38+
List<DeployDatabaseCommand> list = buildDatabaseCommands(context);
39+
sortCommandsBeforeExecute(list, context);
40+
for (DeployDatabaseCommand c : list) {
41+
c.execute(context);
42+
}
43+
}
44+
45+
protected void sortCommandsBeforeExecute(List<DeployDatabaseCommand> list, CommandContext context) {
46+
Collections.sort(list, new DeployDatabaseCommandComparator(context, false));
47+
}
48+
49+
@Override
50+
public void undo(CommandContext context) {
51+
List<DeployDatabaseCommand> list = buildDatabaseCommands(context);
52+
sortCommandsBeforeUndo(list, context);
53+
for (DeployDatabaseCommand c : list) {
54+
c.undo(context);
55+
}
56+
}
57+
58+
protected void sortCommandsBeforeUndo(List<DeployDatabaseCommand> list, CommandContext context) {
59+
Collections.sort(list, new DeployDatabaseCommandComparator(context, true));
60+
}
61+
62+
protected List<DeployDatabaseCommand> buildDatabaseCommands(CommandContext context) {
63+
List<DeployDatabaseCommand> dbCommands = new ArrayList<>();
64+
65+
ConfigDir configDir = context.getAppConfig().getConfigDir();
66+
File dir = configDir.getDatabasesDir();
67+
if (dir != null && dir.exists()) {
68+
Set<String> ignore = new HashSet<>();
69+
for (File f : configDir.getContentDatabaseFiles()) {
70+
ignore.add(f.getName());
71+
}
72+
ignore.add(DeploySchemasDatabaseCommand.DATABASE_FILENAME);
73+
ignore.add(DeployTriggersDatabaseCommand.DATABASE_FILENAME);
74+
75+
ResourceFilenameFilter filter = new ResourceFilenameFilter(ignore);
76+
setResourceFilenameFilter(filter);
77+
78+
for (File f : listFilesInDirectory(dir)) {
79+
if (logger.isDebugEnabled()) {
80+
logger.debug("Will process other database in file: " + f.getName());
81+
}
82+
DeployDatabaseCommand c = new DeployDatabaseCommand();
83+
c.setDatabaseFilename(f.getName());
84+
dbCommands.add(c);
85+
}
86+
}
87+
return dbCommands;
88+
}
89+
}

0 commit comments

Comments
 (0)