com.xmlcalabash.model.DeclareStep Maven / Gradle / Ivy
The newest version!
/*
* DeclareStep.java
*
* Copyright 2008 Mark Logic Corporation.
* Portions Copyright 2007 Sun Microsystems, Inc.
* All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common
* Development and Distribution License("CDDL") (collectively, the
* "License"). You may not use this file except in compliance with the
* License. You can obtain a copy of the License at
* https://xproc.dev.java.net/public/CDDL+GPL.html or
* docs/CDDL+GPL.txt in the distribution. See the License for the
* specific language governing permissions and limitations under the
* License. When distributing the software, include this License Header
* Notice in each file and include the License file at docs/CDDL+GPL.txt.
*/
package com.xmlcalabash.model;
import com.xmlcalabash.core.XProcData;
import net.sf.saxon.s9api.XdmNode;
import net.sf.saxon.s9api.QName;
import com.xmlcalabash.core.XProcRuntime;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import java.util.Hashtable;
import java.util.HashSet;
import java.util.Iterator;
import org.slf4j.Logger;
import com.xmlcalabash.core.XProcConstants;
import com.xmlcalabash.core.XProcException;
import org.slf4j.LoggerFactory;
public class DeclareStep extends CompoundStep implements DeclarationScope {
protected boolean psviRequired = false;
protected String xpathVersion = "2.0";
private QName declaredType = null;
private boolean atomic = true;
protected Hashtable declaredSteps = new Hashtable ();
private List importedLibs = new ArrayList<>();
private List xsltFunctionImports = new ArrayList<>();
private DeclarationScope parentScope = null;
private Vector rest = null;
private HashSet excludedInlineNamespaces = null;
private URI sourceImport = null;
/* Creates a new instance of DeclareStep */
public DeclareStep(XProcRuntime xproc, XdmNode node, String name) {
super(xproc, node, XProcConstants.p_declare_step, name);
}
protected void setXmlContent(Vector nodes) {
rest = nodes;
}
protected Vector getXmlContent() {
return rest;
}
public void setPsviRequired(boolean psvi) {
psviRequired = psvi;
}
public void setXPathVersion(String version) {
xpathVersion = version;
}
public void setDeclaredType(QName type) {
declaredType = type;
}
public void setExcludeInlineNamespaces(HashSet uris) {
excludedInlineNamespaces = uris;
}
public HashSet getExcludeInlineNamespaces() {
return excludedInlineNamespaces;
}
public void setAtomic(boolean isAtomic) {
atomic = isAtomic;
}
public boolean isAtomic() {
return atomic;
}
public boolean isPipeline() {
return !atomic;
}
public QName getDeclaredType() {
return declaredType;
}
public void setParentScope(DeclarationScope decls) {
parentScope = decls;
}
public void declareStep(QName type, DeclareStep step) {
DeclareStep d = getDeclaration(type);
if (d != null) {
if (!d.equals(step))
throw new XProcException(step, "Duplicate step type: " + type);
} else {
declaredSteps.put(type, step);
}
}
public void addImport(PipelineLibrary lib) {
importedLibs.add(lib);
}
public void addXsltFunctionImport(XdmNode lib) {
xsltFunctionImports.add(lib);
}
public void setSourceImport(URI href) {
sourceImport = href;
}
public URI getSourceImport() {
return sourceImport;
}
public DeclareStep getDeclaration() {
return getDeclaration(declaredType);
}
public DeclareStep getDeclaration(QName type) {
DeclareStep decl = null;
if (parentScope != null)
try {
decl = parentScope.getDeclaration(type);
} catch (XProcException e) {
if (XProcConstants.staticError(44).equals(e.getErrorCode())) {
// step was not found
// throw same exception but with more precise location info
throw XProcException.staticError(44, node, "Unexpected step name: " + type);
} else
throw e;
}
for (PipelineLibrary lib : importedLibs) {
DeclareStep d = lib.getDeclaration(type);
if (d != null) {
if (decl == null)
decl = d;
else if (!decl.equals(d))
throw new XProcException(d, "Duplicate step type: " + type);
}
}
{
DeclareStep d = declaredSteps.get(type);
if (d != null) {
if (decl == null)
decl = d;
else if (!decl.equals(d))
throw new XProcException(d, "Duplicate step type: " + type);
}
}
return decl;
}
public Set getInScopeTypes() {
Set decls = new HashSet<>();
decls.addAll(declaredSteps.keySet());
if (parentScope != null)
decls.addAll(parentScope.getInScopeTypes());
for (PipelineLibrary lib : importedLibs)
decls.addAll(lib.getInScopeTypes());
return decls;
}
public List getXsltFunctionImports() {
return xsltFunctionImports;
}
private void setupEnvironment() {
setEnvironment(new Environment(this));
}
protected void patchEnvironment(Environment env) {
if (atomic) {
//nop;
} else {
// See if there's exactly one "ordinary" input
int count = 0;
Input defin = null;
boolean foundPrimary = false;
for (Input input : inputs) {
if (!input.getPort().startsWith("|") && !input.getParameterInput()) {
count++;
foundPrimary |= input.getPrimary();
if (!input.getPrimary() && input.getPrimarySet()) {
// nop; if the port is explicitly marked primary=false, it can't count
} else {
if (defin == null || input.getPrimary()) {
defin = input;
}
}
}
}
if (count == 1 || foundPrimary) {
env.setDefaultReadablePort(defin);
}
}
}
private boolean setup = false;
public void setup() {
if (setup) return;
setup = true;
XProcRuntime runtime = this.runtime;
DeclareStep decl = this;
boolean debug = runtime.getDebug();
if (decl.psviRequired && !runtime.getPSVISupported()) {
throw XProcException.dynamicError(22);
}
if (debug) {
logger.trace("=====================================================================================");
logger.trace("Before augment:");
decl.dump();
}
boolean seenPrimaryDocument = false;
boolean seenPrimaryParameter = false;
for (Input input : decl.inputs()) {
if (!input.getPort().startsWith("|") && input.getPrimary()) {
if (seenPrimaryDocument && !input.getParameterInput()) {
error(XProcException.staticError(30, "At most one primary document input port is allowed"));
}
if (seenPrimaryParameter && input.getParameterInput()) {
error(XProcException.staticError(30, "At most one primary parameter input port is allowed"));
}
if (input.getParameterInput()) {
seenPrimaryParameter = true;
} else {
seenPrimaryDocument = true;
}
}
}
boolean seenPrimary = false;
for (Output output : decl.outputs()) {
if (!output.getPort().endsWith("|") && output.getPrimary()) {
if (seenPrimary) {
error(XProcException.staticError(30, "At most one primary output port is allowed"));
}
seenPrimary = true;
}
}
if (debug) {
logger.trace("After binding pipeline inputs and outputs:");
decl.dump();
}
if (subpipeline.size() == 0) {
error(XProcException.staticError(100, "Declared step has no subpipeline, but is not known.")); // FIXME!
return;
}
decl.augment();
if (debug) {
logger.trace("After augment:");
decl.dump();
}
decl.setupEnvironment();
if (!decl.valid()) {
if (debug) {
decl.dump();
}
return;
}
if (debug) {
logger.trace("After valid:");
decl.dump();
}
if (!decl.orderSteps()) {
if (debug) {
decl.dump();
}
return;
}
if (debug) {
logger.trace("After ordering:");
decl.dump();
}
HashSet vars = new HashSet ();
checkDuplicateVars(vars);
// Are all the primary outputs bound?
if (!checkOutputBindings()) {
if (debug) {
decl.dump();
}
return;
}
}
protected boolean checkOutputBindings() {
HashSet