diff --git a/src/main/java/org/casbin/adapter/JDBCBaseAdapter.java b/src/main/java/org/casbin/adapter/JDBCBaseAdapter.java index c8e25ad..f5769bb 100644 --- a/src/main/java/org/casbin/adapter/JDBCBaseAdapter.java +++ b/src/main/java/org/casbin/adapter/JDBCBaseAdapter.java @@ -24,6 +24,7 @@ import org.casbin.jcasbin.persist.Adapter; import org.casbin.jcasbin.persist.BatchAdapter; import org.casbin.jcasbin.persist.Helper; +import org.casbin.jcasbin.persist.UpdatableAdapter; import javax.sql.DataSource; import java.sql.*; @@ -49,7 +50,7 @@ public String[] toStringArray() { * JDBCAdapter is the JDBC adapter for jCasbin. * It can load policy from JDBC supported database or save policy to it. */ -abstract class JDBCBaseAdapter implements Adapter, BatchAdapter { +abstract class JDBCBaseAdapter implements Adapter, BatchAdapter, UpdatableAdapter { protected static final String DEFAULT_TABLE_NAME = "casbin_rule"; protected static final boolean DEFAULT_REMOVE_POLICY_FAILED = false; protected static final boolean DEFAULT_AUTO_CREATE_TABLE = true; @@ -480,6 +481,47 @@ public void removeFilteredPolicy(String sec, String ptype, int fieldIndex, Strin }); } + /** + * updatePolicy updates a policy rule from the current policy. + */ + @Override + public void updatePolicy(String sec, String ptype, List oldRule, List newRule) { + if (CollectionUtils.isEmpty(oldRule) || CollectionUtils.isEmpty(newRule)) { + return; + } + + String sql = renderActualSql("INSERT INTO casbin_rule (ptype,v0,v1,v2,v3,v4,v5) VALUES(?,?,?,?,?,?,?)"); + + + Failsafe.with(retryPolicy).run(ctx -> { + if (ctx.isRetry()) { + retry(ctx); + } + conn.setAutoCommit(false); + removePolicy(sec, ptype, oldRule); + try (PreparedStatement ps = conn.prepareStatement(sql)) { + CasbinRule line = this.savePolicyLine(ptype, newRule); + + ps.setString(1, line.ptype); + ps.setString(2, line.v0); + ps.setString(3, line.v1); + ps.setString(4, line.v2); + ps.setString(5, line.v3); + ps.setString(6, line.v4); + ps.setString(7, line.v5); + ps.executeUpdate(); + conn.commit(); + } catch (SQLException e) { + conn.rollback(); + + e.printStackTrace(); + throw e; + } finally { + conn.setAutoCommit(true); + } + }); + } + /** * Close the Connection. */ diff --git a/src/test/java/org/casbin/adapter/JDBCAdapterTest.java b/src/test/java/org/casbin/adapter/JDBCAdapterTest.java index 011553c..7e1d02d 100644 --- a/src/test/java/org/casbin/adapter/JDBCAdapterTest.java +++ b/src/test/java/org/casbin/adapter/JDBCAdapterTest.java @@ -257,4 +257,37 @@ public void testRemovePolicy() throws Exception { asList("data2_admin", "data2", "read"), asList("data2_admin", "data2", "write"))); } + + @Test + public void testUpdatePolicy() throws Exception { + JDBCAdapter adapter = new MySQLAdapterCreator().create(); + + // Because the DB is empty at first, + // so we need to load the policy from the file adapter (.CSV) first. + Enforcer e = new Enforcer("examples/rbac_model.conf", "examples/rbac_policy.csv"); + + // This is a trick to save the current policy to the DB. + // We can't call e.savePolicy() because the adapter in the enforcer is still the file adapter. + // The current policy means the policy in the jCasbin enforcer (aka in memory). + adapter.savePolicy(e.getModel()); + + e.clearPolicy(); + testGetPolicy(e, asList()); + + e = new Enforcer("examples/rbac_model.conf", adapter); + testGetPolicy(e, asList( + asList("alice", "data1", "read"), + asList("bob", "data2", "write"), + asList("data2_admin", "data2", "read"), + asList("data2_admin", "data2", "write"))); + + adapter.updatePolicy("p", "p", asList("bob", "data2", "write"), asList("alice", "data2", "read")); + e = new Enforcer("examples/rbac_model.conf", adapter); + testGetPolicy(e, asList( + asList("alice", "data1", "read"), + asList("data2_admin", "data2", "read"), + asList("data2_admin", "data2", "write"), + asList("alice", "data2", "read"))); + + } }