From 4bd2f591c73171cb7bee3d6631fdf60c6d07a37a Mon Sep 17 00:00:00 2001
From: Bernard Labno <bernard.labno@itcrowd.pl>
Date: Fri, 16 Dec 2011 08:51:04 +0000
Subject: [PATCH] Implemented login and searchIssueByProject tests.

---
 pom.xml                                                              |   5 +++--
 src/main/java/pl/com/it_crowd/youtrack/api/Issue.java                |  63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/main/java/pl/com/it_crowd/youtrack/api/rest/Issues.java          | 209 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------------------------------------------------------------------------------
 src/main/java/pl/com/it_crowd/youtrack/api/rest/ObjectFactory.java   |  50 +++++++++++++++-----------------------------------
 src/main/java/pl/com/it_crowd/youtrack/api/rest/YoutrackAPI.java     |  55 +++++++++++++++++++++++++++++++++++++++----------------
 src/main/xjb/bindings.xjb                                            |  18 ++++++++++++++++++
 src/main/xsd/issuesByProject.xsd                                     |   6 +++---
 src/test/java/pl/com/it_crowd/youtrack/api/rest/YoutrackAPITest.java |  53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 292 insertions(+), 167 deletions(-)
 create mode 100644 src/main/java/pl/com/it_crowd/youtrack/api/Issue.java
 create mode 100644 src/main/xjb/bindings.xjb
 create mode 100644 src/test/java/pl/com/it_crowd/youtrack/api/rest/YoutrackAPITest.java

diff --git a/pom.xml b/pom.xml
index 4b8b074..17be54f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
 
-    <groupId>pl.com.it-crowd.youtrack-rest-api</groupId>
+    <groupId>pl.com.it-crowd</groupId>
     <artifactId>youtrack-rest-api</artifactId>
     <version>1.0.0-SNAPSHOT</version>
 
@@ -60,6 +60,7 @@
                             <packageName>pl.com.it_crowd.youtrack.api.rest</packageName>
                             <outputDirectory>${build.sourceDirectory}</outputDirectory>
                             <clearOutputDir>false</clearOutputDir>
+                            <extension>false</extension>
                         </configuration>
                     </plugin>
                 </plugins>
@@ -74,4 +75,4 @@
             <url>http://artifactory.it-crowd.com.pl/libs-snapshot-local</url>
         </snapshotRepository>
     </distributionManagement>
-</project>
\ No newline at end of file
+</project>
diff --git a/src/main/java/pl/com/it_crowd/youtrack/api/Issue.java b/src/main/java/pl/com/it_crowd/youtrack/api/Issue.java
new file mode 100644
index 0000000..f60862f
--- /dev/null
+++ b/src/main/java/pl/com/it_crowd/youtrack/api/Issue.java
@@ -0,0 +1,63 @@
+package pl.com.it_crowd.youtrack.api;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import pl.com.it_crowd.youtrack.api.rest.Issues;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class Issue implements Serializable {
+// ------------------------------ FIELDS ------------------------------
+
+    private static final Log log = LogFactory.getLog(Issue.class);
+    private List<Issues.Issue.Comment> comments;
+    private Map<String, Issues.Issue.Field> fieldMap;
+
+    private Issues.Issue issue;
+
+// --------------------------- CONSTRUCTORS ---------------------------
+
+    public Issue(Issues.Issue issue) {
+        this.issue = issue;
+        fieldMap = new HashMap<String, Issues.Issue.Field>();
+        comments = new ArrayList<Issues.Issue.Comment>();
+        for (Object o : issue.getFieldOrComment()) {
+            if (o instanceof Issues.Issue.Field) {
+                Issues.Issue.Field field = (Issues.Issue.Field) o;
+                fieldMap.put(field.getName(), field);
+            } else if (o instanceof Issues.Issue.Comment) {
+                comments.add((Issues.Issue.Comment) o);
+            } else {
+                log.warn("Object " + o + " is not Field nor Coment");
+            }
+        }
+    }
+
+// -------------------------- OTHER METHODS --------------------------
+
+    public Issues.Issue.Field getField(String field) {
+        return fieldMap.get(field);
+    }
+
+    public String getFieldValue(String fieldName) {
+        Issues.Issue.Field field = fieldMap.get(fieldName);
+        if (field == null) {
+            return null;
+        }
+        List<Issues.Issue.Field.Value> values = field.getValues();
+        return values.isEmpty() ? null : values.get(0).getContent();
+    }
+
+    public String getFieldValue(Fields fieldName) {
+        return getFieldValue(fieldName.name());
+    }
+// -------------------------- ENUMERATIONS --------------------------
+
+    public enum Fields {
+        summary
+    }
+}
diff --git a/src/main/java/pl/com/it_crowd/youtrack/api/rest/Issues.java b/src/main/java/pl/com/it_crowd/youtrack/api/rest/Issues.java
index c6b0128..549ee8e 100644
--- a/src/main/java/pl/com/it_crowd/youtrack/api/rest/Issues.java
+++ b/src/main/java/pl/com/it_crowd/youtrack/api/rest/Issues.java
@@ -2,23 +2,19 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.1-833 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2011.12.05 at 08:56:01 AM CET 
+// Generated on: 2011.12.16 at 09:34:48 AM CET 
 //
 
 package pl.com.it_crowd.youtrack.api.rest;
 
