blob: 80ce2662ae8f46a649a462e515bc12aabf92af6e [file] [log] [blame]
/* Copyright 2004 The Apache Software Foundation
*
* 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 org.apache.xmlbeans.impl.config;
import org.apache.xmlbeans.*;
import org.apache.xmlbeans.impl.schema.StscState;
import org.apache.xmlbeans.impl.xb.xmlconfig.ConfigDocument.Config;
import org.apache.xmlbeans.impl.xb.xmlconfig.*;
import javax.xml.namespace.QName;
import java.io.File;
import java.util.*;
/**
* An implementation of BindingConfig
*/
public class BindingConfigImpl extends BindingConfig {
private final Map _packageMap = new LinkedHashMap();
private final Map _prefixMap = new LinkedHashMap();
private final Map _suffixMap = new LinkedHashMap();
// uri prefix -> package
private final Map<Object,String> _packageMapByUriPrefix = new LinkedHashMap<>();
// uri prefix -> name prefix
private final Map<Object,String> _prefixMapByUriPrefix = new LinkedHashMap<>();
// uri prefix -> name suffix
private final Map<Object,String> _suffixMapByUriPrefix = new LinkedHashMap<>();
private final Map<QName,String> _qnameTypeMap = new LinkedHashMap<>();
private final Map<QName,String> _qnameDocTypeMap = new LinkedHashMap<>();
private final Map<QName,String> _qnameElemMap = new LinkedHashMap<>();
private final Map<QName,String> _qnameAttMap = new LinkedHashMap<>();
private final List<InterfaceExtensionImpl> _interfaceExtensions = new ArrayList<>();
private final List<PrePostExtensionImpl> _prePostExtensions = new ArrayList<>();
private final Map<QName,UserTypeImpl> _userTypes = new LinkedHashMap<>();
public static BindingConfig forConfigDocuments(Config[] configs, File[] javaFiles, File[] classpath) {
return new BindingConfigImpl(configs, javaFiles, classpath);
}
private BindingConfigImpl(Config[] configs, File[] javaFiles, File[] classpath) {
for (Config config : configs) {
Nsconfig[] nsa = config.getNamespaceArray();
for (Nsconfig nsconfig : nsa) {
recordNamespaceSetting(nsconfig.getUri(), nsconfig.getPackage(), _packageMap);
recordNamespaceSetting(nsconfig.getUri(), nsconfig.getPrefix(), _prefixMap);
recordNamespaceSetting(nsconfig.getUri(), nsconfig.getSuffix(), _suffixMap);
recordNamespacePrefixSetting(nsconfig.getUriprefix(), nsconfig.getPackage(), _packageMapByUriPrefix);
recordNamespacePrefixSetting(nsconfig.getUriprefix(), nsconfig.getPrefix(), _prefixMapByUriPrefix);
recordNamespacePrefixSetting(nsconfig.getUriprefix(), nsconfig.getSuffix(), _suffixMapByUriPrefix);
}
Qnameconfig[] qnc = config.getQnameArray();
for (Qnameconfig qnameconfig : qnc) {
List applyto = qnameconfig.xgetTarget().xgetListValue();
QName name = qnameconfig.getName();
String javaname = qnameconfig.getJavaname();
for (Object o : applyto) {
Qnametargetenum a = (Qnametargetenum) o;
switch (a.enumValue().intValue()) {
case Qnametargetenum.INT_TYPE:
_qnameTypeMap.put(name, javaname);
break;
case Qnametargetenum.INT_DOCUMENT_TYPE:
_qnameDocTypeMap.put(name, javaname);
break;
case Qnametargetenum.INT_ACCESSOR_ELEMENT:
_qnameElemMap.put(name, javaname);
break;
case Qnametargetenum.INT_ACCESSOR_ATTRIBUTE:
_qnameAttMap.put(name, javaname);
break;
}
}
}
Extensionconfig[] ext = config.getExtensionArray();
for (Extensionconfig extensionconfig : ext) {
recordExtensionSetting(javaFiles, classpath, extensionconfig);
}
Usertypeconfig[] utypes = config.getUsertypeArray();
for (Usertypeconfig utype : utypes) {
recordUserTypeSetting(javaFiles, classpath, utype);
}
}
secondPhaseValidation();
//todo normalize();
}
void addInterfaceExtension(InterfaceExtensionImpl ext) {
if (ext==null) {
return;
}
_interfaceExtensions.add(ext);
}
void addPrePostExtension(PrePostExtensionImpl ext) {
if (ext==null) {
return;
}
_prePostExtensions.add(ext);
}
void secondPhaseValidation() {
// validate interface methods collisions
Map<InterfaceExtension.MethodSignature,InterfaceExtension.MethodSignature> methodSignatures = new HashMap<>();
for (InterfaceExtensionImpl extension : _interfaceExtensions) {
InterfaceExtensionImpl.MethodSignatureImpl[] methods = (InterfaceExtensionImpl.MethodSignatureImpl[]) extension.getMethods();
for (InterfaceExtensionImpl.MethodSignatureImpl ms : methods) {
if (methodSignatures.containsKey(ms)) {
InterfaceExtensionImpl.MethodSignatureImpl ms2 = (InterfaceExtensionImpl.MethodSignatureImpl) methodSignatures.get(ms);
if (!ms.getReturnType().equals(ms2.getReturnType())) {
BindingConfigImpl.error("Colliding methods '" + ms.getSignature() + "' in interfaces " +
ms.getInterfaceName() + " and " + ms2.getInterfaceName() + ".", null);
}
return;
}
// store it into hashmap
methodSignatures.put(ms, ms);
}
}
// validate that PrePostExtension-s do not intersect
for (int i = 0; i < _prePostExtensions.size() - 1; i++) {
PrePostExtensionImpl a = _prePostExtensions.get(i);
for (int j = 1; j < _prePostExtensions.size(); j++) {
PrePostExtensionImpl b = _prePostExtensions.get(j);
if (a.hasNameSetIntersection(b)) {
BindingConfigImpl.error("The applicable domain for handler '" + a.getHandlerNameForJavaSource() +
"' intersects with the one for '" + b.getHandlerNameForJavaSource() + "'.", null);
}
}
}
}
private static void recordNamespaceSetting(Object key, String value, Map<Object,String> result) {
if (value == null) {
return;
}
if (key == null) {
result.put("", value);
} else if (key instanceof String && "##any".equals(key)) {
result.put(key, value);
} else if (key instanceof List) {
// map uris to value
((List<?>)key).forEach(o -> result.put("##local".equals(o) ? "" : o, value));
}
}
private static void recordNamespacePrefixSetting(List list, String value, Map<Object,String> result) {
if (value == null) {
return;
}
if (list == null) {
return;
}
list.forEach(o -> result.put(o, value));
}
private void recordExtensionSetting(File[] javaFiles, File[] classpath, Extensionconfig ext) {
NameSet xbeanSet = null;
Object key = ext.getFor();
if (key instanceof String && "*".equals(key))
xbeanSet = NameSet.EVERYTHING;
else if (key instanceof List)
{
NameSetBuilder xbeanSetBuilder = new NameSetBuilder();
for (Object o : (List) key) {
String xbeanName = (String) o;
xbeanSetBuilder.add(xbeanName);
}
xbeanSet = xbeanSetBuilder.toNameSet();
}
if (xbeanSet == null)
error("Invalid value of attribute 'for' : '" + key + "'.", ext);
Extensionconfig.Interface[] intfXO = ext.getInterfaceArray();
Extensionconfig.PrePostSet ppXO = ext.getPrePostSet();
Parser loader = new Parser(javaFiles, classpath);
if (intfXO.length > 0 || ppXO != null) {
for (Extensionconfig.Interface anInterface : intfXO) {
addInterfaceExtension(InterfaceExtensionImpl.newInstance(loader, xbeanSet, anInterface));
}
addPrePostExtension(PrePostExtensionImpl.newInstance(loader, xbeanSet, ppXO));
}
}
private void recordUserTypeSetting(File[] javaFiles, File[] classpath, Usertypeconfig usertypeconfig) {
Parser loader = new Parser(javaFiles, classpath);
UserTypeImpl userType = UserTypeImpl.newInstance(loader, usertypeconfig);
_userTypes.put(userType.getName(), userType);
}
private String lookup(Map map, Map mapByUriPrefix, String uri) {
if (uri == null) {
uri = "";
}
String result = (String)map.get(uri);
if (result != null) {
return result;
}
if (mapByUriPrefix != null) {
result = lookupByUriPrefix(mapByUriPrefix, uri);
if (result != null) {
return result;
}
}
return (String)map.get("##any");
}
private String lookupByUriPrefix(Map mapByUriPrefix, String uri) {
if (uri == null) {
return null;
}
if (!mapByUriPrefix.isEmpty()) {
String uriprefix = null;
for (Object o : mapByUriPrefix.keySet()) {
String nextprefix = (String) o;
if (uriprefix != null && nextprefix.length() < uriprefix.length()) {
continue;
}
if (uri.startsWith(nextprefix)) {
uriprefix = nextprefix;
}
}
if (uriprefix != null) {
return (String) mapByUriPrefix.get(uriprefix);
}
}
return null;
}
//package methods
static void warning(String s, XmlObject xo) {
StscState.get().error(s, XmlError.SEVERITY_WARNING, xo);
}
static void error(String s, XmlObject xo) {
StscState.get().error(s, XmlError.SEVERITY_ERROR, xo);
}
//public methods
public String lookupPackageForNamespace(String uri) {
return lookup(_packageMap, _packageMapByUriPrefix, uri);
}
public String lookupPrefixForNamespace(String uri) {
return lookup(_prefixMap, _prefixMapByUriPrefix, uri);
}
public String lookupSuffixForNamespace(String uri) {
return lookup(_suffixMap, _suffixMapByUriPrefix, uri);
}
/** @deprecated replaced with {@link #lookupJavanameForQName(QName, int)} */
public String lookupJavanameForQName(QName qname) {
String result = _qnameTypeMap.get(qname);
return result != null ? result : _qnameDocTypeMap.get(qname);
}
public String lookupJavanameForQName(QName qname, int kind) {
switch (kind) {
case QNAME_TYPE:
return _qnameTypeMap.get(qname);
case QNAME_DOCUMENT_TYPE:
return _qnameDocTypeMap.get(qname);
case QNAME_ACCESSOR_ELEMENT:
return _qnameElemMap.get(qname);
case QNAME_ACCESSOR_ATTRIBUTE:
return _qnameAttMap.get(qname);
}
return null;
}
public UserType lookupUserTypeForQName(QName qname) {
return qname == null ? null : _userTypes.get(qname);
}
public InterfaceExtension[] getInterfaceExtensions() {
return _interfaceExtensions.toArray(new InterfaceExtension[0]);
}
public InterfaceExtension[] getInterfaceExtensions(String fullJavaName) {
return _interfaceExtensions.stream().
filter(i -> i.contains(fullJavaName)).
toArray(InterfaceExtension[]::new);
}
public PrePostExtension[] getPrePostExtensions() {
return _prePostExtensions.toArray(new PrePostExtension[0]);
}
public PrePostExtension getPrePostExtension(String fullJavaName) {
return _prePostExtensions.stream().
filter(p -> p.contains(fullJavaName)).
findFirst().orElse(null);
}
}