Skip to content

Commit e0719eb

Browse files
committed
Add compact method
1 parent a846d5b commit e0719eb

File tree

2 files changed

+158
-0
lines changed

2 files changed

+158
-0
lines changed

acp/src/main/java/com/inrupt/client/acp/AccessControlResource.java

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
import org.apache.commons.rdf.api.Dataset;
3535
import org.apache.commons.rdf.api.Graph;
36+
import org.apache.commons.rdf.api.Quad;
3637
import org.apache.commons.rdf.api.RDFTerm;
3738

3839
/**
@@ -42,20 +43,75 @@ public class AccessControlResource extends RDFSource {
4243

4344
private static final URI SOLID_ACCESS_GRANT = URI.create("http://www.w3.org/ns/solid/vc#SolidAccessGrant");
4445

46+
/**
47+
* Create a new Access Control Resource.
48+
*
49+
* @param identifier the resource identifier
50+
* @param dataset the underlying dataset for the resource
51+
*/
4552
public AccessControlResource(final URI identifier, final Dataset dataset) {
4653
super(identifier, dataset);
4754
dataset.add(null, rdf.createIRI(identifier.toString()), rdf.createIRI(RDF.type.toString()),
4855
rdf.createIRI(ACP.AccessControlResource.toString()));
4956
}
5057

58+
/**
59+
* Retrieve the acp:accessControl structures.
60+
*
61+
* <p>accessControl resources are applied (non-recursively) to a container or resource.
62+
*
63+
* @return a collection of {@link AccessControl} objects
64+
*/
5165
public Set<AccessControl> accessControl() {
5266
return new ACPNode(rdf.createIRI(getIdentifier().toString()), getGraph()).accessControl();
5367
}
5468

69+
/**
70+
* Retrieve the acp:memberAccessControl structures.
71+
*
72+
* <p>memberAccessControl resources are applied recursively to a containment hierarchy.
73+
*
74+
* @return a collection of {@link AccessControl} objects
75+
*/
5576
public Set<AccessControl> memberAccessControl() {
5677
return new ACPNode(rdf.createIRI(getIdentifier().toString()), getGraph()).memberAccessControl();
5778
}
5879

