Esempio n. 1
0
  // Copy the ThreadContainer tree structure down into the underlying Threadable objects
  // (Make the Threadable tree look like the ThreadContainer tree)
  void flush() {
    if (parent != null && threadable == null)
      throw new RuntimeException("no threadable in " + this.toString());

    parent = null;

    if (threadable != null) threadable.setChild(child == null ? null : child.threadable);

    if (child != null) {
      child.flush();
      child = null;
    }

    if (threadable != null) threadable.setNext(next == null ? null : next.threadable);

    if (next != null) {
      next.flush();
      next = null;
    }

    threadable = null;
  }
Esempio n. 2
0
  /** @param threadable */
  private void buildContainer(Threadable threadable) {
    String id = threadable.messageThreadId();
    ThreadContainer container = (ThreadContainer) idTable.get(id);

    // A ThreadContainer exists for this id already. This should be a forward reference, but may
    // be a duplicate id, in which case we will need to generate a bogus placeholder id
    if (container != null) {
      if (container.threadable != null) { // oops! duplicate ids...
        id = "<Bogus-id:" + (bogusIdCount++) + ">";
        container = null;
      } else {
        // The container just contained a forward reference to this message, so let's
        // fill in the threadable field of the container with this message
        container.threadable = threadable;
      }
    }

    // No container exists for that message Id. Create one and insert it into the hash table.
    if (container == null) {
      container = new ThreadContainer();
      container.threadable = threadable;
      idTable.put(id, container);
    }

    // Iterate through all of the references and create ThreadContainers for any references that
    // don't have them.
    ThreadContainer parentRef = null;
    {
      String[] references = threadable.messageThreadReferences();
      for (int i = 0; i < references.length; ++i) {
        String refString = references[i];
        ThreadContainer ref = (ThreadContainer) idTable.get(refString);

        // if this id doesnt have a container, create one
        if (ref == null) {
          ref = new ThreadContainer();
          idTable.put(refString, ref);
        }

        // Link references together in the order they appear in the References: header,
        // IF they dont have a have a parent already &&
        // IF it will not cause a circular reference
        if ((parentRef != null)
            && (ref.parent == null)
            && (parentRef != ref)
            && !(parentRef.findChild(ref))) {
          // Link ref into the parent's child list
          ref.parent = parentRef;
          ref.next = parentRef.child;
          parentRef.child = ref;
        }
        parentRef = ref;
      }
    }

    // parentRef is now set to the container of the last element in the references field. make that
    // be the parent of this container, unless doing so causes a circular reference
    if (parentRef != null && (parentRef == container || container.findChild(parentRef)))
      parentRef = null;

    // if it has a parent already, its because we saw this message in a References: field, and
    // presumed
    // a parent based on the other entries in that field. Now that we have the actual message, we
    // can
    // throw away the old parent and use this new one
    if (container.parent != null) {
      ThreadContainer rest, prev;

      for (prev = null, rest = container.parent.child;
          rest != null;
          prev = rest, rest = rest.next) {
        if (rest == container) break;
      }

      if (rest == null) {
        throw new RuntimeException("Didnt find " + container + " in parent" + container.parent);
      }

      // Unlink this container from the parent's child list
      if (prev == null) container.parent.child = container.next;
      else prev.next = container.next;

      container.next = null;
      container.parent = null;
    }

    // If we have a parent, link container into the parents child list
    if (parentRef != null) {
      container.parent = parentRef;
      container.next = parentRef.child;
      parentRef.child = container;
    }
  }
Esempio n. 3
0
  /**
   * If any two members of the root set have the same subject, merge them. This is to attempt to
   * accomodate messages without References: headers.
   */
  private void gatherSubjects() {

    int count = 0;

    for (ThreadContainer c = root.child; c != null; c = c.next) count++;

    // TODO verify this will avoid rehashing
    HashMap subjectTable = new HashMap((int) (count * 1.2), (float) 0.9);
    count = 0;

    for (ThreadContainer c = root.child; c != null; c = c.next) {
      Threadable threadable = c.threadable;

      // No threadable? If so, it is a dummy node in the root set.
      // Only root set members may be dummies, and they alway have at least 2 kids
      // Take the first kid as representative of the subject
      if (threadable == null) threadable = c.child.threadable;

      String subj = threadable.simplifiedSubject();

      if (subj == null || subj == "") continue;

      ThreadContainer old = (ThreadContainer) subjectTable.get(subj);

      // Add this container to the table iff:
      // - There exists no container with this subject
      // - or this is a dummy container and the old one is not - the dummy one is
      // more interesting as a root, so put it in the table instead
      // - The container in the table has a "Re:" version of this subject, and
      // this container has a non-"Re:" version of this subject. The non-"Re:" version
      // is the more interesting of the two.
      if (old == null
          || (c.threadable == null && old.threadable != null)
          || (old.threadable != null
              && old.threadable.subjectIsReply()
              && c.threadable != null
              && !c.threadable.subjectIsReply())) {
        subjectTable.put(subj, c);
        count++;
      }
    }

    // If the table is empty, we're done
    if (count == 0) return;

    // subjectTable is now populated with one entry for each subject which occurs in the
    // root set. Iterate over the root set, and gather together the difference.
    ThreadContainer prev, c, rest;
    for (prev = null, c = root.child, rest = c.next;
        c != null;
        prev = c, c = rest, rest = (rest == null ? null : rest.next)) {
      Threadable threadable = c.threadable;

      // is it a dummy node?
      if (threadable == null) threadable = c.child.threadable;

      String subj = threadable.simplifiedSubject();

      // Dont thread together all subjectless messages
      if (subj == null || subj == "") continue;

      ThreadContainer old = (ThreadContainer) subjectTable.get(subj);

      if (old == c) // That's us
      continue;

      // We have now found another container in the root set with the same subject
      // Remove the "second" message from the root set
      if (prev == null) root.child = c.next;
      else prev.next = c.next;
      c.next = null;

      if (old.threadable == null && c.threadable == null) {
        // both dummies - merge them
        ThreadContainer tail;
        for (tail = old.child; tail != null && tail.next != null; tail = tail.next) ;

        tail.next = c.child;

        for (tail = c.child; tail != null; tail = tail.next) tail.parent = old;

        c.child = null;
      } else if (old.threadable == null
          || (c.threadable != null
              && c.threadable.subjectIsReply()
              && !old.threadable.subjectIsReply())) {
        // Else if old is empty, or c has "Re:" and old does not  ==> make this message a child of
        // old
        c.parent = old;
        c.next = old.child;
        old.child = c;
      } else {
        //	else make the old and new messages be children of a new dummy container.
        // We create a new container object for old.msg and empty the old container
        ThreadContainer newc = new ThreadContainer();
        newc.threadable = old.threadable;
        newc.child = old.child;

        for (ThreadContainer tail = newc.child; tail != null; tail = tail.next) tail.parent = newc;

        old.threadable = null;
        old.child = null;

        c.parent = old;
        newc.parent = old;

        // Old is now a dummy- give it 2 kids , c and newc
        old.child = c;
        c.next = newc;
      }
      // We've done a merge, so keep the same prev
      c = prev;
    }

    subjectTable.clear();
    subjectTable = null;
  }