Package org.vfny.geoserver.wfs.responses

Source Code of org.vfny.geoserver.wfs.responses.LockResponse

/* Copyright (c) 2001, 2003 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.vfny.geoserver.wfs.responses;

import java.io.IOException;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;

import org.geotools.data.DefaultQuery;
import org.geotools.data.DefaultTransaction;
import org.geotools.data.FeatureLock;
import org.geotools.data.FeatureLocking;
import org.geotools.data.FeatureReader;
import org.geotools.data.FeatureResults;
import org.geotools.data.FeatureSource;
import org.geotools.data.Query;
import org.geotools.data.Transaction;
import org.geotools.feature.Feature;
import org.geotools.feature.IllegalAttributeException;
import org.geotools.filter.Filter;
import org.geotools.filter.FilterFactory;
import org.vfny.geoserver.Request;
import org.vfny.geoserver.Response;
import org.vfny.geoserver.ServiceException;
import org.vfny.geoserver.global.Data;
import org.vfny.geoserver.global.FeatureTypeInfo;
import org.vfny.geoserver.global.GeoServer;
import org.vfny.geoserver.global.NameSpaceInfo;
import org.vfny.geoserver.global.Service;
import org.vfny.geoserver.global.dto.WFSDTO;
import org.vfny.geoserver.wfs.WfsException;
import org.vfny.geoserver.wfs.requests.LockRequest;

/**
* Handles a Lock request and creates a LockResponse string.
*
* @author Chris Holmes, TOPP
* @author Gabriel Rold?n
* @version $Id: LockResponse.java,v 1.15 2004/04/16 06:28:56 jive Exp $
*
* @task TODO: implement response streaming in writeTo instead of the current
*       response String generation
*/
public class LockResponse implements Response {
    /** Standard logging instance for class */
    private static final Logger LOGGER = Logger.getLogger(
            "org.vfny.geoserver.responses");

    /** indicates whether the output should be formatted. */
    private static boolean verbose = false;

    /** the new line character to use in the response. */
    private static String nl = "";

    /** temporal, it will disappear when the response streaming be implemented */
    private String xmlResponse = null;
    FeatureLock featureLock;
    LockRequest request;

    /**
     * Constructor
     *
     * @param gs DOCUMENT ME!
     */
    public LockResponse(GeoServer gs) {
        featureLock = null;
        request = null;
        verbose = gs.isVerbose();
        nl = verbose ? "\n" : "";
    }

    public void execute(Request req) throws WfsException {
        if (!(req instanceof LockRequest)) {
            throw new WfsException("bad request, expected LockRequest, got "
                + req);
        }
    if( (req.getWFS().getServiceLevel() & WFSDTO.SERVICE_LOCKING ) == 0 ){
       // could we catch this during the handler, rather than during execution?
       throw new WfsException("Locking support is not enabled");
    }
        request = (LockRequest) req;
        xmlResponse = getXmlResponse(request);
    }

    public String getContentType(GeoServer gs) {
        return gs.getMimeType();
    }

    public String getContentEncoding(){
        return null;
    }

    public void writeTo(OutputStream out) throws ServiceException {
        try {
            byte[] content = xmlResponse.getBytes();
            out.write(content);
        } catch (IOException ex) {
            throw new WfsException(ex, "", getClass().getName());
        }
    }

