⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dispatcher.java

📁 电子地图服务器,搭建自己的地图服务
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
 * This code is licensed under the GPL 2.0 license, availible at the root
 * application directory.
 */
package org.geoserver.ows;

import org.acegisecurity.AcegiSecurityException;
import org.eclipse.emf.ecore.EObject;
import org.geoserver.ows.security.OperationInterceptor;
import org.geoserver.ows.util.EncodingInfo;
import org.geoserver.ows.util.OwsUtils;
import org.geoserver.ows.util.RequestUtils;
import org.geoserver.ows.util.XmlCharsetDetector;
import org.geoserver.platform.GeoServerExtensions;
import org.geoserver.platform.Operation;
import org.geoserver.platform.Service;
import org.geoserver.platform.ServiceException;
import org.geotools.util.Version;
import org.geotools.xml.EMFUtils;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.namespace.QName;


/**
 * Dispatches an http request to an open web service (OWS).
 * <p>
 * An OWS request contains three bits of information:
 *         <ol>
 *                 <li>The service being called
 *                 <li>The operation of the service to execute
 *                 <li>The version of the service ( optional )
 *  </ol>
 *  Additional, an OWS request can contain an arbitray number of additional
 *  parameters.
 * </p>
 * <p>
 * An OWS request can be specified in two forms. The first form is known as "KVP"
 * in which all the parameters come in the form of a set of key-value pairs.
 * Commonly this type of request is made in an http "GET" request, the parameters
 * being specified in the query string:
 *
 *  <pre>
 *          <code>http://www.xyz.com/geoserver?service=someService&request=someRequest&version=X.Y.Z&param1=...&param2=...
 *  </pre>
 *
 *  This type of request can also be made in a "POST" request in with a
 *  mime-type of "application/x-www-form-urlencoded".
 * </p>
 * <p>
 * The second form is known as "XML" in which all the parameters come in the
 * form of an xml document. This type of request is made in an http "POST"
 * request.
 *
 *         <pre>
 *                 <code>
 *  &lt;?xml version="1.0" encoding="UTF-8"?&gt;
 *  &lt;SomeRequest service="someService" version="X.Y.Z"&gt;
 *    &lt;Param1&gt;...&lt;/Param1&gt;
 *    &lt;Param2&gt;...&lt;/Param2&gt;
 *    ...
 *  &lt;/SomeRequest&gt;
 *                 </code>
 *         </pre>
 * </p>
 * <p>
 * When a request is received, the <b>service</b> the <b>version</b> parameters
 * are used to locate a service desciptor, an instance of {@link Service}. With
 * the service descriptor, the <b>request</b> parameter is used to locate the
 * operation of the service to call.
 * </p>
 *
 * @author Justin Deoliveira, The Open Planning Project, jdeolive@openplans.org
 *
 */
public class Dispatcher extends AbstractController {
    /**
     * Logging instance
     */
    static Logger logger = org.geotools.util.logging.Logging.getLogger("org.geoserver.ows");

    /** flag to control wether the dispatcher is cite compliant */
    boolean citeCompliant = false;

    /** The security interceptor to be used for authorization checks **/
    OperationInterceptor securityInterceptor = null;

    /**
     * Sets the flag to control wether the dispatcher is cite compliante.
     * <p>
     * If set to <code>true</code>, the dispatcher with throw exceptions when
     * it encounters something that is not 100% compliant with CITE standards.
     * An example would be a request which specifies the servce in the context
     * path: '.../geoserver/wfs?request=...' and not with the kvp '&service=wfs'.
     * </p>
     *
     * @param citeCompliant <code>true</code> to set compliance,
     *         <code>false</code> to unset it.
     */
    public void setCiteCompliant(boolean citeCompliant) {
        this.citeCompliant = citeCompliant;
    }

    public boolean isCiteCompliant() {
        return citeCompliant;
    }

