/* * Copyright 2006-2012 The Scriptella Project Team. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package scriptella.driver.xpath; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.InputSource; import scriptella.spi.AbstractConnection; import scriptella.spi.ConnectionParameters; import scriptella.spi.ParametersCallback; import scriptella.spi.ProviderException; import scriptella.spi.QueryCallback; import scriptella.spi.Resource; import javax.xml.parsers.DocumentBuilderFactory; import java.net.URL; import java.util.IdentityHashMap; import java.util.Map; /** * Represents a connection to an XML file. * <p>For configuration details and examples see <a href="package-summary.html">overview page</a>. * * @author Fyodor Kupolov * @version 1.0 */ public class XPathConnection extends AbstractConnection { /** * Name of the <code>cache_queries</code> connection property. * Specifies flag to use queries cache, default is true. * If set to "false" XML document under URL will be parsed for each * <query> or <script> tag in etl script. This allows to update XML content dynamically. */ public static final String CACHE_QUERIES = "cache_queries"; /** * Name of the <code>return_arrays</code> connection property. * Value of <code>true</code> specifies that variables should return a string array, otherwise a single string is returned. */ public static final String RETURN_ARRAYS = "return_arrays"; static final DocumentBuilderFactory DBF = DocumentBuilderFactory.newInstance(); private Map<Resource, XPathQueryExecutor> queriesCache = new IdentityHashMap<Resource, XPathQueryExecutor>(); private XPathExpressionCompiler compiler = new XPathExpressionCompiler(); private Document document; private ThreadLocal<Node> queryContext=new ThreadLocal<Node>(); private URL url; private final boolean returnArrays; protected final boolean cache_queries; /** * For testing purposes only. */ protected XPathConnection() { cache_queries = true; returnArrays = false; } public XPathConnection(ConnectionParameters parameters) { super(Driver.DIALECT, parameters); url = parameters.getResolvedUrl(); cache_queries = parameters.getBooleanProperty(CACHE_QUERIES, true); //TODO implement trim option returnArrays = parameters.getBooleanProperty(RETURN_ARRAYS, false); } public void executeScript(final Resource scriptContent, final ParametersCallback parametersCallback) throws ProviderException { throw new XPathProviderException("Script execution is not supported yet"); } public void executeQuery(Resource queryContent, ParametersCallback parametersCallback, QueryCallback queryCallback) throws ProviderException { XPathQueryExecutor exec = queriesCache.get(queryContent); if (exec == null) { exec = new XPathQueryExecutor(queryContext, getDocument(), queryContent, compiler, counter, returnArrays); if (cache_queries) { queriesCache.put(queryContent, exec); } } exec.execute(queryCallback, parametersCallback); } private Document getDocument() { if (document == null || (!cache_queries)) { try { document = DBF.newDocumentBuilder().parse(new InputSource(url.toString())); } catch (Exception e) { throw new XPathProviderException("Unable to parse document " + url, e); } } return document; } public void close() throws ProviderException { queriesCache = null; document = null; queryContext.remove(); queryContext = null; } }