    /**
     * Parses the LockFeature reqeust and returns either the full xml lock
     * result or just the lockId.
     *
     * @param request the locks to attempt
     * @param getXml if <tt>true</tt> then the full xml response is returned,
     *        if <tt>false</tt> then only the lockId is returned.
     *
     * @return XML response or lockId, depending on getXml
     *
     * @throws WfsException for any problems doing the lock.
     * @throws IOException DOCUMENT ME!
     *
     * @task REVISIT: this will have to be reworked for the next version of the
     *       spec, when getFeatureWithLock can specify lockAction, but we'll
     *       cross that bridge when we come to it.
     * @task TODO: I really think we've got too much code duplication here with
     *       FeatureResponse.  Locking is easily the most complex operation
     *       we've got, and having each do their own thing will easily mess
     *       things up with just a little change.  The fact that the code is
     *       forked has already given me a good amount of greif, but I don't
     *       want to rework it before 1.1.0.  But there should be a single
     *       performLock that both can use, or else really move _all_ the
     *       functionality to geotools. I do understand that
     *       getFeatureWithLock does need to be sure that there are no time
     *       differences between lock acquiring and reporting, but something
     *       needs to be done.
     */
    public static String performLock(LockRequest request, boolean getXml)
        throws WfsException, IOException {
        LOGGER.finer("about to do Lock response on:" + request);

        List locks = request.getLocks();

        if (locks.size() == 0) {
            throw new WfsException("A LockFeature request must contain at "
                + "least one LOCK element");
        }

        LockRequest.Lock curLock = (LockRequest.Lock) locks.get(0);
        boolean lockAll = request.getLockAll();

        FeatureLock fLock = request.toFeatureLock();
        Set lockedFids = new HashSet();
        Set lockFailedFids = new HashSet();
        GeoServer config = request.getGeoServer();
        Data catalog = request.getWFS().getData();
        FilterFactory filterFactory = FilterFactory.createFilterFactory();
        LOGGER.info("locks size is " + locks.size());

        if (locks.size() == 0) {
            throw new WfsException("Lock Request must contain at least one "
                + " Lock element, your request is " + request);
        }

        for (int i = 0, n = locks.size(); i < n; i++) {
            curLock = (LockRequest.Lock) locks.get(i);
            LOGGER.info("curLock is " + curLock);

            String curTypeName = curLock.getFeatureType();
            Filter curFilter = curLock.getFilter();

            FeatureTypeInfo meta = catalog.getFeatureTypeInfo(curTypeName);
            NameSpaceInfo namespace = meta.getDataStoreInfo().getNameSpace();
            FeatureSource source = meta.getFeatureSource();
            FeatureResults features = source.getFeatures(curFilter);

            if( source instanceof FeatureLocking){
                ((FeatureLocking)source).setFeatureLock(fLock);
            }
            FeatureReader reader = null;

            try {
                for (reader = features.reader(); reader.hasNext();) {
                    Feature feature = reader.next();
                    String fid = feature.getID();
                    if( !(source instanceof FeatureLocking)){
                        LOGGER.fine("Lock " + fid +
                                " not supported by data store (authID:"
                                + fLock.getAuthorization() + ")");
                        lockFailedFids.add(fid);
                    }
                    else {
                        Filter fidFilter = filterFactory.createFidFilter(fid);

                        //DEFQuery is just some indirection, should be in the locking interface.
                        //int numberLocked = ((DEFQueryFeatureLocking)source).lockFeature(feature);
                        //HACK: Query.NO_NAMES isn't working in postgis right now,
                        //so we'll just use all.
                        Query query = new DefaultQuery(
                                meta.getTypeName(), fidFilter,
                                Query.DEFAULT_MAX, Query.ALL_NAMES,
                                curLock.getHandle());
                        int numberLocked = ((FeatureLocking)source).lockFeatures( query );

                        if (numberLocked == 1) {
                            LOGGER.fine("Lock " + fid + " (authID:"
                                + fLock.getAuthorization() + ")");
                            lockedFids.add(fid);
                        } else if (numberLocked == 0) {
                            LOGGER.fine("Lock " + fid + " conflict (authID:"
                                + fLock.getAuthorization() + ")");
                            lockFailedFids.add(fid);
                        } else {
                            LOGGER.warning("Lock " + numberLocked + " " + fid
                                + " (authID:" + fLock.getAuthorization()
                                + ") duplicated FeatureID!");
                            lockedFids.add(fid);
                        }
                    }
                }
            } catch (IllegalAttributeException e) {
                // TODO: JG - I really dont like this
                // reader says it will throw this if the attribtues do not match
                // the FeatureTypeInfo
                // I figure if this is thrown we are poorly configured or
                // the DataStoreInfo needs some quality control
                //
                // should rollback the lock as well :-(
                throw new WfsException("Lock request " + curFilter
                    + " did not match " + curTypeName);
            } finally {
                if (reader != null) {
                    reader.close();
                }
            }
        }

        if (lockAll && !lockFailedFids.isEmpty()) {
            // I think we need to release and fail when lockAll fails
            //
            // abort will release the locks
            throw new WfsException("Could not aquire locks for:"
                + lockFailedFids);
        }

        if (getXml) {
            return generateXml(fLock.getAuthorization(), lockAll,
                lockedFids, lockFailedFids, request);
        } else {
            return fLock.getAuthorization();
        }
    }

    /**
     * Convenience function for backwards compatability, gets the full xml
     * response.
     *
     * @param request the locks to attempt.
     *
     * @return The xml response for this request.
     *
     * @throws WfsException If anything goes wrong.
     */
    private static String getXmlResponse(LockRequest request)
        throws WfsException {
        try {
            return performLock(request, true);
        } catch (IOException ioException) {
            ioException.printStackTrace(System.out);

            WfsException wfsException = new WfsException(
                    "Problem aquiring lock");
            wfsException.initCause(ioException);
            throw wfsException;
        }
    }