80+
/**
81+
* Compact the internal data.
82+
*/
83+
public void compact() {
84+
final var accessControls = stream(null, null, rdf.createIRI(RDF.type.toString()),
85+
rdf.createIRI(ACP.AccessControl.toString())).map(Quad::getSubject).toList();
86+
for (final var accessControl : accessControls) {
87+
if (!contains(null, null, null, accessControl)) {
88+
for (final var quad : stream(null, accessControl, null, null).toList()) {
89+
remove(quad);
90+
}
91+
}
92+
}
93+
94+
final var policies = stream(null, null, rdf.createIRI(RDF.type.toString()),
95+
rdf.createIRI(ACP.Policy.toString())).map(Quad::getSubject).toList();
96+
for (final var policy : policies) {
97+
if (!contains(null, null, null, policy)) {
98+
for (final var quad : stream(null, policy, null, null).toList()) {
99+
remove(quad);
100+
}
101+
}
102+
}
103+
104+
final var matchers = stream(null, null, rdf.createIRI(RDF.type.toString()),
105+
rdf.createIRI(ACP.Matcher.toString())).map(Quad::getSubject).toList();
106+
for (final var matcher : matchers) {
107+
if (!contains(null, null, null, matcher)) {
108+
for (final var quad : stream(null, matcher, null, null).toList()) {
109+
remove(quad);
110+
}
111+
}
112+
}
113+
}
114+
59115
static class ACPNode extends WrapperIRI {
60116
public ACPNode(final RDFTerm original, final Graph graph) {
61117
super(original, graph);
@@ -72,6 +128,12 @@ public Set<AccessControl> accessControl() {
72128
}
73129
}
74130

131+
/**
132+
* Add policies to the access control resource.
133+
*
134+
* @param policies the policies to add
135+
* @return the access control structure
136+
*/
75137
public AccessControl accessControl(final Policy... policies) {
76138
final var baseUri = getIdentifier().getScheme() + ":" + getIdentifier().getSchemeSpecificPart();
77139
final var ac = new AccessControl(rdf.createIRI(baseUri + "#" + UUID.randomUUID()), getGraph());
@@ -81,34 +143,85 @@ public AccessControl accessControl(final Policy... policies) {
81143
return ac;
82144
}
83145

146+
/**
147+
* Create a policy that matches authenticated agents.
148+
*
149+
* @param access the access levels, such as Read or Write
150+
* @return the new policy
151+
*/
84152
public Policy authenticatedAgentPolicy(final URI... access) {
85153
return agentPolicy(ACP.AuthenticatedAgent, access);
86154
}
87155

156+
/**
157+
* Create a policy that matches all agents.
158+
*
159+
* @param access the access levels, such as Read or Write
160+
* @return the new policy
161+
*/
88162
public Policy anyAgentPolicy(final URI... access) {
89163
return agentPolicy(ACP.PublicAgent, access);
90164
}
91165

166+
/**
167+
* Create a policy that matches all clients.
168+
*
169+
* @param access the access levels, such as Read or Write
170+
* @return the new policy
171+
*/
92172
public Policy anyClientPolicy(final URI... access) {
93173
return clientPolicy(ACP.PublicClient, access);
94174
}
95175

176+
/**
177+
* Create a policy that matches all issuers.
178+
*
179+
* @param access the access levels, such as Read or Write
180+
* @return the new policy
181+
*/
96182
public Policy anyIssuerPolicy(final URI... access) {
97183
return issuerPolicy(ACP.PublicIssuer, access);
98184
}
99185

186+
/**
187+
* Create a policy that matches access grants.
188+
*
189+
* @param access the access levels, such as Read or Write
190+
* @return the new policy
191+
*/
100192
public Policy accessGrantsPolicy(final URI... access) {
101193
return simplePolicy(matcher -> matcher.vc().add(SOLID_ACCESS_GRANT), access);
102194
}
103195

196+
/**
197+
* Create a policy that matches a particular agent.
198+
*
199+
* @param agent the agent identifier
200+
* @param access the access levels, such as Read or Write
201+
* @return the new policy
202+
*/
104203
public Policy agentPolicy(final URI agent, final URI... access) {
105204
return simplePolicy(matcher -> matcher.agent().add(agent), access);
106205
}
107206

207+
/**
208+
* Create a policy that matches a particular client.
209+
*
210+
* @param client the client identifier
211+
* @param access the access levels, such as Read or Write
212+
* @return the new policy
213+
*/
108214
public Policy clientPolicy(final URI client, final URI... access) {
109215
return simplePolicy(matcher -> matcher.client().add(client), access);
110216
}
111217

218+
/**
219+
* Create a policy that matches a particular issuer.
220+
*
221+
* @param issuer the issuer identifier
222+
* @param access the access levels, such as Read or Write
223+
* @return the new policy
224+
*/
112225
public Policy issuerPolicy(final URI issuer, final URI... access) {
113226
return simplePolicy(matcher -> matcher.issuer().add(issuer), access);
114227
}

acp/src/test/java/com/inrupt/client/acp/AccessControlResourceTest.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,51 @@ void buildAcr() {
179179
assertEquals(10, acr.size());
180180
}
181181

182+
@Test
183+
void testAcr1RemoveValues() {
184+
final var uri = mockHttpServer.acr2();
185+
try (final AccessControlResource acr = client.read(uri, AccessControlResource.class)) {
186+
assertEquals(2, acr.accessControl().size());
187+
assertEquals(3, acr.memberAccessControl().size());
188+
189+
// Check dataset size
190+
assertEquals(29, acr.size());
191+
192+
// Remove single matcher and compact
193+
for (final var accessControl : acr.accessControl()) {
194+
for (final var policy : accessControl.apply()) {
195+
if (policy.allow().contains(ACL.Write) && policy.allow().size() == 2) {
196+
for (final var matcher : policy.allOf()) {
197+
policy.allOf().remove(matcher);
198+
}
199+
}
200+
}
201+
}
202+
assertEquals(28, acr.size());
203+
acr.compact();
204+
assertEquals(26, acr.size());
205+
206+
// Remove single policy and compact
207+
for (final var accessControl : acr.accessControl()) {
208+
for (final var policy : accessControl.apply()) {
209+
if (policy.allow().contains(ACL.Write) && policy.allow().size() == 2) {
210+
accessControl.apply().remove(policy);
211+
}
212+
}
213+
}
214+
assertEquals(25, acr.size());
215+
acr.compact();
216+
assertEquals(22, acr.size());
217+
218+
// Remove single access control and compact - no compaction involved
219+
final var ac = acr.accessControl().stream().findFirst().get();
220+
acr.accessControl().remove(ac);
221+
assertEquals(21, acr.size());
222+
acr.compact();
223+
assertEquals(21, acr.size());
224+
}
225+
}
226+
182227
@Test
183228
void buildAcrWithExistingPolicies() {
184229
final var identifier = "https://data.example/resource";

0 commit comments

Comments
 (0)