nl.b3p.viewer.stripes.EditFeatureActionBean.java Source code

Java tutorial

Introduction

Here is the source code for nl.b3p.viewer.stripes.EditFeatureActionBean.java

Source

/*
 * Copyright (C) 2012-2013 B3Partners B.V.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package nl.b3p.viewer.stripes;

import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.WKTReader;
import java.io.IOException;
import net.sourceforge.stripes.action.ActionBean;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import net.sourceforge.stripes.action.*;
import net.sourceforge.stripes.validation.Validate;
import nl.b3p.viewer.config.app.Application;
import nl.b3p.viewer.config.app.ApplicationLayer;
import nl.b3p.viewer.config.security.Authorizations;
import nl.b3p.viewer.config.services.Layer;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.geotools.data.DataUtilities;
import org.geotools.data.DefaultTransaction;
import org.geotools.data.FeatureSource;
import org.geotools.data.Transaction;
import org.geotools.data.simple.SimpleFeatureStore;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.filter.identity.FeatureIdImpl;
import org.json.JSONException;
import org.json.JSONObject;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.GeometryType;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.identity.FeatureId;

/**
 *
 * @author Matthijs Laan
 */
@UrlBinding("/action/feature/edit")
@StrictBinding
public class EditFeatureActionBean implements ActionBean {
    private static final Log log = LogFactory.getLog(EditFeatureActionBean.class);

    private static final String FID = FeatureInfoActionBean.FID;

    private ActionBeanContext context;

    @Validate
    private Application application;

    @Validate
    private String feature;

    @Validate
    private ApplicationLayer appLayer;

    private Layer layer;
    private SimpleFeatureStore store;
    private JSONObject jsonFeature;

    //<editor-fold defaultstate="collapsed" desc="getters and setters">
    public ActionBeanContext getContext() {
        return context;
    }

    public void setContext(ActionBeanContext context) {
        this.context = context;
    }

    public Application getApplication() {
        return application;
    }

    public void setApplication(Application application) {
        this.application = application;
    }

    public String getFeature() {
        return feature;
    }

    public void setFeature(String feature) {
        this.feature = feature;
    }

    public ApplicationLayer getAppLayer() {
        return appLayer;
    }

    public void setAppLayer(ApplicationLayer appLayer) {
        this.appLayer = appLayer;
    }

    //</editor-fold>
    @DefaultHandler
    public Resolution edit() throws JSONException {
        JSONObject json = new JSONObject();

        json.put("success", Boolean.FALSE);
        String error = null;

        FeatureSource fs = null;
        try {
            do {
                if (appLayer == null) {
                    error = "App layer or service not found";
                    break;
                }
                if (!Authorizations.isAppLayerWriteAuthorized(application, appLayer, context.getRequest())) {
                    error = "U heeft geen rechten om deze kaartlaag te bewerken";
                    break;
                }

                layer = appLayer.getService().getLayer(appLayer.getLayerName());

                if (layer == null) {
                    error = "Layer not found";
                    break;
                }

                if (layer.getFeatureType() == null) {
                    error = "No feature type";
                    break;
                }

                fs = layer.getFeatureType().openGeoToolsFeatureSource();

                if (!(fs instanceof SimpleFeatureStore)) {
                    error = "Feature source does not support editing";
                    break;
                }
                store = (SimpleFeatureStore) fs;

                jsonFeature = new JSONObject(feature);
                if (!this.isFeatureWriteAuthorized(appLayer, jsonFeature, context.getRequest())) {
                    error = "U heeft geen rechten om deze feature toe te voegen en/of te wijzigen";
                    break;
                }
                String fid = jsonFeature.optString(FID, null);

                if (fid == null) {
                    json.put(FID, addNewFeature());
                } else {
                    editFeature(fid);
                    json.put(FID, fid);
                }

                json.put("success", Boolean.TRUE);
            } while (false);
        } catch (Exception e) {
            log.error(String.format("Exception editing feature", e));

            error = e.toString();
            if (e.getCause() != null) {
                error += "; cause: " + e.getCause().toString();
            }
        } finally {
            if (fs != null) {
                fs.getDataStore().dispose();
            }
        }

        if (error != null) {
            json.put("error", error);
            log.error("Returned error message editing feature: " + error);
        }

        return new StreamingResolution("application/json", new StringReader(json.toString(4)));
    }

