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

Commit

Permalink
Merge pull request #288 from marklogic-community/feature/287-mimetypes
Browse files Browse the repository at this point in the history
#287 Don't update mimetype if its properties have not changed
  • Loading branch information
rjrudin authored Jul 9, 2018
2 parents 62e165c + 321f9a8 commit fc1c56e
Show file tree
Hide file tree
Showing 11 changed files with 303 additions and 23 deletions.
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ dependencies {
compile 'org.apache.httpcomponents:httpclient:4.3.5'
compile 'org.springframework:spring-web:4.3.5.RELEASE'

// For EqualsBuilder; added in 3.8.1 to support detecting if a mimetype's properties have changed or not
compile "org.apache.commons:commons-lang3:3.7"

// Don't want to include this in the published jar, just the executable jar
compileOnly "com.beust:jcommander:1.72"

Expand Down
10 changes: 10 additions & 0 deletions src/main/java/com/marklogic/appdeployer/AppConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ public class AppConfig {
// Properties to include in resource payloads
private String[] includeProperties;

private boolean updateMimetypeWhenPropertiesAreEqual = false;

private Map<String, Object> additionalProperties = new HashMap<>();

public AppConfig() {
Expand Down Expand Up @@ -1216,4 +1218,12 @@ public boolean isOptimizeWithCma() {
public void setOptimizeWithCma(boolean optimizeWithCma) {
this.optimizeWithCma = optimizeWithCma;
}

public boolean isUpdateMimetypeWhenPropertiesAreEqual() {
return updateMimetypeWhenPropertiesAreEqual;
}

public void setUpdateMimetypeWhenPropertiesAreEqual(boolean updateMimetypeWhenPropertiesAreEqual) {
this.updateMimetypeWhenPropertiesAreEqual = updateMimetypeWhenPropertiesAreEqual;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,11 @@ public void initialize() {
logger.info("Will include only these properties in all resource payloads: " + Arrays.asList(values));
config.setIncludeProperties(values);
});

propertyConsumerMap.put("mlUpdateMimetypeWhenPropertiesAreEqual", (config, prop) -> {
logger.info("Update mimetype when properties are equal (defaults to false to avoid unnecessary ML restarts): " + prop);
config.setUpdateMimetypeWhenPropertiesAreEqual(Boolean.parseBoolean(prop));
});
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,27 @@ protected File[] getResourceDirs(CommandContext context) {

@Override
protected ResourceManager getResourceManager(CommandContext context) {
return new MimetypeManager(context.getManageClient());
MimetypeManager mgr = new MimetypeManager(context.getManageClient());
if (context.getAppConfig().isUpdateMimetypeWhenPropertiesAreEqual()) {
mgr.setUpdateWhenPropertiesAreEqual(true);
} else {
mgr.setUpdateWhenPropertiesAreEqual(false);
}
return mgr;
}

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

}
87 changes: 87 additions & 0 deletions src/main/java/com/marklogic/mgmt/api/mimetypes/Mimetype.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package com.marklogic.mgmt.api.mimetypes;

import com.marklogic.mgmt.api.Resource;
import com.marklogic.mgmt.resource.ResourceManager;
import com.marklogic.mgmt.resource.mimetypes.MimetypeManager;
import org.apache.commons.lang3.builder.EqualsBuilder;

import javax.xml.bind.annotation.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

@XmlRootElement(name = "mimetype-properties")
@XmlAccessorType(XmlAccessType.FIELD)
public class Mimetype extends Resource {

private String name;

@XmlElementWrapper(name = "extensions")
@XmlElement(name = "extension")
private Set<String> extension;

private String format;

public Mimetype() {
super();
}

public Mimetype(String name, String format, String... extensions) {
this();
this.name = name;
this.format = format;
this.extension = new HashSet<>();
this.extension.addAll(Arrays.asList(extensions));
}

@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!(obj instanceof Mimetype)) {
return false;
}

Mimetype other = (Mimetype) obj;
return new EqualsBuilder()
.append(this.name, other.name)
.append(this.extension, other.extension)
.append(this.format, other.format)
.isEquals();
}

@Override
protected ResourceManager getResourceManager() {
return new MimetypeManager(getClient());
}

@Override
protected String getResourceId() {
return name;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Set<String> getExtension() {
return extension;
}

public void setExtension(Set<String> extension) {
this.extension = extension;
}

public String getFormat() {
return format;
}

public void setFormat(String format) {
this.format = format;
}
}
12 changes: 12 additions & 0 deletions src/main/java/com/marklogic/mgmt/api/mimetypes/package-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@XmlSchema(
namespace = "http://marklogic.com/manage",
elementFormDefault = XmlNsForm.QUALIFIED,
xmlns = {
@XmlNs(prefix = "m", namespaceURI = "http://marklogic.com/manage")
}
)
package com.marklogic.mgmt.api.mimetypes;

import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
Original file line number Diff line number Diff line change
@@ -1,17 +1,75 @@
package com.marklogic.mgmt.resource.mimetypes;

import com.marklogic.mgmt.resource.AbstractResourceManager;
import com.marklogic.mgmt.ManageClient;
import com.marklogic.mgmt.SaveReceipt;
import com.marklogic.mgmt.api.API;
import com.marklogic.mgmt.api.mimetypes.Mimetype;
import com.marklogic.mgmt.mapper.DefaultResourceMapper;
import com.marklogic.mgmt.mapper.ResourceMapper;
import com.marklogic.mgmt.resource.AbstractResourceManager;

public class MimetypeManager extends AbstractResourceManager {

public MimetypeManager(ManageClient client) {
super(client);
}
private boolean updateWhenPropertiesAreEqual = false;
private ResourceMapper resourceMapper;

public MimetypeManager(ManageClient client) {
super(client);
}

@Override
protected String getIdFieldName() {
return "name";
}

/**
* To avoid ML restarting when a mimetype exists but its properties aren't being changed by the incoming payload,
* this method is overridden so a check can be made to see if the properties are different from what's already in
* MarkLogic.
* <p>
* This behavior can be disabled by setting updateWhenPropertiesAreEqual to true.
*
* @param payload
* @param resourceId
* @return
*/
@Override
public SaveReceipt updateResource(String payload, String resourceId) {
if (updateWhenPropertiesAreEqual) {
if (logger.isDebugEnabled()) {
logger.debug(format("updateWhenPropertiesAreEqual is set to true, so mimetype %s will be updated based on the " +
"incoming payload regardless of whether its properties differ from what's already set in MarkLogic or not", resourceId));
}
return super.updateResource(payload, resourceId);
}

if (resourceMapper == null) {
resourceMapper = new DefaultResourceMapper(new API(getManageClient()));
}

Mimetype incomingMimetype = resourceMapper.readResource(payload, Mimetype.class);
final String name = incomingMimetype.getName();

String existingJson = super.getPropertiesAsJson(name);
Mimetype existingMimetype = resourceMapper.readResource(existingJson, Mimetype.class);

if (incomingMimetype.equals(existingMimetype)) {
logger.info(format("The properties in the payload for mimetype %s are the same as what's already set in " +
"MarkLogic, so the mimetype will not be updated", name));
return new SaveReceipt(name, payload, null, null);
}
else {
logger.info(format("The properties in the payload for mimetype %s differ from what's already set in MarkLogic, " +
"so the mimetype will be updated", name));
return super.updateResource(payload, resourceId);
}
}

@Override
protected String getIdFieldName() {
return "name";
}
public void setUpdateWhenPropertiesAreEqual(boolean updateWhenPropertiesAreEqual) {
this.updateWhenPropertiesAreEqual = updateWhenPropertiesAreEqual;
}

public void setResourceMapper(ResourceMapper resourceMapper) {
this.resourceMapper = resourceMapper;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ public void allProperties() {

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

p.setProperty("mlUpdateMimetypeWhenPropertiesAreEqual", "true");

sut = new DefaultAppConfigFactory(new SimplePropertySource(p));
AppConfig config = sut.newAppConfig();

Expand Down Expand Up @@ -344,6 +346,8 @@ public void allProperties() {
map = config.getHostGroups();
assertEquals("Default", map.get("host1"));
assertEquals("other-group", map.get("host2"));

assertTrue(config.isUpdateMimetypeWhenPropertiesAreEqual());
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.marklogic.appdeployer.command.mimetypes;

import com.marklogic.appdeployer.AbstractAppDeployerTest;
import com.marklogic.mgmt.SaveReceipt;
import com.marklogic.mgmt.resource.mimetypes.MimetypeManager;
import org.junit.After;
import org.junit.Test;

public class DontRestartWhenMimetypePropertiesArentUpdatedTest extends AbstractAppDeployerTest {

private MimetypeManager mimetypeManager;

@After
public void teardown() {
mimetypeManager.deleteByIdField("application/ditamap+xml");
assertFalse(mimetypeManager.exists("application/ditamap+xml"));
}

@Test
public void test() {
mimetypeManager = new MimetypeManager(manageClient);

initializeAppDeployer(new DeployMimetypesCommand());

deploySampleApp();

// Deploy again, though we don't have a good way of asserting that ML didn't restart; can check the logs
appConfig.setUpdateMimetypeWhenPropertiesAreEqual(true);
deploySampleApp();

// But we can verify that MimetypeManager doesn't cause an update
String payload = readTestResource("sample-app/src/main/ml-config/mimetypes/ditamap.json");

SaveReceipt receipt = mimetypeManager.save(payload);
assertNull("The response should be null since no call was made to the Manage API since the mimetype " +
"properties weren't updated", receipt.getResponse());
assertFalse(receipt.hasLocationHeader());

// Make sure XML works too
payload = "<mimetype-properties xmlns='http://marklogic.com/manage'>\n" +
" <name>application/ditamap+xml</name>\n" +
" <extensions>\n" +
" <extension>ditamap</extension>\n" +
" </extensions>\n" +
" <format>xml</format>\n" +
"</mimetype-properties>";
receipt = mimetypeManager.save(payload);
assertNull("The response should be null since no call was made to the Manage API since the mimetype " +
"properties weren't updated", receipt.getResponse());
assertFalse(receipt.hasLocationHeader());

// And make sure we do get a restart if the properties change
payload = payload.replace("<format>xml</format>", "<format>text</format>");
receipt = mimetypeManager.save(payload);
try {
assertTrue(receipt.hasLocationHeader());
} finally {
adminManager.waitForRestart();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@

public class ManageMimetypesTest extends AbstractManageResourceTest {

@Override
protected ResourceManager newResourceManager() {
return new MimetypeManager(manageClient);
}
@Override
protected ResourceManager newResourceManager() {
return new MimetypeManager(manageClient);
}

@Override
protected Command newCommand() {
return new DeployMimetypesCommand();
}
@Override
protected Command newCommand() {
return new DeployMimetypesCommand();
}

@Override
protected String[] getResourceNames() {
return new String[] { "application/ditamap+xml" };
}
@Override
protected String[] getResourceNames() {
return new String[]{"application/ditamap+xml"};
}

}
Loading

0 comments on commit fc1c56e

Please sign in to comment.