dev@jax-ws.java.net

Re: XMLStreamReader recycling <was> [Fwd: CVS update [mr-21]: /jax-ws-sources/jaxws-ri/rt/src/com/sun/xml/ws/message/stream/]

From: Oleksiy Stashok <Oleksiy.Stashok_at_Sun.COM>
Date: Thu, 18 Jan 2007 02:31:20 +0100

Hi Paul,

here I reimplemented XMLStreamReaderFactory, taking in account the ideas
you had.
I think code become more difficult. But may be less hacky.
Any suggestions?

Thank you.

WBR,
Alexey.

Paul Sandoz wrote:
> Oleksiy Stashok wrote:
>> Hi.
>>
>> Can you pls. review XMLStreamReaderFactory I'm proposing. I made
>> changes to reuse it for FastInfoset's XMLStreamReader.
>> Actually for now I made Zephyr's factory implementation to be able to
>> work as common pool for all possible implementation of
>> XMLStreamReader. In this case seems name could be changed...
>>
>
> Looks OK. I think you need some JavaDoc.
>
> Some notes:
>
> 1) I do not see the need for two pools; (i almost thought there is no
> need for a Map since if the requested class is different it could
> replace that which is already there, but that could lead to trouble!).
>
> 2) The doCreate method you created will likely fail for a Zephyr
> instance but pass for an FI instance.
>
> 3) As you indicate the Zephyr class no longer fully reflects it's name
> :-( it is tricky because there is a mix of stuff going on, but i
> cannot think of something better.
>
>
> I am wondering if we can resolve this better by using a special
> XMLInputFactory implementation associated with the FI codec (note that
> there is an impl with FI but this contains a whole bunch of other
> stuff and is included with Mustang, for reasons of reducing the JRE
> size). Then we can register that with the appropriate reader class to
> the stream reader factory.
>
> That way we could have:
>
> doCreate(String systemId, InputStream in, boolean rejectDTDs, Class<?
> extends XMLStreamReader> c)
>
> and
>
> doCreate(String systemId, InputStream in, boolean rejectDTDs)
>
> would default to something meaningful i.e. using Zephyr because it is
> configured that way.
>
> Paul.
>
>> WBR,
>> Alexey.
>>
>>
>> Paul Sandoz wrote:
>>> Kohsuke Kawaguchi wrote:
>>>> Paul Sandoz wrote:
>>>>> This recycling is related to the same issue for the FI StAX parsers.
>>>>>
>>>>> I have not looked deeply at the code but it looks like the right
>>>>> place to support the recycling of XML *and* FI XMLStreamReader
>>>>> instances.
>>>>
>>>> Yeah, we can do that. The easiet way is to have FI's
>>>> XMLStreamReader implement RecycleAware. If needed we can move this
>>>> interface on stax-ex
>>>> to do this.
>>>>
>>>
>>> A FI XMLStreamReader instance automatically resets itself when an
>>> InputStream is set so it is not strictly necessary to implement this
>>> interface.
>>>
>>>
>>>>> I am wondering if it is possible to also recycle stream buffers
>>>>> i.e. when the message is no longer used.
>>>>
>>>> I think we should first check if it's indeed costly.
>>>
>>> Agreed, profiling for cases where non-security header blocks are
>>> present should tell is more.
>>>
>>> The reason i have a hunch is the fact that XML StAX parser creation
>>> showed up in the profiler mainly because it created a whole bunch of
>>> memory that could be reused. The same will happen with the
>>> streambuffer for headers.
>>>
>>> Paul.
>>>
>>>> So far, it doesn't seem like this is a big enough problem. Pooling
>>>> has its own overhead and problems, too.
>>>>
>>>> Finding out when a Message is no longer in use is harder than
>>>> finding that out for XMLStreamReader, so doing this is more work.
>>>> We need benefits that justify this work.
>>>>
>>>
>>
>> ------------------------------------------------------------------------
>>
>> package com.sun.xml.ws.api.streaming;
>>
>> import com.sun.istack.NotNull;
>> import com.sun.istack.Nullable;
>> import com.sun.xml.ws.streaming.XMLReaderException;
>> import java.util.HashMap;
>> import java.util.Map;
>> import org.xml.sax.InputSource;
>>
>> import javax.xml.stream.XMLInputFactory;
>> import javax.xml.stream.XMLStreamException;
>> import javax.xml.stream.XMLStreamReader;
>> import java.io.IOException;
>> import java.io.InputStream;
>> import java.io.Reader;
>> import java.io.StringReader;
>> import java.lang.reflect.InvocationTargetException;
>> import java.lang.reflect.Method;
>> import java.net.URL;
>>
>> /**
>> * Factory for {_at_link XMLStreamReader}.
>> *
>> * <p>
>> * This wraps {_at_link XMLInputFactory} and allows us to reuse {_at_link
>> XMLStreamReader} instances
>> * when appropriate.
>> *
>> * @author Kohsuke Kawaguchi
>> */
>> public abstract class XMLStreamReaderFactory {
>> /**
>> * Singleton instance.
>> */
>> private static volatile @NotNull XMLStreamReaderFactory theInstance;
>> static {
>> XMLInputFactory xif = XMLInputFactory.newInstance();
>> xif.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, true);
>> XMLStreamReaderFactory f=null;
>> // this system property can be used to disable the
>> pooling altogether,
>> // in case someone hits an issue with pooling in the
>> production system.
>>
>> if(!Boolean.getBoolean(XMLStreamReaderFactory.class.getName()+".noPool"))
>>
>> f = Zephyr.newInstance(xif);
>> if(f==null)
>> f = new Default(xif);
>> theInstance = f;
>> }
>> /**
>> * Overrides the singleton {_at_link XMLStreamReaderFactory}
>> instance that
>> * the JAX-WS RI uses.
>> */
>> public static void set(XMLStreamReaderFactory f) {
>> if(f==null) throw new IllegalArgumentException();
>> theInstance = f;
>> }
>> public static XMLStreamReaderFactory get() {
>> return theInstance;
>> }
>> public static XMLStreamReader create(InputSource source,
>> boolean rejectDTDs) {
>> try {
>> // Char stream available?
>> if (source.getCharacterStream() != null) {
>> return get().doCreate(source.getSystemId(),
>> source.getCharacterStream(), rejectDTDs);
>> }
>> // Byte stream available?
>> if (source.getByteStream() != null) {
>> return get().doCreate(source.getSystemId(),
>> source.getByteStream(), rejectDTDs);
>> }
>> // Otherwise, open URI
>> return get().doCreate(source.getSystemId(), new
>> URL(source.getSystemId()).openStream(),rejectDTDs);
>> } catch (IOException e) {
>> throw new XMLReaderException("stax.cantCreate",e);
>> }
>> }
>> public static XMLStreamReader create(@Nullable String
>> systemId, InputStream in, boolean rejectDTDs) {
>> return get().doCreate(systemId,in,rejectDTDs);
>> }
>> public static XMLStreamReader create(@Nullable String
>> systemId, Reader reader, boolean rejectDTDs) {
>> return get().doCreate(systemId,reader,rejectDTDs);
>> }
>> /**
>> * Should be invoked when the code finished using an {_at_link
>> XMLStreamReader}.
>> *
>> * <p>
>> * If the recycled instance implements {_at_link RecycleAware},
>> * {_at_link RecycleAware#onRecycled()} will be invoked to let the
>> instance
>> * know that it's being recycled.
>> *
>> * <p>
>> * It is not a hard requirement to call this method on every
>> {_at_link XMLStreamReader}
>> * instance. Not doing so just reduces the performance by
>> throwing away
>> * possibly reusable instances. So the caller should always
>> consider the effort
>> * it takes to recycle vs the possible performance gain by doing so.
>> *
>> * <p>
>> * This method may be invked by multiple threads concurrently.
>> *
>> * @param r
>> * The {_at_link XMLStreamReader} instance that the caller
>> finished using.
>> * This could be any {_at_link XMLStreamReader} implementation,
>> not just
>> * the ones that were created from this factory. So the
>> implementation
>> * of this class needs to be aware of that.
>> */
>> public static void recycle(XMLStreamReader r) {
>> get().doRecycle(r);
>> }
>> // implementations
>> public abstract XMLStreamReader doCreate(String systemId,
>> InputStream in, boolean rejectDTDs);
>> public abstract XMLStreamReader doCreate(String systemId,
>> Reader reader, boolean rejectDTDs);
>> public abstract XMLStreamReader doCreate(Class<? extends
>> XMLStreamReader> implClass);
>> public abstract void doRecycle(XMLStreamReader r);
>> /**
>> * Interface that can be implemented by {_at_link XMLStreamReader} to
>> * be notified when it's recycled.
>> *
>> * <p>
>> * This provides a filtering {_at_link XMLStreamReader} an
>> opportunity to
>> * recycle its inner {_at_link XMLStreamReader}.
>> */
>> public interface RecycleAware {
>> void onRecycled();
>> }
>> /**
>> * {_at_link XMLStreamReaderFactory} implementation for SJSXP/JAXP RI.
>> */
>> public static final class Zephyr extends XMLStreamReaderFactory {
>> private final XMLInputFactory xif;
>> private final ThreadLocal<XMLStreamReader> pool = new
>> ThreadLocal<XMLStreamReader>();
>> private final ThreadLocal<Map<Class,
>> XMLStreamReader>> customPool = new ThreadLocal<Map<Class,
>> XMLStreamReader>>();
>> /**
>> * Sun StAX impl <code>XMLReaderImpl.setInputSource()</code>
>> method via reflection.
>> */
>> private final Method setInputSourceMethod;
>> /**
>> * Sun StAX impl <code>XMLReaderImpl.reset()</code> method
>> via reflection.
>> */
>> private final Method resetMethod;
>> /**
>> * The Sun StAX impl's {_at_link XMLStreamReader} implementation
>> clas.
>> */
>> private final Class zephyrClass;
>> /**
>> * Creates {_at_link Zephyr} instance if the given {_at_link
>> XMLInputFactory} is the one
>> * from Zephyr.
>> */
>> public static @Nullable
>> XMLStreamReaderFactory newInstance(XMLInputFactory
>> xif) {
>> // check if this is from Zephyr
>> try {
>> Class<?> clazz = xif.createXMLStreamReader(new
>> StringReader("<foo/>")).getClass();
>>
>> if(!clazz.getName().startsWith("com.sun.xml.stream."))
>> return null; // nope
>> return new Zephyr(xif,clazz);
>> } catch (NoSuchMethodException e) {
>> return null; // this factory is not for zephyr
>> } catch (XMLStreamException e) {
>> return null; // impossible to fail to parse
>> <foo/>, but anyway
>> }
>> }
>> public Zephyr(XMLInputFactory xif, Class clazz)
>> throws NoSuchMethodException {
>> zephyrClass = clazz;
>> setInputSourceMethod = clazz.getMethod("setInputSource",
>> InputSource.class);
>> resetMethod = clazz.getMethod("reset");
>> try {
>> // Turn OFF internal factory caching in Zephyr.
>> // Santiago told me that this makes it thread-safe.
>> xif.setProperty("reuse-instance", false);
>> } catch (IllegalArgumentException e) {
>> // falls through
>> }
>> this.xif = xif;
>> }
>> /**
>> * Fetchs an instance from the pool if available, otherwise
>> null.
>> */
>> private @Nullable XMLStreamReader fetch() {
>> XMLStreamReader sr = pool.get();
>> if(sr==null) return null;
>> pool.set(null);
>> return sr;
>> }
>> private @Nullable XMLStreamReader fetch(Class
>> implClass) {
>> if (zephyrClass.equals(implClass)) return fetch();
>> Map<Class, XMLStreamReader> implMap =
>> getCustomPoolImplMap();
>> XMLStreamReader sr = implMap.get(implClass);
>> if(sr==null) return null;
>> implMap.put(implClass, null);
>> return sr;
>> }
>> public void doRecycle(XMLStreamReader r) {
>> if(zephyrClass.isInstance(r)) {
>> pool.set(r);
>> } else {
>> offerToCustomPool(r);
>> }
>> if(r instanceof RecycleAware)
>> ((RecycleAware)r).onRecycled();
>> }
>> public XMLStreamReader doCreate(String systemId,
>> InputStream in, boolean rejectDTDs) {
>> try {
>> XMLStreamReader xsr = fetch();
>> if(xsr==null)
>> return xif.createXMLStreamReader(systemId,in);
>> // try re-using this instance.
>> InputSource is = new InputSource(systemId);
>> is.setByteStream(in);
>> reuse(xsr,is);
>> return xsr;
>> } catch (IllegalAccessException e) {
>> throw new XMLReaderException("stax.cantCreate",e);
>> } catch (InvocationTargetException e) {
>> throw new XMLReaderException("stax.cantCreate",e);
>> } catch (XMLStreamException e) {
>> throw new XMLReaderException("stax.cantCreate",e);
>> }
>> }
>> public XMLStreamReader doCreate(String systemId,
>> Reader in, boolean rejectDTDs) {
>> try {
>> XMLStreamReader xsr = fetch();
>> if(xsr==null)
>> return xif.createXMLStreamReader(systemId,in);
>> // try re-using this instance.
>> InputSource is = new InputSource(systemId);
>> is.setCharacterStream(in);
>> reuse(xsr,is);
>> return xsr;
>> } catch (IllegalAccessException e) {
>> throw new XMLReaderException("stax.cantCreate",e);
>> } catch (InvocationTargetException e) {
>> throw new XMLReaderException("stax.cantCreate",e);
>> } catch (XMLStreamException e) {
>> throw new XMLReaderException("stax.cantCreate",e);
>> }
>> }
>> public XMLStreamReader doCreate(Class<? extends
>> XMLStreamReader> implClass) {
>> XMLStreamReader xsr = fetch(implClass);
>> if(xsr != null) {
>> return xsr;
>> }
>>
>> try {
>> return implClass.newInstance();
>> } catch (IllegalAccessException e) {
>> throw new XMLReaderException("stax.cantCreate",e);
>> } catch (InstantiationException e) {
>> throw new XMLReaderException("stax.cantCreate",e);
>> }
>> }
>> private void offerToCustomPool(XMLStreamReader xsr) {
>> Map<Class, XMLStreamReader> implMap =
>> getCustomPoolImplMap();
>> implMap.put(xsr.getClass(), xsr);
>> }
>> private Map<Class, XMLStreamReader>
>> getCustomPoolImplMap() {
>> Map<Class, XMLStreamReader> implMap = customPool.get();
>> if (implMap == null) {
>> implMap = new HashMap<Class, XMLStreamReader>(2);
>> customPool.set(implMap);
>> }
>> return implMap;
>> }
>> private void reuse(XMLStreamReader xsr, InputSource
>> in) throws IllegalAccessException, InvocationTargetException {
>> resetMethod.invoke(xsr);
>> setInputSourceMethod.invoke(xsr,in);
>> }
>> }
>> /**
>> * Default {_at_link XMLStreamReaderFactory} implementation
>> * that can work with any {_at_link XMLInputFactory}.
>> *
>> * <p>
>> * {_at_link XMLInputFactory} is not required to be thread-safe, so the
>> * create method on this implementation is synchronized.
>> */
>> public static final class Default extends NoLock {
>> public Default(XMLInputFactory xif) {
>> super(xif);
>> }
>> public synchronized XMLStreamReader doCreate(String
>> systemId, InputStream in, boolean rejectDTDs) {
>> return super.doCreate(systemId, in, rejectDTDs);
>> }
>> public synchronized XMLStreamReader doCreate(String
>> systemId, Reader in, boolean rejectDTDs) {
>> return super.doCreate(systemId, in, rejectDTDs);
>> }
>> public synchronized XMLStreamReader doCreate(Class<?
>> extends XMLStreamReader> implClass) {
>> return super.doCreate(implClass);
>> }
>> }
>> /**
>> * Similar to {_at_link Default} but doesn't do any synchronization.
>> *
>> * <p>
>> * This is useful when you know your {_at_link XMLInputFactory} is
>> thread-safe by itself.
>> */
>> public static class NoLock extends XMLStreamReaderFactory {
>> private final XMLInputFactory xif;
>> public NoLock(XMLInputFactory xif) {
>> this.xif = xif;
>> }
>> public XMLStreamReader doCreate(String systemId,
>> InputStream in, boolean rejectDTDs) {
>> try {
>> return xif.createXMLStreamReader(systemId,in);
>> } catch (XMLStreamException e) {
>> throw new XMLReaderException("stax.cantCreate",e);
>> }
>> }
>> public XMLStreamReader doCreate(String systemId,
>> Reader in, boolean rejectDTDs) {
>> try {
>> return xif.createXMLStreamReader(systemId,in);
>> } catch (XMLStreamException e) {
>> throw new XMLReaderException("stax.cantCreate",e);
>> }
>> }
>> public XMLStreamReader doCreate(Class<? extends
>> XMLStreamReader> implClass) {
>> try {
>> return implClass.newInstance();
>> } catch (IllegalAccessException e) {
>> throw new XMLReaderException("stax.cantCreate",e);
>> } catch (InstantiationException e) {
>> throw new XMLReaderException("stax.cantCreate",e);
>> }
>> }
>> public void doRecycle(XMLStreamReader r) {
>> // there's no way to recycle with the default StAX API.
>> }
>> }
>> }
>>
>>
>>
>> ------------------------------------------------------------------------
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe_at_jax-ws.dev.java.net
>> For additional commands, e-mail: dev-help_at_jax-ws.dev.java.net
>


