1 /* |
1 /* |
2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
5 * This code is free software; you can redistribute it and/or modify it |
6 * under the terms of the GNU General Public License version 2 only, as |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this |
7 * published by the Free Software Foundation. Oracle designates this |
33 import java.util.HashMap; |
33 import java.util.HashMap; |
34 import java.util.Iterator; |
34 import java.util.Iterator; |
35 import java.util.List; |
35 import java.util.List; |
36 import java.util.Map; |
36 import java.util.Map; |
37 import java.util.concurrent.Callable; |
37 import java.util.concurrent.Callable; |
38 import java.util.logging.Level; |
|
39 import java.util.logging.Logger; |
|
40 |
38 |
41 import javax.xml.XMLConstants; |
39 import javax.xml.XMLConstants; |
42 import javax.xml.bind.JAXBElement; |
40 import javax.xml.bind.JAXBElement; |
43 import javax.xml.bind.UnmarshalException; |
41 import javax.xml.bind.UnmarshalException; |
44 import javax.xml.bind.Unmarshaller; |
42 import javax.xml.bind.Unmarshaller; |
196 */ |
194 */ |
197 public final class State { |
195 public final class State { |
198 /** |
196 /** |
199 * Loader that owns this element. |
197 * Loader that owns this element. |
200 */ |
198 */ |
201 public Loader loader; |
199 private Loader loader; |
202 /** |
200 /** |
203 * Once {@link #loader} is completed, this receiver |
201 * Once {@link #loader} is completed, this receiver |
204 * receives the result. |
202 * receives the result. |
205 */ |
203 */ |
206 public Receiver receiver; |
204 private Receiver receiver; |
207 |
205 |
208 public Intercepter intercepter; |
206 private Intercepter intercepter; |
209 |
|
210 |
207 |
211 /** |
208 /** |
212 * Object being unmarshalled by this {@link #loader}. |
209 * Object being unmarshalled by this {@link #loader}. |
213 */ |
210 */ |
214 public Object target; |
211 private Object target; |
215 |
212 |
216 /** |
213 /** |
217 * Hack for making JAXBElement unmarshalling work. |
214 * Hack for making JAXBElement unmarshalling work. |
218 * |
215 * |
219 * <p> |
216 * <p> |
238 * Yes, I know this is a hack, and no, I'm not proud of it. |
235 * Yes, I know this is a hack, and no, I'm not proud of it. |
239 * |
236 * |
240 * @see ElementBeanInfoImpl.IntercepterLoader#startElement(State, TagName) |
237 * @see ElementBeanInfoImpl.IntercepterLoader#startElement(State, TagName) |
241 * @see ElementBeanInfoImpl.IntercepterLoader#intercept(State, Object) |
238 * @see ElementBeanInfoImpl.IntercepterLoader#intercept(State, Object) |
242 */ |
239 */ |
243 public Object backup; |
240 private Object backup; |
244 |
241 |
245 /** |
242 /** |
246 * Number of {@link UnmarshallingContext#nsBind}s declared thus far. |
243 * Number of {@link UnmarshallingContext#nsBind}s declared thus far. |
247 * (The value of {@link UnmarshallingContext#nsLen} when this state is pushed. |
244 * (The value of {@link UnmarshallingContext#nsLen} when this state is pushed. |
248 */ |
245 */ |
254 * This should be set by either a parent {@link Loader} when |
251 * This should be set by either a parent {@link Loader} when |
255 * {@link Loader#childElement(State, TagName)} is called |
252 * {@link Loader#childElement(State, TagName)} is called |
256 * or by a child {@link Loader} when |
253 * or by a child {@link Loader} when |
257 * {@link Loader#startElement(State, TagName)} is called. |
254 * {@link Loader#startElement(State, TagName)} is called. |
258 */ |
255 */ |
259 public String elementDefaultValue; |
256 private String elementDefaultValue; |
260 |
257 |
261 /** |
258 /** |
262 * {@link State} for the parent element |
259 * {@link State} for the parent element |
263 * |
260 * |
264 * {@link State} objects form a doubly linked list. |
261 * {@link State} objects form a doubly linked list. |
265 */ |
262 */ |
266 public State prev; |
263 private State prev; |
267 private State next; |
264 private State next; |
268 |
265 |
269 public boolean nil = false; |
266 private boolean nil = false; |
|
267 |
|
268 /** |
|
269 * specifies that we are working with mixed content |
|
270 */ |
|
271 private boolean mixed = false; |
270 |
272 |
271 /** |
273 /** |
272 * Gets the context. |
274 * Gets the context. |
273 */ |
275 */ |
274 public UnmarshallingContext getContext() { |
276 public UnmarshallingContext getContext() { |
278 @SuppressWarnings("LeakingThisInConstructor") |
280 @SuppressWarnings("LeakingThisInConstructor") |
279 private State(State prev) { |
281 private State(State prev) { |
280 this.prev = prev; |
282 this.prev = prev; |
281 if (prev!=null) { |
283 if (prev!=null) { |
282 prev.next = this; |
284 prev.next = this; |
|
285 if (prev.mixed) // parent is in mixed mode |
|
286 this.mixed = true; |
283 } |
287 } |
284 } |
288 } |
285 |
289 |
286 private void push() { |
290 private void push() { |
287 if (logger.isLoggable(Level.FINEST)) { |
291 if (logger.isLoggable(Level.FINEST)) { |
288 logger.log(Level.FINEST, "State.push"); |
292 logger.log(Level.FINEST, "State.push"); |
289 } |
293 } |
290 if (next==null) { |
294 if (next==null) { |
291 assert current == this; |
295 assert current == this; |
292 allocateMoreStates(); |
296 next = new State(this); |
293 } |
297 } |
294 nil = false; |
298 nil = false; |
295 State n = next; |
299 State n = next; |
296 n.numNsDecl = nsLen; |
300 n.numNsDecl = nsLen; |
297 current = n; |
301 current = n; |
302 logger.log(Level.FINEST, "State.pop"); |
306 logger.log(Level.FINEST, "State.pop"); |
303 } |
307 } |
304 assert prev!=null; |
308 assert prev!=null; |
305 loader = null; |
309 loader = null; |
306 nil = false; |
310 nil = false; |
|
311 mixed = false; |
307 receiver = null; |
312 receiver = null; |
308 intercepter = null; |
313 intercepter = null; |
309 elementDefaultValue = null; |
314 elementDefaultValue = null; |
310 target = null; |
315 target = null; |
311 current = prev; |
316 current = prev; |
|
317 next = null; |
|
318 } |
|
319 |
|
320 public boolean isMixed() { |
|
321 return mixed; |
|
322 } |
|
323 |
|
324 public Object getTarget() { |
|
325 return target; |
|
326 } |
|
327 |
|
328 public void setLoader(Loader loader) { |
|
329 if (loader instanceof StructureLoader) // set mixed mode |
|
330 mixed = !((StructureLoader)loader).getBeanInfo().hasElementOnlyContentModel(); |
|
331 this.loader = loader; |
|
332 } |
|
333 |
|
334 public void setReceiver(Receiver receiver) { |
|
335 this.receiver = receiver; |
|
336 } |
|
337 |
|
338 public State getPrev() { |
|
339 return prev; |
|
340 } |
|
341 |
|
342 public void setIntercepter(Intercepter intercepter) { |
|
343 this.intercepter = intercepter; |
|
344 } |
|
345 |
|
346 public void setBackup(Object backup) { |
|
347 this.backup = backup; |
|
348 } |
|
349 |
|
350 public void setTarget(Object target) { |
|
351 this.target = target; |
|
352 } |
|
353 |
|
354 public Object getBackup() { |
|
355 return backup; |
|
356 } |
|
357 |
|
358 public boolean isNil() { |
|
359 return nil; |
|
360 } |
|
361 |
|
362 public void setNil(boolean nil) { |
|
363 this.nil = nil; |
|
364 } |
|
365 |
|
366 public Loader getLoader() { |
|
367 return loader; |
|
368 } |
|
369 |
|
370 public String getElementDefaultValue() { |
|
371 return elementDefaultValue; |
|
372 } |
|
373 |
|
374 public void setElementDefaultValue(String elementDefaultValue) { |
|
375 this.elementDefaultValue = elementDefaultValue; |
312 } |
376 } |
313 } |
377 } |
314 |
378 |
315 /** |
379 /** |
316 * Stub to the user-specified factory method. |
380 * Stub to the user-specified factory method. |
346 */ |
410 */ |
347 public UnmarshallingContext( UnmarshallerImpl _parent, AssociationMap assoc) { |
411 public UnmarshallingContext( UnmarshallerImpl _parent, AssociationMap assoc) { |
348 this.parent = _parent; |
412 this.parent = _parent; |
349 this.assoc = assoc; |
413 this.assoc = assoc; |
350 this.root = this.current = new State(null); |
414 this.root = this.current = new State(null); |
351 allocateMoreStates(); |
|
352 } |
415 } |
353 |
416 |
354 public void reset(InfosetScanner scanner,boolean isInplaceMode, JaxBeanInfo expectedType, IDResolver idResolver) { |
417 public void reset(InfosetScanner scanner,boolean isInplaceMode, JaxBeanInfo expectedType, IDResolver idResolver) { |
355 this.scanner = scanner; |
418 this.scanner = scanner; |
356 this.isInplaceMode = isInplaceMode; |
419 this.isInplaceMode = isInplaceMode; |
391 } catch (Exception e) { |
454 } catch (Exception e) { |
392 handleError(e); |
455 handleError(e); |
393 } |
456 } |
394 |
457 |
395 return null; |
458 return null; |
396 } |
|
397 |
|
398 /** |
|
399 * Allocates a few more {@link State}s. |
|
400 * |
|
401 * Allocating multiple {@link State}s at once allows those objects |
|
402 * to be allocated near each other, which reduces the working set |
|
403 * of CPU. It improves the chance the relevant data is in the cache. |
|
404 */ |
|
405 private void allocateMoreStates() { |
|
406 // this method should be used only when we run out of a state. |
|
407 assert current.next==null; |
|
408 |
|
409 State s = current; |
|
410 for (int i=0; i<8; i++) { |
|
411 s = new State(s); |
|
412 } |
|
413 } |
459 } |
414 |
460 |
415 public void clearStates() { |
461 public void clearStates() { |
416 State last = current; |
462 State last = current; |
417 while (last.next != null) last = last.next; |
463 while (last.next != null) last = last.next; |
513 current.loader.startElement(current,tagName); |
559 current.loader.startElement(current,tagName); |
514 } |
560 } |
515 |
561 |
516 @Override |
562 @Override |
517 public void text(CharSequence pcdata) throws SAXException { |
563 public void text(CharSequence pcdata) throws SAXException { |
518 State cur = current; |
|
519 pushCoordinator(); |
564 pushCoordinator(); |
520 try { |
565 try { |
521 if(cur.elementDefaultValue!=null) { |
566 if (current.elementDefaultValue != null) { |
522 if(pcdata.length()==0) { |
567 if (pcdata.length() == 0) { |
523 // send the default value into the unmarshaller instead |
568 // send the default value into the unmarshaller instead |
524 pcdata = cur.elementDefaultValue; |
569 pcdata = current.elementDefaultValue; |
525 } |
570 } |
526 } |
571 } |
527 cur.loader.text(cur,pcdata); |
572 current.loader.text(current, pcdata); |
528 } finally { |
573 } finally { |
529 popCoordinator(); |
574 popCoordinator(); |
530 } |
575 } |
531 } |
576 } |
532 |
577 |