Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to change merging behavior at runtime. #5

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion src/main/java/org/atteo/xmlcombiner/XmlCombiner.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,17 @@ public interface Filter {
*/
void postProcess(Element recessive, Element dominant, Element result);
}

/**
* Allows to change the element merge behavior at runtime.
*/
public interface MergeFilter {
/**
* Specify merging technique for the element.
* @param element current element for which to provide the merging behavior
*/
CombineChildren query(Element element);
}

private final DocumentBuilder documentBuilder;
private final Document document;
Expand All @@ -93,7 +104,14 @@ public interface Filter {
public void postProcess(Element recessive, Element dominant, Element result) {
}
};
private static final MergeFilter DEFAULT_MERGE_FILTER = new MergeFilter() {
@Override
public CombineChildren query(Element element) {
return CombineChildren.MERGE;
}
};
private Filter filter = NULL_FILTER;
private MergeFilter mergeFilter = DEFAULT_MERGE_FILTER;
private final ChildContextsMapper childContextMapper = new KeyAttributesChildContextsMapper();

public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException,
Expand Down Expand Up @@ -176,6 +194,17 @@ public void setFilter(Filter filter) {
}
this.filter = filter;
}

/**
* Sets the merging behavior filter.
*/
public void setFilter(MergeFilter mergeFilter) {
if (mergeFilter == null) {
this.mergeFilter = DEFAULT_MERGE_FILTER;
return;
}
this.mergeFilter = mergeFilter;
}

/**
* Combine given file.
Expand Down Expand Up @@ -260,7 +289,13 @@ private Context combine(Context recessive, Context dominant) {
if (combineChildren == null) {
combineChildren = getCombineChildren(recessive.getElement());
if (combineChildren == null) {
combineChildren = CombineChildren.MERGE;
combineChildren = mergeFilter.query(dominant.getElement());
if (combineChildren == null) {
combineChildren = mergeFilter.query(recessive.getElement());
if (combineChildren == null) {
combineChildren = CombineChildren.MERGE;
}
}
}
}

Expand Down
165 changes: 162 additions & 3 deletions src/test/java/org/atteo/xmlcombiner/XmlCombinerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
*/
package org.atteo.xmlcombiner;

import static org.assertj.core.api.Assertions.assertThat;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLIdentical;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLNotEqual;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringWriter;
Expand All @@ -31,10 +36,8 @@
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import static org.assertj.core.api.Assertions.assertThat;
import org.custommonkey.xmlunit.Diff;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLIdentical;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLNotEqual;
import org.junit.Ignore;
import org.junit.Test;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
Expand Down Expand Up @@ -674,6 +677,162 @@ public void postProcess(Element recessive, Element dominant, Element result) {
assertXMLIdentical(new Diff(result, combineWithKeysAndFilter(Lists.<String>newArrayList(), filter, recessive,
dominant)), true);
}

@Ignore
@Test
public void supportRuntimeMergeFilterSelective() throws Exception {
//TODO: make it work - needs XmlCombiner logic fix
String recessive = "\n"
+ "<root>\n"
+ " <config>\n"
+ " <service>\n"
+ " <option>1.1</option>\n"
+ " <option>1.2</option>\n"
+ " </service>\n"
+ " </config>\n"
+ " <config>\n"
+ " <service>\n"
+ " <option>1.3</option>\n"
+ " <option>1.4</option>\n"
+ " </service>\n"
+ " </config>\n"
+ "</root>";
String dominant = "\n"
+ "<root>\n"
+ " <config>\n"
+ " <service>\n"
+ " <option>1.1</option>\n"
+ " <option>1.2</option>\n"
+ " </service>\n"
+ " </config>\n"
+ " <config>\n"
+ " <service>\n"
+ " <option>1.3</option>\n"
+ " <option>1.4</option>\n"
+ " </service>\n"
+ " </config>\n"
+ "</root>";
String expected = "\n"
+ "<root>\n"
+ " <config>\n"
+ " <service>\n"
+ " <option>1.1</option>\n"
+ " <option>1.2</option>\n"
+ " </service>\n"
+ " <service>\n"
+ " <option>1.1</option>\n"
+ " <option>1.2</option>\n"
+ " </service>\n"
+ " <service>\n"
+ " <option>1.3</option>\n"
+ " <option>1.4</option>\n"
+ " </service>\n"
+ " <service>\n"
+ " <option>1.3</option>\n"
+ " <option>1.4</option>\n"
+ " </service>\n"
+ " </config>"
+ "</root>";

XmlCombiner.MergeFilter filter = new XmlCombiner.MergeFilter() {
@Override
public CombineChildren query(Element element) {
if (element.getTagName().equals("root")) {
return CombineChildren.MERGE; // for config tags
} else if (element.getTagName().equals("config")) {
return CombineChildren.APPEND; // for service tags
}

return CombineChildren.MERGE; // for config tags
}
};

applyMergeFilter(new String[]{recessive, dominant}, filter, expected, false);
}

@Test
public void supportRuntimeMergeFilterAppendDifferent() throws Exception {
String recessive = "\n"
+ "<config>\n"
+ " <service name='a'/>\n"
+ " <service name='b'/>\n"
+ "</config>";
String dominant = "\n"
+ "<config>\n"
+ " <service name='c'/>\n"
+ " <service name='d'/>\n"
+ "</config>";
String expected = "\n"
+ "<config>\n"
+ " <service name='a'/>\n"
+ " <service name='b'/>\n"
+ " <service name='c'/>\n"
+ " <service name='d'/>\n"
+ "</config>";

XmlCombiner.MergeFilter filter = new XmlCombiner.MergeFilter() {
@Override
public CombineChildren query(Element element) {
return CombineChildren.APPEND;
}
};

applyMergeFilter(new String[]{recessive, dominant}, filter, expected, true);
}

@Test
public void supportRuntimeMergeFilterSameAppend() throws Exception {
String recessive = "\n"
+ "<config>\n"
+ " <service name='a'/>\n"
+ " <service name='b'/>\n"
+ "</config>";
String dominant = "\n"
+ "<config>\n"
+ " <service name='a'/>\n"
+ " <service name='b'/>\n"
+ "</config>";
String expected = "\n"
+ "<config>\n"
+ " <service name='a'/>\n"
+ " <service name='b'/>\n"
+ " <service name='a'/>\n"
+ " <service name='b'/>\n"
+ "</config>";

XmlCombiner.MergeFilter filter = new XmlCombiner.MergeFilter() {
@Override
public CombineChildren query(Element element) {
return CombineChildren.APPEND;
}
};

applyMergeFilter(new String[]{recessive, dominant}, filter, expected, true);
}

private void applyMergeFilter(String[] inputs, XmlCombiner.MergeFilter filter, String expected, boolean identical) throws Exception {
XmlCombiner combiner = new XmlCombiner();
combiner.setFilter(filter);

for (String input : inputs) {
combiner.combine(new ByteArrayInputStream(input.getBytes()));
}
Document combinedResult = combiner.buildDocument();

Transformer transformer = TransformerFactory.newInstance().newTransformer();
StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(combinedResult), new StreamResult(writer));
String result = writer.toString();

if (identical) {
assertXMLIdentical(new Diff(result, expected), true);
} else {
System.out.println(expected);
System.out.println("-");
System.out.println(result);
assertXMLEqual(expected, result);
}
}


@Test
Expand Down