92 |
92 |
93 public <T extends XmlAdapter> boolean containsAdapter(Class<T> type) { |
93 public <T extends XmlAdapter> boolean containsAdapter(Class<T> type) { |
94 return adapters.containsKey(type); |
94 return adapters.containsKey(type); |
95 } |
95 } |
96 |
96 |
|
97 // this much is necessary to avoid calling get and set twice when we push. |
|
98 private static final ThreadLocal<Coordinator> activeTable = new ThreadLocal<Coordinator>(); |
|
99 |
97 /** |
100 /** |
98 * The {@link Coordinator} in charge before this {@link Coordinator}. |
101 * The {@link Coordinator} in charge before this {@link Coordinator}. |
99 */ |
102 */ |
100 private Object old; |
103 private Coordinator old; |
101 |
|
102 /** |
|
103 * A 'pointer' to a {@link Coordinator} that keeps track of the currently active {@link Coordinator}. |
|
104 * Having this improves the runtime performance. |
|
105 */ |
|
106 private Object[] table; |
|
107 |
|
108 /** |
|
109 * When we set {@link #table} to null, record who did it. |
|
110 * This is for trouble-shooting a possible concurrency issue reported at: |
|
111 * http://forums.java.net/jive/thread.jspa?threadID=15132 |
|
112 */ |
|
113 public Exception guyWhoSetTheTableToNull; |
|
114 |
|
115 /** |
|
116 * Associates this {@link Coordinator} with the current thread. |
|
117 * Should be called at the very beginning of the episode. |
|
118 */ |
|
119 protected final void setThreadAffinity() { |
|
120 table = activeTable.get(); |
|
121 assert table!=null; |
|
122 } |
|
123 |
|
124 /** |
|
125 * Dis-associate this {@link Coordinator} with the current thread. |
|
126 * Sohuld be called at the end of the episode to avoid memory leak. |
|
127 */ |
|
128 protected final void resetThreadAffinity() { |
|
129 if (activeTable != null) { |
|
130 activeTable.remove(); |
|
131 } |
|
132 if(debugTableNPE) |
|
133 guyWhoSetTheTableToNull = new Exception(); // remember that we set it to null |
|
134 table = null; |
|
135 } |
|
136 |
104 |
137 /** |
105 /** |
138 * Called whenever an execution flow enters the realm of this {@link Coordinator}. |
106 * Called whenever an execution flow enters the realm of this {@link Coordinator}. |
139 */ |
107 */ |
140 protected final void pushCoordinator() { |
108 protected final void pushCoordinator() { |
141 old = table[0]; |
109 old = activeTable.get(); |
142 table[0] = this; |
110 activeTable.set(this); |
143 } |
111 } |
144 |
112 |
145 /** |
113 /** |
146 * Called whenever an execution flow exits the realm of this {@link Coordinator}. |
114 * Called whenever an execution flow exits the realm of this {@link Coordinator}. |
147 */ |
115 */ |
148 protected final void popCoordinator() { |
116 protected final void popCoordinator() { |
149 assert table[0]==this; |
117 if (old != null) |
150 table[0] = old; |
118 activeTable.set(old); |
|
119 else |
|
120 activeTable.remove(); |
151 old = null; // avoid memory leak |
121 old = null; // avoid memory leak |
152 } |
122 } |
153 |
123 |
154 public static Coordinator _getInstance() { |
124 public static Coordinator _getInstance() { |
155 return (Coordinator) activeTable.get()[0]; |
125 return activeTable.get(); |
156 } |
126 } |
157 |
|
158 // this much is necessary to avoid calling get and set twice when we push. |
|
159 private static final ThreadLocal<Object[]> activeTable = new ThreadLocal<Object[]>() { |
|
160 @Override |
|
161 public Object[] initialValue() { |
|
162 return new Object[1]; |
|
163 } |
|
164 }; |
|
165 |
127 |
166 // |
128 // |
167 // |
129 // |
168 // ErrorHandler implementation |
130 // ErrorHandler implementation |
169 // |
131 // |