    protected void preprocessRequest(HttpServletRequest request)
        throws Exception {
        //set the charset
        Charset charSet = null;

        try {
            charSet = Charset.forName(request.getCharacterEncoding());
        } catch (Exception e) {
            //TODO: make this server settable
            charSet = Charset.forName("UTF-8");
        }

        request.setCharacterEncoding(charSet.name());
    }

    protected ModelAndView handleRequestInternal(HttpServletRequest httpRequest,
        HttpServletResponse httpResponse) throws Exception {
        preprocessRequest(httpRequest);

        //create a new request instance
        Request request = new Request();

        //set request / response
        request.httpRequest = httpRequest;
        request.httpResponse = httpResponse;

        Service service = null;

        try {
            //initialize the request
            init(request);

            //find the service
            try {
                service = service(request);
            } catch (Throwable t) {
                exception(t, null, request);

                return null;
            }

            //throw any outstanding errors
            if (request.error != null) {
                throw request.error;
            }

            //dispatch the operation
            Operation operation = dispatch(request, service);

            //execute it
            Object result = execute(request, operation);

            //write the response
            if (result != null) {
                response(result, request, operation);
            }
        } catch (AcegiSecurityException e) {
            // make Acegi exceptions flow so that exception transformer filter can handle them
            throw e;
        } catch (Throwable t) {
            exception(t, service, request);
        }

        return null;
    }

    Request init(Request request) throws ServiceException, IOException {
        HttpServletRequest httpRequest = request.httpRequest;

        //figure out method
        request.get = "GET".equalsIgnoreCase(httpRequest.getMethod())
            || "application/x-www-form-urlencoded".equals(httpRequest.getContentType());

        //create the kvp map
        parseKVP(request);
        
        if ( !request.get ) {
            //wrap the input stream in a buffer input stream
            request.input = reader(httpRequest);

            //mark the input stream, support up to 2KB, TODO: make this configuratable
            request.input.mark(2048);
            
            if (logger.isLoggable(Level.FINE)) {
                char[] req = new char[1024];
                int read = request.input.read(req, 0, 1024);
                if (read < 1024) {
                    logger.fine("Raw XML request starts with: " + new String(req));
                } else {
                    logger.fine("Raw XML request starts with: " + new String(req) + "...");
                }
                request.input.reset();
            }
        }

        return request;
    }

    BufferedReader reader(HttpServletRequest httpRequest)
        throws IOException {
        //create a buffer so we can reset the input stream
        BufferedInputStream input = new BufferedInputStream(httpRequest.getInputStream());
        input.mark(2048);

        //create object to hold encoding info
        EncodingInfo encoding = new EncodingInfo();

        //call this method to set the encoding info
        XmlCharsetDetector.getCharsetAwareReader(input, encoding);

        //call this method to create the reader
        Reader reader = XmlCharsetDetector.createReader(input, encoding);

        //rest the input
        input.reset();

        //ensure the reader is a buffered reader
        if (reader instanceof BufferedReader) {
            return (BufferedReader) reader;
        }

        return new BufferedReader(reader);
    }

    Service service(Request req) throws Exception {
        //check kvp
        if (req.kvp != null) {

            req.service = normalize((String) req.kvp.get("service"));
            req.version = normalize((String) req.kvp.get("version"));
            req.request = normalize((String) req.kvp.get("request"));
            req.outputFormat = normalize((String) req.kvp.get("outputFormat"));
        } 
        //check the body
        if (req.input != null) {
            Map xml = readOpPost(req.input);
            if (req.service == null) {
                req.service = normalize((String) xml.get("service"));    
            }
            if (req.version == null) {
                req.version = normalize((String) xml.get("version"));    
            }
            if (req.request == null) {
                req.request = normalize((String) xml.get("request"));    
            }
            if (req.outputFormat == null) {
                req.outputFormat = normalize((String) xml.get("outputFormat"));    
            }
        }

        //try to infer from context
        //JD: for cite compliance, a service *must* be specified explicitley by 
        // either a kvp, or an xml attribute, however in reality the context 
        // is often a good way to infer the service or request 
        String service = req.service;

        if ((service == null) || (req.request == null)) {
            Map map = readOpContext(req.httpRequest);

            if (service == null) {
                service = normalize((String) map.get("service"));

                if ((service != null) && !citeCompliant) {
                    req.service = service;
                }
            }

            if (req.request == null) {
                req.request = normalize((String) map.get("request"));
            }
        }

        if (service == null) {
            //give up 
            throw new ServiceException("Could not determine service", "MissingParameterValue",
                "service");
        }

        //load from teh context
        return findService(service, req.version);
    }