package com.sun.xml.ws.api.streaming;

import com.sun.istack.NotNull;
import com.sun.istack.Nullable;
import com.sun.xml.ws.streaming.XMLReaderException;
import java.util.HashMap;
import java.util.Map;
import org.xml.sax.InputSource;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;

/**
 * Factory for {_at_link XMLStreamReader}.
 *
 * <p>
 * This wraps {_at_link XMLInputFactory} and allows us to reuse {_at_link XMLStreamReader} instances
 * when appropriate.
 *
 * @author Kohsuke Kawaguchi
 */
public abstract class XMLStreamReaderFactory {
    
    /**
     * Singleton instance.
     */
    private static volatile @NotNull XMLStreamReaderFactory theInstance;
    
    static {
        XMLInputFactory xif = XMLInputFactory.newInstance();
        xif.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, true);
        
        XMLStreamReaderFactory f=null;
        
        // this system property can be used to disable the pooling altogether,
        // in case someone hits an issue with pooling in the production system.
        if(!Boolean.getBoolean(XMLStreamReaderFactory.class.getName()+".noPool"))
            f = Zephyr.newInstance(xif);
        if(f==null)
            f = Default.newInstance(xif);
        
        theInstance = f;
    }
    
    /**
     * Overrides the singleton {_at_link XMLStreamReaderFactory} instance that
     * the JAX-WS RI uses.
     */
    public static void set(XMLStreamReaderFactory f) {
        if(f==null) throw new IllegalArgumentException();
        theInstance = f;
    }
    
    public static XMLStreamReaderFactory get() {
        return theInstance;
    }
    
    public static XMLStreamReader create(InputSource source, boolean rejectDTDs) {
        try {
            // Char stream available?
            if (source.getCharacterStream() != null) {
                return get().doCreate(source.getSystemId(), source.getCharacterStream(), rejectDTDs);
            }
            
            // Byte stream available?
            if (source.getByteStream() != null) {
                return get().doCreate(source.getSystemId(), source.getByteStream(), rejectDTDs);
            }
            
            // Otherwise, open URI
            return get().doCreate(source.getSystemId(), new URL(source.getSystemId()).openStream(),rejectDTDs);
        } catch (IOException e) {
            throw new XMLReaderException("stax.cantCreate",e);
        }
    }
    
    public static XMLStreamReader create(@Nullable String systemId, InputStream in, boolean rejectDTDs) {
        return get().doCreate(systemId,in,rejectDTDs);
    }
    
    public static XMLStreamReader create(@Nullable String systemId, Reader reader, boolean rejectDTDs) {
        return get().doCreate(systemId,reader,rejectDTDs);
    }
    
    /**
     * Should be invoked when the code finished using an {_at_link XMLStreamReader}.
     *
     * <p>
     * If the recycled instance implements {_at_link RecycleAware},
     * {_at_link RecycleAware#onRecycled()} will be invoked to let the instance
     * know that it's being recycled.
     *
     * <p>
     * It is not a hard requirement to call this method on every {_at_link XMLStreamReader}
     * instance. Not doing so just reduces the performance by throwing away
     * possibly reusable instances. So the caller should always consider the effort
     * it takes to recycle vs the possible performance gain by doing so.
     *
     * <p>
     * This method may be invked by multiple threads concurrently.
     *
     * @param r
     * The {_at_link XMLStreamReader} instance that the caller finished using.
     * This could be any {_at_link XMLStreamReader} implementation, not just
     * the ones that were created from this factory. So the implementation
     * of this class needs to be aware of that.
     */
    public static void recycle(XMLStreamReader r) {
        get().doRecycle(r);
    }
    
    // implementations
    
    public abstract void registerXMLInputFactory(Class<? extends XMLStreamReader> clazz, XMLInputFactory factory);
    
    public abstract XMLStreamReader doCreate(String systemId, InputStream in, boolean rejectDTDs);
    
    public abstract XMLStreamReader doCreate(String systemId, Reader reader, boolean rejectDTDs);
    
    public abstract XMLStreamReader doCreate(String systemId, InputStream in, boolean rejectDTDs, Class<? extends XMLStreamReader> clazz);
    
    public abstract void doRecycle(XMLStreamReader r);
    
    /**
     * Interface that can be implemented by {_at_link XMLStreamReader} to
     * be notified when it's recycled.
     *
     * <p>
     * This provides a filtering {_at_link XMLStreamReader} an opportunity to
     * recycle its inner {_at_link XMLStreamReader}.
     */
    public interface RecycleAware {
        void onRecycled();
    }
    
    /**
     * {_at_link XMLStreamReaderFactory} implementation for SJSXP/JAXP RI.
     */
    public static final class Zephyr extends XMLStreamReaderFactory {
        private final Map<Class<?>, XMLInputFactory> xifMap;
        
        private final ThreadLocal<Map<Class<?>, XMLStreamReader>> pool = new ThreadLocal<Map<Class<?>, XMLStreamReader>>();
        
        /**
         * Sun StAX impl <code>XMLReaderImpl.setInputSource()</code> method via reflection.
         */
        private final Method setInputSourceMethod;
        
        /**
         * Sun StAX impl <code>XMLReaderImpl.reset()</code> method via reflection.
         */
        private final Method resetMethod;
        
        /**
         * The Sun StAX impl's {_at_link XMLStreamReader} implementation clas.
         */
        private final Class zephyrClass;
        
        /**
         * Creates {_at_link Zephyr} instance if the given {_at_link XMLInputFactory} is the one
         * from Zephyr.
         */
        public static @Nullable
                XMLStreamReaderFactory newInstance(XMLInputFactory xif) {
            // check if this is from Zephyr
            try {
                Class<?> clazz = xif.createXMLStreamReader(new StringReader("<foo/>")).getClass();
                
                if(!clazz.getName().startsWith("com.sun.xml.stream."))
                    return null; // nope
                
                return new Zephyr(xif,clazz);
            } catch (NoSuchMethodException e) {
                return null; // this factory is not for zephyr
            } catch (XMLStreamException e) {
                return null; // impossible to fail to parse <foo/>, but anyway
            }
        }
        
        public Zephyr(XMLInputFactory xif, Class clazz) throws NoSuchMethodException {
            zephyrClass = clazz;
            setInputSourceMethod = clazz.getMethod("setInputSource", InputSource.class);
            resetMethod = clazz.getMethod("reset");
            
            try {
                // Turn OFF internal factory caching in Zephyr.
                // Santiago told me that this makes it thread-safe.
                xif.setProperty("reuse-instance", false);
            } catch (IllegalArgumentException e) {
                // falls through
            }
            
            xifMap = new HashMap<Class<?>, XMLInputFactory>(4);
            xifMap.put(clazz, xif);
        }
        
        
        public void doRecycle(XMLStreamReader r) {
            offer(r);
            
            if(r instanceof RecycleAware)
                ((RecycleAware)r).onRecycled();
        }
        
        public void registerXMLInputFactory(Class<? extends XMLStreamReader> clazz, XMLInputFactory factory) {
            xifMap.put(clazz, factory);
        }
        
        /*
         * Method returns XMLStreamReader either from pool, if any available, or creates a new one.
         * If XMLStreamReader is taken from pool, than systemId and in arguments are not used
         */
        public XMLStreamReader doCreate(String systemId, InputStream in, boolean rejectDTDs, Class<? extends XMLStreamReader> clazz) {
            try {
                XMLStreamReader xsr = fetch(clazz);
                if(xsr==null)
                    return xifMap.get(clazz).createXMLStreamReader(systemId,in);
                
                return xsr;
            } catch (XMLStreamException e) {
                throw new XMLReaderException("stax.cantCreate",e);
            }
        }
        
        /*
         * Method returns Zephyr XMLStreamReader either from pool, if any available, or creates a new one.
         * If instance is taken from pool - its state will be reset with new systemId and in values
         */
        public XMLStreamReader doCreate(String systemId, InputStream in, boolean rejectDTDs) {
            try {
                XMLStreamReader xsr = fetch(zephyrClass);
                if(xsr==null)
                    return xifMap.get(zephyrClass).createXMLStreamReader(systemId,in);
                
                // try re-using this instance.
                InputSource is = new InputSource(systemId);
                is.setByteStream(in);
                reuse(xsr,is);
                return xsr;
            } catch (IllegalAccessException e) {
                throw new XMLReaderException("stax.cantCreate",e);
            } catch (InvocationTargetException e) {
                throw new XMLReaderException("stax.cantCreate",e);
            } catch (XMLStreamException e) {
                throw new XMLReaderException("stax.cantCreate",e);
            }
        }
        
        public XMLStreamReader doCreate(String systemId, Reader in, boolean rejectDTDs) {
            try {
                XMLStreamReader xsr = fetch(zephyrClass);
                if(xsr==null)
                    return xifMap.get(zephyrClass).createXMLStreamReader(systemId,in);
                
                // try re-using this instance.
                InputSource is = new InputSource(systemId);
                is.setCharacterStream(in);
                reuse(xsr,is);
                return xsr;
            } catch (IllegalAccessException e) {
                throw new XMLReaderException("stax.cantCreate",e);
            } catch (InvocationTargetException e) {
                throw new XMLReaderException("stax.cantCreate",e);
            } catch (XMLStreamException e) {
                throw new XMLReaderException("stax.cantCreate",e);
            }
        }
        
        /**
         * Fetchs an instance from the pool if available, otherwise null.
         */
        private XMLStreamReader fetch(Class<? extends XMLStreamReader> clazz) {
            Map<Class<?>, XMLStreamReader> implMap = getPoolMap();
            return implMap.remove(clazz);
        }
        
        private void offer(XMLStreamReader reader) {
            Map<Class<?>, XMLStreamReader> implMap = getPoolMap();
            implMap.put(reader.getClass(), reader);
        }
        
        private Map<Class<?>, XMLStreamReader> getPoolMap() {
            Map<Class<?>, XMLStreamReader> implMap = pool.get();
            if (implMap == null) {
                implMap = new HashMap<Class<?>, XMLStreamReader>(4);
                pool.set(implMap);
            }
            
            return implMap;
        }
        
        private void reuse(XMLStreamReader xsr, InputSource in) throws IllegalAccessException, InvocationTargetException {
            resetMethod.invoke(xsr);
            setInputSourceMethod.invoke(xsr,in);
        }
        
    }
    
    /**
     * Default {_at_link XMLStreamReaderFactory} implementation
     * that can work with any {_at_link XMLInputFactory}.
     *
     * <p>
     * {_at_link XMLInputFactory} is not required to be thread-safe, so the
     * create method on this implementation is synchronized.
     */
    public static final class Default extends NoLock {
        /**
         * Creates Default instance
         */
        public static @Nullable
                XMLStreamReaderFactory newInstance(XMLInputFactory xif) {
            try {
                Class<?> clazz = xif.createXMLStreamReader(new StringReader("<foo/>")).getClass();
                return new Default(xif, clazz);
            } catch (XMLStreamException e) {
                e.printStackTrace();
                return null; // impossible to fail to parse <foo/>, but anyway
            }
        }
        
        public Default(XMLInputFactory xif, Class<?> clazz) {
            super(xif, clazz);
        }
        
        public synchronized XMLStreamReader doCreate(String systemId, InputStream in, boolean rejectDTDs) {
            return super.doCreate(systemId, in, rejectDTDs);
        }
        
        public synchronized XMLStreamReader doCreate(String systemId, Reader in, boolean rejectDTDs) {
            return super.doCreate(systemId, in, rejectDTDs);
        }
        
        public synchronized XMLStreamReader doCreate(String systemId, InputStream in, boolean rejectDTDs, Class<? extends XMLStreamReader> clazz) {
            return super.doCreate(systemId, in, rejectDTDs, clazz);
        }
    }
    
    /**
     * Similar to {_at_link Default} but doesn't do any synchronization.
     *
     * <p>
     * This is useful when you know your {_at_link XMLInputFactory} is thread-safe by itself.
     */
    public static class NoLock extends XMLStreamReaderFactory {
        private final Map<Class, XMLInputFactory> xifMap;
        
        /**
         * Default XMLStreamReader implementation class
         */
        private final Class defaultReaderClass;
        
        public NoLock(XMLInputFactory xif, Class<?> clazz) {
            defaultReaderClass = clazz;
            xifMap = new HashMap<Class, XMLInputFactory>(4);
            xifMap.put(defaultReaderClass, xif);
        }
        
        public void registerXMLInputFactory(Class<? extends XMLStreamReader> clazz, XMLInputFactory factory) {
            xifMap.put(clazz, factory);
        }
        
        public XMLStreamReader doCreate(String systemId, InputStream in, boolean rejectDTDs) {
            return doCreate(systemId, in, rejectDTDs, defaultReaderClass);
        }
        
        public XMLStreamReader doCreate(String systemId, InputStream in, boolean rejectDTDs, Class<? extends XMLStreamReader> clazz) {
            try {
                return xifMap.get(clazz).createXMLStreamReader(systemId,in);
            } catch (XMLStreamException e) {
                throw new XMLReaderException("stax.cantCreate",e);
            }
        }
        
        public XMLStreamReader doCreate(String systemId, Reader in, boolean rejectDTDs) {
            try {
                return xifMap.get(defaultReaderClass).createXMLStreamReader(systemId,in);
            } catch (XMLStreamException e) {
                throw new XMLReaderException("stax.cantCreate",e);
            }
        }
        
        public void doRecycle(XMLStreamReader r) {
            // there's no way to recycle with the default StAX API.
        }
    }
}


