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

Commit fc1c56e

Browse files
authored
Merge pull request #288 from marklogic-community/feature/287-mimetypes
#287 Don't update mimetype if its properties have not changed
2 parents 62e165c + 321f9a8 commit fc1c56e

File tree

11 files changed

+303
-23
lines changed

11 files changed

+303
-23
lines changed

build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ dependencies {
2121
compile 'org.apache.httpcomponents:httpclient:4.3.5'
2222
compile 'org.springframework:spring-web:4.3.5.RELEASE'
2323

24+
// For EqualsBuilder; added in 3.8.1 to support detecting if a mimetype's properties have changed or not
25+
compile "org.apache.commons:commons-lang3:3.7"
26+
2427
// Don't want to include this in the published jar, just the executable jar
2528
compileOnly "com.beust:jcommander:1.72"
2629

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,8 @@ public class AppConfig {
216216
// Properties to include in resource payloads
217217
private String[] includeProperties;
218218

219+
private boolean updateMimetypeWhenPropertiesAreEqual = false;
220+
219221
private Map<String, Object> additionalProperties = new HashMap<>();
220222

221223
public AppConfig() {
@@ -1216,4 +1218,12 @@ public boolean isOptimizeWithCma() {
12161218
public void setOptimizeWithCma(boolean optimizeWithCma) {
12171219
this.optimizeWithCma = optimizeWithCma;
12181220
}
1221+
1222+
public boolean isUpdateMimetypeWhenPropertiesAreEqual() {
1223+
return updateMimetypeWhenPropertiesAreEqual;
1224+
}
1225+
1226+
public void setUpdateMimetypeWhenPropertiesAreEqual(boolean updateMimetypeWhenPropertiesAreEqual) {
1227+
this.updateMimetypeWhenPropertiesAreEqual = updateMimetypeWhenPropertiesAreEqual;
1228+
}
12191229
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,11 @@ public void initialize() {
625625
logger.info("Will include only these properties in all resource payloads: " + Arrays.asList(values));
626626
config.setIncludeProperties(values);
627627
});
628+
629+
propertyConsumerMap.put("mlUpdateMimetypeWhenPropertiesAreEqual", (config, prop) -> {
630+
logger.info("Update mimetype when properties are equal (defaults to false to avoid unnecessary ML restarts): " + prop);
631+
config.setUpdateMimetypeWhenPropertiesAreEqual(Boolean.parseBoolean(prop));
632+
});
628633
}
629634

630635
@Override

src/main/java/com/marklogic/appdeployer/command/mimetypes/DeployMimetypesCommand.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,27 @@ protected File[] getResourceDirs(CommandContext context) {
2424

2525
@Override
2626
protected ResourceManager getResourceManager(CommandContext context) {
27-
return new MimetypeManager(context.getManageClient());
27+
MimetypeManager mgr = new MimetypeManager(context.getManageClient());
28+
if (context.getAppConfig().isUpdateMimetypeWhenPropertiesAreEqual()) {
29+
mgr.setUpdateWhenPropertiesAreEqual(true);
30+
} else {
31+
mgr.setUpdateWhenPropertiesAreEqual(false);
32+
}
33+
return mgr;
2834
}
2935

3036
/**
3137
* As of ML 8.0-4, any time a mimetype is created or updated, ML must be restarted.
38+
*
39+
* In ml-app-deployer 3.8.1 though, a restart won't occur on an update if the mimetype properties have not changed.
3240
*/
3341
@Override
3442
protected void afterResourceSaved(ResourceManager mgr, CommandContext context, File resourceFile,
3543
SaveReceipt receipt) {
36-
logger.info("Waiting for restart after saving mimetype");
37-
context.getAdminManager().waitForRestart();
44+
if (receipt != null && receipt.hasLocationHeader()) {
45+
logger.info("Waiting for restart after saving mimetype");
46+
context.getAdminManager().waitForRestart();
47+
}
3848
}
3949

4050
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package com.marklogic.mgmt.api.mimetypes;
2+
3+
import com.marklogic.mgmt.api.Resource;
4+
import com.marklogic.mgmt.resource.ResourceManager;
5+
import com.marklogic.mgmt.resource.mimetypes.MimetypeManager;
6+
import org.apache.commons.lang3.builder.EqualsBuilder;
7+
8+
import javax.xml.bind.annotation.*;
9+
import java.util.Arrays;
10+
import java.util.HashSet;
11+
import java.util.Set;
12+
13+
@XmlRootElement(name = "mimetype-properties")
14+
@XmlAccessorType(XmlAccessType.FIELD)
15+
public class Mimetype extends Resource {
16+
17+
private String name;
18+
19+
@XmlElementWrapper(name = "extensions")
20+
@XmlElement(name = "extension")
21+
private Set<String> extension;
22+
23+
private String format;
24+
25+
public Mimetype() {
26+
super();
27+
}
28+
29+
public Mimetype(String name, String format, String... extensions) {
30+
this();
31+
this.name = name;
32+
this.format = format;
33+
this.extension = new HashSet<>();
34+
this.extension.addAll(Arrays.asList(extensions));
35+
}
36+
37+
@Override
38+
public boolean equals(Object obj) {
39+
if (obj == null) {
40+
return false;
41+
}
42+
if (!(obj instanceof Mimetype)) {
43+
return false;
44+
}
45+
46+
Mimetype other = (Mimetype) obj;
47+
return new EqualsBuilder()
48+
.append(this.name, other.name)
49+
.append(this.extension, other.extension)
50+
.append(this.format, other.format)
51+
.isEquals();
52+
}
53+
54+
@Override
55+
protected ResourceManager getResourceManager() {
56+
return new MimetypeManager(getClient());
57+
}
58+
59+
@Override
60+
protected String getResourceId() {
61+
return name;
62+
}
63+
64+
public String getName() {
65+
return name;
66+
}
67+
68+
public void setName(String name) {
69+
this.name = name;
70+
}
71+
72+
public Set<String> getExtension() {
73+
return extension;
74+
}
75+
76+
public void setExtension(Set<String> extension) {
77+
this.extension = extension;
78+
}
79+
80+
public String getFormat() {
81+
return format;
82+
}
83+
84+
public void setFormat(String format) {
85+
this.format = format;
86+
}
87+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
@XmlSchema(
2+
namespace = "http://marklogic.com/manage",
3+
elementFormDefault = XmlNsForm.QUALIFIED,
4+
xmlns = {
5+
@XmlNs(prefix = "m", namespaceURI = "http://marklogic.com/manage")
6+
}
7+
)
8+
package com.marklogic.mgmt.api.mimetypes;
9+
10+
import javax.xml.bind.annotation.XmlNs;
11+
import javax.xml.bind.annotation.XmlNsForm;
12+
import javax.xml.bind.annotation.XmlSchema;
Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,75 @@
11
package com.marklogic.mgmt.resource.mimetypes;
22

3-
import com.marklogic.mgmt.resource.AbstractResourceManager;
43
import com.marklogic.mgmt.ManageClient;
4+
import com.marklogic.mgmt.SaveReceipt;
5+
import com.marklogic.mgmt.api.API;
6+
import com.marklogic.mgmt.api.mimetypes.Mimetype;
7+
import com.marklogic.mgmt.mapper.DefaultResourceMapper;
8+
import com.marklogic.mgmt.mapper.ResourceMapper;
9+
import com.marklogic.mgmt.resource.AbstractResourceManager;
510

611
public class MimetypeManager extends AbstractResourceManager {
712

8-
public MimetypeManager(ManageClient client) {
9-
super(client);
10-
}
13+
private boolean updateWhenPropertiesAreEqual = false;
14+
private ResourceMapper resourceMapper;
15+
16+
public MimetypeManager(ManageClient client) {
17+
super(client);
18+
}
19+
20+
@Override
21+
protected String getIdFieldName() {
22+
return "name";
23+
}
24+
25+
/**
26+
* To avoid ML restarting when a mimetype exists but its properties aren't being changed by the incoming payload,
27+
* this method is overridden so a check can be made to see if the properties are different from what's already in
28+
* MarkLogic.
29+
* <p>
30+
* This behavior can be disabled by setting updateWhenPropertiesAreEqual to true.
31+
*
32+
* @param payload
33+
* @param resourceId
34+
* @return
35+
*/
36+
@Override
37+
public SaveReceipt updateResource(String payload, String resourceId) {
38+
if (updateWhenPropertiesAreEqual) {
39+
if (logger.isDebugEnabled()) {
40+
logger.debug(format("updateWhenPropertiesAreEqual is set to true, so mimetype %s will be updated based on the " +
41+
"incoming payload regardless of whether its properties differ from what's already set in MarkLogic or not", resourceId));
42+
}
43+
return super.updateResource(payload, resourceId);
44+
}
45+
46+
if (resourceMapper == null) {
47+
resourceMapper = new DefaultResourceMapper(new API(getManageClient()));
48+
}
49+
50+
Mimetype incomingMimetype = resourceMapper.readResource(payload, Mimetype.class);
51+
final String name = incomingMimetype.getName();
52+
53+
String existingJson = super.getPropertiesAsJson(name);
54+
Mimetype existingMimetype = resourceMapper.readResource(existingJson, Mimetype.class);
55+
56+
if (incomingMimetype.equals(existingMimetype)) {
57+
logger.info(format("The properties in the payload for mimetype %s are the same as what's already set in " +
58+
"MarkLogic, so the mimetype will not be updated", name));
59+
return new SaveReceipt(name, payload, null, null);
60+
}
61+
else {
62+
logger.info(format("The properties in the payload for mimetype %s differ from what's already set in MarkLogic, " +
63+
"so the mimetype will be updated", name));
64+
return super.updateResource(payload, resourceId);
65+
}
66+
}
1167

12-
@Override
13-
protected String getIdFieldName() {
14-
return "name";
15-
}
68+
public void setUpdateWhenPropertiesAreEqual(boolean updateWhenPropertiesAreEqual) {
69+
this.updateWhenPropertiesAreEqual = updateWhenPropertiesAreEqual;
70+
}
1671

72+
public void setResourceMapper(ResourceMapper resourceMapper) {
73+
this.resourceMapper = resourceMapper;
74+
}
1775
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@ public void allProperties() {
197197

198198
p.setProperty("mlHostGroups", "host1,Default,host2,other-group");
199199

200+
p.setProperty("mlUpdateMimetypeWhenPropertiesAreEqual", "true");
201+
200202
sut = new DefaultAppConfigFactory(new SimplePropertySource(p));
201203
AppConfig config = sut.newAppConfig();
202204

@@ -344,6 +346,8 @@ public void allProperties() {
344346
map = config.getHostGroups();
345347
assertEquals("Default", map.get("host1"));
346348
assertEquals("other-group", map.get("host2"));
349+
350+
assertTrue(config.isUpdateMimetypeWhenPropertiesAreEqual());
347351
}
348352

349353
/**
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.marklogic.appdeployer.command.mimetypes;
2+
3+
import com.marklogic.appdeployer.AbstractAppDeployerTest;
4+
import com.marklogic.mgmt.SaveReceipt;
5+
import com.marklogic.mgmt.resource.mimetypes.MimetypeManager;
6+
import org.junit.After;
7+
import org.junit.Test;
8+
9+
public class DontRestartWhenMimetypePropertiesArentUpdatedTest extends AbstractAppDeployerTest {
10+
11+
private MimetypeManager mimetypeManager;
12+
13+
@After
14+
public void teardown() {
15+
mimetypeManager.deleteByIdField("application/ditamap+xml");
16+
assertFalse(mimetypeManager.exists("application/ditamap+xml"));
17+
}
18+
19+
@Test
20+
public void test() {
21+
mimetypeManager = new MimetypeManager(manageClient);
22+
23+
initializeAppDeployer(new DeployMimetypesCommand());
24+
25+
deploySampleApp();
26+
27+
// Deploy again, though we don't have a good way of asserting that ML didn't restart; can check the logs
28+
appConfig.setUpdateMimetypeWhenPropertiesAreEqual(true);
29+
deploySampleApp();
30+
31+
// But we can verify that MimetypeManager doesn't cause an update
32+
String payload = readTestResource("sample-app/src/main/ml-config/mimetypes/ditamap.json");
33+
34+
SaveReceipt receipt = mimetypeManager.save(payload);
35+
assertNull("The response should be null since no call was made to the Manage API since the mimetype " +
36+
"properties weren't updated", receipt.getResponse());
37+
assertFalse(receipt.hasLocationHeader());
38+
39+
// Make sure XML works too
40+
payload = "<mimetype-properties xmlns='http://marklogic.com/manage'>\n" +
41+
" <name>application/ditamap+xml</name>\n" +
42+
" <extensions>\n" +
43+
" <extension>ditamap</extension>\n" +
44+
" </extensions>\n" +
45+
" <format>xml</format>\n" +
46+
"</mimetype-properties>";
47+
receipt = mimetypeManager.save(payload);
48+
assertNull("The response should be null since no call was made to the Manage API since the mimetype " +
49+
"properties weren't updated", receipt.getResponse());
50+
assertFalse(receipt.hasLocationHeader());
51+
52+
// And make sure we do get a restart if the properties change
53+
payload = payload.replace("<format>xml</format>", "<format>text</format>");
54+
receipt = mimetypeManager.save(payload);
55+
try {
56+
assertTrue(receipt.hasLocationHeader());
57+
} finally {
58+
adminManager.waitForRestart();
59+
}
60+
}
61+
}

src/test/java/com/marklogic/appdeployer/command/mimetypes/ManageMimetypesTest.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,19 @@
77

88
public class ManageMimetypesTest extends AbstractManageResourceTest {
99

10-
@Override
11-
protected ResourceManager newResourceManager() {
12-
return new MimetypeManager(manageClient);
13-
}
10+
@Override
11+
protected ResourceManager newResourceManager() {
12+
return new MimetypeManager(manageClient);
13+
}
1414

15-
@Override
16-
protected Command newCommand() {
17-
return new DeployMimetypesCommand();
18-
}
15+
@Override
16+
protected Command newCommand() {
17+
return new DeployMimetypesCommand();
18+
}
1919

20-
@Override
21-
protected String[] getResourceNames() {
22-
return new String[] { "application/ditamap+xml" };
23-
}
20+
@Override
21+
protected String[] getResourceNames() {
22+
return new String[]{"application/ditamap+xml"};
23+
}
2424

2525
}

0 commit comments

Comments
 (0)