source: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/OAIResumptionToken.java@ 31912

Last change on this file since 31912 was 31912, checked in by ak19, 7 years ago

Now GS3 tries to obtain the _earliesttimestamp entry of the oai-inf.db for each collection to, work out the earliest among them to be the earliest timestamp of the repository. For each collection, if there is no such entry or the oai-inf db doesn't exist or can't be accessed, the collection falls back to using the value in the build config file as before. Also as before, if that doesn't exist either, it uses the lastmod date of the collection (I think also taken from build config) as the next fallback value.

File size: 11.1 KB
Line 
1/*
2 * OAIResumptionToken.java
3 * Copyright (C) 2014 New Zealand Digital Library, http://www.nzdl.org
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20package org.greenstone.gsdl3.util;
21
22import org.greenstone.util.GlobalProperties;
23
24import org.w3c.dom.*;
25
26import java.io.File;
27import java.net.URL;
28import java.util.HashMap;
29import java.util.Iterator;
30import java.util.Map;
31import java.util.Set;
32
33
34// import file Logger.java
35import org.apache.log4j.*;
36
37/** */
38public class OAIResumptionToken {
39
40
41
42 // Other fields we save
43 public static final String CURRENT_SET = "current_set";
44 public static final String CURRENT_CURSOR = "current_cursor";
45
46 // for token XML
47 public static final String TOKEN = "token";
48 public static final String TOKEN_LIST = "tokenList";
49 public static final String NAME = "name";
50 public static final String EXPIRATION = "expiration";
51 public static final String INITIAL_TIME = "initial";
52 //public static final String FROM
53 public static final String FILE_SEPARATOR = File.separator;
54 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.util.GSXML.class.getName());
55
56 public static XMLConverter converter = new XMLConverter();
57 public static Element resumption_token_elem = null;
58 //used when saving the token file
59 public static File resumption_token_file = null;
60
61 private static HashMap<String, HashMap<String,String>> stored_tokens = new HashMap<String, HashMap<String,String>>();
62
63 private static HashMap<String, Long> expiration_data = new HashMap<String, Long>();
64
65 /** initialize stored resumption tokens and clear any expired ones*/
66 public static void init() {
67 if (!findOrCreateTokenFile()) {
68 // can't read in old tokens
69 logger.error("Can't find token file, so we can't initialise tokens");
70 return;
71 }
72
73 Document token_doc = converter.getDOM(resumption_token_file, "utf-8");
74 Element token_elem = null;
75 if (token_doc != null) {
76 token_elem = token_doc.getDocumentElement();
77 } else {
78 logger.error("Failed to parse oai resumption token file OAIResumptionToken.xml.");
79 resetTokenFile();
80 return;
81 }
82
83 // read in stored tokens
84 NodeList tokens = token_elem.getElementsByTagName(TOKEN);
85 for(int i=0; i<tokens.getLength(); i++) {
86 Element token = (Element)tokens.item(i);
87 String set = token.getAttribute(OAIXML.SET);
88 if (set.isEmpty()) {
89 set = null;
90 }
91 String meta_prefix = token.getAttribute(OAIXML.METADATA_PREFIX);
92 if (meta_prefix.isEmpty()) {
93 meta_prefix = null;
94 }
95 String from = token.getAttribute(OAIXML.FROM);
96 if (from.isEmpty()) {
97 from = null;
98 }
99 String until = token.getAttribute(OAIXML.UNTIL);
100 if (until.isEmpty()) {
101 until = null;
102 }
103 storeToken(token.getAttribute(NAME), set, meta_prefix, from, until, token.getAttribute(EXPIRATION));
104
105 }
106 }
107 // store the token read in from saved tokens file
108 protected static void storeToken(String name, String set, String metadata_prefix, String from, String until, String expiration) {
109 HashMap<String, String> data = new HashMap<String, String>();
110 data.put(OAIXML.FROM, from);
111 data.put(OAIXML.UNTIL, until);
112 data.put(OAIXML.SET, set);
113 data.put(OAIXML.METADATA_PREFIX, metadata_prefix);
114 stored_tokens.put(name, data);
115 expiration_data.put(name, new Long(expiration));
116 }
117
118 /** generate the token, and store all the data for it */
119 public static String createAndStoreResumptionToken(String set, String metadata_prefix, String from, String until, String cursor, String current_set, String current_cursor) {
120 HashMap<String, String> data = new HashMap<String, String>();
121 long expiration_date = System.currentTimeMillis();
122 String base_token_name = ""+expiration_date;
123 stored_tokens.put(base_token_name, data);
124 expiration_date += (OAIXML.getTokenExpiration());
125 expiration_data.put(base_token_name, new Long(expiration_date));
126 String token_name = base_token_name+":" + cursor + ":" + current_set +":"+ current_cursor;
127 data.put(OAIXML.FROM, from);
128 data.put(OAIXML.UNTIL, until);
129 data.put(OAIXML.SET, set);
130 data.put(OAIXML.METADATA_PREFIX, metadata_prefix);
131 return token_name;
132
133 }
134
135 public static long getExpirationDate(String token) {
136 if (token.indexOf(":") != -1) {
137 token = token.substring(0, token.indexOf(":"));
138 }
139 return expiration_data.get(token).longValue();
140 }
141
142 public static String updateToken(String token, String cursor, String current_set, String current_cursor) {
143 if (token.indexOf(":") != -1) {
144 token = token.substring(0, token.indexOf(":"));
145 }
146
147 // when we are generating a new token, we update the expiration date to allow the new token to have the full length of time
148 long exp_date = System.currentTimeMillis();
149 exp_date += (OAIXML.getTokenExpiration());
150 expiration_data.put(token, exp_date);
151
152 token = token + ":" + cursor + ":" + current_set + ":" + current_cursor;
153 return token;
154 }
155
156 /** check that this token is currently valid */
157 public static boolean isValidToken(String token) {
158 // we clear expired tokens each time we check one.
159 clearExpiredTokens();
160 // take off the set/cursor parts to check for the main key
161 if (token.indexOf(":") != -1) {
162 token = token.substring(0, token.indexOf(":"));
163 logger.info("looking up "+token);
164 }
165 if (stored_tokens.containsKey(token)) {
166 return true;
167 }
168 return false;
169 }
170
171 public static HashMap<String, String> getTokenData(String token) {
172 // find the base name
173 String base_name = token;
174 if (token.indexOf(":") != -1) {
175 base_name = token.substring(0, token.indexOf(":"));
176 logger.info("getting data for "+base_name);
177 }
178 HashMap<String, String> data = new HashMap<String, String>(stored_tokens.get(base_name));
179 if (data == null) {
180 logger.warn("data was null!!");
181 return null;
182 }
183 // add in cursor, etc from the token name
184 if (base_name != token) {
185 String[] parts = token.split(":");
186 if (parts.length != 4) {
187 // something wrong!!
188 }
189 data.put(OAIXML.CURSOR, parts[1]);
190 data.put(CURRENT_SET, parts[2]);
191 data.put(CURRENT_CURSOR, parts[3]);
192 data.put(INITIAL_TIME, base_name);
193 }
194 return data;
195
196 }
197
198 // used to manually expire a particular token - eg when one of its collections has changed since token was issued.
199 public static void expireToken(String token) {
200 if (token.indexOf(":") != -1) {
201 token = token.substring(0, token.indexOf(":"));
202 }
203 expiration_data.remove(token);
204 stored_tokens.remove(token);
205 }
206 // read through all stored expiry dates, and delete any tokens that are too
207 // old
208 public static void clearExpiredTokens() {
209
210 Set<Map.Entry<String,Long>> token_set = expiration_data.entrySet();
211 Iterator<Map.Entry<String,Long>> i = token_set.iterator();
212 int size = expiration_data.size();
213 logger.info("start tokens "+size);
214 Long time_now = System.currentTimeMillis();
215 while (i.hasNext()==true) {
216 Map.Entry<String,Long> entry = i.next();
217 String key = entry.getKey();
218 Long exp = entry.getValue();
219 if (exp < time_now) {
220 logger.info("token "+key+" is expired, "+ OAIXML.getTime(exp));
221 i.remove();
222 // also remove the token from the stored tokens
223 stored_tokens.remove(key);
224 }
225 }
226 size = expiration_data.size();
227 logger.info("end tokens "+size);
228 }
229
230 protected static boolean findOrCreateTokenFile() {
231
232 try {
233 URL token_file_url = Class.forName("org.greenstone.gsdl3.OAIServer").getClassLoader().getResource("OAIResumptionToken.xml");
234 if (token_file_url != null) {
235 resumption_token_file = new File(token_file_url.toURI());
236 if (resumption_token_file != null && resumption_token_file.exists()) {
237 return true;
238 }
239 else {
240 logger.error("Resumption token file found, "+ token_file_url.toURI()+" but couldn't create a file from it.");
241 }
242 }
243 } catch (Exception e) {
244 logger.error("couldn't find or work with ResumptionToken.xml "+e.getMessage());
245 }
246 // if we have got here, have't managed to load file via class loader -
247 // it may not exist yet.
248 // try and create a new empty one
249 if (resetTokenFile()) {
250 return true;
251 }
252 return false;
253 }
254
255 // If there was no file, or something went wrong with the file, use this to
256 // create a new one.
257 public static boolean resetTokenFile() {
258 resumption_token_file = new File(GlobalProperties.getGSDL3Home() +
259 FILE_SEPARATOR + "WEB-INF" +
260 FILE_SEPARATOR + "classes" +
261 FILE_SEPARATOR + "OAIResumptionToken.xml");
262 try {
263 if (!resumption_token_file.exists()) {
264
265 if (!resumption_token_file.createNewFile()) {
266 logger.error("Couldn't create a new resumption token file "+ resumption_token_file.getPath());
267 resumption_token_file = null;
268 return false;
269 }
270 }
271 } catch (Exception e) {
272 logger.error("Couldn't create a new resumption token file "+ resumption_token_file.getPath()+", "+e.getMessage());
273 resumption_token_file = null;
274 return false;
275 }
276 Document doc = converter.newDOM();
277 Element elem = doc.createElement(TOKEN_LIST);
278 if (converter.writeDOM(elem, resumption_token_file)) {
279 return true;
280 }
281 resumption_token_file = null;
282 return false;
283 }
284
285
286 public static boolean saveTokensToFile() {
287 clearExpiredTokens();
288 if (resumption_token_file == null) {
289 logger.warn("no available resumption token file, not storing tokens");
290 return false;
291 }
292
293 // Create an XML representation of the stored tokens
294 Document doc = converter.newDOM();
295 Element token_list = doc.createElement(TOKEN_LIST);
296
297 if (stored_tokens.size() == 0) {
298 // nothing to store, store an empty file
299 converter.writeDOM(token_list, resumption_token_file);
300 return true;
301 }
302 Set<String> keys = stored_tokens.keySet();
303 Iterator<String> i = keys.iterator();
304 while(i.hasNext()) {
305 String token = i.next();
306 HashMap<String, String> data = stored_tokens.get(token);
307 Element token_elem = doc.createElement(TOKEN);
308 token_elem.setAttribute(NAME, token);
309 token_elem.setAttribute(OAIXML.FROM, data.get(OAIXML.FROM));
310 token_elem.setAttribute(OAIXML.UNTIL, data.get(OAIXML.UNTIL));
311 token_elem.setAttribute(OAIXML.SET, data.get(OAIXML.SET));
312 token_elem.setAttribute(OAIXML.METADATA_PREFIX, data.get(OAIXML.METADATA_PREFIX));
313 token_elem.setAttribute(EXPIRATION, ""+expiration_data.get(token));
314 token_list.appendChild(token_elem);
315 }
316 converter.writeDOM(token_list, resumption_token_file);
317 return true;
318 }
319
320}
Note: See TracBrowser for help on using the repository browser.