1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.mycore.lod.controller;
20
21 import java.io.IOException;
22 import java.net.URI;
23 import java.util.Date;
24 import java.util.List;
25 import java.util.Optional;
26 import java.util.concurrent.TimeUnit;
27 import java.util.function.Function;
28
29 import org.jdom2.Document;
30 import org.jdom2.Element;
31 import org.mycore.common.MCRConstants;
32 import org.mycore.common.content.MCRJDOMContent;
33 import org.mycore.datamodel.classifications2.MCRCategory;
34 import org.mycore.datamodel.classifications2.MCRCategoryDAO;
35 import org.mycore.datamodel.classifications2.MCRCategoryDAOFactory;
36 import org.mycore.datamodel.classifications2.MCRCategoryID;
37 import org.mycore.datamodel.classifications2.model.MCRClass;
38 import org.mycore.datamodel.classifications2.model.MCRClassCategory;
39 import org.mycore.datamodel.classifications2.utils.MCRSkosTransformer;
40 import org.mycore.frontend.MCRFrontendUtil;
41 import org.mycore.frontend.jersey.MCRCacheControl;
42 import org.mycore.lod.MCRJerseyLodApp;
43 import org.mycore.restapi.converter.MCRDetailLevel;
44 import org.mycore.restapi.v2.MCRErrorResponse;
45 import org.mycore.restapi.v2.MCRRestUtils;
46
47 import io.swagger.v3.oas.annotations.Operation;
48 import io.swagger.v3.oas.annotations.media.Content;
49 import io.swagger.v3.oas.annotations.media.Schema;
50 import io.swagger.v3.oas.annotations.responses.ApiResponse;
51 import jakarta.ws.rs.GET;
52 import jakarta.ws.rs.Path;
53 import jakarta.ws.rs.PathParam;
54 import jakarta.ws.rs.container.ContainerRequestContext;
55 import jakarta.ws.rs.core.Context;
56 import jakarta.ws.rs.core.MediaType;
57 import jakarta.ws.rs.core.Response;
58
59
60
61
62
63
64 @Path("/classification")
65 public class MCRLodClassification {
66
67
68 public static final String ERROR_MCRCLASS_NOT_FOUND = "MCRCLASS_NOT_FOUND";
69
70
71 public static final String ERROR_MCRCLASS_ID_MISMATCH = "MCRCLASS_ID_MISMATCH";
72
73
74 public static final String ERROR_MCRCLASS_TRANSFORMATION = "MCRCLASS_TRANSFORMATION";
75
76
77 private static final String PARAM_CLASSID = "classid";
78
79
80 private static final String PARAM_CATEGID = "categid";
81
82 @Context
83 ContainerRequestContext request;
84
85
86
87
88
89
90
91
92
93 @GET
94 @MCRCacheControl(maxAge = @MCRCacheControl.Age(time = 1, unit = TimeUnit.HOURS),
95 sMaxAge = @MCRCacheControl.Age(time = 1, unit = TimeUnit.HOURS))
96 public Response outputLODClassificationRoot() {
97 MCRCategoryDAO categoryDAO = MCRCategoryDAOFactory.getInstance();
98 Date lastModified = new Date(categoryDAO.getLastModified());
99 Optional<Response> cachedResponse = MCRRestUtils.getCachedResponse(request.getRequest(), lastModified);
100 if (cachedResponse.isPresent()) {
101 return cachedResponse.get();
102 }
103
104 try {
105 Document classRdfxml = createClassList();
106 String rdfxmlString = new MCRJDOMContent(classRdfxml).asString();
107 List<String> mimeTypes = request.getAcceptableMediaTypes().parallelStream().map(x -> x.toString()).toList();
108 URI uri = request.getUriInfo().getBaseUri();
109 return MCRJerseyLodApp.returnLinkedData(rdfxmlString, uri, mimeTypes);
110 } catch (IOException e) {
111 throw MCRErrorResponse.fromStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode())
112 .withErrorCode(ERROR_MCRCLASS_TRANSFORMATION)
113 .withMessage("Could create classification list.")
114 .toException();
115 }
116 }
117
118
119
120
121
122
123 @GET
124 @MCRCacheControl(maxAge = @MCRCacheControl.Age(time = 1, unit = TimeUnit.DAYS),
125 sMaxAge = @MCRCacheControl.Age(time = 1, unit = TimeUnit.DAYS))
126 @Path("/{" + PARAM_CLASSID + "}")
127 public Response getClassification(@PathParam(PARAM_CLASSID) String classId) {
128 List<MediaType> mediaTypes = request.getAcceptableMediaTypes();
129 return getClassification(MCRCategoryID.rootID(classId),
130 dao -> dao.getCategory(MCRCategoryID.rootID(classId), 1), mediaTypes,
131 request.getUriInfo().getBaseUri());
132 }
133
134
135
136
137
138
139
140
141 @GET
142 @MCRCacheControl(maxAge = @MCRCacheControl.Age(time = 1, unit = TimeUnit.DAYS),
143 sMaxAge = @MCRCacheControl.Age(time = 1, unit = TimeUnit.DAYS))
144 @Path("/{" + PARAM_CLASSID + "}/{" + PARAM_CATEGID + "}")
145 @Operation(summary = "Returns Classification with the given " + PARAM_CLASSID + " and " + PARAM_CATEGID + ".",
146 responses = @ApiResponse(content = {
147 @Content(schema = @Schema(implementation = MCRClass.class)),
148 @Content(schema = @Schema(implementation = MCRClassCategory.class))
149 },
150 description = "If media type parameter " + MCRDetailLevel.MEDIA_TYPE_PARAMETER
151 + " is 'summary' an MCRClassCategory is returned. "
152 + "In other cases MCRClass with different detail level."),
153 tags = MCRRestUtils.TAG_MYCORE_CLASSIFICATION)
154
155 public Response getClassification(@PathParam(PARAM_CLASSID) String classId,
156 @PathParam(PARAM_CATEGID) String categId) {
157
158 MCRCategoryID categoryId = new MCRCategoryID(classId, categId);
159 return getClassification(categoryId, dao -> dao.getRootCategory(categoryId, 0),
160 request.getAcceptableMediaTypes(),
161 request.getUriInfo().getBaseUri());
162 }
163
164 private Response getClassification(MCRCategoryID categId, Function<MCRCategoryDAO, MCRCategory> categorySupplier,
165 List<MediaType> acceptMediaTypes, URI uri) {
166 MCRCategoryDAO categoryDAO = MCRCategoryDAOFactory.getInstance();
167 String classId = categId.getRootID();
168 Date lastModified = getLastModifiedDate(classId, categoryDAO);
169 Optional<Response> cachedResponse = MCRRestUtils.getCachedResponse(request.getRequest(), lastModified);
170 if (cachedResponse.isPresent()) {
171 return cachedResponse.get();
172 }
173 MCRCategory classification = categorySupplier.apply(categoryDAO);
174 if (classification == null) {
175 throw MCRErrorResponse.fromStatus(Response.Status.NOT_FOUND.getStatusCode())
176 .withErrorCode(ERROR_MCRCLASS_NOT_FOUND)
177 .withMessage("Could not find classification or category in " + classId + ".")
178 .toException();
179 }
180 try {
181 Document classRdfXml = MCRSkosTransformer.getSkosInRDFXML(classification, categId);
182 String rdfxmlString = new MCRJDOMContent(classRdfXml).asString();
183 List<String> mimeTypes = acceptMediaTypes.parallelStream().map(x -> x.toString()).toList();
184 return MCRJerseyLodApp.returnLinkedData(rdfxmlString, uri, mimeTypes);
185 } catch (IOException e) {
186 throw MCRErrorResponse.fromStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode())
187 .withErrorCode(ERROR_MCRCLASS_TRANSFORMATION)
188 .withMessage("Could not find classification or category in " + classId + ".")
189 .toException();
190 }
191 }
192
193 private Document createClassList() {
194 Element eBag = new Element("Bag", MCRConstants.RDF_NAMESPACE);
195 MCRCategoryDAO categoryDAO = MCRCategoryDAOFactory.getInstance();
196 for (MCRCategory categ : categoryDAO.getRootCategories()) {
197 eBag.addContent(new Element("li", MCRConstants.RDF_NAMESPACE)
198 .setAttribute("resource",
199 MCRFrontendUtil.getBaseURL() + "open-data/classification/" + categ.getId().toString(),
200 MCRConstants.RDF_NAMESPACE));
201 }
202 return new Document(eBag);
203 }
204
205 private static Date getLastModifiedDate(@PathParam(PARAM_CLASSID) String classId, MCRCategoryDAO categoryDAO) {
206 long categoryLastModified = categoryDAO.getLastModified(classId);
207 return new Date(categoryLastModified > 0 ? categoryLastModified : categoryDAO.getLastModified());
208 }
209
210 }