Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that implements utility methods for a metadata catalog
4
 *  Copyright: 2009 Regents of the University of California and the
5
 *             National Center for Ecological Analysis and Synthesis
6
 *    Authors: Michael Daigle
7
 *
8
 *   '$Author: daigle $'
9
 *     '$Date: 2009-08-04 14:32:58 -0700 (Tue, 04 Aug 2009) $'
10
 * '$Revision: 5015 $'
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 2 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program; if not, write to the Free Software
24
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
 */
26

    
27
package edu.ucsb.nceas.metacat.util;
28

    
29
import java.io.PrintWriter;
30
import java.sql.SQLException;
31
import java.util.Calendar;
32
import java.util.Date;
33
import java.util.GregorianCalendar;
34
import java.util.Hashtable;
35
import java.util.SimpleTimeZone;
36
import java.util.Stack;
37
import java.util.TimeZone;
38
import java.util.Vector;
39

    
40
import javax.servlet.http.HttpServletRequest;
41
import javax.servlet.http.HttpServletResponse;
42

    
43
import org.apache.log4j.Logger;
44

    
45
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
46
import edu.ucsb.nceas.metacat.DBSAXHandler;
47
import edu.ucsb.nceas.metacat.McdbException;
48
import edu.ucsb.nceas.metacat.NodeRecord;
49
import edu.ucsb.nceas.metacat.PermissionController;
50
import edu.ucsb.nceas.metacat.properties.PropertyService;
51
import edu.ucsb.nceas.metacat.service.SessionService;
52
import edu.ucsb.nceas.metacat.shared.MetacatUtilException;
53
import edu.ucsb.nceas.metacat.util.SessionData;
54
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
55
import edu.ucsb.nceas.utilities.ParseLSIDException;
56
import edu.ucsb.nceas.utilities.LSIDUtil;
57

    
58
/**
59
 * A suite of utility classes for the metadata catalog server
60
 */
