Skip to content

Commit

Permalink
[GEOS-7347] Allow to enter an allowed area in Geofence UI
Browse files Browse the repository at this point in the history
  • Loading branch information
Nuno Oliveira committed Dec 17, 2015
1 parent 95c9112 commit 47881c3
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 28 deletions.
Expand Up @@ -41,6 +41,10 @@
<label for="access"><wicket:message key="access"></wicket:message></label> <label for="access"><wicket:message key="access"></wicket:message></label>
<select wicket:id="access" id="access" /> <select wicket:id="access" id="access" />
</li> </li>
<li>
<label wicket:id="allowedAreaLabel"></label>
<textarea wicket:id="allowedArea" id="allowedArea" style="width: 50%; height:100px;"></textarea>
</li>
</ul> </ul>
</fieldset> </fieldset>
</li> </li>
Expand Down
Expand Up @@ -5,6 +5,7 @@
package org.geoserver.geofence.web; package org.geoserver.geofence.web;


import java.io.IOException; import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
Expand All @@ -13,24 +14,28 @@
import java.util.TreeSet; import java.util.TreeSet;
import java.util.logging.Level; import java.util.logging.Level;


import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.io.WKTReader;
import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.OnChangeAjaxBehavior; import org.apache.wicket.ajax.form.OnChangeAjaxBehavior;
import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.*;
import org.apache.wicket.markup.html.form.IChoiceRenderer;
import org.apache.wicket.markup.html.form.SubmitLink;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.link.BookmarkablePageLink; import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import org.apache.wicket.model.CompoundPropertyModel; import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.ResourceModel; import org.apache.wicket.model.ResourceModel;
import org.geoserver.catalog.Predicates; import org.geoserver.catalog.Predicates;
import org.geoserver.catalog.ResourceInfo; import org.geoserver.catalog.ResourceInfo;
import org.geoserver.catalog.WorkspaceInfo; import org.geoserver.catalog.WorkspaceInfo;
import org.geoserver.catalog.util.CloseableIterator; import org.geoserver.catalog.util.CloseableIterator;
import org.geoserver.geofence.core.model.RuleLimits;
import org.geoserver.geofence.core.model.enums.GrantType; import org.geoserver.geofence.core.model.enums.GrantType;
import org.geoserver.geofence.services.dto.ShortRule; import org.geoserver.geofence.services.dto.ShortRule;
import org.geoserver.platform.GeoServerExtensions; import org.geoserver.platform.GeoServerExtensions;
import org.geoserver.platform.Service; import org.geoserver.platform.Service;
import org.geoserver.platform.exception.GeoServerRuntimException;
import org.geoserver.security.GeoServerRoleService; import org.geoserver.security.GeoServerRoleService;
import org.geoserver.security.GeoServerSecurityManager; import org.geoserver.security.GeoServerSecurityManager;
import org.geoserver.security.impl.GeoServerRole; import org.geoserver.security.impl.GeoServerRole;
Expand All @@ -52,86 +57,141 @@
* *
*/ */
public class GeofenceRulePage extends GeoServerSecuredPage { public class GeofenceRulePage extends GeoServerSecuredPage {

private class RuleFormData implements Serializable {

ShortRule rule;
RuleLimits ruleLimits;
String allowedArea;
}


protected DropDownChoice<String> userChoice, roleChoice, serviceChoice, requestChoice, workspaceChoice, layerChoice, accessChoice; protected DropDownChoice<String> userChoice, roleChoice, serviceChoice, requestChoice, workspaceChoice, layerChoice, accessChoice;
protected DropDownChoice<GrantType> grantTypeChoice; protected DropDownChoice<GrantType> grantTypeChoice;


protected TextArea<String> allowedArea;
protected Label allowedAreaLabel;

public GeofenceRulePage(final ShortRule rule, final GeofenceRulesModel rules) { public GeofenceRulePage(final ShortRule rule, final GeofenceRulesModel rules) {

RuleFormData ruleFormData = new RuleFormData();
ruleFormData.rule = rule;
final RuleLimits ruleLimits = rules.getRulesLimits(rule.getId());
if (ruleLimits == null) {
ruleFormData.ruleLimits = new RuleLimits();
} else {
ruleFormData.ruleLimits = ruleLimits;
ruleFormData.allowedArea = getAllowedAreaAsString(ruleLimits);
}

CompoundPropertyModel ruleFormModel = new CompoundPropertyModel<RuleFormData>(ruleFormData);

// build the form // build the form
final Form<ShortRule> form = new Form<ShortRule>("form", new CompoundPropertyModel<ShortRule>(rule)); final Form<RuleFormData> form = new Form<>("form", ruleFormModel);
add(form); add(form);

form.add(new TextField<Integer>("priority").setRequired(true)); form.add(new TextField<>("priority", ruleFormModel.bind("rule.priority")).setRequired(true));

form.add(roleChoice = new DropDownChoice<>("roleName", ruleFormModel.bind("rule.roleName"), getRoleNames()));
form.add(roleChoice = new DropDownChoice<String>("roleName", getRoleNames()));
roleChoice.add(new OnChangeAjaxBehavior() { roleChoice.add(new OnChangeAjaxBehavior() {
private static final long serialVersionUID = -2880886409750911044L; private static final long serialVersionUID = -2880886409750911044L;


@Override @Override
protected void onUpdate(AjaxRequestTarget target) { protected void onUpdate(AjaxRequestTarget target) {
userChoice.setChoices(getUserNames(roleChoice.getConvertedInput())); userChoice.setChoices(getUserNames(roleChoice.getConvertedInput()));
((ShortRule) form.getModelObject()).setUserName(null); form.getModelObject().rule.setUserName(null);
userChoice.modelChanged(); userChoice.modelChanged();
target.addComponent(userChoice); target.addComponent(userChoice);
} }
}); });
roleChoice.setNullValid(true); roleChoice.setNullValid(true);


form.add(userChoice = new DropDownChoice<String>("userName", getUserNames(rule.getRoleName()))); form.add(userChoice = new DropDownChoice<>("userName", ruleFormModel.bind("rule.userName"), getUserNames(rule.getRoleName())));
userChoice.setOutputMarkupId(true); userChoice.setOutputMarkupId(true);
userChoice.setNullValid(true); userChoice.setNullValid(true);

form.add(serviceChoice = new DropDownChoice<String>("service", getServiceNames())); form.add(serviceChoice = new DropDownChoice<>("service", ruleFormModel.bind("rule.service"), getServiceNames()));
serviceChoice.add(new OnChangeAjaxBehavior() { serviceChoice.add(new OnChangeAjaxBehavior() {
private static final long serialVersionUID = -5925784823433092831L; private static final long serialVersionUID = -5925784823433092831L;


@Override @Override
protected void onUpdate(AjaxRequestTarget target) { protected void onUpdate(AjaxRequestTarget target) {
requestChoice.setChoices(getOperationNames(serviceChoice.getConvertedInput())); requestChoice.setChoices(getOperationNames(serviceChoice.getConvertedInput()));
((ShortRule) form.getModelObject()).setRequest(null); form.getModelObject().rule.setRequest(null);
requestChoice.modelChanged(); requestChoice.modelChanged();
target.addComponent(requestChoice); target.addComponent(requestChoice);
} }
}); });
serviceChoice.setNullValid(true); serviceChoice.setNullValid(true);

form.add(requestChoice = new DropDownChoice<String>("request", getOperationNames(rule.getService()), form.add(requestChoice = new DropDownChoice<>("request", ruleFormModel.bind("rule.request"),
new CaseConversionRenderer())); getOperationNames(rule.getService()), new CaseConversionRenderer()));
requestChoice.setOutputMarkupId(true); requestChoice.setOutputMarkupId(true);
requestChoice.setNullValid(true); requestChoice.setNullValid(true);


form.add(workspaceChoice = new DropDownChoice<String>("workspace", getWorkspaceNames())); form.add(workspaceChoice = new DropDownChoice<>("workspace", ruleFormModel.bind("rule.workspace"),
getWorkspaceNames()));
workspaceChoice.add(new OnChangeAjaxBehavior() { workspaceChoice.add(new OnChangeAjaxBehavior() {
private static final long serialVersionUID = 732177308220189475L; private static final long serialVersionUID = 732177308220189475L;


@Override @Override
protected void onUpdate(AjaxRequestTarget target) { protected void onUpdate(AjaxRequestTarget target) {
layerChoice.setChoices(getLayerNames(workspaceChoice.getConvertedInput())); layerChoice.setChoices(getLayerNames(workspaceChoice.getConvertedInput()));
((ShortRule) form.getModelObject()).setLayer(null); form.getModelObject().rule.setLayer(null);
layerChoice.modelChanged(); layerChoice.modelChanged();
target.addComponent(layerChoice); target.addComponent(layerChoice);
} }
}); });
workspaceChoice.setNullValid(true); workspaceChoice.setNullValid(true);


form.add(layerChoice = new DropDownChoice<String>("layer", getLayerNames(rule.getWorkspace()))); form.add(layerChoice = new DropDownChoice<>("layer", ruleFormModel.bind("rule.layer"), getLayerNames(rule.getWorkspace())));
layerChoice.setOutputMarkupId(true); layerChoice.setOutputMarkupId(true);
layerChoice.setNullValid(true); layerChoice.setNullValid(true);


form.add(grantTypeChoice = form.add(grantTypeChoice = new DropDownChoice<>("access", ruleFormModel.bind("rule.access"),
new DropDownChoice<GrantType>("access", Arrays.asList(GrantType.values()), new GrantTypeRenderer())); Arrays.asList(GrantType.values()), new GrantTypeRenderer()));
grantTypeChoice.setRequired(true); grantTypeChoice.setRequired(true);


grantTypeChoice.add(new OnChangeAjaxBehavior() {

@Override
protected void onUpdate(AjaxRequestTarget target) {
if (grantTypeChoice.getConvertedInput().equals(GrantType.LIMIT)) {
allowedAreaLabel.setVisible(true);
allowedArea.setVisible(true);
} else {
allowedAreaLabel.setVisible(false);
allowedArea.setVisible(false);
}
target.addComponent(allowedAreaLabel);
target.addComponent(allowedArea);
}
});

form.add(allowedAreaLabel = new Label("allowedAreaLabel", new ResourceModel("allowedArea", "Allow area")));
allowedAreaLabel.setVisible(form.getModelObject().rule.getAccess() != null
&& form.getModelObject().rule.getAccess().equals(GrantType.LIMIT));
allowedAreaLabel.setOutputMarkupId(true);
allowedAreaLabel.setOutputMarkupPlaceholderTag(true);

form.add(allowedArea = new TextArea<>("allowedArea", ruleFormModel.bind("allowedArea")));
allowedArea.setConvertedInput(form.getModelObject().allowedArea);
allowedArea.setVisible(form.getModelObject().rule.getAccess() != null
&& form.getModelObject().rule.getAccess().equals(GrantType.LIMIT));
allowedArea.setOutputMarkupId(true);
allowedArea.setOutputMarkupPlaceholderTag(true);


// build the submit/cancel // build the submit/cancel
form.add(new SubmitLink("save") { form.add(new SubmitLink("save") {
private static final long serialVersionUID = 3735176778941168701L; private static final long serialVersionUID = 3735176778941168701L;


@Override @Override
public void onSubmit() { public void onSubmit() {
ShortRule rule = (ShortRule) getForm().getModelObject(); RuleFormData ruleFormData = (RuleFormData) getForm().getModelObject();
try { try {
rules.save(rule); rules.save(ruleFormData.rule);
if (ruleFormData.rule.getAccess().equals(GrantType.LIMIT)) {
rules.save(ruleFormData.rule.getId(), parseAllowedArea(ruleFormData.allowedArea));
}
doReturn(GeofenceServerPage.class); doReturn(GeofenceServerPage.class);
} catch (DuplicateKeyException e) { } catch (DuplicateKeyException e) {
error(new ResourceModel("GeofenceRulePage.duplicate").getObject()); error(new ResourceModel("GeofenceRulePage.duplicate").getObject());
Expand All @@ -143,6 +203,50 @@ public void onSubmit() {
form.add(new BookmarkablePageLink<ShortRule>("cancel", GeofenceServerPage.class)); form.add(new BookmarkablePageLink<ShortRule>("cancel", GeofenceServerPage.class));
} }


private String getAllowedAreaAsString(RuleLimits ruleLimits) {
if (ruleLimits == null || ruleLimits.getAllowedArea() == null) {
return "";
}
MultiPolygon multiPolygon = ruleLimits.getAllowedArea();
return "SRID=" + multiPolygon.getSRID() + ";" + multiPolygon.toText();
}

private MultiPolygon parseAllowedArea(String allowedArea) {
if (allowedArea == null || allowedArea.isEmpty()) {
return null;
}
String[] allowedAreaParts = allowedArea.split(";");
if (allowedAreaParts.length != 2) {
throw new GeoServerRuntimException(String.format(
"Invalid allowed area '%s' expecting SRID=<CODE>;<WKT>.", allowedArea));
}
Integer srid;
Geometry geometry;
try {
srid = Integer.valueOf(allowedAreaParts[0].split("=")[1]);
geometry = new WKTReader().read(allowedAreaParts[1]);
} catch (Exception exception) {
String message = String.format(
"Error parsing SRID '%s' or WKT geometry '%s' expecting SRID=<CODE>;<WKT>.",
allowedAreaParts[0], allowedAreaParts[1]);
LOGGER.log(Level.WARNING, message, exception);
throw new GeoServerRuntimException(message, exception);
}
MultiPolygon multiPolygon = castToMultiPolygon(geometry);
multiPolygon.setSRID(srid);
return multiPolygon;
}

private MultiPolygon castToMultiPolygon(Geometry geometry) {
if (geometry instanceof MultiPolygon) {
return (MultiPolygon) geometry;
}
if (geometry instanceof Polygon) {
return new MultiPolygon(new Polygon[]{(Polygon) geometry}, new GeometryFactory());
}
throw new GeoServerRuntimException(String.format(
"Invalid geometry of type '%s' expect a Polygon or MultiPolygon.", geometry.getClass().getSimpleName()));
}


/** /**
* Returns a sorted list of workspace names * Returns a sorted list of workspace names
Expand Down
Expand Up @@ -10,10 +10,12 @@
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;


import com.vividsolutions.jts.geom.MultiPolygon;
import org.apache.wicket.extensions.markup.html.repeater.util.SortParam; import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
import org.apache.wicket.model.IModel; import org.apache.wicket.model.IModel;
import org.apache.wicket.model.PropertyModel; import org.apache.wicket.model.PropertyModel;
import org.geoserver.geofence.core.model.Rule; import org.geoserver.geofence.core.model.Rule;
import org.geoserver.geofence.core.model.RuleLimits;
import org.geoserver.geofence.core.model.enums.GrantType; import org.geoserver.geofence.core.model.enums.GrantType;
import org.geoserver.geofence.services.RuleAdminService; import org.geoserver.geofence.services.RuleAdminService;
import org.geoserver.geofence.services.dto.ShortRule; import org.geoserver.geofence.services.dto.ShortRule;
Expand Down Expand Up @@ -204,7 +206,28 @@ public ShortRule newRule() {
rule.setPriority(0); rule.setPriority(0);
return rule; return rule;
} }


public void save(Long ruleId, MultiPolygon allowedArea) {
Rule rule = adminService().get(ruleId);
RuleLimits ruleLimits = rule.getRuleLimits();
if (ruleLimits == null) {
ruleLimits = new RuleLimits();
ruleLimits.setRule(rule);
}
ruleLimits.setAllowedArea(allowedArea);
adminService().setLimits(ruleId, ruleLimits);
}

public RuleLimits getRulesLimits(Long ruleId) {
if(ruleId != null) {
Rule rule = adminService().get(ruleId);
if(rule != null) {
return rule.getRuleLimits();
}
}
return null;
}

protected static void syncRule(ShortRule shortRule, Rule rule) { protected static void syncRule(ShortRule shortRule, Rule rule) {
rule.setPriority(shortRule.getPriority()); rule.setPriority(shortRule.getPriority());
rule.setUsername(shortRule.getUserName()); rule.setUsername(shortRule.getUserName());
Expand Down
Expand Up @@ -41,4 +41,5 @@ GeofenceRulePage.access.nullValid=*
GeofenceRulePage.ALLOW=ALLOW GeofenceRulePage.ALLOW=ALLOW
GeofenceRulePage.DENY=DENY GeofenceRulePage.DENY=DENY
GeofenceRulePage.LIMIT=LIMIT GeofenceRulePage.LIMIT=LIMIT
GeofenceRulePage.duplicate=An identical rule is already present. Duplicates are not allowed. GeofenceRulePage.duplicate=An identical rule is already present. Duplicates are not allowed.
GeofenceRulePage.allowedArea=Allowed area (WKT)

0 comments on commit 47881c3

Please sign in to comment.