1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.net.nntp;
19
20 /**
21 * A placeholder utility class, used for constructing a tree of Threadables
22 * Original implementation by Jamie Zawinski.
23 * See the Grendel source for more details <a href="http://lxr.mozilla.org/mozilla/source/grendel/sources/grendel/view/Threader.java#511">here</a>
24 * Threadable objects
25 * @author Rory Winston <rwinston@apache.org>
26 */
27 class ThreadContainer {
28 Threadable threadable;
29 ThreadContainer parent;
30 // ThreadContainer prev;
31 ThreadContainer next;
32 ThreadContainer child;
33
34 /**
35 *
36 * @param container
37 * @return true if child is under self's tree. Detects circular references
38 */
39 boolean findChild(ThreadContainer target) {
40 if (child == null) {
41 return false;
42 } else if (child == target) {
43 return true;
44 } else {
45 return child.findChild(target);
46 }
47 }
48
49 // Copy the ThreadContainer tree structure down into the underlying Threadable objects
50 // (Make the Threadable tree look like the ThreadContainer tree)
51 // TODO convert this to an iterative function - this can blow the stack
52 // with very large Threadable trees
53 void flush() {
54 if (parent != null && threadable == null) {
55 throw new RuntimeException("no threadable in " + this.toString());
56 }
57
58 parent = null;
59
60 if (threadable != null) {
61 threadable.setChild(child == null ? null : child.threadable);
62 }
63
64 if (child != null) {
65 child.flush();
66 child = null;
67 }
68
69 if (threadable != null) {
70 threadable.setNext(next == null ? null : next.threadable);
71 }
72
73 if (next != null) {
74 next.flush();
75 next = null;
76 }
77
78 threadable = null;
79 }
80
81 /**
82 * Reverse the entire set of children
83 *
84 */
85 void reverseChildren() {
86 if (child != null) {
87 ThreadContainer kid, prev, rest;
88 for (prev = null, kid = child, rest = kid.next;
89 kid != null;
90 prev = kid,
91 kid = rest,
92 rest = (rest == null ? null : rest.next))
93 {
94 kid.next = prev;
95 }
96
97 child = prev;
98
99 // Do it for the kids
100 for (kid = child; kid != null; kid = kid.next) {
101 kid.reverseChildren();
102 }
103 }
104 }
105 }