    /**
     * Creates the xml for a lock response.
     *
     * @param lockId the lockId to print in the response.
     * @param lockAll indicates if information about which features were locked
     *        should be printed.
     * @param lockedFeatures a list of features locked by the request.  This is
     *        not used if lockAll is false.
     * @param notLockedFeatures a list of features that matched the filter but
     *        were not locked by the request.  This is not used if lockAll is
     *        false.
     * @param request DOCUMENT ME!
     *
     * @return The xml response of this lock.
     */
    private static String generateXml(String lockId, boolean lockAll,
        Set lockedFeatures, Set notLockedFeatures, Request request) {
        String indent = verbose ? "   " : "";
        String xmlHeader = "<?xml version=\"1.0\" encoding=\""
            + request.getWFS().getGeoServer().getCharSet().displayName() + "\"?>";
        StringBuffer returnXml = new StringBuffer(xmlHeader);
        returnXml.append(nl + "<WFS_LockFeatureResponse " + nl);
        returnXml.append(indent + "xmlns=\"http://www.opengis.net/wfs\" " + nl);

        //this not needed yet, only when FeaturesLocked element used.
        //TODO: get rid of this hardcoding, and make a common utility to get all
        //these namespace imports, as everyone is using them, and changes should
        //go through to all the operations.
        if (!lockAll) {
            returnXml.append(indent
                + "xmlns:ogc=\"http://www.opengis.net/ogc\" " + nl);
        }

        returnXml.append(indent + "xmlns:xsi=\"http://www.w3.org/2001/"
            + "XMLSchema-instance\" " + nl);
        returnXml.append(indent + "xsi:schemaLocation=\"http://www.opengis");
        returnXml.append(".net/wfs ");
        returnXml.append(request.getSchemaBaseUrl());
        returnXml.append("wfs/1.0.0/WFS-transaction.xsd\">");
        returnXml.append(nl);
        returnXml.append(indent + "<LockId>" + lockId + "</LockId>" + nl);

        if (!lockAll) {
            if ((lockedFeatures != null) && (lockedFeatures.size() > 0)) {
                returnXml.append(indent + "<FeaturesLocked>" + nl);

                for (Iterator i = lockedFeatures.iterator(); i.hasNext();) {
                    returnXml.append(indent + indent);
                    returnXml.append("<ogc:FeatureId fid=\"" + i.next()
                        + "\"/>" + nl);
                }

                returnXml.append(indent + "</FeaturesLocked>" + nl);
            }

            if ((notLockedFeatures != null) && (notLockedFeatures.size() > 0)) {
                returnXml.append("<FeaturesNotLocked>" + nl);

                for (Iterator i = notLockedFeatures.iterator(); i.hasNext();) {
                    returnXml.append(indent + indent);
                    returnXml.append("<ogc:FeatureId fid=\"" + i.next()
                        + "\"/>" + nl);
                }

                returnXml.append("</FeaturesNotLocked>" + nl);
            }
        }

        returnXml.append("</WFS_LockFeatureResponse>");

        return returnXml.toString();
    }

    /**
     * Release locks if lockAll failed.
     *
     * @see org.vfny.geoserver.Response#abort()
     */
    public void abort(Service gs) {
        if (request == null) {
            return; // request was not attempted
        }

        if (featureLock == null) {
            return; // we have no locks
        }

        Data catalog = gs.getData();

        // I think we need to release and fail when lockAll fails
        //
        try {
            GeoServer config = gs.getGeoServer();

            for (Iterator i = request.getLocks().iterator(); i.hasNext();) {
                LockRequest.Lock curLock = (LockRequest.Lock) i.next();

                String curTypeName = curLock.getFeatureType();

                FeatureTypeInfo meta = catalog.getFeatureTypeInfo(curTypeName);
                FeatureLocking source = (FeatureLocking) meta.getFeatureSource();

                Transaction t = new DefaultTransaction();

                try {
                    t.addAuthorization(featureLock.getAuthorization());
                    source.getDataStore().getLockingManager().release(featureLock
                        .getAuthorization(), t);
                } finally {
                    t.close();
                }
            }
        } catch (IOException ioException) {
            LOGGER.warning("Abort not complete:" + ioException);
        }
    }
}
TOP

Related Classes of org.vfny.geoserver.wfs.responses.LockResponse

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.