/*
 * The contents of this file are subject to the terms
 * of the Common Development and Distribution License
 * (the License). You may not use this file except in
 * compliance with the License.
 *
 * You can obtain a copy of the license at
 * https://glassfish.dev.java.net/public/CDDLv1.0.html.
 * See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL
 * Header Notice in each file and include the License file
 * at https://glassfish.dev.java.net/public/CDDLv1.0.html.
 * If applicable, add the following below the CDDL Header,
 * with the fields enclosed by brackets [] replaced by
 * you own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * Copyright 2006 Sun Microsystems Inc. All Rights Reserved
 */

package com.sun.xml.ws.encoding.fastinfoset;

import java.io.InputStream;
import java.io.Reader;
import javax.xml.stream.EventFilter;
import javax.xml.stream.StreamFilter;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLReporter;
import javax.xml.stream.XMLResolver;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.util.XMLEventAllocator;
import javax.xml.transform.Source;

/**
 * @author Alexey Stashok
 */
public class FastInfosetXMLInputFactory extends XMLInputFactory {
    public boolean isPropertySupported(String string) {
        return false;
    }
    
    public XMLReporter getXMLReporter() {
        return null;
    }
    
    public void setXMLReporter(XMLReporter xMLReporter) {
    }
    
    public XMLResolver getXMLResolver() {
        return null;
    }
    
