source: gs3-extensions/iiif-servlet/trunk/src/src/main/java/edu/illinois/library/cantaloupe/resource/iiif/v2/GSInformationResource.java@ 32874

Last change on this file since 32874 was 32874, checked in by davidb, 5 years ago

Next round of changes, migrating from OAI imprint to what is needed for IIIF

File size: 8.7 KB
Line 
1package edu.illinois.library.cantaloupe.resource.iiif.v2;
2
3import java.io.IOException;
4import java.nio.file.Files;
5import java.nio.file.NoSuchFileException;
6import java.nio.file.Path;
7import java.util.List;
8
9import edu.illinois.library.cantaloupe.RestletApplication;
10import edu.illinois.library.cantaloupe.cache.CacheFacade;
11import edu.illinois.library.cantaloupe.config.Configuration;
12import edu.illinois.library.cantaloupe.config.Key;
13import edu.illinois.library.cantaloupe.image.Format;
14import edu.illinois.library.cantaloupe.image.Identifier;
15import edu.illinois.library.cantaloupe.image.Info;
16import edu.illinois.library.cantaloupe.processor.Processor;
17import edu.illinois.library.cantaloupe.processor.ProcessorFactory;
18import edu.illinois.library.cantaloupe.source.Source;
19import edu.illinois.library.cantaloupe.source.SourceFactory;
20import edu.illinois.library.cantaloupe.resource.JSONRepresentation;
21import edu.illinois.library.cantaloupe.processor.ProcessorConnector;
22import org.restlet.data.MediaType;
23import org.restlet.data.Preference;
24import org.restlet.data.Reference;
25import org.restlet.representation.EmptyRepresentation;
26import org.restlet.representation.Representation;
27import org.restlet.resource.Get;
28
29import org.greenstone.gsdl3.IIIFServerBridge;
30
31/**
32 * Handles IIIF Image API 2.x information requests.
33 *
34 * @see <a href="http://iiif.io/api/image/2.1/#information-request">Information
35 * Requests</a>
36 */
37public class GSInformationResource extends InformationResource {
38
39 /**
40 * Redirects {@literal /:identifier} to {@literal /:identifier/info.json},
41 * respecting the Servlet context root and
42 * {@link #PUBLIC_IDENTIFIER_HEADER} header.
43 */
44 public static class RedirectingResource extends IIIF2Resource {
45 @Get
46 public Representation doGet() {
47 final Reference newRef = new Reference(
48 getPublicRootReference() +
49 RestletApplication.IIIF_2_PATH + "/" +
50 getPublicIdentifier() +
51 "/info.json");
52 redirectSeeOther(newRef);
53 return new EmptyRepresentation();
54 }
55 }
56
57 /**
58 * Responds to information requests.
59 *
60 * @return {@link ImageInfo} instance serialized as JSON.
61 */
62 @Get
63 public Representation doGet() throws Exception {
64 final Configuration config = Configuration.getInstance();
65 final Identifier identifier = getIdentifier();
66 final CacheFacade cacheFacade = new CacheFacade();
67
68 // If we don't need to resolve first, and are using a cache, and the
69 // cache contains an info matching the request, skip all the setup and
70 // just return the cached info.
71 if (!isResolvingFirst()) {
72 try {
73 Info info = cacheFacade.getInfo(identifier);
74 if (info != null) {
75 // The source format will be null or UNKNOWN if the info was
76 // serialized in version < 3.4.
77 final Format format = info.getSourceFormat();
78 if (format != null && !Format.UNKNOWN.equals(format)) {
79 final Processor processor = new ProcessorFactory().
80 newProcessor(format);
81 commitCustomResponseHeaders();
82 return newRepresentation(info, processor);
83 }
84 }
85 } catch (IOException e) {
86 // Don't rethrow -- it's still possible to service the request.
87 getLogger().severe(e.getMessage());
88 }
89 }
90
91 String identifier_str = identifier.toString();
92 String[] strs = identifier_str.split(":", 3);
93 if(strs == null || strs.length < 3) {
94 System.err.println("identifier is not in the form site:coll:id" + identifier_str);
95 return null;
96 }
97 String site_name = strs[0];
98 String coll_name = strs[1];
99 String doc_id = strs[2];
100
101 // Move into Constructor, ,and keep hashmap ???
102 IIIFServerBridge gs_iiif_bridge = new IIIFServerBridge();
103 gs_iiif_bridge.init(site_name);
104 String collect_image_filename = gs_iiif_bridge.doGetDocumentMessage(coll_name + ":" + doc_id);
105 String site_image_filename = site_name + "/collect/" + coll_name + "/index/assoc/" + collect_image_filename;
106
107 //System.err.println("**** gs_message = " + XMLConverter.getPrettyString(gs_message_elem));
108 System.err.println("**** Greenstone site image filename = " + site_image_filename);
109
110 final Source source = new SourceFactory().newSource(
111 identifier, getDelegateProxy());
112
113 System.err.println("***** identifier = " + identifier);
114 System.err.println("***** source path = " + ((edu.illinois.library.cantaloupe.source.FileSource)source).getPath());
115
116 // If we are resolving first, or if the source image is not present in
117 // the source cache (if enabled), check access to it in preparation for
118 // retrieval.
119 final Path sourceImage = cacheFacade.getSourceCacheFile(identifier);
120 if (sourceImage == null || isResolvingFirst()) {
121 try {
122 source.checkAccess();
123 } catch (NoSuchFileException e) { // this needs to be rethrown!
124 if (config.getBoolean(Key.CACHE_SERVER_PURGE_MISSING, false)) {
125 // If the image was not found, purge it from the cache.
126 cacheFacade.purgeAsync(identifier);
127 }
128 throw e;
129 }
130 }
131
132 // Get the format of the source image.
133 // If we are not resolving first, and there is a hit in the source
134 // cache, read the format from the source-cached-file, as we will
135 // expect source cache access to be more efficient.
136 // Otherwise, read it from the source.
137 Format format = Format.UNKNOWN;
138 if (!isResolvingFirst() && sourceImage != null) {
139 List<edu.illinois.library.cantaloupe.image.MediaType> mediaTypes =
140 edu.illinois.library.cantaloupe.image.MediaType.detectMediaTypes(sourceImage);
141 if (!mediaTypes.isEmpty()) {
142 format = mediaTypes.get(0).toFormat();
143 }
144 } else {
145 format = source.getFormat();
146 }
147
148 // Obtain an instance of the processor assigned to that format.
149 try (Processor processor = new ProcessorFactory().newProcessor(format)) {
150 // Connect it to the source.
151 tempFileFuture = new ProcessorConnector().connect(
152 source, processor, identifier, format);
153
154 final Info info = getOrReadInfo(identifier, processor);
155
156 commitCustomResponseHeaders();
157
158 return newRepresentation(info, processor);
159 }
160 }
161
162 /**
163 * @return Full image URI corresponding to the given identifier, respecting
164 * the {@literal X-Forwarded-*} and
165 * {@link #PUBLIC_IDENTIFIER_HEADER} reverse proxy headers.
166 */
167 private String getImageURI() {
168 return getPublicRootReference() + RestletApplication.IIIF_2_PATH + "/" +
169 getPublicIdentifier();
170 }
171
172 private MediaType getNegotiatedMediaType() {
173 MediaType mediaType;
174 // If the client has requested JSON-LD, set the content type to
175 // that; otherwise set it to JSON.
176 List<Preference<MediaType>> preferences = getRequest().getClientInfo().
177 getAcceptedMediaTypes();
178 if (preferences.get(0) != null && preferences.get(0).toString().
179 startsWith("application/ld+json")) {
180 mediaType = new MediaType("application/ld+json");
181 } else {
182 mediaType = new MediaType("application/json");
183 }
184 return mediaType;
185 }
186
187 private Representation newRepresentation(Info info,
188 Processor processor) {
189 final ImageInfoFactory factory = new ImageInfoFactory(
190 processor.getSupportedFeatures(),
191 processor.getSupportedIIIF2Qualities(),
192 processor.getAvailableOutputFormats());
193 factory.setDelegateProxy(getDelegateProxy());
194
195 final ImageInfo<String, Object> imageInfo = factory.newImageInfo(
196 getImageURI(), info, getPageIndex());
197 final MediaType mediaType = getNegotiatedMediaType();
198
199 return new JSONRepresentation(imageInfo, mediaType, () -> {
200 if (tempFileFuture != null) {
201 Path tempFile = tempFileFuture.get();
202 if (tempFile != null) {
203 Files.deleteIfExists(tempFile);
204 }
205 }
206 return null;
207 });
208 }
209
210 private boolean isResolvingFirst() {
211 return Configuration.getInstance().
212 getBoolean(Key.CACHE_SERVER_RESOLVE_FIRST, true);
213 }
214
215}
Note: See TracBrowser for help on using the repository browser.