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

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

Mostly code tidy-up. In IIIFServerBridge.java, edit to remove hard-wired path

File size: 8.4 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 gs_message = gs_iiif_bridge.doGetDocumentMessage(coll_name + ":" + doc_id);
105
106 final Source source = new SourceFactory().newSource(
107 identifier, getDelegateProxy());
108
109 System.err.println("***** identifier = " + identifier);
110 System.err.println("***** source path = " + ((edu.illinois.library.cantaloupe.source.FileSource)source).getPath());
111
112 // If we are resolving first, or if the source image is not present in
113 // the source cache (if enabled), check access to it in preparation for
114 // retrieval.
115 final Path sourceImage = cacheFacade.getSourceCacheFile(identifier);
116 if (sourceImage == null || isResolvingFirst()) {
117 try {
118 source.checkAccess();
119 } catch (NoSuchFileException e) { // this needs to be rethrown!
120 if (config.getBoolean(Key.CACHE_SERVER_PURGE_MISSING, false)) {
121 // If the image was not found, purge it from the cache.
122 cacheFacade.purgeAsync(identifier);
123 }
124 throw e;
125 }
126 }
127
128 // Get the format of the source image.
129 // If we are not resolving first, and there is a hit in the source
130 // cache, read the format from the source-cached-file, as we will
131 // expect source cache access to be more efficient.
132 // Otherwise, read it from the source.
133 Format format = Format.UNKNOWN;
134 if (!isResolvingFirst() && sourceImage != null) {
135 List<edu.illinois.library.cantaloupe.image.MediaType> mediaTypes =
136 edu.illinois.library.cantaloupe.image.MediaType.detectMediaTypes(sourceImage);
137 if (!mediaTypes.isEmpty()) {
138 format = mediaTypes.get(0).toFormat();
139 }
140 } else {
141 format = source.getFormat();
142 }
143
144 // Obtain an instance of the processor assigned to that format.
145 try (Processor processor = new ProcessorFactory().newProcessor(format)) {
146 // Connect it to the source.
147 tempFileFuture = new ProcessorConnector().connect(
148 source, processor, identifier, format);
149
150 final Info info = getOrReadInfo(identifier, processor);
151
152 commitCustomResponseHeaders();
153
154 return newRepresentation(info, processor);
155 }
156 }
157
158 /**
159 * @return Full image URI corresponding to the given identifier, respecting
160 * the {@literal X-Forwarded-*} and
161 * {@link #PUBLIC_IDENTIFIER_HEADER} reverse proxy headers.
162 */
163 private String getImageURI() {
164 return getPublicRootReference() + RestletApplication.IIIF_2_PATH + "/" +
165 getPublicIdentifier();
166 }
167
168 private MediaType getNegotiatedMediaType() {
169 MediaType mediaType;
170 // If the client has requested JSON-LD, set the content type to
171 // that; otherwise set it to JSON.
172 List<Preference<MediaType>> preferences = getRequest().getClientInfo().
173 getAcceptedMediaTypes();
174 if (preferences.get(0) != null && preferences.get(0).toString().
175 startsWith("application/ld+json")) {
176 mediaType = new MediaType("application/ld+json");
177 } else {
178 mediaType = new MediaType("application/json");
179 }
180 return mediaType;
181 }
182
183 private Representation newRepresentation(Info info,
184 Processor processor) {
185 final ImageInfoFactory factory = new ImageInfoFactory(
186 processor.getSupportedFeatures(),
187 processor.getSupportedIIIF2Qualities(),
188 processor.getAvailableOutputFormats());
189 factory.setDelegateProxy(getDelegateProxy());
190
191 final ImageInfo<String, Object> imageInfo = factory.newImageInfo(
192 getImageURI(), info, getPageIndex());
193 final MediaType mediaType = getNegotiatedMediaType();
194
195 return new JSONRepresentation(imageInfo, mediaType, () -> {
196 if (tempFileFuture != null) {
197 Path tempFile = tempFileFuture.get();
198 if (tempFile != null) {
199 Files.deleteIfExists(tempFile);
200 }
201 }
202 return null;
203 });
204 }
205
206 private boolean isResolvingFirst() {
207 return Configuration.getInstance().
208 getBoolean(Key.CACHE_SERVER_RESOLVE_FIRST, true);
209 }
210
211}
Note: See TracBrowser for help on using the repository browser.