1616 */
1717package com .atomgraph .linkeddatahub .resource ;
1818
19+ import com .atomgraph .core .util .ModelUtils ;
1920import com .atomgraph .linkeddatahub .apps .model .Application ;
21+ import com .atomgraph .linkeddatahub .server .io .ValidatingModelProvider ;
2022import jakarta .inject .Inject ;
2123import jakarta .ws .rs .BadRequestException ;
2224import jakarta .ws .rs .GET ;
25+ import jakarta .ws .rs .InternalServerErrorException ;
2326import jakarta .ws .rs .NotFoundException ;
2427import jakarta .ws .rs .PATCH ;
28+ import jakarta .ws .rs .core .Context ;
29+ import jakarta .ws .rs .core .EntityTag ;
30+ import jakarta .ws .rs .core .Request ;
2531import jakarta .ws .rs .core .Response ;
32+ import jakarta .ws .rs .ext .MessageBodyReader ;
33+ import jakarta .ws .rs .ext .Providers ;
2634import java .io .IOException ;
2735import org .apache .jena .query .Dataset ;
2836import org .apache .jena .query .DatasetFactory ;
@@ -44,18 +52,24 @@ public class Settings
4452
4553 private final Application application ;
4654 private final com .atomgraph .linkeddatahub .Application system ;
55+ private final Providers providers ;
56+ private final Request request ;
4757
4858 /**
4959 * Constructs the Settings endpoint.
5060 *
5161 * @param application the current dataspace application
5262 * @param system the system application
63+ * @param providers JAX-RS provider registry
64+ * @param request JAX-RS request context
5365 */
5466 @ Inject
55- public Settings (Application application , com .atomgraph .linkeddatahub .Application system )
67+ public Settings (Application application , com .atomgraph .linkeddatahub .Application system , @ Context Providers providers , @ Context Request request )
5668 {
5769 this .application = application ;
5870 this .system = system ;
71+ this .providers = providers ;
72+ this .request = request ;
5973 }
6074
6175 /**
@@ -76,7 +90,13 @@ public Response get()
7690
7791 if (log .isDebugEnabled ()) log .debug ("Retrieved settings for dataspace <{}>" , getApplication ().getURI ());
7892
79- return Response .ok (dataspaceModel ).build ();
93+ EntityTag entityTag = getEntityTag (dataspaceModel );
94+ Response .ResponseBuilder rb = getRequest ().evaluatePreconditions (entityTag );
95+ if (rb != null ) return rb .build ();
96+
97+ return Response .ok (dataspaceModel ).
98+ tag (entityTag ).
99+ build ();
80100 }
81101
82102 /**
@@ -103,6 +123,16 @@ public Response patch(UpdateRequest updateRequest) throws IOException
103123 Dataset dataset = DatasetFactory .wrap (dataspaceModel );
104124 UpdateAction .execute (updateRequest , dataset );
105125
126+ // if PATCH results in an empty model, reject it as Bad Request
127+ if (dataspaceModel .isEmpty ())
128+ {
129+ if (log .isWarnEnabled ()) log .warn ("PATCH resulted in empty dataspace model for <{}>" , getApplication ().getURI ());
130+ throw new BadRequestException ("PATCH cannot result in empty dataspace model" );
131+ }
132+
133+ // validate the updated model
134+ validate (dataspaceModel );
135+
106136 // Write the updated model back to the context dataset file
107137 getSystem ().updateDataspace (getApplication (), dataspaceModel );
108138
@@ -131,4 +161,49 @@ public com.atomgraph.linkeddatahub.Application getSystem()
131161 return system ;
132162 }
133163
164+ /**
165+ * Returns the JAX-RS providers registry.
166+ *
167+ * @return the providers
168+ */
169+ public Providers getProviders ()
170+ {
171+ return providers ;
172+ }
173+
174+ /**
175+ * Validates model against SPIN and SHACL constraints.
176+ *
177+ * @param model RDF model
178+ * @return validated model
179+ */
180+ public Model validate (Model model )
181+ {
182+ MessageBodyReader <Model > reader = getProviders ().getMessageBodyReader (Model .class , null , null , com .atomgraph .core .MediaType .APPLICATION_NTRIPLES_TYPE );
183+ if (reader instanceof ValidatingModelProvider validatingModelProvider ) return validatingModelProvider .processRead (model );
184+
185+ throw new InternalServerErrorException ("Could not obtain ValidatingModelProvider instance" );
186+ }
187+
188+ /**
189+ * Returns the JAX-RS request context.
190+ *
191+ * @return the request
192+ */
193+ public Request getRequest ()
194+ {
195+ return request ;
196+ }
197+
198+ /**
199+ * Generates an ETag for the given model.
200+ *
201+ * @param model RDF model
202+ * @return entity tag
203+ */
204+ public EntityTag getEntityTag (Model model )
205+ {
206+ return new EntityTag (Long .toHexString (ModelUtils .hashModel (model )));
207+ }
208+
134209}
0 commit comments