Commit ea864f53e97a822f322ad9c26f1a7de98462e0cf

Authored by bernard
1 parent 8f984e42

Handle command error

1   -package pl.itcrowd.youtrack.api;
2   -
3   -import org.apache.commons.io.IOUtils;
4   -import pl.itcrowd.youtrack.api.rest.ObjectFactory;
5   -
6   -import javax.xml.bind.JAXBContext;
7   -import javax.xml.bind.JAXBElement;
8   -import javax.xml.bind.JAXBException;
9   -import java.io.IOException;
10   -import java.io.Reader;
11   -import java.io.StringReader;
12   -
13   -//TODO methods from this class should be probably merged with YoutrackUnmarshaller
14   -public final class ErrorUnmarshaller {
15   -
16   - public static String unmarshal(String string) throws JAXBException, IOException
17   - {
18   - return unmarshal(new StringReader(string));
19   - }
20   -
21   - public static String unmarshal(Reader reader) throws JAXBException, IOException
22   - {
23   - String content = IOUtils.toString(reader);
24   - try {
25   - JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class);
26   - @SuppressWarnings("unchecked")
27   - final JAXBElement<String> element = (JAXBElement<String>) jaxbContext.createUnmarshaller().unmarshal(new StringReader(content));
28   - return element.getValue();
29   - } catch (JAXBException e) {
30   -// TODO we need logging here
31   - System.err.println("Cannot unmarshal input stream.\n" + content + e);
32   - throw e;
33   - }
34   - }
35   -
36   - private ErrorUnmarshaller()
37   - {
38   - }
39   -}
... ... @@ -345,13 +345,14 @@ public class YoutrackAPI {
345 345
346 346 private String execute(HttpUriRequest request) throws IOException
347 347 {
  348 + request.addHeader("Accept","application/xml");
348 349 final HttpResponse response = httpClient.execute(request);
349 350 final StatusLine statusLine = response.getStatusLine();
350 351 final HttpEntity entity = response.getEntity();
351 352 String responseText = entity == null ? null : EntityUtils.toString(entity);
352 353 if (statusLine.getStatusCode() >= 300) {
353 354 try {
354   - final String error = ErrorUnmarshaller.unmarshal(responseText);
  355 + final String error = YoutrackUnmarshaller.unmarshalError(responseText);
355 356 throw new YoutrackErrorException(error, statusLine.getStatusCode());
356 357 } catch (JAXBException e) {
357 358 LOG.error("Cannot unmarshal following response text:\n" + responseText, e);
... ...
1 1 package pl.itcrowd.youtrack.api;
2 2
  3 +import org.apache.commons.io.IOUtils;
  4 +import org.apache.commons.logging.Log;
  5 +import org.apache.commons.logging.LogFactory;
  6 +import pl.itcrowd.youtrack.api.exceptions.YoutrackAPIException;
  7 +import pl.itcrowd.youtrack.api.rest.ErrorType;
3 8 import pl.itcrowd.youtrack.api.rest.ObjectFactory;
4 9
5 10 import javax.xml.bind.JAXBContext;
  11 +import javax.xml.bind.JAXBElement;
6 12 import javax.xml.bind.JAXBException;
  13 +import java.io.IOException;
7 14 import java.io.Reader;
  15 +import java.io.Serializable;
8 16 import java.io.StringReader;
9 17
10 18 public final class YoutrackUnmarshaller {
11 19
  20 + private static Log LOG = LogFactory.getLog(YoutrackUnmarshaller.class);
  21 +
  22 + private YoutrackUnmarshaller()
  23 + {
  24 + }
  25 +
  26 + public static String unmarshalError(String string) throws JAXBException, IOException
  27 + {
  28 + return unmarshalError(new StringReader(string));
  29 + }
  30 +
  31 + public static String unmarshalError(Reader reader) throws JAXBException, IOException
  32 + {
  33 + String content = IOUtils.toString(reader);
  34 + try {
  35 + JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class);
  36 + @SuppressWarnings("unchecked")
  37 + final JAXBElement<ErrorType> element = (JAXBElement<ErrorType>) jaxbContext.createUnmarshaller().unmarshal(new StringReader(content));
  38 + final ErrorType value = element.getValue();
  39 + final int contentSize = value.getContent().size();
  40 + if (contentSize == 0) {
  41 + return "";
  42 + } else if (contentSize == 1) {
  43 + final Serializable serializable = value.getContent().get(0);
  44 + if (serializable instanceof JAXBElement) {
  45 + if ("message".equals(((JAXBElement) serializable).getName().getLocalPart())) {
  46 + final Object messageValue = ((JAXBElement) serializable).getValue();
  47 + return messageValue == null ? "" : messageValue.toString();
  48 + }
  49 + } else {
  50 + return serializable == null ? "" : serializable.toString();
  51 + }
  52 + } else if (contentSize == 2) {
  53 + for (Serializable serializable : value.getContent()) {
  54 + if (serializable instanceof JAXBElement) {
  55 + if ("message".equals(((JAXBElement) serializable).getName().getLocalPart())) {
  56 + final Object messageValue = ((JAXBElement) serializable).getValue();
  57 + return messageValue == null ? "" : messageValue.toString();
  58 + }
  59 + }
  60 + }
  61 + }
  62 + throw new YoutrackAPIException("Cannot unserialize error.\n" + content);
  63 + } catch (JAXBException e) {
  64 + LOG.error("Cannot unmarshal error.\n" + content, e);
  65 + throw e;
  66 + }
  67 + }
  68 +
12 69 public static Object unmarshall(String string) throws JAXBException
13 70 {
14 71 return unmarshall(new StringReader(string));
... ... @@ -18,8 +75,4 @@ public final class YoutrackUnmarshaller {
18 75 {
19 76 return JAXBContext.newInstance(ObjectFactory.class).createUnmarshaller().unmarshal(reader);
20 77 }
21   -
22   - private YoutrackUnmarshaller()
23   - {
24   - }
25 78 }
... ...
... ... @@ -108,8 +108,8 @@ public class Comment {
108 108 * <p/>
109 109 * Objects of the following type(s) are allowed in the list
110 110 * {@link JAXBElement }{@code <}{@link Comment.Value }{@code >}
111   - * {@link JAXBElement }{@code <}{@link String }{@code >}
112 111 * {@link String }
  112 + * {@link JAXBElement }{@code <}{@link String }{@code >}
113 113 */
114 114 public List<Serializable> getContent()
115 115 {
... ...
  1 +//
  2 +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.1-833
  3 +// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
  4 +// Any modifications to this file will be lost upon recompilation of the source schema.
  5 +//
  6 +package pl.itcrowd.youtrack.api.rest;
  7 +
  8 +import javax.xml.bind.JAXBElement;
  9 +import javax.xml.bind.annotation.XmlAccessType;
  10 +import javax.xml.bind.annotation.XmlAccessorType;
  11 +import javax.xml.bind.annotation.XmlElementRef;
  12 +import javax.xml.bind.annotation.XmlElementRefs;
  13 +import javax.xml.bind.annotation.XmlMixed;
  14 +import javax.xml.bind.annotation.XmlType;
  15 +import java.io.Serializable;
  16 +import java.util.ArrayList;
  17 +import java.util.List;
  18 +
  19 +/**
  20 + * <p>Java class for errorType complex type.
  21 + * <p/>
  22 + * <p>The following schema fragment specifies the expected content contained within this class.
  23 + * <p/>
  24 + * <pre>
  25 + * &lt;complexType name="errorType">
  26 + * &lt;complexContent>
  27 + * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
  28 + * &lt;sequence>
  29 + * &lt;element name="message" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
  30 + * &lt;element name="field" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
  31 + * &lt;/sequence>
  32 + * &lt;/restriction>
  33 + * &lt;/complexContent>
  34 + * &lt;/complexType>
  35 + * </pre>
  36 + */
  37 +@XmlAccessorType(XmlAccessType.FIELD)
  38 +@XmlType(name = "errorType", propOrder = {"content"})
  39 +public class ErrorType {
  40 +
  41 + @XmlElementRefs({@XmlElementRef(name = "message", type = JAXBElement.class), @XmlElementRef(name = "field", type = JAXBElement.class)})
  42 + @XmlMixed
  43 + protected List<Serializable> content;
  44 +
  45 + /**
  46 + * Gets the value of the content property.
  47 + * <p/>
  48 + * <p/>
  49 + * This accessor method returns a reference to the live list,
  50 + * not a snapshot. Therefore any modification you make to the
  51 + * returned list will be present inside the JAXB object.
  52 + * This is why there is not a <CODE>set</CODE> method for the content property.
  53 + * <p/>
  54 + * <p/>
  55 + * For example, to add a new item, do as follows:
  56 + * <pre>
  57 + * getContent().add(newItem);
  58 + * </pre>
  59 + * <p/>
  60 + * <p/>
  61 + * <p/>
  62 + * Objects of the following type(s) are allowed in the list
  63 + * {@link JAXBElement }{@code <}{@link String }{@code >}
  64 + * {@link String }
  65 + * {@link JAXBElement }{@code <}{@link String }{@code >}
  66 + */
  67 + public List<Serializable> getContent()
  68 + {
  69 + if (content == null) {
  70 + content = new ArrayList<Serializable>();
  71 + }
  72 + return this.content;
  73 + }
  74 +}
... ...
... ... @@ -37,7 +37,7 @@ import java.util.List;
37 37 @XmlType(name = "issueType", propOrder = {"fieldOrComment"})
38 38 public class Issue {
39 39
40   - @XmlElements({@XmlElement(name = "comment", type = Comment.class), @XmlElement(name = "field", type = Field.class)})
  40 + @XmlElements({@XmlElement(name = "field", type = Field.class), @XmlElement(name = "comment", type = Comment.class)})
41 41 protected List<Object> fieldOrComment;
42 42
43 43 @XmlAttribute
... ... @@ -61,8 +61,8 @@ public class Issue {
61 61 * <p/>
62 62 * <p/>
63 63 * Objects of the following type(s) are allowed in the list
64   - * {@link Comment }
65 64 * {@link Field }
  65 + * {@link Comment }
66 66 */
67 67 public List<Object> getFieldOrComment()
68 68 {
... ...
... ... @@ -38,6 +38,10 @@ public class ObjectFactory {
38 38
39 39 private final static QName _CommentValue_QNAME = new QName("", "value");
40 40
  41 + private final static QName _ErrorTypeField_QNAME = new QName("", "field");
  42 +
  43 + private final static QName _ErrorTypeMessage_QNAME = new QName("", "message");
  44 +
41 45 /**
42 46 * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: pl.itcrowd.youtrack.api.rest
43 47 */
... ... @@ -46,27 +50,27 @@ public class ObjectFactory {
46 50 }
47 51
48 52 /**
49   - * Create an instance of {@link Comment.Value }
  53 + * Create an instance of {@link Field }
50 54 */
51   - public Comment.Value createCommentValue()
  55 + public Field createField()
52 56 {
53   - return new Comment.Value();
  57 + return new Field();
54 58 }
55 59
56 60 /**
57   - * Create an instance of {@link EnumerationValue }
  61 + * Create an instance of {@link Enumeration }
58 62 */
59   - public EnumerationValue createEnumerationValue()
  63 + public Enumeration createEnumeration()
60 64 {
61   - return new EnumerationValue();
  65 + return new Enumeration();
62 66 }
63 67
64 68 /**
65   - * Create an instance of {@link Issue }
  69 + * Create an instance of {@link User }
66 70 */
67   - public Issue createIssue()
  71 + public User createUser()
68 72 {
69   - return new Issue();
  73 + return new User();
70 74 }
71 75
72 76 /**
... ... @@ -78,59 +82,67 @@ public class ObjectFactory {
78 82 }
79 83
80 84 /**
81   - * Create an instance of {@link User }
  85 + * Create an instance of {@link Issues }
82 86 */
83   - public User createUser()
  87 + public Issues createIssues()
84 88 {
85   - return new User();
  89 + return new Issues();
86 90 }
87 91
88 92 /**
89   - * Create an instance of {@link Issues }
  93 + * Create an instance of {@link AssigneeList }
90 94 */
91   - public Issues createIssues()
  95 + public AssigneeList createAssigneeList()
92 96 {
93   - return new Issues();
  97 + return new AssigneeList();
94 98 }
95 99
96 100 /**
97   - * Create an instance of {@link Field }
  101 + * Create an instance of {@link Field.Value }
98 102 */
99   - public Field createField()
  103 + public Field.Value createFieldValue()
100 104 {
101   - return new Field();
  105 + return new Field.Value();
102 106 }
103 107
104 108 /**
105   - * Create an instance of {@link Comment }
  109 + * Create an instance of {@link AssigneeType }
106 110 */
107   - public Comment createComment()
  111 + public AssigneeType createAssigneeType()
108 112 {
109   - return new Comment();
  113 + return new AssigneeType();
110 114 }
111 115
112 116 /**
113   - * Create an instance of {@link AssigneeList.Assignees }
  117 + * Create an instance of {@link ErrorType }
114 118 */
115   - public AssigneeList.Assignees createAssigneeListAssignees()
  119 + public ErrorType createErrorType()
116 120 {
117   - return new AssigneeList.Assignees();
  121 + return new ErrorType();
118 122 }
119 123
120 124 /**
121   - * Create an instance of {@link Enumeration }
  125 + * Create an instance of {@link AssignedByType }
122 126 */
123   - public Enumeration createEnumeration()
  127 + public AssignedByType createAssignedByType()
124 128 {
125   - return new Enumeration();
  129 + return new AssignedByType();
126 130 }
127 131
128 132 /**
129   - * Create an instance of {@link AssigneeList }
  133 + * Create an instance of {@link EnumerationValue }
130 134 */
131   - public AssigneeList createAssigneeList()
  135 + public EnumerationValue createEnumerationValue()
132 136 {
133   - return new AssigneeList();
  137 + return new EnumerationValue();
  138 + }
  139 +
  140 + /**
  141 + * Create an instance of {@link AssigneeList.Assignees }
  142 + */
  143 + public AssigneeList.Assignees createAssigneeListAssignees()
  144 + {
  145 + return new AssigneeList.Assignees();
134 146 }
135 147
136 148 /**
... ... @@ -142,36 +154,36 @@ public class ObjectFactory {
142 154 }
143 155
144 156 /**
145   - * Create an instance of {@link Field.Value }
  157 + * Create an instance of {@link Comment }
146 158 */
147   - public Field.Value createFieldValue()
  159 + public Comment createComment()
148 160 {
149   - return new Field.Value();
  161 + return new Comment();
150 162 }
151 163
152 164 /**
153   - * Create an instance of {@link AssignedByType }
  165 + * Create an instance of {@link Comment.Value }
154 166 */
155   - public AssignedByType createAssignedByType()
  167 + public Comment.Value createCommentValue()
156 168 {
157   - return new AssignedByType();
  169 + return new Comment.Value();
158 170 }
159 171
160 172 /**
161   - * Create an instance of {@link AssigneeType }
  173 + * Create an instance of {@link Issue }
162 174 */
163   - public AssigneeType createAssigneeType()
  175 + public Issue createIssue()
164 176 {
165   - return new AssigneeType();
  177 + return new Issue();
166 178 }
167 179
168 180 /**
169   - * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}}
  181 + * Create an instance of {@link JAXBElement }{@code <}{@link ErrorType }{@code >}}
170 182 */
171 183 @XmlElementDecl(namespace = "", name = "error")
172   - public JAXBElement<String> createError(String value)
  184 + public JAXBElement<ErrorType> createError(ErrorType value)
173 185 {
174   - return new JAXBElement<String>(_Error_QNAME, String.class, null, value);
  186 + return new JAXBElement<ErrorType>(_Error_QNAME, ErrorType.class, null, value);
175 187 }
176 188
177 189 /**
... ... @@ -218,4 +230,22 @@ public class ObjectFactory {
218 230 {
219 231 return new JAXBElement<Comment.Value>(_CommentValue_QNAME, Comment.Value.class, Comment.class, value);
220 232 }
  233 +
  234 + /**
  235 + * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}}
  236 + */
  237 + @XmlElementDecl(namespace = "", name = "field", scope = ErrorType.class)
  238 + public JAXBElement<String> createErrorTypeField(String value)
  239 + {
  240 + return new JAXBElement<String>(_ErrorTypeField_QNAME, String.class, ErrorType.class, value);
  241 + }
  242 +
  243 + /**
  244 + * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}}
  245 + */
  246 + @XmlElementDecl(namespace = "", name = "message", scope = ErrorType.class)
  247 + public JAXBElement<String> createErrorTypeMessage(String value)
  248 + {
  249 + return new JAXBElement<String>(_ErrorTypeMessage_QNAME, String.class, ErrorType.class, value);
  250 + }
221 251 }
... ...
1 1 <?xml version="1.0" encoding="UTF-8"?>
2 2 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3   - <xs:element name="error" type="xs:string"/>
  3 +
  4 + <xs:include schemaLocation="types.xsd"/>
  5 +
  6 + <xs:element name="error" type="errorType"/>
  7 +
4 8 </xs:schema>
\ No newline at end of file
... ...
... ... @@ -30,6 +30,13 @@
30 30 </xs:simpleContent>
31 31 </xs:complexType>
32 32
  33 + <xs:complexType name="errorType" mixed="true">
  34 + <xs:sequence>
  35 + <xs:element type="xs:string" name="message" minOccurs="0"/>
  36 + <xs:element type="xs:string" name="field" minOccurs="0"/>
  37 + </xs:sequence>
  38 + </xs:complexType>
  39 +
33 40 <xs:complexType name="fieldType">
34 41 <xs:sequence id="value" maxOccurs="unbounded" minOccurs="0">
35 42 <xs:element name="value">
... ...
  1 +package pl.itcrowd.youtrack.api.rest;
  2 +
  3 +import org.junit.Test;
  4 +import pl.itcrowd.youtrack.api.YoutrackUnmarshaller;
  5 +import pl.itcrowd.youtrack.api.exceptions.YoutrackAPIException;
  6 +
  7 +import javax.xml.bind.JAXBException;
  8 +import java.io.IOException;
  9 +
  10 +import static junit.framework.Assert.assertEquals;
  11 +
  12 +public class YoutrackUnmarshallerTest {
  13 +
  14 + @Test
  15 + public void unmarshalEmptyError() throws JAXBException, IOException
  16 + {
  17 +// Given
  18 + final String extendedErrorResponse = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><error></error>";
  19 +
  20 +// When
  21 + final String errorText = YoutrackUnmarshaller.unmarshalError(extendedErrorResponse);
  22 +
  23 +// THen
  24 + assertEquals("", errorText);
  25 + }
  26 +
  27 + @Test
  28 + public void unmarshalError() throws JAXBException, IOException
  29 + {
  30 +// Given
  31 + final String extendedErrorResponse = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><error>Estimated completion time</error>";
  32 +
  33 +// When
  34 + final String errorText = YoutrackUnmarshaller.unmarshalError(extendedErrorResponse);
  35 +
  36 +// THen
  37 + assertEquals("Estimated completion time", errorText);
  38 + }
  39 +
  40 + @Test
  41 + public void unmarshalExtendedError() throws JAXBException, IOException
  42 + {
  43 +// Given
  44 + final String extendedErrorResponse = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><error><message>Estimate task before starting work on it</message><field>Estimated completion time</field></error>";
  45 +
  46 +// When
  47 + final String errorText = YoutrackUnmarshaller.unmarshalError(extendedErrorResponse);
  48 +
  49 +// Then
  50 + assertEquals("Estimate task before starting work on it", errorText);
  51 + }
  52 +
  53 + @Test
  54 + public void unmarshalExtendedErrorWithMessageOnly() throws JAXBException, IOException
  55 + {
  56 +// Given
  57 + final String extendedErrorResponse = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><error><message>Estimate task before starting work on it</message></error>";
  58 +
  59 +// When
  60 + final String errorText = YoutrackUnmarshaller.unmarshalError(extendedErrorResponse);
  61 +
  62 +// Then
  63 + assertEquals("Estimate task before starting work on it", errorText);
  64 + }
  65 +
  66 + @Test
  67 + public void unmarshalExtendedErrorWithEmptyMessage() throws JAXBException, IOException
  68 + {
  69 +// Given
  70 + final String extendedErrorResponse = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><error><message></message><field>Estimated completion time</field></error>";
  71 +
  72 +// When
  73 + final String errorText = YoutrackUnmarshaller.unmarshalError(extendedErrorResponse);
  74 +
  75 +// Then
  76 + assertEquals("", errorText);
  77 + }
  78 +
  79 + @Test(expected = YoutrackAPIException.class)
  80 + public void unmarshalExtendedErrorWithoutMessage() throws JAXBException, IOException
  81 + {
  82 +// Given
  83 + final String extendedErrorResponse = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><error><field>Estimated completion time</field></error>";
  84 +
  85 +// When
  86 + YoutrackUnmarshaller.unmarshalError(extendedErrorResponse);
  87 + }
  88 +}
... ...
Please register or login to post a comment