-import javax.xml.bind.JAXBElement;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlElementRef;
 import javax.xml.bind.annotation.XmlElements;
-import javax.xml.bind.annotation.XmlMixed;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlValue;
-import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -100,7 +96,9 @@ import java.util.List;
  * </pre>
  */
 @XmlAccessorType(XmlAccessType.FIELD)
-@XmlType(name = "", propOrder = {"issue"})
+@XmlType(name = "", propOrder = {
+    "issue"
+})
 @XmlRootElement(name = "issues")
 public class Issues {
 
@@ -126,8 +124,7 @@ public class Issues {
      * Objects of the following type(s) are allowed in the list
      * {@link Issues.Issue }
      */
-    public List<Issues.Issue> getIssue()
-    {
+    public List<Issues.Issue> getIssue() {
         if (issue == null) {
             issue = new ArrayList<Issues.Issue>();
         }
@@ -202,12 +199,16 @@ public class Issues {
      * </pre>
      */
     @XmlAccessorType(XmlAccessType.FIELD)
-    @XmlType(name = "", propOrder = {"fieldOrComment"})
+    @XmlType(name = "", propOrder = {
+        "fieldOrComment"
+    })
     public static class Issue {
 
-        @XmlElements({@XmlElement(name = "field", type = Issues.Issue.Field.class), @XmlElement(name = "comment", type = Issues.Issue.Comment.class)})
+        @XmlElements({
+            @XmlElement(name = "field", type = Issues.Issue.Field.class),
+            @XmlElement(name = "comment", type = Issues.Issue.Comment.class)
+        })
         protected List<Object> fieldOrComment;
-
         @XmlAttribute
         protected String id;
 
@@ -232,8 +233,7 @@ public class Issues {
          * {@link Issues.Issue.Field }
          * {@link Issues.Issue.Comment }
          */
-        public List<Object> getFieldOrComment()
-        {
+        public List<Object> getFieldOrComment() {
             if (fieldOrComment == null) {
                 fieldOrComment = new ArrayList<Object>();
             }
@@ -246,8 +246,7 @@ public class Issues {
          * @return possible object is
          *         {@link String }
          */
-        public String getId()
-        {
+        public String getId() {
             return id;
         }
 
@@ -257,8 +256,7 @@ public class Issues {
          * @param value allowed object is
          *              {@link String }
          */
-        public void setId(String value)
-        {
+        public void setId(String value) {
             this.id = value;
         }
 
@@ -298,34 +296,28 @@ public class Issues {
          * </pre>
          */
         @XmlAccessorType(XmlAccessType.FIELD)
-        @XmlType(name = "", propOrder = {"replies", "value"})
+        @XmlType(name = "", propOrder = {
+            "replies",
+            "value"
+        })
         public static class Comment {
 
             protected String replies;
-
             protected Issues.Issue.Comment.Value value;
-
             @XmlAttribute
             protected String id;
-
             @XmlAttribute
             protected String author;
-
             @XmlAttribute
             protected String issueId;
-
             @XmlAttribute
             protected String deleted;
-
             @XmlAttribute
             protected String text;
-
             @XmlAttribute
             protected String shownForIssueAuthor;
-
             @XmlAttribute
             protected String created;
-
             @XmlAttribute
             protected String name;
 
@@ -335,8 +327,7 @@ public class Issues {
              * @return possible object is
              *         {@link String }
              */
-            public String getReplies()
-            {
+            public String getReplies() {
                 return replies;
             }
 
@@ -346,8 +337,7 @@ public class Issues {
              * @param value allowed object is
              *              {@link String }
              */
-            public void setReplies(String value)
-            {
+            public void setReplies(String value) {
                 this.replies = value;
             }
 
@@ -357,8 +347,7 @@ public class Issues {
              * @return possible object is
              *         {@link Issues.Issue.Comment.Value }
              */
-            public Issues.Issue.Comment.Value getValue()
-            {
+            public Issues.Issue.Comment.Value getValue() {
                 return value;
             }
 
@@ -368,8 +357,7 @@ public class Issues {
              * @param value allowed object is
              *              {@link Issues.Issue.Comment.Value }
              */
-            public void setValue(Issues.Issue.Comment.Value value)
-            {
+            public void setValue(Issues.Issue.Comment.Value value) {
                 this.value = value;
             }
 
@@ -379,8 +367,7 @@ public class Issues {
              * @return possible object is
              *         {@link String }
              */
-            public String getId()
-            {
+            public String getId() {
                 return id;
             }
 
@@ -390,8 +377,7 @@ public class Issues {
              * @param value allowed object is
              *              {@link String }
              */
-            public void setId(String value)
-            {
+            public void setId(String value) {
                 this.id = value;
             }
 
@@ -401,8 +387,7 @@ public class Issues {
              * @return possible object is
              *         {@link String }
              */
-            public String getAuthor()
-            {
+            public String getAuthor() {
                 return author;
             }
 
@@ -412,8 +397,7 @@ public class Issues {
              * @param value allowed object is
              *              {@link String }
              */
-            public void setAuthor(String value)
-            {
+            public void setAuthor(String value) {
                 this.author = value;
             }
 
@@ -423,8 +407,7 @@ public class Issues {
              * @return possible object is
              *         {@link String }
              */
-            public String getIssueId()
-            {
+            public String getIssueId() {
                 return issueId;
             }
 
@@ -434,8 +417,7 @@ public class Issues {
              * @param value allowed object is
              *              {@link String }
              */
-            public void setIssueId(String value)
-            {
+            public void setIssueId(String value) {
                 this.issueId = value;
             }
 
@@ -445,8 +427,7 @@ public class Issues {
              * @return possible object is
              *         {@link String }
              */
-            public String getDeleted()
-            {
+            public String getDeleted() {
                 return deleted;
             }
 
@@ -456,8 +437,7 @@ public class Issues {
              * @param value allowed object is
              *              {@link String }
              */
-            public void setDeleted(String value)
-            {
+            public void setDeleted(String value) {
                 this.deleted = value;
             }
 
@@ -467,8 +447,7 @@ public class Issues {
              * @return possible object is
              *         {@link String }
              */
-            public String getText()
-            {
+            public String getText() {
                 return text;
             }
 
@@ -478,8 +457,7 @@ public class Issues {
              * @param value allowed object is
              *              {@link String }
              */
-            public void setText(String value)
-            {
+            public void setText(String value) {
                 this.text = value;
             }
 
@@ -489,8 +467,7 @@ public class Issues {
              * @return possible object is
              *         {@link String }
              */
-            public String getShownForIssueAuthor()
-            {
+            public String getShownForIssueAuthor() {
                 return shownForIssueAuthor;
             }
 
@@ -500,8 +477,7 @@ public class Issues {
              * @param value allowed object is
              *              {@link String }
              */
-            public void setShownForIssueAuthor(String value)
-            {
+            public void setShownForIssueAuthor(String value) {
                 this.shownForIssueAuthor = value;
             }
 
@@ -511,8 +487,7 @@ public class Issues {
              * @return possible object is
              *         {@link String }
              */
-            public String getCreated()
-            {
+            public String getCreated() {
                 return created;
             }
 
@@ -522,8 +497,7 @@ public class Issues {
              * @param value allowed object is
              *              {@link String }
              */
-            public void setCreated(String value)
-            {
+            public void setCreated(String value) {
                 this.created = value;
             }
 
@@ -533,8 +507,7 @@ public class Issues {
              * @return possible object is
              *         {@link String }
              */
-            public String getName()
-            {
+            public String getName() {
                 return name;
             }
 
@@ -544,8 +517,7 @@ public class Issues {
              * @param value allowed object is
              *              {@link String }
              */
-            public void setName(String value)
-            {
+            public void setName(String value) {
                 this.name = value;
             }
 
@@ -566,15 +538,15 @@ public class Issues {
              * </pre>
              */
             @XmlAccessorType(XmlAccessType.FIELD)
-            @XmlType(name = "", propOrder = {"value"})
+            @XmlType(name = "", propOrder = {
+                "value"
+            })
             public static class Value {
 
                 @XmlValue
                 protected String value;
-
                 @XmlAttribute
                 protected String type;
-
                 @XmlAttribute
                 protected String role;
 
@@ -584,8 +556,7 @@ public class Issues {
                  * @return possible object is
                  *         {@link String }
                  */
-                public String getValue()
-                {
+                public String getValue() {
                     return value;
                 }
 
@@ -595,8 +566,7 @@ public class Issues {
                  * @param value allowed object is
                  *              {@link String }
                  */
-                public void setValue(String value)
-                {
+                public void setValue(String value) {
                     this.value = value;
                 }
 
@@ -606,8 +576,7 @@ public class Issues {
                  * @return possible object is
                  *         {@link String }
                  */
-                public String getType()
-                {
+                public String getType() {
                     return type;
                 }
 
@@ -617,8 +586,7 @@ public class Issues {
                  * @param value allowed object is
                  *              {@link String }
                  */
-                public void setType(String value)
-                {
+                public void setType(String value) {
                     this.type = value;
                 }
 
@@ -628,8 +596,7 @@ public class Issues {
                  * @return possible object is
                  *         {@link String }
                  */
-                public String getRole()
-                {
+                public String getRole() {
                     return role;
                 }
 
@@ -639,11 +606,12 @@ public class Issues {
                  * @param value allowed object is
                  *              {@link String }
                  */
-                public void setRole(String value)
-                {
+                public void setRole(String value) {
                     this.role = value;
                 }
+
             }
+
         }
 
         /**
@@ -674,43 +642,41 @@ public class Issues {
          * </pre>
          */
         @XmlAccessorType(XmlAccessType.FIELD)
-        @XmlType(name = "", propOrder = {"content"})
+        @XmlType(name = "", propOrder = {
+            "values"
+        })
         public static class Field {
 
-            @XmlElementRef(name = "value", type = JAXBElement.class)
-            @XmlMixed
-            protected List<Serializable> content;
-
+            @XmlElement(name = "value")
+            protected List<Issues.Issue.Field.Value> values;
             @XmlAttribute
             protected String name;
 
             /**
-             * Gets the value of the content property.
+             * Gets the value of the values property.
              * <p/>
              * <p/>
              * This accessor method returns a reference to the live list,
              * not a snapshot. Therefore any modification you make to the
              * returned list will be present inside the JAXB object.
-             * This is why there is not a <CODE>set</CODE> method for the content property.
+             * This is why there is not a <CODE>set</CODE> method for the values property.
              * <p/>
              * <p/>
              * For example, to add a new item, do as follows:
              * <pre>
-             *    getContent().add(newItem);
+             *    getValues().add(newItem);
              * </pre>
              * <p/>
              * <p/>
              * <p/>
              * Objects of the following type(s) are allowed in the list
-             * {@link String }
-             * {@link JAXBElement }{@code <}{@link Issues.Issue.Field.Value }{@code >}
+             * {@link Issues.Issue.Field.Value }
              */
-            public List<Serializable> getContent()
-            {
-                if (content == null) {
-                    content = new ArrayList<Serializable>();
+            public List<Issues.Issue.Field.Value> getValues() {
+                if (values == null) {
+                    values = new ArrayList<Issues.Issue.Field.Value>();
                 }
-                return this.content;
+                return this.values;
             }
 
             /**
@@ -719,8 +685,7 @@ public class Issues {
              * @return possible object is
              *         {@link String }
              */
-            public String getName()
-            {
+            public String getName() {
                 return name;
             }
 
@@ -730,8 +695,7 @@ public class Issues {
              * @param value allowed object is
              *              {@link String }
              */
-            public void setName(String value)
-            {
+            public void setName(String value) {
                 this.name = value;
             }
 
@@ -752,23 +716,45 @@ public class Issues {
              * </pre>
              */
             @XmlAccessorType(XmlAccessType.FIELD)
-            @XmlType(name = "")
+            @XmlType(name = "", propOrder = {
+                "content"
+            })
             public static class Value {
 
+                @XmlValue
+                protected String content;
                 @XmlAttribute
                 protected String type;
-
                 @XmlAttribute
                 protected String role;
 
                 /**
+                 * Gets the value of the content property.
+                 *
+                 * @return possible object is
+                 *         {@link String }
+                 */
+                public String getContent() {
+                    return content;
+                }
+
+                /**
+                 * Sets the value of the content property.
+                 *
+                 * @param value allowed object is
+                 *              {@link String }
+                 */
+                public void setContent(String value) {
+                    this.content = value;
+                }
+
+                /**
                  * Gets the value of the type property.
                  *
                  * @return possible object is
                  *         {@link String }
                  */
-                public String getType()
-                {
+                public String getType() {
                     return type;
                 }
 
@@ -778,8 +764,7 @@ public class Issues {
                  * @param value allowed object is
                  *              {@link String }
                  */
-                public void setType(String value)
-                {
+                public void setType(String value) {
                     this.type = value;
                 }
 
@@ -789,8 +774,7 @@ public class Issues {
                  * @return possible object is
                  *         {@link String }
                  */
-                public String getRole()
-                {
+                public String getRole() {
                     return role;
                 }
 
@@ -800,11 +784,14 @@ public class Issues {
                  * @param value allowed object is
                  *              {@link String }
                  */
-                public void setRole(String value)
-                {
+                public void setRole(String value) {
                     this.role = value;
                 }
+
             }
+
         }
+
     }
+
 }
diff --git a/src/main/java/pl/com/it_crowd/youtrack/api/rest/ObjectFactory.java b/src/main/java/pl/com/it_crowd/youtrack/api/rest/ObjectFactory.java
index aaa5260..b10762e 100644
--- a/src/main/java/pl/com/it_crowd/youtrack/api/rest/ObjectFactory.java
+++ b/src/main/java/pl/com/it_crowd/youtrack/api/rest/ObjectFactory.java
@@ -2,15 +2,12 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.1-833 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2011.12.05 at 08:56:01 AM CET 
+// Generated on: 2011.12.16 at 09:34:48 AM CET 
 //
 
 package pl.com.it_crowd.youtrack.api.rest;
 
-import javax.xml.bind.JAXBElement;
-import javax.xml.bind.annotation.XmlElementDecl;
 import javax.xml.bind.annotation.XmlRegistry;
-import javax.xml.namespace.QName;
 
 /**
  * This object contains factory methods for each
@@ -28,69 +25,52 @@ import javax.xml.namespace.QName;
 @XmlRegistry
 public class ObjectFactory {
 
-    private final static QName _IssuesIssueFieldValue_QNAME = new QName("", "value");
-
     /**
      * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: pl.com.it_crowd.youtrack.api.rest
      */
-    public ObjectFactory()
-    {
+    public ObjectFactory() {
     }
 
     /**
      * Create an instance of {@link Issues.Issue.Comment.Value }
      */
-    public Issues.Issue.Comment.Value createIssuesIssueCommentValue()
-    {
+    public Issues.Issue.Comment.Value createIssuesIssueCommentValue() {
         return new Issues.Issue.Comment.Value();
     }
 
     /**
-     * Create an instance of {@link Issues.Issue.Comment }
-     */
-    public Issues.Issue.Comment createIssuesIssueComment()
-    {
-        return new Issues.Issue.Comment();
-    }
-
-    /**
      * Create an instance of {@link Issues.Issue.Field }
      */
-    public Issues.Issue.Field createIssuesIssueField()
-    {
+    public Issues.Issue.Field createIssuesIssueField() {
         return new Issues.Issue.Field();
     }
 
     /**
      * Create an instance of {@link Issues }
      */
-    public Issues createIssues()
-    {
+    public Issues createIssues() {
         return new Issues();
     }
 
     /**
-     * Create an instance of {@link Issues.Issue }
+     * Create an instance of {@link Issues.Issue.Field.Value }
      */
-    public Issues.Issue createIssuesIssue()
-    {
-        return new Issues.Issue();
+    public Issues.Issue.Field.Value createIssuesIssueFieldValue() {
+        return new Issues.Issue.Field.Value();
     }
 
     /**
-     * Create an instance of {@link Issues.Issue.Field.Value }
+     * Create an instance of {@link Issues.Issue.Comment }
      */
-    public Issues.Issue.Field.Value createIssuesIssueFieldValue()
-    {
-        return new Issues.Issue.Field.Value();
+    public Issues.Issue.Comment createIssuesIssueComment() {
+        return new Issues.Issue.Comment();
     }
 
     /**
-     * Create an instance of {@link JAXBElement }{@code <}{@link Issues.Issue.Field.Value }{@code >}}
+     * Create an instance of {@link Issues.Issue }
      */
-    @XmlElementDecl(namespace = "", name = "value", scope = Issues.Issue.Field.class)
-    public JAXBElement<Issues.Issue.Field.Value> createIssuesIssueFieldValue(Issues.Issue.Field.Value value)
-    {
-        return new JAXBElement<Issues.Issue.Field.Value>(_IssuesIssueFieldValue_QNAME, Issues.Issue.Field.Value.class, Issues.Issue.Field.class, value);
+    public Issues.Issue createIssuesIssue() {
+        return new Issues.Issue();
     }
+
 }
diff --git a/src/main/java/pl/com/it_crowd/youtrack/api/rest/YoutrackAPI.java b/src/main/java/pl/com/it_crowd/youtrack/api/rest/YoutrackAPI.java
index 9b64c5f..75b49c7 100644
--- a/src/main/java/pl/com/it_crowd/youtrack/api/rest/YoutrackAPI.java
+++ b/src/main/java/pl/com/it_crowd/youtrack/api/rest/YoutrackAPI.java
@@ -1,59 +1,82 @@
 package pl.com.it_crowd.youtrack.api.rest;
 
 import com.gargoylesoftware.htmlunit.BrowserVersion;
+import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
 import com.gargoylesoftware.htmlunit.HttpMethod;
 import com.gargoylesoftware.htmlunit.Page;
 import com.gargoylesoftware.htmlunit.WebClient;
 import com.gargoylesoftware.htmlunit.WebRequest;
 import com.gargoylesoftware.htmlunit.WebResponse;
+import com.gargoylesoftware.htmlunit.html.DomNode;
 import com.gargoylesoftware.htmlunit.util.NameValuePair;
+import com.gargoylesoftware.htmlunit.xml.XmlPage;
+import org.apache.http.auth.AuthenticationException;
+import pl.com.it_crowd.youtrack.api.Issue;
 import pl.com.it_crowd.youtrack.api.IssuesUnmarshaller;
 
 import javax.xml.bind.JAXBException;
 import java.io.IOException;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.List;
 
 public class YoutrackAPI {
+// ------------------------------ FIELDS ------------------------------
 
     private String serviceLocation;
 
     private WebClient webClient;
 
-    public String getServiceLocation()
-    {
-        return serviceLocation;
-    }
+// --------------------------- CONSTRUCTORS ---------------------------
 
-    public YoutrackAPI(String serviceLocation)
-    {
+    public YoutrackAPI(String serviceLocation) {
         this.serviceLocation = serviceLocation;
         this.webClient = new WebClient(BrowserVersion.FIREFOX_3_6);
         this.webClient.setJavaScriptEnabled(false);
         this.webClient.setCssEnabled(false);
     }
 
-    public YoutrackAPI(String serviceLocation, String username, String password) throws IOException
-    {
+    public YoutrackAPI(String serviceLocation, String username, String password) throws IOException, AuthenticationException {
         this(serviceLocation);
         login(username, password);
     }
 
-    public void login(String username, String password) throws IOException
-    {
+// --------------------- GETTER / SETTER METHODS ---------------------
+
+    public String getServiceLocation() {
+        return serviceLocation;
+    }
+
+// -------------------------- OTHER METHODS --------------------------
+
+    public void login(String username, String password) throws IOException, AuthenticationException {
         ArrayList<NameValuePair> requestParameters = new ArrayList<NameValuePair>();
         requestParameters.add(new NameValuePair("login", username));
         requestParameters.add(new NameValuePair("password", password));
         WebRequest request = new WebRequest(new URL(serviceLocation + "/rest/user/login"), HttpMethod.POST);
         request.setRequestParameters(requestParameters);
-        WebResponse response = webClient.getPage(request).getWebResponse();
-        System.out.println(response);
-        System.out.println(response.getContentAsString());
+        try {
+            webClient.getPage(request);
+        } catch (FailingHttpStatusCodeException e) {
+            if (e.getStatusCode() == 403) {
+                DomNode error = ((XmlPage) webClient.getCurrentWindow().getEnclosedPage()).getFirstChild();
+                if (error != null) {
+                    throw new AuthenticationException(error.getTextContent());
+                }
+            }
+            throw e;
+        }
     }
 
-    public Issues searchIssuesByProject(String project, String filter) throws JAXBException, IOException
-    {
+    public List<Issue> searchIssuesByProject(String project, String filter) throws JAXBException, IOException {
         String url = serviceLocation + "/rest/issue/byproject/" + project + "?filter=" + filter;
-        return IssuesUnmarshaller.unmarshal(webClient.<Page>getPage(url).getWebResponse().getContentAsStream());
+        WebResponse webResponse = webClient.<Page>getPage(url).getWebResponse();
+//        System.out.println(webResponse.getContentAsString());
+        List<Issues.Issue> issues = IssuesUnmarshaller.unmarshal(webResponse.getContentAsStream()).getIssue();
+        List<Issue> result = new ArrayList<Issue>();
+        for (Issues.Issue issue : issues) {
+            result.add(new Issue(issue));
+        }
+        return result;
     }
 }
diff --git a/src/main/xjb/bindings.xjb b/src/main/xjb/bindings.xjb
new file mode 100644
index 0000000..95d5880
--- /dev/null
+++ b/src/main/xjb/bindings.xjb
@@ -0,0 +1,18 @@
+<jxb:bindings version="1.0"
+              xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
+              xmlns:xs="http://www.w3.org/2001/XMLSchema"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
+        >
+    <jxb:bindings schemaLocation="../xsd/issuesByProject.xsd" node="/xs:schema">
+
+        <jxb:globalBindings localScoping="nested"/>
+        <jxb:bindings node="//xs:element[@name='issues']">
+            <jxb:bindings node=".//xs:element[@name='field']">
+                <jxb:bindings node=".//xs:element[@name='value']">
+                    <jxb:property name="values"/>
+                </jxb:bindings>
+            </jxb:bindings>
+        </jxb:bindings>
+    </jxb:bindings>
+</jxb:bindings>
\ No newline at end of file
diff --git a/src/main/xsd/issuesByProject.xsd b/src/main/xsd/issuesByProject.xsd
index a8e4eb0..261031c 100644
--- a/src/main/xsd/issuesByProject.xsd
+++ b/src/main/xsd/issuesByProject.xsd
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
     <xs:element name="issues">
         <xs:complexType>
             <xs:sequence>
@@ -7,10 +7,10 @@
                     <xs:complexType>
                         <xs:choice maxOccurs="unbounded" minOccurs="0">
                             <xs:element name="field">
-                                <xs:complexType mixed="true">
+                                <xs:complexType>
                                     <xs:sequence>
                                         <xs:element name="value" maxOccurs="unbounded" minOccurs="0">
-                                            <xs:complexType>
+                                            <xs:complexType mixed="true">
                                                 <xs:attribute type="xs:string" name="type" use="optional"/>
                                                 <xs:attribute type="xs:string" name="role" use="optional"/>
                                             </xs:complexType>
diff --git a/src/test/java/pl/com/it_crowd/youtrack/api/rest/YoutrackAPITest.java b/src/test/java/pl/com/it_crowd/youtrack/api/rest/YoutrackAPITest.java
new file mode 100644
index 0000000..fa86ee8
--- /dev/null
+++ b/src/test/java/pl/com/it_crowd/youtrack/api/rest/YoutrackAPITest.java
@@ -0,0 +1,53 @@
+package pl.com.it_crowd.youtrack.api.rest;
+
+import junit.framework.Assert;
+import org.apache.http.auth.AuthenticationException;
+import org.junit.Test;
+import pl.com.it_crowd.youtrack.api.Issue;
+
+import javax.xml.bind.JAXBException;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * This test requires setting JVM params youtrackUsername and youtrackPassword.
+ */
+public class YoutrackAPITest {
+// -------------------------- OTHER METHODS --------------------------
+
+    @Test(expected = AuthenticationException.class)
+    public void loginFailureTest() throws IOException, AuthenticationException {
+        final String username = "someFakeLogin";
+        final String password = "someFakePassword";
+        new YoutrackAPI("http://youtrack.it-crowd.com.pl", username, password);
+    }
+
+    @Test
+    public void loginTest() throws IOException, AuthenticationException {
+        final String username = getUsername();
+        final String password = getPassword();
+        new YoutrackAPI("http://youtrack.it-crowd.com.pl", username, password);
+        YoutrackAPI api = new YoutrackAPI("http://youtrack.it-crowd.com.pl");
+        api.login(username, password);
+    }
+
+    @Test
+    public void searchIssuesByProjectTest() throws IOException, AuthenticationException, JAXBException {
+        YoutrackAPI api = new YoutrackAPI("http://youtrack.it-crowd.com.pl", getUsername(), getPassword());
+        List<Issue> issues = api.searchIssuesByProject("SM", null);
+        Assert.assertTrue(!issues.isEmpty());
+        for (Issue issue : issues) {
+            String summary = issue.getFieldValue(Issue.Fields.summary);
+            Assert.assertNotNull(summary);
+            Assert.assertTrue(!"".equals(summary.trim()));
+        }
+    }
+
+    private String getPassword() {
+        return System.getProperty("youtrackPassword");
+    }
+
+    private String getUsername() {
+        return System.getProperty("youtrackUsername");
+    }
+}
--
libgit2 0.24.0