src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/Coordinator.java

changeset 397
b99d7e355d4b
parent 286
f50545b5e2f1
child 637
9c07ef4934dd
equal deleted inserted replaced
393:6cdc6ed98780 397:b99d7e355d4b
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 //
205 // bail-out of the parse with a SAX exception, but convert it into 167 // bail-out of the parse with a SAX exception, but convert it into
206 // an UnmarshalException back in in the AbstractUnmarshaller 168 // an UnmarshalException back in in the AbstractUnmarshaller
207 throw saxException; 169 throw saxException;
208 } 170 }
209 } 171 }
210
211 public static boolean debugTableNPE;
212
213 static {
214 try {
215 debugTableNPE = Boolean.getBoolean(Coordinator.class.getName()+".debugTableNPE");
216 } catch (SecurityException t) {
217 }
218 }
219 } 172 }

mercurial