blob: c3aeda9e78f69e05b8186d48804ae1dbc51249d4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.vxquery.context;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import javax.xml.namespace.QName;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.vxquery.collations.Collation;
import org.apache.vxquery.functions.Function;
import org.apache.vxquery.types.AttributeType;
import org.apache.vxquery.types.ElementType;
import org.apache.vxquery.types.SchemaType;
import org.apache.vxquery.types.SequenceType;
public class StaticContextImpl implements StaticContext {
private final StaticContext parent;
private final Map<String, String> namespaceMap;
private final Map<QName, XQueryVariable> variableMap;
protected final Map<String, Collation> collationMap;
protected final Map<QName, Function[]> functionMap;
protected final Map<String, SequenceType> documentTypeMap;
protected final Map<String, SequenceType> collectionTypeMap;
protected final List<Pair<String, List<String>>> moduleImports;
protected final List<Pair<String, List<String>>> schemaImports;
protected final Map<QName, SchemaType> schemaTypeMap;
protected final Map<SequenceType, Integer> sequenceTypeMap;
protected final List<SequenceType> sequenceTypeList;
protected final Map<QName, AttributeType> attributeDeclarationMap;
protected final Map<QName, ElementType> elementDeclarationMap;
protected final Map<QName, String> options;
private BoundarySpaceProperty boundarySpaceProperty;
private String defaultFunctionNamespaceUri;
private String defaultElementNamespaceUri;
private OrderingModeProperty orderingModeProperty;
private EmptyOrderProperty emptyOrderProperty;
private String defaultCollation;
private String baseUri;
private ConstructionModeProperty constructionModeProperty;
private CopyNamespacesModeProperty copyNamespacesModeProperty;
private SequenceType defaultCollectionType;
private int typeCounter;
public StaticContextImpl(StaticContext parent) {
this.parent = parent;
namespaceMap = new LinkedHashMap<String, String>();
variableMap = new LinkedHashMap<QName, XQueryVariable>();
collationMap = new LinkedHashMap<String, Collation>();
functionMap = new LinkedHashMap<QName, Function[]>();
documentTypeMap = new LinkedHashMap<String, SequenceType>();
collectionTypeMap = new LinkedHashMap<String, SequenceType>();
moduleImports = new ArrayList<Pair<String, List<String>>>();
schemaImports = new ArrayList<Pair<String, List<String>>>();
schemaTypeMap = new LinkedHashMap<QName, SchemaType>();
sequenceTypeMap = new HashMap<SequenceType, Integer>();
sequenceTypeList = new ArrayList<SequenceType>();
attributeDeclarationMap = new LinkedHashMap<QName, AttributeType>();
elementDeclarationMap = new LinkedHashMap<QName, ElementType>();
options = new LinkedHashMap<QName, String>();
typeCounter = parent == null ? 0 : parent.getMaxSequenceTypeCode();
}
@Override
public StaticContext getParent() {
return parent;
}
@Override
public String lookupNamespaceUri(String prefix) {
if (namespaceMap.containsKey(prefix)) {
return namespaceMap.get(prefix);
}
if (parent != null) {
return parent.lookupNamespaceUri(prefix);
}
return null;
}
@Override
public void registerNamespaceUri(String prefix, String uri) {
namespaceMap.put(prefix, uri);
}
@Override
public Collation lookupCollation(String collationName) {
if (collationMap.containsKey(collationName)) {
return collationMap.get(collationName);
}
if (parent != null) {
return parent.lookupCollation(collationName);
}
return null;
}
@Override
public void registerCollation(String collationName, Collation collation) {
collationMap.put(collationName, collation);
}
@Override
public Function lookupFunction(QName functionName, int arity) {
if (functionMap.containsKey(functionName)) {
Function[] fns = functionMap.get(functionName);
if (fns != null && fns.length > arity && fns[arity] != null) {
return fns[arity];
}
}
if (parent != null) {
return parent.lookupFunction(functionName, arity);
}
return null;
}
@Override
public Function[] lookupFunctions(QName functionName) {
if (functionMap.containsKey(functionName)) {
return functionMap.get(functionName);
}
if (parent != null) {
return parent.lookupFunctions(functionName);
}
return null;
}
@Override
public void registerFunction(Function function) {
Function fns[] = functionMap.get(function.getName());
int arity = function.getSignature().getArity();
if (fns == null) {
fns = new Function[arity + 1];
fns[arity] = function;
functionMap.put(function.getName(), fns);
} else if (fns.length <= arity) {
Function newFns[] = new Function[arity + 1];
System.arraycopy(fns, 0, newFns, 0, fns.length);
newFns[arity] = function;
functionMap.put(function.getName(), newFns);
} else {
fns[arity] = function;
}
}
@Override
public Iterator<Function> listFunctions() {
return new Iterator<Function>() {
private Iterator<Function[]> faIter = functionMap.values().iterator();
private Function[] fa = null;
private int faIdx = 0;
@Override
public boolean hasNext() {
fetchNext();
return fa != null;
}
@Override
public Function next() {
fetchNext();
if (fa == null) {
throw new NoSuchElementException();
}
return fa[faIdx++];
}
private void fetchNext() {
while (true) {
if (fa != null && faIdx < fa.length) {
if (fa[faIdx] != null) {
break;
}
++faIdx;
} else {
if (faIter.hasNext()) {
fa = faIter.next();
faIdx = 0;
} else {
fa = null;
break;
}
}
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
@Override
public SequenceType lookupDocumentType(String docUri) {
if (documentTypeMap.containsKey(docUri)) {
return documentTypeMap.get(docUri);
}
if (parent != null) {
return parent.lookupDocumentType(docUri);
}
return null;
}
@Override
public void registerDocumentType(String docUri, SequenceType type) {
documentTypeMap.put(docUri, type);
}
@Override
public XQueryVariable lookupVariable(QName name) {
if (variableMap.containsKey(name)) {
return variableMap.get(name);
}
if (parent != null) {
return parent.lookupVariable(name);
}
return null;
}
@Override
public void registerVariable(XQueryVariable var) {
variableMap.put(var.getName(), var);
}
@Override
public Iterator<XQueryVariable> listVariables() {
return Collections.unmodifiableCollection(variableMap.values()).iterator();
}
@Override
public SequenceType lookupCollectionType(String collectionUri) {
if (collectionTypeMap.containsKey(collectionUri)) {
return collectionTypeMap.get(collectionUri);
}
if (parent != null) {
return parent.lookupCollectionType(collectionUri);
}
return null;
}
@Override
public void registerCollectionType(String collectionUri, SequenceType type) {
collectionTypeMap.put(collectionUri, type);
}
@Override
public Iterator<Pair<String, List<String>>> listModules() {
return new ConcatenatingIterator<Pair<String, List<String>>>() {
@Override
protected Iterator<Pair<String, List<String>>> getCurrentIterator() {
return moduleImports.iterator();
}
@Override
protected Iterator<Pair<String, List<String>>> getParentIterator() {
if (parent != null) {
return parent.listModules();
}
return null;
}
};
}
@Override
public void registerModuleImport(String uri, List<String> locations) {
moduleImports.add(Pair.<String, List<String>> of(uri, locations));
}
@Override
public Iterator<Pair<String, List<String>>> listSchemas() {
return new ConcatenatingIterator<Pair<String, List<String>>>() {
@Override
protected Iterator<Pair<String, List<String>>> getCurrentIterator() {
return schemaImports.iterator();
}
@Override
protected Iterator<Pair<String, List<String>>> getParentIterator() {
if (parent != null) {
return parent.listSchemas();
}
return null;
}
};
}
@Override
public void registerSchemaImport(String uri, List<String> locations) {
schemaImports.add(Pair.<String, List<String>> of(uri, locations));
}
@Override
public SchemaType lookupSchemaType(QName name) {
if (schemaTypeMap.containsKey(name)) {
return schemaTypeMap.get(name);
}
if (parent != null) {
return parent.lookupSchemaType(name);
}
return null;
}
@Override
public void registerSchemaType(QName name, SchemaType type) {
schemaTypeMap.put(name, type);
}
@Override
public int lookupSequenceType(SequenceType type) {
if (sequenceTypeMap.containsKey(type)) {
return sequenceTypeMap.get(type);
}
if (parent != null) {
return parent.lookupSequenceType(type);
}
return -1;
}
@Override
public SequenceType lookupSequenceType(int code) {
int maxParentTypeCode = parent == null ? 0 : parent.getMaxSequenceTypeCode();
if (code >= maxParentTypeCode) {
return sequenceTypeList.get(code - maxParentTypeCode);
}
return parent.lookupSequenceType(code);
}
@Override
public int encodeSequenceType(SequenceType type) {
int code = lookupSequenceType(type);
if (code == -1) {
code = typeCounter++;
sequenceTypeMap.put(type, code);
sequenceTypeList.add(type);
return code;
}
return code;
}
List<SequenceType> getSequenceTypeList() {
return sequenceTypeList;
}
@Override
public int getMaxSequenceTypeCode() {
return typeCounter;
}
@Override
public AttributeType lookupAttributeDeclaration(QName name) {
if (attributeDeclarationMap.containsKey(name)) {
return attributeDeclarationMap.get(name);
}
if (parent != null) {
return parent.lookupAttributeDeclaration(name);
}
return null;
}
@Override
public void registerAttributeDeclaration(QName name, AttributeType attrDecl) {
attributeDeclarationMap.put(name, attrDecl);
}
@Override
public ElementType lookupElementDeclaration(QName name) {
if (elementDeclarationMap.containsKey(name)) {
return elementDeclarationMap.get(name);
}
if (parent != null) {
return parent.lookupElementDeclaration(name);
}
return null;
}
@Override
public void registerElementDeclaration(QName name, ElementType elemDecl) {
elementDeclarationMap.put(name, elemDecl);
}
@Override
public BoundarySpaceProperty getBoundarySpaceProperty() {
if (boundarySpaceProperty != null) {
return boundarySpaceProperty;
}
if (parent != null) {
return parent.getBoundarySpaceProperty();
}
return null;
}
@Override
public void setBoundarySpaceProperty(BoundarySpaceProperty boundarySpaceProperty) {
this.boundarySpaceProperty = boundarySpaceProperty;
}
@Override
public String getDefaultFunctionNamespaceUri() {
if (defaultFunctionNamespaceUri != null) {
return defaultFunctionNamespaceUri;
}
if (parent != null) {
return parent.getDefaultFunctionNamespaceUri();
}
return null;
}
@Override
public void setDefaultFunctionNamespaceUri(String uri) {
this.defaultFunctionNamespaceUri = uri;
}
@Override
public String getDefaultElementNamespaceUri() {
if (defaultElementNamespaceUri != null) {
return defaultElementNamespaceUri;
}
if (parent != null) {
return parent.getDefaultElementNamespaceUri();
}
return null;
}
@Override
public void setDefaultElementNamespaceUri(String uri) {
this.defaultElementNamespaceUri = uri;
}
@Override
public OrderingModeProperty getOrderingModeProperty() {
if (orderingModeProperty != null) {
return orderingModeProperty;
}
if (parent != null) {
return parent.getOrderingModeProperty();
}
return null;
}
@Override
public void setOrderingModeProperty(OrderingModeProperty orderingMode) {
this.orderingModeProperty = orderingMode;
}
@Override
public EmptyOrderProperty getEmptyOrderProperty() {
if (emptyOrderProperty != null) {
return emptyOrderProperty;
}
if (parent != null) {
return parent.getEmptyOrderProperty();
}
return null;
}
@Override
public void setEmptyOrderProperty(EmptyOrderProperty emptyOrder) {
this.emptyOrderProperty = emptyOrder;
}
@Override
public String getDefaultCollation() {
if (defaultCollation != null) {
return defaultCollation;
}
if (parent != null) {
return parent.getDefaultCollation();
}
return null;
}
@Override
public void setDefaultCollation(String defaultCollation) {
this.defaultCollation = defaultCollation;
}
@Override
public String getBaseUri() {
if (baseUri != null) {
return baseUri;
}
if (parent != null) {
return parent.getBaseUri();
}
return null;
}
@Override
public void setBaseUri(String baseUri) {
this.baseUri = baseUri;
}
@Override
public ConstructionModeProperty getConstructionModeProperty() {
if (constructionModeProperty != null) {
return constructionModeProperty;
}
if (parent != null) {
return parent.getConstructionModeProperty();
}
return null;
}
@Override
public void setConstructionModeProperty(ConstructionModeProperty constructionMode) {
this.constructionModeProperty = constructionMode;
}
@Override
public CopyNamespacesModeProperty getCopyNamespacesModeProperty() {
if (copyNamespacesModeProperty != null) {
return copyNamespacesModeProperty;
}
if (parent != null) {
return parent.getCopyNamespacesModeProperty();
}
return null;
}
@Override
public void setCopyNamespacesModeProperty(CopyNamespacesModeProperty copyNamespacesMode) {
this.copyNamespacesModeProperty = copyNamespacesMode;
}
@Override
public SequenceType getDefaultCollectionType() {
if (defaultCollectionType != null) {
return defaultCollectionType;
}
if (parent != null) {
return parent.getDefaultCollectionType();
}
return null;
}
@Override
public void setDefaultCollectionType(SequenceType type) {
this.defaultCollectionType = type;
}
@Override
public void setOption(QName name, String value) {
options.put(name, value);
}
@Override
public String getOption(QName name) {
if (options.containsKey(name)) {
return options.get(name);
}
if (parent != null) {
return parent.getOption(name);
}
return null;
}
public IStaticContextFactory createFactory() {
return StaticContextImplFactory.createInstance(this);
}
private abstract class ConcatenatingIterator<T> implements Iterator<T> {
Iterator<T> currListIter = getCurrentIterator();
Iterator<T> parentIter = null;
T nextItem = null;
@Override
public boolean hasNext() {
fetchNext();
return nextItem != null;
}
protected abstract Iterator<T> getCurrentIterator();
protected abstract Iterator<T> getParentIterator();
@Override
public T next() {
if (hasNext()) {
T item = nextItem;
nextItem = null;
return item;
}
return null;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
private void fetchNext() {
if (nextItem != null) {
return;
}
if (currListIter != null) {
if (currListIter.hasNext()) {
nextItem = currListIter.next();
} else {
currListIter = null;
parentIter = getParentIterator();
}
}
if (nextItem == null && parentIter != null) {
if (parentIter.hasNext()) {
nextItem = parentIter.next();
} else {
parentIter = null;
}
}
}
}
}