/* (c) 2015 - 2016 Open Source Geospatial Foundation - all rights reserved
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.geofence.web;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import com.vividsolutions.jts.geom.MultiPolygon;
import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.PropertyModel;
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.services.RuleAdminService;
import org.geoserver.geofence.services.dto.ShortRule;
import org.geoserver.web.GeoServerApplication;
import org.geoserver.web.wicket.GeoServerDataProvider;
/**
*
* Functions as between webgui and internal geofence db
*
* @author Niels Charlier
*
*/
public class GeofenceRulesModel extends GeoServerDataProvider<ShortRule> {
private static final long serialVersionUID = 478867886089304835L;
/**
* Makes columns that are unsortable and display "*" instead of empty when null
*
*/
public static class RuleBeanProperty<T> extends BeanProperty<T> {
private static final long serialVersionUID = 483799722644223445L;
public RuleBeanProperty(String key, String propertyPath) {
super(key, propertyPath);
}
@Override
public Comparator<T> getComparator() { //unsortable
return null;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public IModel getModel(IModel<T> itemModel) { //replace null by *
return new PropertyModel<Object>(itemModel, getPropertyPath()) {
private static final long serialVersionUID = 1L;
@Override
public Object getObject() {
Object o = super.getObject();
return o == null ? "*" : o;
}
};
}
}
public static final Property<ShortRule> PRIORITY = new BeanProperty<ShortRule>("priority", "priority");
public static final Property<ShortRule> ROLE = new RuleBeanProperty<ShortRule>("roleName", "roleName");
public static final Property<ShortRule> USER = new RuleBeanProperty<ShortRule>("userName", "userName");
public static final Property<ShortRule> SERVICE = new RuleBeanProperty<ShortRule>("service", "service");
public static final Property<ShortRule> REQUEST = new RuleBeanProperty<ShortRule>("request", "request");
public static final Property<ShortRule> WORKSPACE = new RuleBeanProperty<ShortRule>("workspace", "workspace");
public static final Property<ShortRule> LAYER = new RuleBeanProperty<ShortRule>("layer", "layer");
public static final Property<ShortRule> ACCESS = new RuleBeanProperty<ShortRule>("access", "access");
public static final Property<ShortRule> BUTTONS = new PropertyPlaceholder<ShortRule>( "buttons" );
private static RuleAdminService adminService() {
return (RuleAdminService) GeoServerApplication.get().getBean("ruleAdminService");
}
/**
* We will keep local copy, always sorted on priority
* to support the up and down arrows easily
*/
protected List<ShortRule> rules;
public GeofenceRulesModel() {
rules = adminService().getAll();
setSort("priority", SortOrder.ASCENDING);
}
@Override
protected Comparator<ShortRule> getComparator(SortParam<?> sort) {
return null; //disable on-the-fly sorting
}
@Override
public void setSort(Object property, SortOrder order) {
super.setSort(property, order);
Collections.sort(rules, super.getComparator(new SortParam<>(property, order == SortOrder.ASCENDING)));
}
@Override
public void setSort(SortParam<Object> param) {
super.setSort(param);
//enable in-memory sorting
Collections.sort(rules, super.getComparator(param));
}
@Override
protected List<org.geoserver.web.wicket.GeoServerDataProvider.Property<ShortRule>> getProperties() {
return Arrays.asList(PRIORITY, ROLE, USER, SERVICE, REQUEST, WORKSPACE, LAYER, ACCESS, BUTTONS);
}
@Override
protected List<ShortRule> getItems() {
return rules;
}
public void save(ShortRule rule) {
if (rule.getId() == null) {
shiftIfNecessary(rule.getPriority(), rule);
//local
int i = 0;
while (i < rules.size() && rules.get(i).getPriority() < rule.getPriority()) {
i++;
}
rules.add(i, rule);
//db
Rule bigRule = new Rule();
syncRule(rule, bigRule);
rule.setId(adminService().insert(bigRule));
} else {
//db
Rule bigRule = adminService().get(rule.getId());
if (bigRule.getPriority() != rule.getPriority()) {
shiftIfNecessary(rule.getPriority(), rule);
}
syncRule(rule, bigRule);
adminService().update(bigRule);
}
}
public void remove(Collection<ShortRule> selected) {
//local
rules.removeAll(selected);
//db
for (ShortRule rule : selected) {
adminService().delete(rule.getId());
}
}
public boolean canUp(ShortRule rule) {
return rules.indexOf(rule) > 0;
}
public void moveUp(ShortRule rule) {
int index = rules.indexOf(rule);
if (index > 0) {
swap(rule, rules.get(index - 1));
//local sort
rules.remove(index);
rules.add(index - 1, rule);
}
}
public boolean canDown(ShortRule rule) {
return rules.indexOf(rule) < rules.size() - 1;
}
public void moveDown(ShortRule rule) {
int index = rules.indexOf(rule);
if (index < rules.size() - 1) {
swap(rule, rules.get(index + 1));
//local sort
rules.remove(index);
rules.add(index + 1, rule);
}
}
protected void swap(ShortRule rule, ShortRule otherRule) {
//local
long p = otherRule.getPriority();
otherRule.setPriority(rule.getPriority());
rule.setPriority(p);
//db
adminService().swap(rule.getId(), otherRule.getId());
}
protected void shiftIfNecessary(long priority, ShortRule keep){
//detect if necessary
boolean necessary = false;
for (ShortRule rule : rules) {
if (rule.getPriority() == priority) {
necessary = true;
continue;
}
}
if (necessary) {
//local
for (ShortRule rule : rules) {
if (rule.getPriority() >= priority && rule != keep) {
rule.setPriority(rule.getPriority() + 1);
}
}
//db
adminService().shift(priority, 1);
}
}
public ShortRule newRule() {
ShortRule rule = new ShortRule();
rule.setAccess(GrantType.ALLOW);
rule.setPriority(0);
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) {
rule.setPriority(shortRule.getPriority());
rule.setUsername(shortRule.getUserName());
rule.setRolename(shortRule.getRoleName());
rule.setService(shortRule.getService());
rule.setRequest(shortRule.getRequest());
rule.setWorkspace(shortRule.getWorkspace());
rule.setLayer(shortRule.getLayer());
rule.setAccess(shortRule.getAccess());
}
}