61
public class DocumentUtil
62
{
63
	
64
    public static AbstractDatabase dbAdapter;
65
    
66
    private static Logger logMetacat = Logger.getLogger(DocumentUtil.class);
67
    private static char separator = '.';
68
    private static String prefix = "autogen";
69
    
70
    static {
71
        try {
72
        	separator = PropertyService.getProperty("document.accNumSeparator").charAt(0);    	
73
        } catch (PropertyNotFoundException pnfe) {
74
        	logMetacat.error("DocumentUtil() - Could not retrieve accession number separator. " 
75
        			+ "Separator set to '.' : " + pnfe.getMessage());
76
        }
77
        try {
78
            prefix = PropertyService.getProperty("document.accNumPrefix");      
79
        } catch (PropertyNotFoundException pnfe) {
80
            logMetacat.error("DocumentUtil() - Could not retrieve accession number prefix. " 
81
                    + "Prefix set to " + prefix + ": " + pnfe.getMessage());
82
        }
83
    }
84

    
85
    /**
86
     * Get docid from online/url string
87
     */
88
    public static String getDocIdWithRevFromOnlineURL(String url)
89
    {
90
        String docid = null;
91
        String DOCID = "docid";
92
        boolean find = false;
93
        char limited = '&';
94
        int count = 0; //keep track how many & was found
95
        Vector list = new Vector();// keep index number for &
96
        if (url == null) {
97
            logMetacat.debug("DocumentUtil.getDocIdWithRevFromOnlineURL - url is null and null will be returned");
98
            return docid;
99
        }
100
        // the first element in list is 0
101
        list.add(new Integer(0));
102
        for (int i = 0; i < url.length(); i++) {
103
            if (url.charAt(i) == limited) {
104
                // count plus 1
105
                count++;
106
                list.add(new Integer(i));
107
                // get substring beween two &
108
                String str = url.substring(
109
                        ((Integer) list.elementAt(count - 1)).intValue(), i);
110
                logMetacat.debug("DocumentUtil.getDocIdWithRevFromOnlineURL - substring between two & is: " + str);
111
                //if the subString contains docid, we got it
112
                if (str.indexOf(DOCID) != -1) {
113
                    //get index of '="
114
                    int start = getIndexForGivenChar(str, '=') + 1;
115
                    int end = str.length();
116
                    docid = str.substring(start, end);
117
                    find = true;
118
                }//if
119
            }//if
120
        }//for
121
        //if not find, we need check the subtring between the index of last &
122
        // and
123
        // the end of string
124
        if (!find) {
125
            logMetacat.debug("DocumentUtil.getDocIdWithRevFromOnlineURL - Checking the last substring");
126
            String str = url.substring(((Integer) list.elementAt(count))
127
                    .intValue() + 1, url.length());
128
            logMetacat.debug("DocumentUtil.getDocIdWithRevFromOnlineURL - Last substring is: " + str);
129
            if (str.indexOf(DOCID) != -1) {
130
                //get index of '="
131
                int start = getIndexForGivenChar(str, '=') + 1;
132
                int end = str.length();
133
                docid = str.substring(start, end);
134
                find = true;
135
            }//if
136
        }//if
137
        logMetacat.debug("DocumentUtil.getDocIdWithRevFromOnlineURL - The docid from online url is:" + docid);
138
        return docid.trim();
139
    }
140

    
141

    
142
    /**
143
     * Eocgorid identifier will look like: ecogrid://knb/tao.1.1
144
     * The AccessionNumber tao.1.1 will be returned. If the given doesn't
145
     * contains ecogrid, null will be returned.
146
     * @param identifier String
147
     * @return String
148
     */
149
    public static String getAccessionNumberFromEcogridIdentifier(String identifier)
150
    {
151
      String accessionNumber = null;
152
      if (identifier != null && identifier.startsWith(DBSAXHandler.ECOGRID))
153
      {
154
        // find the last "/" in identifier
155
        int indexOfLastSlash = identifier.lastIndexOf("/");
156
        int start = indexOfLastSlash+1;
157
        int end   = identifier.length();
158
        accessionNumber = identifier.substring(start, end);
159
      }
160
      logMetacat.info("DocumentUtil.getAccessionNumberFromEcogridIdentifier - The accession number from url is " +
161
                                 accessionNumber);
162
      return accessionNumber;
163
    }
164

    
165
    private static int getIndexForGivenChar(String str, char character)
166
    {
167
        int index = -1;
168
        // make sure str is not null
169
        if (str == null) {
170
            logMetacat.debug("DocumentUtil.getIndexForGivenChar - " +
171
                    "The given str is null and -1 will be returned");
172
            return index;
173
        }
174
        // got though the string
175
        for (int i = 0; i < str.length(); i++) {
176
            // find the first one then break the loop
177
            if (str.charAt(i) == character) {
178
                index = i;
179
                break;
180
            }//if
181
        }//for
182
        logMetacat.info("DocumentUtil.getIndexForGivenChar - the index for char " + 
183
        		character + " is: " + index);
184
        return index;
185
    }
186

    
187
    /**
188
     * Utility method to get docid from a given string
189
     *
190
     * @param string, the given string should be these two format: 1) str1.str2
191
     *            in this case docid= str1.str2 2) str1.str2.str3, in this case
192
     *            docid =str1.str2
193
     * @param the sperator char
194
     */
195
    public static String getDocIdFromString(String str)
196
    {
197
        String docId = null;
198
        if (str == null) {
199
            logMetacat.debug(
200
                    "DocumentUtil.getDocIdFromString - The given str is null and null will be returned"
201
                            + " in getDocIdfromString");
202
            return docId;
203
        } //make sure docid is not null
204
        int dotNumber = 0;//count how many dots in given string
205
        int indexOfLastDot = 0;
206

    
207
        for (int i = 0; i < str.length(); i++) {
208
            if (str.charAt(i) == separator) {
209
                dotNumber++;//count how many dots
210
                indexOfLastDot = i;//keep the last dot postion
211
            }
212
        }//for
213

    
214
        //The string formatt is wrong, because it has more than two or less
215
        // than
216
        //one seperator
217
        if (dotNumber > 2 || dotNumber < 1) {
218
            docId = null;
219
        } else if (dotNumber == 2) //the case for str1.str2.str3
220
        {
221
            docId = str.substring(0, indexOfLastDot);
222
        } else if (dotNumber == 1) //the case for str1.str2
223
        {
224
            docId = str;
225
        }
226

    
227
        return docId;
228
    }//getDocIdFromString
229

    
230
    /**
231
     * Utility method to get version number from a given string
232
     *
233
     * @param string, the given string should be these two format: 1)
234
     *            str1.str2(no version) version =-1; 2) str1.str2.str3, in this
235
     *            case version = str3; 3) other, vresion =-2
236
     */
237
    public static int getVersionFromString(String str)
238
            throws NumberFormatException
239
    {
240
        int version = -1;
241
        String versionString = null;
242
        int dotNumber = 0;//count how many dots in given string
243
        int indexOfLastDot = 0;
244

    
245
        for (int i = 0; i < str.length(); i++) {
246
            if (str.charAt(i) == separator) {
247
                dotNumber++;//count how many dots
248
                indexOfLastDot = i;//keep the last dot postion
249
            }
250
        }//for
251

    
252
        //The string formatt is wrong, because it has more than two or less
253
        // than
254
        //one seperator
255
        if (dotNumber > 2 || dotNumber < 1) {
256
            version = -2;
257
        } else if (dotNumber == 2 && (indexOfLastDot != (str.length() - 1)))
258
        //the case for str1.str2.str3
259
        {
260
            versionString = str.substring((indexOfLastDot + 1), str.length());
261
            version = Integer.parseInt(versionString);
262
        } else if (dotNumber == 1) //the case for str1.str2
263
        {
264
            version = -1;
265
        }
266

    
267
        return version;
268
    }//getVersionFromString
269

    
270
    /**
271
     * Utility method to get version string from a given string
272
     *
273
     * @param string, the given string should be these two format: 1)
274
     *            str1.str2(no version) version=null; 2) str1.str2.str3, in
275
     *            this case version = str3; 3) other, vresion =null;
276
     */
277
    public static String getRevisionStringFromString(String str)
278
            throws NumberFormatException
279
    {
280
        // String to store the version
281
        String versionString = null;
282
        int dotNumber = 0;//count how many dots in given string
283
        int indexOfLastDot = 0;
284

    
285
        for (int i = 0; i < str.length(); i++) {
286
            if (str.charAt(i) == separator) {
287
                dotNumber++;//count how many dots
288
                indexOfLastDot = i;//keep the last dot postion
289
            }
290
        }//for
291

    
292
        //The string formatt is wrong, because it has more than two or less
293
        // than
294
        //one seperator
295
        if (dotNumber > 2 || dotNumber < 1) {
296
            versionString = null;
297
        } else if (dotNumber == 2 && (indexOfLastDot != (str.length() - 1))) {
298
            //the case for str1.str2.str3
299
            // indexOfLastDot != (str.length() -1) means get rid of str1.str2.
300
            versionString = str.substring((indexOfLastDot + 1), str.length());
301
        } else if (dotNumber == 1) //the case for str1.str2 or str1.str2.
302
        {
303
            versionString = null;
304
        }
305

    
306
        return versionString;
307
    }//getVersionFromString
308

    
309
    /**
310
     * This method will get docid from an AccessionNumber. There is no
311
     * assumption the accessnumber will be str1.str2.str3. It can be more. So
312
     * we think the docid will be get rid of last part
313
     */
314
    public static String getDocIdFromAccessionNumber(String accessionNumber)
315
    {
316
        String docid = null;
317
        if (accessionNumber == null) { return docid; }
318
        int indexOfLastSeperator = accessionNumber.lastIndexOf(separator);
319
        docid = accessionNumber.substring(0, indexOfLastSeperator);
320
        logMetacat.debug("DocumentUtil.getDocIdFromAccessionNumber - after parsing accession number, docid is "
321
                + docid);
322
        return docid;
323
    }
324

    
325
    /**
326
     * This method will get inline data id without the revision number.
327
     * So if inlineData.1.2 is passed as input, inlineData.2 is returned.
328
     */
329
    public static String getInlineDataIdWithoutRev(String accessionNumber)
330
    {
331
        String docid = null;
332
        if (accessionNumber == null) { return docid; }
333
        int indexOfLastSeperator = accessionNumber.lastIndexOf(separator);
334
        String version = accessionNumber.substring(indexOfLastSeperator,
335
                                                   accessionNumber.length());
336
        accessionNumber = accessionNumber.substring(0, indexOfLastSeperator);
337
        indexOfLastSeperator = accessionNumber.lastIndexOf(separator);
338
        docid = accessionNumber.substring(0, indexOfLastSeperator) + version;
339
        logMetacat.debug("DocumentUtil.getInlineDataIdWithoutRev - after parsing accessionnumber, docid is "
340
                                 + docid);
341

    
342
        return docid;
343
    }
344

    
345
    /**
346
     * This method will call both getDocIdFromString and
347
     * getDocIdFromAccessionNumber. So first, if the string looks str1.str2,
348
     * the docid will be str1.str2. If the string is str1.str2.str3, the docid
349
     * will be str1.str2. If the string is str1.str2.str3.str4 or more, the
350
     * docid will be str1.str2.str3. If the string look like str1, null will be
351
     * returned
352
     *
353
     */
354
    public static String getSmartDocId(String str)
355
    {
356
        String docid = null;
357
        //call geDocIdFromString first.
358
        docid = getDocIdFromString(str);
359
        // If docid is null, try to call getDocIdFromAccessionNumber
360
        // it will handle the seperator more than2
361
        if (docid == null) {
362
            docid = getDocIdFromAccessionNumber(str);
363
        }
364
        logMetacat.debug("DocumentUtil.getSmartDocId - The docid get from smart docid getor is "
365
                + docid);
366
        return docid;
367
    }
368

    
369
    /**
370
     * This method will get revision from an AccessionNumber. There is no
371
     * assumption the accessnumber will be str1.str2.str3. It can be more. So
372
     * we think the docid will be get rid of last part
373
     */
374
    public static int getRevisionFromAccessionNumber(String accessionNumber)
375
            throws NumberFormatException
376
    {
377
        String rev = null;
378
        int revNumber = -1;
379
        if (accessionNumber == null) { return revNumber; }
380
        int indexOfLastSeperator = accessionNumber.lastIndexOf(separator);
381
        rev = accessionNumber.substring(indexOfLastSeperator + 1,
382
                accessionNumber.length());
383
        revNumber = Integer.parseInt(rev);
384
        logMetacat.debug("DocumentUtil.getRevisionFromAccessionNumber - after parsing accessionnumber, rev is "
385
                + revNumber);
386
        return revNumber;
387
    }
388

    
389
    /**
390
     * Method to get docidwithrev from eml2 inline data id The eml inline data
391
     * id would look like eml.200.2.3
392
     */
393
    public static String getDocIdWithoutRevFromInlineDataID(String inlineDataID)
394
    {
395
        String docidWithoutRev = null;
396
        if (inlineDataID == null) { return docidWithoutRev; }
397
        char charSeperator = separator;
398
        int targetNumberOfSeperator = 2;// we want to know his index
399
        int numberOfSeperator = 0;
400
        for (int i = 0; i < inlineDataID.length(); i++) {
401
            // meet seperator, increase number of seperator
402
            if (inlineDataID.charAt(i) == charSeperator) {
403
                numberOfSeperator++;
404
            }
405
            // if number of seperator reach the target one, record the index(i)
406
            // and get substring and terminate the loop
407
            if (numberOfSeperator == targetNumberOfSeperator) {
408
                docidWithoutRev = inlineDataID.substring(0, i);
409
                break;
410
            }
411
        }
412

    
413
        logMetacat.debug("DocumentUtil.getDocIdWithoutRevFromInlineDataID - Docid without rev from inlinedata id: "
414
                + docidWithoutRev);
415
        return docidWithoutRev;
416

    
417
    }
418
    
419
    /**
420
     * Revise stack change a stack to opposite order
421
     */
422
    public static Stack<NodeRecord> reviseStack(Stack<NodeRecord> stack)
423
    {
424
        Stack result = new Stack();
425
        // make sure the parameter is correct
426
        if (stack == null || stack.isEmpty()) {
427
            result = stack;
428
            return result;
429
        }
430

    
431
        while (!stack.isEmpty()) {
432
            Object obj = stack.pop();
433
            result.push(obj);
434
        }
435
        return result;
436
    }
437
    
438
    public static void isAuthorized(PrintWriter out, Hashtable<String,String[]> params, 
439
    		HttpServletRequest request, HttpServletResponse response) throws MetacatUtilException {
440
    	
441
    	String resourceLsid;
442
    	String[] resourceLsids = params.get("resourceLsid");
443
    	if (resourceLsids == null) {
444
    		throw new MetacatUtilException("DocumentUtil.isAuthorized - " + 
445
    				"resourceLsid parameter cannot be null.");
446
    	}
447
    	resourceLsid = resourceLsids[0];
448
    	 
449
    	String permission;
450
    	String[] permissions = params.get("permission");
451
    	if (permissions == null) {
452
    		throw new MetacatUtilException("DocumentUtil.isAuthorized - " + 
453
    				"permission parameter cannot be null.");
454
    	}
455
    	permission = permissions[0];
456
    	
457
    	String sessionId;
458
    	String[] sessionIds = params.get("sessionId");
459
    	if (sessionIds == null) {
460
    		throw new MetacatUtilException("DocumentUtil.isAuthorized - " + 
461
    				"sessionId parameter cannot be null.");
462
    	}
463
    	sessionId = sessionIds[0];
464
    	
465
    	String isAuthorized = "false";
466
    	String message = "";
467
    	
468
    	String result = "<resourceAuthorization>";
469
    	result += "<resourceId>" + resourceLsid + "</resourceId>"; 
470
    	result += "<permission>" + permission + "</permission>";
471
    	result += "<sessionId>" + sessionId + "</sessionId>";
472

    
473
    	if (!SessionService.isSessionRegistered(sessionId)) {
474
    		message = "Session is not logged in";
475
    	} else {
476
    		SessionData sessionData = SessionService.getRegisteredSession(sessionId);
477
    		
478
    		String docId = null;
479
    		try {
480
    			docId = LSIDUtil.getDocId(resourceLsid, true);
481
    			PermissionController pc = new PermissionController(docId);   
482
    			if (pc.hasPermission(sessionData.getUserName(), sessionData.getGroupNames(), permission)) {
483
    				isAuthorized = "true";
484
    				message = " docid: " + docId + " is authorized for session";
485
    			}
486
    		} catch (ParseLSIDException ple) {
487
    			message = "unparseable resource lsid: " + ple.getMessage();
488
    		} catch (McdbException me) {
489
    			message = "could not create permission controller for docid: " + docId + " : " + me.getMessage();
490
    		} catch (SQLException sqle) {
491
    			message = "SQL error getting permissions for docid: " + docId + " : " + sqle.getMessage();
492
    		}
493
    	}
494
    	
495
    	result += "<isAuthorized>" + isAuthorized + "</isAuthorized>";
496
    	result += "<message>" + message + "</message>";
497
    	result += "</resourceAuthorization>";
498
    	
499
    	out.write(result);
500
    }
501
    
502
    /**
503
     * Create a unique docid for use in inserts and updates using the default
504
     * prefix from the document.accNumPrefix property. Does not include the 
505
     * 'revision' part of the id if revision is '0', otherwise sets the 
506
     * revision number to 'revision'.
507
     * 
508
     * @param idPrefix the prefix to be used to construct the scope portion of the docid
509
     * @param revision the integer revision to use for this docid
510
     * @return a String docid based on the current date and time
511
     */
512
    public static String generateDocumentId(int revision) {
513
        return generateDocumentId(prefix, revision);
514
    }
515
    
516
    /**
517
     * Create a unique docid for use in inserts and updates using the prefix
518
     * that is provided. Does not include the 'revision' part of the id if 
519
     * revision is '0', otherwise sets the revision number to 'revision'.
520
     * 
521
     * @param idPrefix the prefix to be used to construct the scope portion of the docid
522
     * @param revision the integer revision to use for this docid
523
     * @return a String docid based on the current date and time
524
     */
525
    public static String generateDocumentId(String idPrefix, int revision)
526
    {
527
        StringBuffer docid = new StringBuffer(idPrefix);
528
        docid.append(".");
529

    
530
        // Create a calendar to get the date formatted properly
531
        String[] ids = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000);
532
        SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids[0]);
533
        pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
534
        pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
535
        Calendar calendar = new GregorianCalendar(pdt);
536
        Date trialTime = new Date();
537
        calendar.setTime(trialTime);
538
        docid.append(calendar.get(Calendar.YEAR));
539
        docid.append(calendar.get(Calendar.DAY_OF_YEAR));
540
        docid.append(calendar.get(Calendar.HOUR_OF_DAY));
541
        docid.append(calendar.get(Calendar.MINUTE));
542
        docid.append(calendar.get(Calendar.SECOND));
543
        docid.append(calendar.get(Calendar.MILLISECOND));
544

    
545
        if (revision > 0) {
546
            docid.append(".").append(revision);
547
        }
548
        return docid.toString();
549
    }
550
}
(4-4/14)