/*
* Copyright (c) 2015 Data Harmonisation Panel
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution. If not, see <http://www.gnu.org/licenses/>.
*
* Contributors:
* Data Harmonisation Panel <http://www.dhpanel.eu>
*/
package eu.esdihumboldt.hale.io.wfs.ui;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import org.apache.http.client.utils.URIBuilder;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Maps.EntryTransformer;
import eu.esdihumboldt.hale.io.wfs.WFSVersion;
/**
* Utilities related to KVP encoded WFS requests.
*
* @author Simon Templer
*/
public class KVPUtil {
/**
* Add typename and namespace parameters for a WFS request to the given URI
* builder.
*
* @param builder the builder for the WFS request URI
* @param selected the type names to include
* @param version the targeted WFS version
*/
public static void addTypeNameParameter(URIBuilder builder, Iterable<QName> selected,
WFSVersion version) {
// namespaces mapped to prefixes
Map<String, String> namespaces = new HashMap<>();
// type names with updated prefix
Set<QName> typeNames = new HashSet<>();
for (QName type : selected) {
String prefix;
if (type.getNamespaceURI() != null && !type.getNamespaceURI().isEmpty()) {
prefix = namespaces.get(type.getNamespaceURI());
if (prefix == null) {
// no mapping yet for namespace
String candidate = type.getPrefix();
prefix = addPrefix(candidate, type.getNamespaceURI(), namespaces);
}
}
else {
// default namespace
prefix = XMLConstants.DEFAULT_NS_PREFIX;
}
// add updated type
typeNames.add(new QName(type.getNamespaceURI(), type.getLocalPart(), prefix));
}
final String paramNamespaces;
final String paramTypenames;
final String prefixNamespaceDelim;
switch (version) {
case V1_1_0:
paramNamespaces = "NAMESPACE";
paramTypenames = "TYPENAME";
prefixNamespaceDelim = "=";
break;
case V2_0_0:
case V2_0_2:
/*
* XXX below are the values as defined in the WFS 2 specification.
* There have been problems with some GeoServer instances if used in
* that manner.
*/
paramNamespaces = "NAMESPACES";
paramTypenames = "TYPENAMES";
prefixNamespaceDelim = ",";
break;
default:
// fall-back to WFS 1.1
paramNamespaces = "NAMESPACE";
paramTypenames = "TYPENAME";
prefixNamespaceDelim = "=";
}
// add namespace prefix definitions
if (!namespaces.isEmpty()) {
builder.addParameter(
paramNamespaces,
Joiner.on(',').join(
Maps.transformEntries(namespaces,
new EntryTransformer<String, String, String>() {
@Override
public String transformEntry(String namespace, String prefix) {
StringBuilder sb = new StringBuilder();
sb.append("xmlns(");
sb.append(prefix);
sb.append(prefixNamespaceDelim);
sb.append(namespace);
sb.append(")");
return sb.toString();
}
}).values()));
}
// add type names
if (!typeNames.isEmpty()) {
builder.addParameter(
paramTypenames,
Joiner.on(',').join(
Iterables.transform(typeNames, new Function<QName, String>() {
@Override
public String apply(QName typeName) {
String prefix = typeName.getPrefix();
if (prefix == null || prefix.isEmpty()) {
return typeName.getLocalPart();
}
return prefix + ":" + typeName.getLocalPart();
}
})));
}
}
/**
* Add a new prefix.
*
* @param candidate the prefix candidate
* @param namespace the namespace to be associated to the prefix
* @param namespaces the current namespaces mapped to prefixes
* @return the prefix to use
*/
private static String addPrefix(String candidate, final String namespace,
final Map<String, String> namespaces) {
int num = 1;
while (namespaces.values().contains(candidate)) {
candidate = "ns" + num;
num++;
}
namespaces.put(namespace, candidate);
return candidate;
}
}