Package org.geotools.data.wfs

Source Code of org.geotools.data.wfs.WFSRemoteTransactionState

/*
*    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;

import static org.geotools.data.wfs.internal.Loggers.info;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.namespace.QName;

import org.geotools.data.Transaction;
import org.geotools.data.Transaction.State;
import org.geotools.data.TransactionStateDiff;
import org.geotools.data.wfs.WFSDiff.BatchUpdate;
import org.geotools.data.wfs.internal.TransactionRequest;
import org.geotools.data.wfs.internal.TransactionRequest.Delete;
import org.geotools.data.wfs.internal.TransactionRequest.Insert;
import org.geotools.data.wfs.internal.TransactionRequest.Update;
import org.geotools.data.wfs.internal.TransactionResponse;
import org.geotools.data.wfs.internal.WFSClient;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.Name;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory;
import org.opengis.filter.identity.FeatureId;
import org.opengis.filter.identity.Identifier;

class WFSRemoteTransactionState implements State {

    private final WFSDataStore dataStore;

    private Transaction transaction;

    private Map<Name, WFSContentState> localStates;

    public WFSRemoteTransactionState(WFSDataStore dataStore) {
        this.dataStore = dataStore;
        this.localStates = new HashMap<Name, WFSContentState>();
    }

    public synchronized WFSDiff getDiff(final Name typeName) {
        WFSContentState localState = localStates.get(typeName);
        if (null == localState) {
            throw new IllegalStateException("Not watching " + typeName);
        }
        WFSDiff diff = localState.getLocalTransactionState().getDiff();
        return diff;
    }

    @Override
    public void setTransaction(Transaction transaction) {
        this.transaction = transaction;
    }

    @Override
    public void rollback() throws IOException {
        clear(); // rollback differences
    }

    @Override
    public void addAuthorization(String AuthID) throws IOException {
        // not needed?
    }

    @Override
    public synchronized void commit() throws IOException {
        try {
            commitInternal();
        } finally {
            // If the commit fails or succeeds, state is reset
            clear();
        }
    }

    /**
     * This state takes ownership of each type's diff, so lets clear them all
     */
    private void clear() {
        for (WFSContentState localState : localStates.values()) {
            WFSLocalTransactionState localTransactionState = localState.getLocalTransactionState();
            WFSDiff diff = localTransactionState.getDiff();
            diff.clear();
        }
    }

    private void commitInternal() throws IOException {
        if (this.localStates.isEmpty()) {
            return;
        }
        WFSClient wfs = dataStore.getWfsClient();
        TransactionRequest transactionRequest = wfs.createTransaction();

        List<MutableFeatureId> requestedInsertFids = new ArrayList<MutableFeatureId>();

        for (Name typeName : localStates.keySet()) {
            List<MutableFeatureId> addedFids = applyDiff(typeName, transactionRequest);
            requestedInsertFids.addAll(addedFids);
        }

        TransactionResponse transactionResponse = wfs.issueTransaction(transactionRequest);
        List<FeatureId> insertedFids = transactionResponse.getInsertedFids();
        int deleteCount = transactionResponse.getDeleteCount();
        int updatedCount = transactionResponse.getUpdatedCount();
        info(getClass().getSimpleName(), "::commit(): Updated: ", updatedCount, ", Deleted: ",
                deleteCount, ", Inserted: ", insertedFids);

        if (requestedInsertFids.size() != insertedFids.size()) {
            throw new IllegalStateException("Asked to add " + requestedInsertFids.size()
                    + " Features but got " + insertedFids.size() + " insert results");
        }

        for (int i = 0; i < requestedInsertFids.size(); i++) {
            MutableFeatureId local = requestedInsertFids.get(i);
            FeatureId inserted = insertedFids.get(i);
            local.setID(inserted.getID());
            local.setFeatureVersion(inserted.getFeatureVersion());
        }
    }

    private List<MutableFeatureId> applyDiff(final Name localTypeName,
            TransactionRequest transactionRequest) throws IOException {

        final WFSContentState localState = localStates.get(localTypeName);
        final WFSLocalTransactionState localTransactionState = localState
                .getLocalTransactionState();
        final WFSDiff diff = localTransactionState.getDiff();

        List<MutableFeatureId> addedFeatureIds = new LinkedList<MutableFeatureId>();

        final QName remoteTypeName = dataStore.getRemoteTypeName(localTypeName);

        applyBatchUpdates(remoteTypeName, diff, transactionRequest);

        final Set<String> ignored = diff.getBatchModified();

        final SimpleFeatureType remoteType = dataStore.getRemoteSimpleFeatureType(remoteTypeName);

        // Create a single insert element with all the inserts for this type
        final Map<String, SimpleFeature> added = diff.getAdded();
        if (added.size() > 0) {
            Insert insert = transactionRequest.createInsert(remoteTypeName);

            SimpleFeatureBuilder builder = new SimpleFeatureBuilder(remoteType);
            for (String fid : diff.getAddedOrder()) {
                if (ignored.contains(fid)) {
                    continue;
                }
                SimpleFeature localFeature = added.get(fid);
                MutableFeatureId addedFid = (MutableFeatureId) localFeature.getIdentifier();
                addedFeatureIds.add(addedFid);

                SimpleFeature remoteFeature = SimpleFeatureBuilder.retype(localFeature, builder);

                insert.add(remoteFeature);
            }
            transactionRequest.add(insert);
        }

        final Map<String, SimpleFeature> modified = diff.getModified();

        // Create a single delete element with all the deletes for this type
        Set<Identifier> ids = new LinkedHashSet<Identifier>();
        for (Map.Entry<String, SimpleFeature> entry : modified.entrySet()) {
            if (!(TransactionStateDiff.NULL == entry.getValue())) {
                continue;// not a delete
            }
            String rid = entry.getKey();
            if (ignored.contains(rid)) {
                continue;
            }
            Identifier featureId = featureId(rid);
            ids.add(featureId);
        }
        if (!ids.isEmpty()) {
            Filter deleteFilter = dataStore.getFilterFactory().id(ids);
            Delete delete = transactionRequest.createDelete(remoteTypeName, deleteFilter);
            transactionRequest.add(delete);
        }

        // Create one update element per modified feature. Batch modified ones should have been
        // added as a single update element at applyBatchUpdate before
        for (Map.Entry<String, SimpleFeature> entry : modified.entrySet()) {
            String fid = entry.getKey();
            SimpleFeature feature = entry.getValue();

            if (TransactionStateDiff.NULL == feature) {
                continue;// not an update
            }
            if (ignored.contains(fid)) {
                continue;
            }
            applySingleUpdate(remoteTypeName, feature, transactionRequest);
        }

        return addedFeatureIds;
    }

    private void applySingleUpdate(QName remoteTypeName, SimpleFeature feature,
            TransactionRequest transactionRequest) throws IOException {

        // so bad, this is going to update a lot of unnecessary properties. We'd need to make
        // DiffContentFeatureWriter's live and current attributes protected and extend write so that
        // it records the truly modified attributes instead

        Collection<Property> properties = feature.getProperties();

        List<QName> propertyNames = new ArrayList<QName>();
        List<Object> newValues = new ArrayList<Object>();

        for (Property p : properties) {
            QName attName = new QName(remoteTypeName.getNamespaceURI(), p.getName().getLocalPart());
            Object attValue = p.getValue();
            propertyNames.add(attName);
            newValues.add(attValue);
        }

        Filter updateFilter = dataStore.getFilterFactory().id(
                Collections.singleton(feature.getIdentifier()));

        Update update = transactionRequest.createUpdate(remoteTypeName, propertyNames, newValues,
                updateFilter);
        transactionRequest.add(update);
    }

    private void applyBatchUpdates(QName remoteTypeName, WFSDiff diff,
            TransactionRequest transactionRequest) {

        List<BatchUpdate> batchUpdates = diff.getBatchUpdates();

        for (BatchUpdate batch : batchUpdates) {

            List<QName> propertyNames = new ArrayList<QName>(batch.properties.length);
            for (Name attName : batch.properties) {
                propertyNames.add(new QName(remoteTypeName.getNamespaceURI(), attName
                        .getLocalPart()));
            }
            List<Object> newValues = Arrays.asList(batch.values);
            Filter updateFilter = batch.filter;

            Update update = transactionRequest.createUpdate(remoteTypeName, propertyNames,
                    newValues, updateFilter);

            transactionRequest.add(update);
        }

    }

    private Identifier featureId(final String rid) {
        final FilterFactory ff = dataStore.getFilterFactory();
        String fid = rid;
        String featureVersion = null;
        int versionSeparatorIdx = rid.indexOf(FeatureId.VERSION_SEPARATOR);
        if (-1 != versionSeparatorIdx) {
            fid = rid.substring(0, versionSeparatorIdx);
            featureVersion = rid.substring(versionSeparatorIdx + 1);
        }
        FeatureId featureId = ff.featureId(fid, featureVersion);
        return featureId;
    }

    public void watch(WFSContentState localState) {
        Name typeName = localState.getEntry().getName();
        localStates.put(typeName, localState);
    }
}
TOP

Related Classes of org.geotools.data.wfs.WFSRemoteTransactionState

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.