    public Resolution delete() throws JSONException {
        JSONObject json = new JSONObject();

        json.put("success", Boolean.FALSE);
        String error = null;

        FeatureSource fs = null;
        try {
            do {
                if (appLayer == null) {
                    error = "App layer or service not found";
                    break;
                }
                if (!Authorizations.isAppLayerWriteAuthorized(application, appLayer, context.getRequest())) {
                    error = "U heeft geen rechten om deze kaartlaag te bewerken";
                    break;
                }

                layer = appLayer.getService().getLayer(appLayer.getLayerName());

                if (layer == null) {
                    error = "Layer not found";
                    break;
                }

                if (layer.getFeatureType() == null) {
                    error = "No feature type";
                    break;
                }

                fs = layer.getFeatureType().openGeoToolsFeatureSource();

                if (!(fs instanceof SimpleFeatureStore)) {
                    error = "Feature source does not support editing";
                    break;
                }
                store = (SimpleFeatureStore) fs;

                jsonFeature = new JSONObject(feature);
                if (!this.isFeatureWriteAuthorized(appLayer, jsonFeature, context.getRequest())) {
                    error = "U heeft geen rechten om deze feature toe te voegen en/of te wijzigen";
                    break;
                }
                String fid = jsonFeature.optString(FID, null);

                if (fid == null) {
                    error = "Feature without FID can't be deleted";
                    break;
                } else {
                    deleteFeature(fid);
                }

                json.put("success", Boolean.TRUE);
            } while (false);
        } catch (Exception e) {
            log.error(String.format("Exception editing feature", e));

            error = e.toString();
            if (e.getCause() != null) {
                error += "; cause: " + e.getCause().toString();
            }
        } finally {
            if (fs != null) {
                fs.getDataStore().dispose();
            }
        }

        if (error != null) {
            json.put("error", error);
            log.error("Returned error message editing feature: " + error);
        }

        return new StreamingResolution("application/json", new StringReader(json.toString(4)));
    }

    private String addNewFeature() throws Exception {

        SimpleFeature f = DataUtilities.template(store.getSchema());

        Transaction transaction = new DefaultTransaction("create");
        store.setTransaction(transaction);

        for (AttributeDescriptor ad : store.getSchema().getAttributeDescriptors()) {
            if (ad.getType() instanceof GeometryType) {
                String wkt = jsonFeature.optString(ad.getLocalName(), null);
                Geometry g = null;
                if (wkt != null) {
                    g = new WKTReader().read(wkt);
                }
                f.setDefaultGeometry(g);
            } else {
                String v = jsonFeature.optString(ad.getLocalName());
                f.setAttribute(ad.getLocalName(), StringUtils.defaultIfBlank(v, null));
            }
        }

        log.debug(String.format("Creating new feature in feature source source #%d: %s",
                layer.getFeatureType().getId(), f.toString()));

        try {
            List<FeatureId> ids = store.addFeatures(DataUtilities.collection(f));

            transaction.commit();
            return ids.get(0).getID();
        } catch (Exception e) {
            transaction.rollback();
            throw e;
        } finally {
            transaction.close();
        }
    }

    private void deleteFeature(String fid) throws IOException, Exception {
        Transaction transaction = new DefaultTransaction("edit");
        store.setTransaction(transaction);

        FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
        Filter filter = ff.id(new FeatureIdImpl(fid));

        try {
            store.removeFeatures(filter);
            transaction.commit();
        } catch (Exception e) {
            transaction.rollback();
            throw e;
        } finally {
            transaction.close();
        }
    }

    private void editFeature(String fid) throws Exception {
        Transaction transaction = new DefaultTransaction("edit");
        store.setTransaction(transaction);

        FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
        Filter filter = ff.id(new FeatureIdImpl(fid));

        List<String> attributes = new ArrayList<String>();
        List values = new ArrayList();
        for (Iterator<String> it = jsonFeature.keys(); it.hasNext();) {
            String attribute = it.next();
            if (!FID.equals(attribute)) {

                AttributeDescriptor ad = store.getSchema().getDescriptor(attribute);

                if (ad != null) {
                    attributes.add(attribute);

                    if (ad.getType() instanceof GeometryType) {
                        String wkt = jsonFeature.getString(ad.getLocalName());
                        Geometry g = null;
                        if (wkt != null) {
                            g = new WKTReader().read(wkt);
                        }
                        values.add(g);
                    } else {
                        String v = jsonFeature.getString(attribute);
                        values.add(StringUtils.defaultIfBlank(v, null));
                    }
                } else {
                    log.warn(String.format("Attribute \"%s\" not in feature type; ignoring", attribute));
                }
            }
        }

        log.debug(String.format("Modifying feature source #%d fid=%s, attributes=%s, values=%s",
                layer.getFeatureType().getId(), fid, attributes.toString(), values.toString()));

        try {
            store.modifyFeatures(attributes.toArray(new String[] {}), values.toArray(), filter);

            transaction.commit();
        } catch (Exception e) {
            transaction.rollback();
            throw e;
        } finally {
            transaction.close();
        }
    }

    private boolean isFeatureWriteAuthorized(ApplicationLayer appLayer, JSONObject jsonFeature,
            HttpServletRequest request) {
        if (appLayer.getDetails() != null && appLayer.getDetails().containsKey("editfeature.usernameAttribute")) {
            String attr = appLayer.getDetails().get("editfeature.usernameAttribute").getValue();

            String featureUsername = jsonFeature.optString(attr);
            if (featureUsername != null && featureUsername.equals(request.getRemoteUser())) {
                return true;
            } else {
                return false;
            }
        }
        return true;
    }
}