private void addLink(TopLevelObject obj, String linkURI, String linkRel) {
   Link l = objFactory.createLinksLink();
   l.setOwner(this.getClass().getCanonicalName());
   l.setValue(linkURI);
   l.setRel(linkRel);
   addLink(obj, l);
 }
  @Override
  public TaskList retrieveTasks(StoryList stories)
      throws IOException, ClientProtocolException, ConnectorException, TransformerException,
          URISyntaxException {
    RallyRestApi restApi = new RallyRestApi(new URI(RALLY_SERVER_URL), username, password);
    QueryRequest taskQuery = new QueryRequest("Task");

    TaskList taskList = objFactory.createTaskList();
    try {
      for (StoryType story : stories.getStory()) {
        String storyID = story.getIdentifier();
        Link storyLink = findLinkByRel(story, RALLY_OBJECT_URL_REL);
        if (storyLink != null) {
          storyLink.setRel(RALLY_PARENT_URL_REL);
        }

        NDC.push("retrieving tasks for " + storyID);
        logger.debug(NDC.peek());
        QueryFilter filter = new QueryFilter("WorkProduct.FormattedID", "=", storyID);
        taskQuery.setQueryFilter(filter);
        QueryResponse query = restApi.query(taskQuery);
        if (query.wasSuccessful()) {
          for (JsonElement e : query.getResults()) {
            if (e == null) continue;
            TaskType task = objFactory.createTaskType();
            JsonObject jsonTask = e.getAsJsonObject();
            String taskName = jsonTask.get("Name").getAsString();

            task.setParentIdentifier(storyID);
            task.setDescription(fixDescription(getValueOrDefault(jsonTask.get("Description"), "")));
            if (!jsonTask.get("Owner").isJsonNull()) {
              task.setOwner(
                  getValueOrDefault(
                      jsonTask.get("Owner").getAsJsonObject().get("_refObjectName"), ""));
            }
            task.setFullName(taskName);
            task.setShortName((taskName.length() > 30) ? taskName.substring(0, 30) : taskName);
            task.setIdentifier(jsonTask.get("FormattedID").getAsString());
            task.setDetailedEstimate(getValueOrDefault(jsonTask.get("Estimate"), new Double(0.0)));
            task.setTodoRemaining(getValueOrDefault(jsonTask.get("Estimate"), new Double(0.0)));
            task.setEffortApplied(getValueOrDefault(jsonTask.get("Actuals"), new Double(0.0)));
            task.setDescription(fixDescription(getValueOrDefault(jsonTask.get("Description"), "")));
            addLink(story, jsonTask.get("_ref").getAsString(), RALLY_OBJECT_URL_REL);

            addLink(task, jsonTask.get("_ref").getAsString(), RALLY_OBJECT_URL_REL);
            addLink(task, storyLink);
            taskList.getTask().add(task);
          }
        }
      }
    } finally {
      NDC.pop();
      restApi.close();
    }
    return taskList;
  }
 private Link findLinkByRel(TopLevelObject obj, String linkRel) {
   Links links = obj.getLinks();
   if (links != null) {
     for (Link l : links.getLink()) {
       if (l.getRel().equalsIgnoreCase(linkRel)) {
         Link cloned = objFactory.createLinksLink();
         cloned.setOwner(l.getOwner());
         cloned.setRel(l.getRel());
         cloned.setValue(l.getValue());
         return cloned;
       }
     }
   }
   return null;
 }