Skip to content
This repository was archived by the owner on Mar 12, 2020. It is now read-only.

Commit 91d7ea3

Browse files
author
Eric Meyer
committed
Ensures that exceptions during changeset generation will cause an invalid changeset with a useful error message.
1 parent f13c87a commit 91d7ea3

File tree

3 files changed

+169
-7
lines changed

3 files changed

+169
-7
lines changed

src/main/java/com/t11e/discovery/datatool/ChangesetController.java

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import java.io.IOException;
44
import java.io.OutputStream;
5+
import java.io.OutputStreamWriter;
6+
import java.io.PrintWriter;
57
import java.text.DateFormat;
68
import java.text.Format;
79
import java.text.SimpleDateFormat;
@@ -110,19 +112,48 @@ public void publishImpl(
110112
HTTP_DATE_FORMAT.format(end != null ? end : new Date()));
111113
response.setHeader("X-t11e-type", changesetType);
112114
final OutputStream os = HttpUtil.getCompressedResponseStream(request, response);
115+
final PrintWriter writer = new PrintWriter(new OutputStreamWriter(os, "utf-8"));
116+
boolean success = false;
113117
{
114118
final XMLStreamWriter xml =
115-
StaxUtil.newOutputFactory().createXMLStreamWriter(os);
119+
StaxUtil.newOutputFactory().createXMLStreamWriter(writer);
116120
xml.writeStartDocument();
117121
xml.writeCharacters("\n");
118122
xml.writeStartElement("changeset");
119123
xml.writeCharacters("\n");
120-
changesetExtractor.writeChangeset(new XmlChangesetWriter(xml),
121-
changesetType, start, end);
122-
xml.writeEndElement();
123-
xml.writeCharacters("\n");
124-
xml.writeEndDocument();
125-
xml.flush();
124+
try
125+
{
126+
changesetExtractor.writeChangeset(new XmlChangesetWriter(xml),
127+
changesetType, start, end);
128+
success = true;
129+
}
130+
catch (final RuntimeException e)
131+
{
132+
if (!response.isCommitted())
133+
{
134+
response.reset();
135+
throw e;
136+
}
137+
xml.flush();
138+
reportException(writer, e);
139+
}
140+
catch (final Exception e)
141+
{
142+
if (!response.isCommitted())
143+
{
144+
response.reset();
145+
throw new RuntimeException(e);
146+
}
147+
xml.flush();
148+
reportException(writer, e);
149+
}
150+
if (success)
151+
{
152+
xml.writeEndElement();
153+
xml.writeCharacters("\n");
154+
xml.writeEndDocument();
155+
xml.flush();
156+
}
126157
}
127158
if (os instanceof GZIPOutputStream)
128159
{
@@ -131,6 +162,19 @@ public void publishImpl(
131162
}
132163
}
133164

