/**
* <copyright>
*
* Copyright (c) 2002-2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM - Initial API and implementation
*
* </copyright>
*
* $Id: XMLParserPoolImpl.java,v 1.11 2008/12/22 14:25:53 emerks Exp $
*/
package org.eclipse.emf.ecore.xmi.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.eclipse.emf.ecore.xmi.XMLDefaultHandler;
import org.eclipse.emf.ecore.xmi.XMLHelper;
import org.eclipse.emf.ecore.xmi.XMLLoad;
import org.eclipse.emf.ecore.xmi.XMLParserPool;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.xml.sax.SAXException;
/**
* This is the default thread safe implementation of XMLParserPool.
* This implementation is tuned for caching parsers and handlers created using same loading options.
* To avoid possible memory leak (in case user is trying to parse documents using different options for every parse),
* there is a restriction on the size of the pool.
* The key used for handler caching is based on the option map passed to load.
*/
public class XMLParserPoolImpl implements XMLParserPool
{
private final Map<Map<?, ?>, List<SAXParser>> parserCache = new HashMap<Map<?, ?>, List<SAXParser>>();
private final Map<Map<?, ?>, List<XMLDefaultHandler>> handlersCache;
private final int size;
/**
* Creates an instance that caches only parsers but not handlers.
* @see #XMLParserPoolImpl(boolean)
*/
public XMLParserPoolImpl()
{
this(200, false);
}
/**
* Creates an instance that caches parsers and caches handlers as specified.
* @param useHandlerCache indicates whether handler caching should be use.
* @see #XMLParserPoolImpl(boolean)
*/
public XMLParserPoolImpl(boolean useHandlerCache)
{
this(200, useHandlerCache);
}
/**
* Creates an instance that caches parsers and caches handlers as specified.
* @param size indicates the maximum number of instances parser or handler instances that will be cached.
* @param useHandlerCache indicates whether handler caching should be use.
* @see #XMLParserPoolImpl(boolean)
*/
public XMLParserPoolImpl(int size, boolean useHandlerCache)
{
this.size = size;
handlersCache = useHandlerCache ? new HashMap<Map<?, ?>, List<XMLDefaultHandler>>() : null;
}
/**
* @see XMLParserPool#get(Map, Map, boolean)
*/
public synchronized SAXParser get(Map<String, Boolean> features, Map<String, ?> properties, boolean useLexicalHandler) throws ParserConfigurationException, SAXException
{
Map<Object, Object> map = new HashMap<Object, Object>();
map.putAll(features);
map.putAll(properties);
map.put(XMLResource.OPTION_USE_LEXICAL_HANDLER, useLexicalHandler ? Boolean.TRUE : Boolean.FALSE);
if (parserCache.size() > size)
{
parserCache.clear();
}
List<SAXParser> list = parserCache.get(map);
if (list != null)
{
int size = list.size();
if (size > 0)
{
return list.remove(size - 1);
}
else
{
return makeParser(features, properties);
}
}
else
{
parserCache.put(map, new ArrayList<SAXParser>());
return makeParser(features, properties);
}
}
/**
* @see XMLParserPool#release(SAXParser, Map, Map, boolean)
*/
public synchronized void release(SAXParser parser, Map<String, Boolean> features, Map<String, ?> properties, boolean useLexicalHandler)
{
Map<Object, Object> map = new HashMap<Object, Object>();
map.putAll(features);
map.putAll(properties);
map.put(XMLResource.OPTION_USE_LEXICAL_HANDLER, useLexicalHandler ? Boolean.TRUE : Boolean.FALSE);
List<SAXParser> list = parserCache.get(map);
if (list.size() < size)
{
list.add(parser);
}
}
protected SAXParser makeParser(Map<String, Boolean> features, Map<String, ?> properties) throws ParserConfigurationException, SAXException
{
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setValidating(false);
factory.setNamespaceAware(true);
SAXParser parser = factory.newSAXParser();
// set parser features and properties
if (features != null)
{
for (Map.Entry<String, Boolean> entry : features.entrySet())
{
parser.getXMLReader().setFeature(entry.getKey(), entry.getValue());
}
}
if (properties != null)
{
for (Map.Entry<String, ?> entry : properties.entrySet())
{
parser.getXMLReader().setProperty(entry.getKey(), entry.getValue());
}
}
return parser;
}
public synchronized XMLDefaultHandler getDefaultHandler(XMLResource resource, XMLLoad xmlLoad, XMLHelper helper, Map<?, ?> options)
{
if (handlersCache != null)
{
if (handlersCache.size() > size)
{
handlersCache.clear();
}
List<XMLDefaultHandler> list = handlersCache.get(options);
if (list != null)
{
int size = list.size();
if (size > 0)
{
XMLDefaultHandler handler = list.remove(size - 1);
handler.prepare(resource, helper, options);
return handler;
}
}
else
{
handlersCache.put(options, new ArrayList<XMLDefaultHandler>());
}
}
return xmlLoad.createDefaultHandler();
}
public synchronized void releaseDefaultHandler(XMLDefaultHandler handler, Map<?, ?> options)
{
if (handlersCache != null)
{
handler.reset();
List<XMLDefaultHandler> list = handlersCache.get(options);
if (list == null)
{
list = new ArrayList<XMLDefaultHandler>();
handlersCache.put(options, list);
}
else if (list.size() < size)
{
list.add(handler);
}
}
}
}