    public void setXMLResolver(XMLResolver xMLResolver) {
    }
    
    public XMLEventAllocator getEventAllocator() {
        return null;
    }
    
    public void setEventAllocator(XMLEventAllocator xMLEventAllocator) {
    }
    
    public Object getProperty(String string) throws IllegalArgumentException {
        return null;
    }
    
    public void setProperty(String string, Object object) throws IllegalArgumentException {
    }
    
    public XMLEventReader createXMLEventReader(InputStream inputStream) throws XMLStreamException {
        return null;
    }
    
    public XMLEventReader createXMLEventReader(Reader reader) throws XMLStreamException {
        return null;
    }
    
    public XMLEventReader createXMLEventReader(XMLStreamReader xMLStreamReader) throws XMLStreamException {
        return null;
    }
    
    public XMLEventReader createXMLEventReader(Source source) throws XMLStreamException {
        return null;
    }
    
    public XMLStreamReader createXMLStreamReader(InputStream inputStream) throws XMLStreamException {
        return null;
    }
    
    public XMLStreamReader createXMLStreamReader(Reader reader) throws XMLStreamException {
        return null;
    }
    
    public XMLStreamReader createXMLStreamReader(Source source) throws XMLStreamException {
        return null;
    }
    
    public XMLEventReader createXMLEventReader(String string, InputStream inputStream) throws XMLStreamException {
        return null;
    }
    
    public XMLEventReader createXMLEventReader(String string, Reader reader) throws XMLStreamException {
        return null;
    }
    
    public XMLEventReader createXMLEventReader(InputStream inputStream, String string) throws XMLStreamException {
        return null;
    }
    
    public XMLEventReader createFilteredReader(XMLEventReader xMLEventReader, EventFilter eventFilter) throws XMLStreamException {
        return null;
    }
    
    public XMLStreamReader createXMLStreamReader(String string, InputStream inputStream) throws XMLStreamException {
        return FastInfosetCodec.createNewStreamReader(inputStream, false);
    }
    
    public XMLStreamReader createXMLStreamReader(String string, Reader reader) throws XMLStreamException {
        return null;
    }
    
    public XMLStreamReader createXMLStreamReader(InputStream inputStream, String string) throws XMLStreamException {
        return null;
    }
    
    public XMLStreamReader createFilteredReader(XMLStreamReader xMLStreamReader, StreamFilter streamFilter) throws XMLStreamException {
        return null;
    }
}