All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.saxon.expr.accum.AccumulatorManager Maven / Gradle / Ivy

There is a newer version: 12.5
Show newest version
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2018-2022 Saxonica Limited
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package net.sf.saxon.expr.accum;

import net.sf.saxon.expr.XPathContext;
import net.sf.saxon.expr.XPathContextMajor;
import net.sf.saxon.om.NodeInfo;
import net.sf.saxon.om.TreeInfo;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.tree.tiny.TinyTree;
import net.sf.saxon.tree.wrapper.VirtualCopy;
import net.sf.saxon.tree.wrapper.VirtualTreeInfo;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;

/**
 * Manager for accumulator functions (XSLT 3.0).
 *
 * 

In principle there is a dataset containing accumulator values for every accumulator/document pair. * In addition, if the same stylesheet is run concurrently in multiple transformations, and a document * is shared between these transformations, the data values for the accumulator can differ between the * two transformations, because the accumulator rules can depend on values of stylesheet parameters * or on context variables such as current-dateTime.

* *

It is important that the accumulator data for a tree does not cause the tree to be locked in * memory for the duration of a transformation. We therefore keep a weak reference to the tree. For * each tree, until it is garbage collected, there is a map from accumulator names to accumulator data.

*/ public class AccumulatorManager { private final transient WeakHashMap> accumulatorDataIndex = new WeakHashMap>(); private final transient WeakHashMap> applicableAccumulators = new WeakHashMap>(); public AccumulatorManager() { } /** * By default, all accumulators are applicable to any given tree. If this method is called, * a specific set of accumulators are registered as applicable. This set may be empty. * @param tree the document tree in question * @param accumulators the set of accumulators that are appicable */ public void setApplicableAccumulators(TreeInfo tree, Set accumulators) { applicableAccumulators.put(tree, accumulators); } /** * Ask whether a particular accumulator is applicable to a particular tree * @param tree the tree in question * @param accumulator the accumulator in question * @return true if the accumulator is applicable to this tree, otherwise false */ public boolean isApplicable(TreeInfo tree, Accumulator accumulator) { Set accSet = applicableAccumulators.get(tree); return accSet == null || accSet.contains(accumulator); } private static final AccumulatorData MARKER = new AccumulatorData(null); /** * Get the data relating to a particular accumulator for a particular unstreamed document tree * * @param doc the source document tree in question * @param acc the required accumulator * @param context the XPath dynamic evaluation context * @return a data structure holding the evaluated values of the accumulator for this source document * @throws XPathException if any dynamic error occurs */ public synchronized IAccumulatorData getAccumulatorData(TreeInfo doc, Accumulator acc, XPathContext context) throws XPathException { Map map = accumulatorDataIndex.get(doc); if (map != null) { IAccumulatorData data = map.get(acc); if (data != null) { if (data == MARKER) { throw new XPathException("Accumulator " + acc.getAccumulatorName().getDisplayName() + " requires access to its own value", "XTDE3400"); } return data; } } else { map = new HashMap(); accumulatorDataIndex.put(doc, map); } map.put(acc, MARKER); if (doc instanceof VirtualTreeInfo && ((VirtualTreeInfo)doc).isCopyAccumulators()) { NodeInfo original = ((VirtualCopy) doc.getRootNode()).getOriginalNode(); IAccumulatorData originalData = getAccumulatorData(original.getTreeInfo(), acc, context); VirtualAccumulatorData vad = new VirtualAccumulatorData(originalData); map.put(acc, vad); return vad; } else if (doc instanceof TinyTree && ((TinyTree)doc).getCopiedFrom() != null) { IAccumulatorData original = getAccumulatorData(((TinyTree) doc).getCopiedFrom().getTreeInfo(), acc, context); return new PathMappedAccumulatorData(original, ((TinyTree) doc).getCopiedFrom()); } else { AccumulatorData d = new AccumulatorData(acc); XPathContextMajor c2 = context.newCleanContext(); c2.setCurrentComponent(acc.getDeclaringComponent()); try { d.buildIndex(doc.getRootNode(), c2); map.put(acc, d); return d; } catch (XPathException err) { IAccumulatorData failed = new FailedAccumulatorData(acc, err); map.put(acc, failed); return failed; } } } /** * Add the accumulator data for a particular accumulator, if it does not already exist * @param doc the document/tree whose accumulator data is being added * @param acc the accumulator in question * @param accData the data holding the values of the accumulator for the nodes in this tree */ public synchronized void addAccumulatorData(TreeInfo doc, Accumulator acc, IAccumulatorData accData) { Map map = accumulatorDataIndex.get(doc); if (map != null) { IAccumulatorData data = map.get(acc); if (data != null) { return; } } else { map = new HashMap(); accumulatorDataIndex.put(doc, map); } map.put(acc, accData); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy