001: /*
002: * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.xml.internal.bind.v2.runtime;
027:
028: import java.util.HashMap;
029:
030: import javax.xml.bind.ValidationEvent;
031: import javax.xml.bind.ValidationEventHandler;
032: import javax.xml.bind.ValidationEventLocator;
033: import javax.xml.bind.annotation.adapters.XmlAdapter;
034: import javax.xml.bind.helpers.ValidationEventImpl;
035:
036: import com.sun.xml.internal.bind.v2.ClassFactory;
037: import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext;
038:
039: import org.xml.sax.ErrorHandler;
040: import org.xml.sax.SAXException;
041: import org.xml.sax.SAXParseException;
042:
043: /**
044: * Object that coordinates the marshalling/unmarshalling.
045: *
046: * <p>
047: * This class takes care of the logic that allows code to obtain
048: * {@link UnmarshallingContext} and {@link XMLSerializer} instances
049: * during the unmarshalling/marshalling.
050: *
051: * <p>
052: * This is done by using a {@link ThreadLocal}. Therefore one unmarshalling/marshalling
053: * episode has to be done from the beginning till end by the same thread.
054: * (Note that the same {@link Coordinator} can be then used by a different thread
055: * for an entirely different episode.)
056: *
057: * This class also maintains the user-configured instances of {@link XmlAdapter}s.
058: *
059: * <p>
060: * This class implements {@link ErrorHandler} and propages erros to this object
061: * as the {@link ValidationEventHandler}, which will be implemented in a derived class.
062: *
063: * @author Kohsuke Kawaguchi
064: */
065: public abstract class Coordinator implements ErrorHandler,
066: ValidationEventHandler {
067:
068: private final HashMap<Class<? extends XmlAdapter>, XmlAdapter> adapters = new HashMap<Class<? extends XmlAdapter>, XmlAdapter>();
069:
070: public final XmlAdapter putAdapter(Class<? extends XmlAdapter> c,
071: XmlAdapter a) {
072: if (a == null)
073: return adapters.remove(c);
074: else
075: return adapters.put(c, a);
076: }
077:
078: /**
079: * Gets the instance of the adapter.
080: *
081: * @return
082: * always non-null.
083: */
084: public final <T extends XmlAdapter> T getAdapter(Class<T> key) {
085: T v = key.cast(adapters.get(key));
086: if (v == null) {
087: v = ClassFactory.create(key);
088: putAdapter(key, v);
089: }
090: return v;
091: }
092:
093: public <T extends XmlAdapter> boolean containsAdapter(Class<T> type) {
094: return adapters.containsKey(type);
095: }
096:
097: /**
098: * The {@link Coordinator} in charge before this {@link Coordinator}.
099: */
100: 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 Coordinator[] 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: guyWhoSetTheTableToNull = new Exception(); // remember that we set it to null
130: table = null;
131: }
132:
133: /**
134: * Called whenever an execution flow enters the realm of this {@link Coordinator}.
135: */
136: protected final void pushCoordinator() {
137: old = table[0];
138: table[0] = this ;
139: }
140:
141: /**
142: * Called whenever an execution flow exits the realm of this {@link Coordinator}.
143: */
144: protected final void popCoordinator() {
145: assert table[0] == this ;
146: table[0] = old;
147: old = null; // avoid memory leak
148: }
149:
150: public static Coordinator _getInstance() {
151: return activeTable.get()[0];
152: }
153:
154: // this much is necessary to avoid calling get and set twice when we push.
155: private static final ThreadLocal<Coordinator[]> activeTable = new ThreadLocal<Coordinator[]>() {
156: public Coordinator[] initialValue() {
157: return new Coordinator[1];
158: }
159: };
160:
161: //
162: //
163: // ErrorHandler implementation
164: //
165: //
166: /**
167: * Gets the current location. Used for reporting the error source location.
168: */
169: protected abstract ValidationEventLocator getLocation();
170:
171: public final void error(SAXParseException exception)
172: throws SAXException {
173: propagateEvent(ValidationEvent.ERROR, exception);
174: }
175:
176: public final void warning(SAXParseException exception)
177: throws SAXException {
178: propagateEvent(ValidationEvent.WARNING, exception);
179: }
180:
181: public final void fatalError(SAXParseException exception)
182: throws SAXException {
183: propagateEvent(ValidationEvent.FATAL_ERROR, exception);
184: }
185:
186: private void propagateEvent(int severity,
187: SAXParseException saxException) throws SAXException {
188:
189: ValidationEventImpl ve = new ValidationEventImpl(severity,
190: saxException.getMessage(), getLocation());
191:
192: Exception e = saxException.getException();
193: if (e != null) {
194: ve.setLinkedException(e);
195: } else {
196: ve.setLinkedException(saxException);
197: }
198:
199: // call the client's event handler. If it returns false, then bail-out
200: // and terminate the unmarshal operation.
201: boolean result = handleEvent(ve);
202: if (!result) {
203: // bail-out of the parse with a SAX exception, but convert it into
204: // an UnmarshalException back in in the AbstractUnmarshaller
205: throw saxException;
206: }
207: }
208:
209: }
|