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

Commit 4d4d6b4

Browse files
committed
#333 TDE templates are now validated by default when loading schemas
1 parent 9832b28 commit 4d4d6b4

File tree

9 files changed

+128
-7
lines changed

9 files changed

+128
-7
lines changed

gradle.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
group=com.marklogic
22
javadocsDir=../gh-pages-marklogic-java/javadocs
3-
version=3.12.0
4-
mlJavaclientUtilVersion=3.10.0
3+
version=3.13.dev
4+
mlJavaclientUtilVersion=3.11.dev
55
mlJunitVersion=3.1.0
66

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ public class AppConfig {
125125
private boolean incrementalDeploy = false;
126126

127127
private String schemasPath;
128+
private boolean tdeValidationEnabled = true;
128129

129130
private List<ConfigDir> configDirs;
130131

@@ -1286,4 +1287,12 @@ public ReplicaBuilderStrategy getReplicaBuilderStrategy() {
12861287
public void setReplicaBuilderStrategy(ReplicaBuilderStrategy replicaBuilderStrategy) {
12871288
this.replicaBuilderStrategy = replicaBuilderStrategy;
12881289
}
1290+
1291+
public boolean isTdeValidationEnabled() {
1292+
return tdeValidationEnabled;
1293+
}
1294+
1295+
public void setTdeValidationEnabled(boolean tdeValidationEnabled) {
1296+
this.tdeValidationEnabled = tdeValidationEnabled;
1297+
}
12891298
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,11 @@ public void initialize() {
270270
config.setSchemasPath(path);
271271
});
272272

273+
propertyConsumerMap.put("mlTdeValidationEnabled", (config, prop) -> {
274+
logger.info("TDE validation enabled: " + prop);
275+
config.setTdeValidationEnabled(Boolean.parseBoolean(prop));
276+
});
277+
273278
propertyConsumerMap.put("mlSchemasDatabaseName", (config, prop) -> {
274279
logger.info("Schemas database name: " + prop);
275280
config.setSchemasDatabaseName(prop);

src/main/java/com/marklogic/appdeployer/command/schemas/LoadSchemasCommand.java

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
package com.marklogic.appdeployer.command.schemas;
22

33
import com.marklogic.appdeployer.AppConfig;
4+
import com.marklogic.appdeployer.ConfigDir;
45
import com.marklogic.appdeployer.command.AbstractCommand;
56
import com.marklogic.appdeployer.command.CommandContext;
67
import com.marklogic.appdeployer.command.SortOrderConstants;
78
import com.marklogic.client.DatabaseClient;
89
import com.marklogic.client.FailedRequestException;
910
import com.marklogic.client.ext.schemasloader.SchemasLoader;
1011
import com.marklogic.client.ext.schemasloader.impl.DefaultSchemasLoader;
12+
import com.marklogic.mgmt.api.API;
13+
import com.marklogic.mgmt.api.database.Database;
14+
import com.marklogic.mgmt.mapper.DefaultResourceMapper;
15+
import com.marklogic.mgmt.mapper.ResourceMapper;
1116

1217
import java.io.File;
1318
import java.io.FileFilter;
@@ -61,7 +66,7 @@ protected void loadSchemas(String schemasPath, String schemasDatabaseName, Comma
6166
logger.info(format("Loading schemas into database %s from: %s", schemasDatabaseName, schemasPath));
6267
DatabaseClient client = buildDatabaseClient(schemasDatabaseName, context);
6368
try {
64-
SchemasLoader schemasLoader = buildSchemasLoader(context, client);
69+
SchemasLoader schemasLoader = buildSchemasLoader(context, client, schemasDatabaseName);
6570
schemasLoader.loadSchemas(schemasPath);
6671
logger.info("Finished loading schemas from: " + schemasPath);
6772
} catch (FailedRequestException fre) {
@@ -81,18 +86,64 @@ protected DatabaseClient buildDatabaseClient(String schemasDatabaseName, Command
8186

8287
/**
8388
* Will utilize schemasFileFilter in AppConfig if it's been set.
89+
* <p>
90+
* So given a schemasDatabaseName,
8491
*
8592
* @param context
8693
* @param client
8794
* @return
8895
*/
89-
protected SchemasLoader buildSchemasLoader(CommandContext context, DatabaseClient client) {
90-
AppConfig config = context.getAppConfig();
91-
DefaultSchemasLoader schemasLoader = new DefaultSchemasLoader(client);
92-
FileFilter filter = config.getSchemasFileFilter();
96+
protected SchemasLoader buildSchemasLoader(CommandContext context, DatabaseClient client, String schemasDatabaseName) {
97+
AppConfig appConfig = context.getAppConfig();
98+
99+
String tdeValidationDatabase = null;
100+
if (appConfig.isTdeValidationEnabled()) {
101+
tdeValidationDatabase = findContentDatabaseAssociatedWithSchemasDatabase(context, schemasDatabaseName);
102+
if (tdeValidationDatabase != null) {
103+
logger.info(format("TDE templates loaded into %s will be validated against content database %s",
104+
schemasDatabaseName, tdeValidationDatabase));
105+
}
106+
} else {
107+
logger.info("TDE validation is disabled");
108+
}
109+
110+
DefaultSchemasLoader schemasLoader = new DefaultSchemasLoader(client, tdeValidationDatabase);
111+
FileFilter filter = appConfig.getSchemasFileFilter();
93112
if (filter != null) {
94113
schemasLoader.addFileFilter(filter);
95114
}
96115
return schemasLoader;
97116
}
117+
118+
/**
119+
* In order to validate a TDE template, a content database must be found that is associated with the given
120+
* schemas database. This method looks at the databases directory in each config directory and tries to find a
121+
* database resource file that defines a database associated with the given schemas database.
122+
*
123+
* @param context
124+
* @param schemasDatabaseName
125+
* @return
126+
*/
127+
protected String findContentDatabaseAssociatedWithSchemasDatabase(CommandContext context, String schemasDatabaseName) {
128+
String tdeValidationDatabase = null;
129+
ResourceMapper resourceMapper = new DefaultResourceMapper(new API(context.getManageClient()));
130+
for (ConfigDir configDir : context.getAppConfig().getConfigDirs()) {
131+
File dbDir = configDir.getDatabasesDir();
132+
if (dbDir != null && dbDir.exists()) {
133+
for (File f : listFilesInDirectory(dbDir)) {
134+
String payload = copyFileToString(f, context);
135+
try {
136+
Database db = resourceMapper.readResource(payload, Database.class);
137+
if (schemasDatabaseName.equals(db.getSchemaDatabase())) {
138+
tdeValidationDatabase = db.getDatabaseName();
139+
break;
140+
}
141+
} catch (Exception ex) {
142+
logger.warn("Unexpected error when reading database file to determine database for TDE validation: " + ex.getMessage());
143+
}
144+
}
145+
}
146+
}
147+
return tdeValidationDatabase;
148+
}
98149
}

src/test/java/com/marklogic/appdeployer/DefaultAppConfigFactoryTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ public void allProperties() {
211211
p.setProperty("mlSchemasDatabaseName", "my-schemas-db");
212212
p.setProperty("mlTriggersDatabaseName", "my-triggers-db");
213213
p.setProperty("mlSchemasPath", "/my/schemas");
214+
p.setProperty("mlTdeValidationEnabled", "false");
214215
p.setProperty("mlDeleteForests", "false");
215216
p.setProperty("mlDeleteReplicas", "false");
216217
p.setProperty("mlGroupName", "other-group");
@@ -323,6 +324,7 @@ public void allProperties() {
323324
assertEquals("my-schemas-db", config.getSchemasDatabaseName());
324325
assertEquals("my-triggers-db", config.getTriggersDatabaseName());
325326
assertEquals("/my/schemas", config.getSchemasPath());
327+
assertFalse(config.isTdeValidationEnabled());
326328
assertFalse(config.isDeleteForests());
327329
assertFalse(config.isDeleteReplicas());
328330
assertEquals("other-group", config.getGroupName());

src/test/java/com/marklogic/appdeployer/command/schemas/LoadSchemasTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ public void testCustomSchemasPathWithCustomFileFilter() {
6363

6464
appConfig.setSchemasPath("src/test/resources/schemas-marklogic9");
6565
appConfig.setSchemasFileFilter(new CustomFileFilter());
66+
appConfig.setTdeValidationEnabled(false);
6667
appDeployer.deploy(appConfig);
6768

6869
DatabaseClient client = appConfig.newSchemasDatabaseClient();
@@ -89,6 +90,20 @@ public void nullSchemaPath() {
8990
logger.info("Verifies that no error occurs when the schemas path is null");
9091
}
9192

93+
@Test
94+
public void tdeValidationEnabled() {
95+
initializeAppDeployer(new DeployOtherDatabasesCommand(), new DeployContentDatabasesCommand(1), newCommand());
96+
appConfig.getFirstConfigDir().setBaseDir(new File("src/test/resources/sample-app/tde-validation"));
97+
try {
98+
deploySampleApp();
99+
fail("The deploy should have failed because of a bad TDE template");
100+
} catch (Exception ex) {
101+
String message = ex.getCause().getMessage();
102+
assertTrue(message.startsWith("TDE template failed validation"));
103+
assertTrue(message.contains("TDE-REPEATEDCOLUMN"));
104+
}
105+
}
106+
92107
@After
93108
public void cleanup() {
94109
undeploySampleApp();
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"database-name" : "%%DATABASE%%",
3+
"schema-database": "%%SCHEMAS_DATABASE%%"
4+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"template": {
3+
"context": "/example",
4+
"description": "This is a description with quotes in it '\"",
5+
"collections": [
6+
"example"
7+
],
8+
"rows": [
9+
{
10+
"schemaName": "Example",
11+
"viewName": "default",
12+
"columns": [
13+
{
14+
"name": "Id",
15+
"scalarType": "string",
16+
"val": "Id"
17+
},
18+
{
19+
"name": "DuplicateColumn",
20+
"scalarType": "string",
21+
"val": "DuplicateColumn"
22+
},
23+
{
24+
"name": "DuplicateColumn",
25+
"scalarType": "string",
26+
"val": "DuplicateColumn"
27+
}
28+
]
29+
}
30+
]
31+
}
32+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"database-name": "%%SCHEMAS_DATABASE%%"
3+
}

0 commit comments

Comments
 (0)