/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2008-2014, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.data.wfs.internal;
import static org.geotools.data.wfs.internal.HttpMethod.GET;
import static org.geotools.data.wfs.internal.HttpMethod.POST;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Properties;
import java.util.logging.Level;
import javax.xml.namespace.QName;
import org.apache.commons.io.IOUtils;
import org.geotools.data.ows.AbstractRequest;
import org.geotools.data.ows.HTTPResponse;
import org.geotools.data.ows.Request;
import org.geotools.factory.FactoryNotFoundException;
import org.geotools.util.logging.Logging;
public abstract class WFSRequest extends AbstractRequest implements Request {
protected final WFSStrategy strategy;
protected final WFSOperationType operation;
protected final WFSConfig config;
private final boolean doPost;
private QName typeName;
private String outputFormat;
private String handle;
public WFSRequest(final WFSOperationType operation, final WFSConfig config,
final WFSStrategy strategy) {
super(url(operation, config, strategy), (Properties) null);
this.operation = operation;
this.config = config;
this.strategy = strategy;
this.handle = strategy.newRequestHandle(operation);
switch (config.getPreferredMethod()) {
case HTTP_POST:
this.doPost = strategy.supportsOperation(operation, POST);
break;
case HTTP_GET:
this.doPost = !strategy.supportsOperation(operation, GET);
break;
default:
this.doPost = strategy.supportsOperation(operation, POST);
break;
}
this.outputFormat = strategy.getDefaultOutputFormat(operation);
setProperty(SERVICE, "WFS");
setProperty(VERSION, strategy.getVersion());
setProperty(REQUEST, operation.getName());
}
public String getOutputFormat() {
return outputFormat;
}
public String getHandle() {
return handle;
}
public void setHandle(String handle) {
this.handle = handle;
}
/**
* @param outputFormat
* the outputFormat to set
*/
public void setOutputFormat(String outputFormat) {
this.outputFormat = outputFormat;
}
public void setTypeName(QName typeName) {
this.typeName = typeName;
}
public QName getTypeName() {
return typeName;
}
public WFSStrategy getStrategy() {
return strategy;
}
private static URL url(final WFSOperationType operation, final WFSConfig config,
final WFSStrategy strategy) {
final boolean suportsGet = strategy.supportsOperation(operation, GET);
final boolean suportsPost = strategy.supportsOperation(operation, POST);
if (!(suportsGet || suportsPost)) {
throw new IllegalArgumentException("WFS doesn't support " + operation.getName());
}
HttpMethod method;
switch (config.getPreferredMethod()) {
case AUTO:
case HTTP_POST:
method = suportsPost ? POST : GET;
break;
default:
method = suportsPost ? POST : GET;
break;
}
URL targetUrl = strategy.getOperationURL(operation, method);
return targetUrl;
}
public WFSOperationType getOperation() {
return operation;
}
@Override
public boolean requiresPost() {
return doPost;
}
@Override
protected void initService() {
}
@Override
protected void initVersion() {
}
@Override
protected void initRequest() {
}
@Override
public URL getFinalURL() {
if (requiresPost()) {
return super.getFinalURL();
}
URL finalURL = strategy.buildUrlGET(this);
return finalURL;
}
@Override
public String getPostContentType() {
// As per WFS 1.1.0 (OGC 04-094) 6.5.1
// "When using the HTTP POST method, the content type for XML encoded WFS requests must be set to text/xml."
// .. and
// As per WFS 2.0.0 (OGC 09-025r1 and ISO/DIS 19142) Annex D.2
// "When using the HTTP POST method, the content type for XML encoded WFS requests shall be set to text/xml."
return "text/xml";
}
@Override
public void performPostOutput(OutputStream outputStream) throws IOException {
InputStream in = strategy.getPostContents(this);
try {
IOUtils.copy(in, outputStream);
} finally {
in.close();
}
}
@Override
public WFSResponse createResponse(HTTPResponse response) throws IOException {
final String contentType = response.getContentType();
if (contentType == null) {
Logging.getLogger(WFSRequest.class).warning(
this.getOperation() + " request returned null content type for URL "
+ getFinalURL());
}
WFSResponseFactory responseFactory;
try {
responseFactory = WFSExtensions.findResponseFactory(this, contentType);
} catch (FactoryNotFoundException fnf) {
Loggers.MODULE.log(Level.WARNING, fnf.getMessage());
try {
if (contentType != null && contentType.startsWith("text")) {
byte buff[] = new byte[1024];
response.getResponseStream().read(buff);
Loggers.MODULE.info("Failed response snippet: " + new String(buff));
}
throw fnf;
} catch (Exception ignore) {
throw fnf;
}
}
WFSResponse wfsResponse = responseFactory.createResponse(this, response);
return wfsResponse;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(getOperation().toString());
sb.append("[");
sb.append("\n\thandle: ").append(handle);
sb.append("\n\toutputFormat: <").append(outputFormat).append(">");
sb.append("\n\tmethod: ").append(doPost ? "POST" : "GET");
sb.append("\n\tonlineResource: <").append(onlineResource).append(">");
try {
sb.append("\n\tfinal URL: <").append(getFinalURL()).append(">");
} catch (Exception e) {
sb.append("\n\tfinal URL error: <").append(e.getMessage()).append(">");
}
return sb.append("\n]").toString();
}
}