    String normalize(String value) {
        if (value == null) {
            return null;
        }

        if ("".equals(value.trim())) {
            return null;
        }

        return value.trim();
    }

    Operation dispatch(Request req, Service serviceDescriptor)
        throws Throwable {
        if (req.request == null) {
            String msg = "Could not determine geoserver request from http request " + req.httpRequest;
            throw new ServiceException(msg, "MissingParameterValue", "request");
        }

        // lookup the operation, initial lookup based on (service,request)
        Object serviceBean = serviceDescriptor.getService();
        Method operation = OwsUtils.method(serviceBean.getClass(), req.request);

        if (operation == null) {
            String msg = "No such operation " + req;
            throw new ServiceException(msg, "OperationNotSupported", req.request);
        }

        //step 4: setup the paramters
        Object[] parameters = new Object[operation.getParameterTypes().length];

        for (int i = 0; i < parameters.length; i++) {
            Class parameterType = operation.getParameterTypes()[i];

            //first check for servlet request and response
            if (parameterType.isAssignableFrom(HttpServletRequest.class)) {
                parameters[i] = req.httpRequest;
            } else if (parameterType.isAssignableFrom(HttpServletResponse.class)) {
                parameters[i] = req.httpResponse;
            }
            //next check for input and output
            else if (parameterType.isAssignableFrom(InputStream.class)) {
                parameters[i] = req.httpRequest.getInputStream();
            } else if (parameterType.isAssignableFrom(OutputStream.class)) {
                parameters[i] = req.httpResponse.getOutputStream();
            } else {
                //check for a request object
                Object requestBean = null;

                if (req.kvp != null) {
                    //use the kvp reader mechanism
                    requestBean = parseRequestKVP(parameterType, req);
                }
                if (req.input != null) {
                    //use the xml reader mechanism
                    requestBean = parseRequestXML(requestBean,req.input, req);
                }
                
                // GEOS-934  and GEOS-1288
                Method setBaseUrl = OwsUtils.setter(requestBean.getClass(), "baseUrl", String.class);
                if (setBaseUrl != null) {
                    setBaseUrl.invoke(requestBean, new String[] { RequestUtils.baseURL(req.httpRequest)});
                }

                // another couple of thos of those lovley cite things, version+service has to specified for 
                // non capabilities request, so if we dont have either thus far, check the request
                // objects to try and find one
                // TODO: should make this configurable
                if (requestBean != null) {
                    //if we dont have a version thus far, check the request object
                    if (req.service == null) {
                        req.service = lookupRequestBeanProperty(requestBean, "service", false);
                    }

                    if (req.version == null) {
                        req.version = lookupRequestBeanProperty(requestBean, "version", false);
                    }

                    if (req.outputFormat == null) {
                        req.outputFormat = lookupRequestBeanProperty(requestBean, "outputFormat",
                                true);
                    }

                    parameters[i] = requestBean;
                }
            }
        }

        //if we are in cite compliant mode, do some additional checks to make
        // sure the "mandatory" parameters are specified, even though we 
        // succesfully dispatched the request.
        if (citeCompliant) {
            if (!"GetCapabilities".equalsIgnoreCase(req.request)) {
                if (req.version == null) {
                    //must be a version on non-capabilities requests
                    throw new ServiceException("Could not determine version",
                        "MissingParameterValue", "version");
                } else {
                    //version must be valid
                    if (!req.version.matches("[0-99].[0-99].[0-99]")) {
                        throw new ServiceException("Invalid version: " + req.version,
                            "InvalidParameterValue", "version");
                    }

                    //make sure the versoin actually exists

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -