3030import java .util .Set ;
3131import java .util .UUID ;
3232import java .util .function .Consumer ;
33+ import java .util .stream .Collectors ;
3334
3435import org .apache .commons .rdf .api .Dataset ;
3536import org .apache .commons .rdf .api .Graph ;
37+ import org .apache .commons .rdf .api .IRI ;
3638import org .apache .commons .rdf .api .Quad ;
3739import org .apache .commons .rdf .api .RDFTerm ;
3840
@@ -51,8 +53,7 @@ public class AccessControlResource extends RDFSource {
5153 */
5254 public AccessControlResource (final URI identifier , final Dataset dataset ) {
5355 super (identifier , dataset );
54- dataset .add (null , rdf .createIRI (identifier .toString ()), rdf .createIRI (RDF .type .toString ()),
55- rdf .createIRI (ACP .AccessControlResource .toString ()));
56+ dataset .add (null , asIRI (identifier ), asIRI (RDF .type ), asIRI (ACP .AccessControlResource ));
5657 }
5758
5859 /**
@@ -63,7 +64,7 @@ public AccessControlResource(final URI identifier, final Dataset dataset) {
6364 * @return a collection of {@link AccessControl} objects
6465 */
6566 public Set <AccessControl > accessControl () {
66- return new ACPNode (rdf . createIRI (getIdentifier (). toString ()), getGraph ()).accessControl ();
67+ return new ACPNode (asIRI (getIdentifier ()), getGraph ()).accessControl ();
6768 }
6869
6970 /**
@@ -74,15 +75,15 @@ public Set<AccessControl> accessControl() {
7475 * @return a collection of {@link AccessControl} objects
7576 */
7677 public Set <AccessControl > memberAccessControl () {
77- return new ACPNode (rdf . createIRI (getIdentifier (). toString ()), getGraph ()).memberAccessControl ();
78+ return new ACPNode (asIRI (getIdentifier ()), getGraph ()).memberAccessControl ();
7879 }
7980
8081 /**
8182 * Compact the internal data.
8283 */
8384 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 ();
85+ final var accessControls = stream (null , null , asIRI (RDF .type ), asIRI ( ACP . AccessControl ))
86+ .map (Quad ::getSubject ).toList ();
8687 for (final var accessControl : accessControls ) {
8788 if (!contains (null , null , null , accessControl )) {
8889 for (final var quad : stream (null , accessControl , null , null ).toList ()) {
@@ -91,8 +92,7 @@ public void compact() {
9192 }
9293 }
9394
94- final var policies = stream (null , null , rdf .createIRI (RDF .type .toString ()),
95- rdf .createIRI (ACP .Policy .toString ())).map (Quad ::getSubject ).toList ();
95+ final var policies = stream (null , null , asIRI (RDF .type ), asIRI (ACP .Policy )).map (Quad ::getSubject ).toList ();
9696 for (final var policy : policies ) {
9797 if (!contains (null , null , null , policy )) {
9898 for (final var quad : stream (null , policy , null , null ).toList ()) {
@@ -101,8 +101,7 @@ public void compact() {
101101 }
102102 }
103103
104- final var matchers = stream (null , null , rdf .createIRI (RDF .type .toString ()),
105- rdf .createIRI (ACP .Matcher .toString ())).map (Quad ::getSubject ).toList ();
104+ final var matchers = stream (null , null , asIRI (RDF .type ), asIRI (ACP .Matcher )).map (Quad ::getSubject ).toList ();
106105 for (final var matcher : matchers ) {
107106 if (!contains (null , null , null , matcher )) {
108107 for (final var quad : stream (null , matcher , null , null ).toList ()) {
@@ -112,18 +111,74 @@ public void compact() {
112111 }
113112 }
114113
114+ /**
115+ * Merge two or more policies into a single policies with combined matchers.
116+ *
117+ * @param policies the policies to merge
118+ * @return the merged policy
119+ */
120+ public Policy merge (final Policy ... policies ) {
121+ final var baseUri = getIdentifier ().getScheme () + ":" + getIdentifier ().getSchemeSpecificPart ();
122+ final var policy = new Policy (asIRI (baseUri + "#" + UUID .randomUUID ()), getGraph ());
123+ for (final var p : policies ) {
124+ policy .allOf ().addAll (p .allOf ());
125+ policy .anyOf ().addAll (p .anyOf ());
126+ policy .noneOf ().addAll (p .noneOf ());
127+ }
128+ return policy ;
129+ }
130+
131+ public enum MatcherType {
132+ AGENT (ACP .agent ), CLIENT (ACP .client ), ISSUER (ACP .issuer ), VC (ACP .vc );
133+
134+ private final URI predicate ;
135+
136+ MatcherType (final URI predicate ) {
137+ this .predicate = predicate ;
138+ }
139+
140+ public IRI asIRI () {
141+ return AccessControlResource .asIRI (predicate );
142+ }
143+
144+ public URI asURI () {
145+ return predicate ;
146+ }
147+ }
148+
149+ /**
150+ * Find a policy, given a type, value and set of modes.
151+ *
152+ * @param type the matcher type
153+ * @param value the matcher value
154+ * @param modes the expected modes of the enclosing policy
155+ * @return the matched policies
156+ */
157+ public Set <Policy > find (final MatcherType type , final URI value , final Set <URI > modes ) {
158+ return stream (null , null , type .asIRI (), asIRI (value ))
159+ .map (Quad ::getSubject )
160+ .flatMap (matcher -> stream (null , null , null , matcher ))
161+ .map (Quad ::getSubject )
162+ .filter (policy -> contains (null , policy , asIRI (RDF .type ), asIRI (ACP .Policy )))
163+ .filter (policy -> stream (null , policy , asIRI (ACP .allow ), null )
164+ .map (Quad ::getObject ).filter (IRI .class ::isInstance ).map (IRI .class ::cast )
165+ .map (IRI ::getIRIString ).map (URI ::create ).toList ().containsAll (modes ))
166+ .map (policy -> new Policy (policy , getGraph ()))
167+ .collect (Collectors .toSet ());
168+ }
169+
115170 static class ACPNode extends WrapperIRI {
116171 public ACPNode (final RDFTerm original , final Graph graph ) {
117172 super (original , graph );
118173 }
119174
120175 public Set <AccessControl > memberAccessControl () {
121- return objects (rdf . createIRI (ACP .memberAccessControl . toString () ),
176+ return objects (asIRI (ACP .memberAccessControl ),
122177 AccessControl ::asResource , ValueMappings .as (AccessControl .class ));
123178 }
124179
125180 public Set <AccessControl > accessControl () {
126- return objects (rdf . createIRI (ACP .accessControl . toString () ),
181+ return objects (asIRI (ACP .accessControl ),
127182 AccessControl ::asResource , ValueMappings .as (AccessControl .class ));
128183 }
129184 }
@@ -136,7 +191,7 @@ public Set<AccessControl> accessControl() {
136191 */
137192 public AccessControl accessControl (final Policy ... policies ) {
138193 final var baseUri = getIdentifier ().getScheme () + ":" + getIdentifier ().getSchemeSpecificPart ();
139- final var ac = new AccessControl (rdf . createIRI (baseUri + "#" + UUID .randomUUID ()), getGraph ());
194+ final var ac = new AccessControl (asIRI (baseUri + "#" + UUID .randomUUID ()), getGraph ());
140195 for (final var policy : policies ) {
141196 ac .apply ().add (policy );
142197 }
@@ -228,14 +283,22 @@ public Policy issuerPolicy(final URI issuer, final URI... access) {
228283
229284 Policy simplePolicy (final Consumer <Matcher > handler , final URI ... access ) {
230285 final var baseUri = getIdentifier ().getScheme () + ":" + getIdentifier ().getSchemeSpecificPart ();
231- final var matcher = new Matcher (rdf . createIRI (baseUri + "#" + UUID .randomUUID ()), getGraph ());
286+ final var matcher = new Matcher (asIRI (baseUri + "#" + UUID .randomUUID ()), getGraph ());
232287 handler .accept (matcher );
233288
234- final var policy = new Policy (rdf . createIRI (baseUri + "#" + UUID .randomUUID ()), getGraph ());
289+ final var policy = new Policy (asIRI (baseUri + "#" + UUID .randomUUID ()), getGraph ());
235290 for (final var item : access ) {
236291 policy .allow ().add (item );
237292 }
238293 policy .allOf ().add (matcher );
239294 return policy ;
240295 }
296+
297+ private static IRI asIRI (final URI uri ) {
298+ return asIRI (uri .toString ());
299+ }
300+
301+ private static IRI asIRI (final String uri ) {
302+ return rdf .createIRI (uri );
303+ }
241304}
0 commit comments