165+
private void reportException(final PrintWriter writer, final Throwable t)
166+
{
167+
writer.println();
168+
writer.println();
169+
writer.println();
170+
writer.println(
171+
"*** An exception occured. Since the response has already been committed, we're causing the changeset " +
172+
"to be invalid, and including the exception details here. " + t.getLocalizedMessage());
173+
writer.print("*** Exception was: ");
174+
t.printStackTrace(writer);
175+
writer.flush();
176+
}
177+
134178
public void setChangesetService(final ChangesetService changesetService)
135179
{
136180
this.changesetService = changesetService;
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.t11e.discovery.datatool;
2+
3+
import java.io.IOException;
4+
import java.util.Date;
5+
6+
import javax.servlet.http.HttpServletResponse;
7+
import javax.xml.stream.XMLStreamException;
8+
9+
import junit.framework.Assert;
10+
11+
import org.junit.Test;
12+
import org.springframework.mock.web.MockHttpServletRequest;
13+
import org.springframework.mock.web.MockHttpServletResponse;
14+
15+
public class ChangesetControllerTest
16+
{
17+
private final ChangesetController controller = new ChangesetController();
18+
19+
@Test
20+
public void testExceptionDuringCommitedResponse()
21+
throws XMLStreamException, IOException
22+
{
23+
final ChangesetExtractor changesetExtractor = new ChangesetExtractor()
24+
{
25+
@Override
26+
public void writeChangeset(final ChangesetWriter writer, final String changesetType, final Date start,
27+
final Date end)
28+
{
29+
throw new RuntimeException("Here is the root cause");
30+
}
31+
@Override
32+
public String determineType(final Date start)
33+
{
34+
return "snapshot";
35+
}
36+
};
37+
final MockHttpServletRequest request = new MockHttpServletRequest();
38+
final MockHttpServletResponse response = new MockHttpServletResponse();
39+
response.setCommitted(true);
40+
controller.publishImpl(request, response, changesetExtractor, null, null);
41+
Assert.assertEquals(HttpServletResponse.SC_OK, response.getStatus());
42+
final String responseAsString = response.getContentAsString();
43+
Assert.assertTrue("Response should contain exception notification, but was " + responseAsString,
44+
responseAsString.contains("*** An exception occured."));
45+
Assert.assertFalse("Changeset should not be closed, but was " + responseAsString,
46+
responseAsString.contains("</changeset>"));
47+
}
48+
49+
@Test
50+
public void testExceptionDuringUncommitedResponse()
51+
throws XMLStreamException, IOException
52+
{
53+
final ChangesetExtractor changesetExtractor = new ChangesetExtractor()
54+
{
55+
@Override
56+
public void writeChangeset(final ChangesetWriter writer, final String changesetType, final Date start,
57+
final Date end)
58+
{
59+
throw new RuntimeException("Here is the root cause");
60+
}
61+
62+
@Override
63+
public String determineType(final Date start)
64+
{
65+
return "snapshot";
66+
}
67+
};
68+
final MockHttpServletRequest request = new MockHttpServletRequest();
69+
final MockHttpServletResponse response = new MockHttpServletResponse();
70+
try
71+
{
72+
controller.publishImpl(request, response, changesetExtractor, null, null);
73+
Assert.fail("Should thow exception if response is not committed.");
74+
}
75+
catch (final RuntimeException e)
76+
{
77+
Assert.assertEquals("Here is the root cause", e.getMessage());
78+
}
79+
}
80+
81+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<config xmlns="http://transparensee.com/schema/datatool-config-4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://transparensee.com/schema/datatool-config-4 http://transparensee.com/schema/datatool-config-4.xsd">
3+
<dataSources>
4+
<driver name="dataSource" class="org.apache.derby.jdbc.EmbeddedDriver">
5+
<url>jdbc:derby:memory:test;create=true</url>
6+
</driver>
7+
</dataSources>
8+
<profiles>
9+
<sqlProfile name="sqlProfile" dataSource="dataSource">
10+
<retrieveSql startColumn="startTime" endColumn="endTime"><![CDATA[
11+
select lastRun as startTime, CURRENT_TIMESTAMP as endTime from IntegrationProfile where name = :name
12+
]]></retrieveSql>
13+
<updateSql><![CDATA[
14+
update IntegrationProfile set lastRun = :lastRun where name = :name
15+
]]></updateSql>
16+
</sqlProfile>
17+
</profiles>
18+
<publishers>
19+
<sqlPublisher name="test-invalid-subq" dataSource="dataSource" profile="sqlProfile">
20+
<snapshot>
21+
<set-item idColumn="id">
22+
<query><![CDATA[
23+
select * from IntegrationContent
24+
]]></query>
25+
<subquery>
26+
select no_such_column from IntegrationContent
27+
</subquery>
28+
</set-item>
29+
<remove-item idColumn="id">
30+
<query><![CDATA[
31+
select id from IntegrationDeleted
32+
]]></query>
33+
</remove-item>
34+
</snapshot>
35+
</sqlPublisher>
36+
</publishers>
37+
</config>

0 commit comments

Comments
 (0)