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
    private static int documentIdCounter = 0;
65

    
66
	public static AbstractDatabase dbAdapter;
67
    
68
    private static Logger logMetacat = Logger.getLogger(DocumentUtil.class);
69
    private static char separator = '.';
70
    private static String prefix = "autogen";
71
    
72
    static {
73
        try {
74
        	separator = PropertyService.getProperty("document.accNumSeparator").charAt(0);    	
75
        } catch (PropertyNotFoundException pnfe) {
76
        	logMetacat.error("DocumentUtil() - Could not retrieve accession number separator. " 
77
        			+ "Separator set to '.' : " + pnfe.getMessage());
78
        }
79
        try {
80
            prefix = PropertyService.getProperty("document.accNumPrefix");      
81
        } catch (PropertyNotFoundException pnfe) {
82
            logMetacat.error("DocumentUtil() - Could not retrieve accession number prefix. " 
83
                    + "Prefix set to " + prefix + ": " + pnfe.getMessage());
84
        }
85
    }
86

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

    
143

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

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

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

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

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

    
229
        return docId;
230
    }//getDocIdFromString
231

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

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

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

    
269
        return version;
270
    }//getVersionFromString
271

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

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

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

    
308
        return versionString;
309
    }//getVersionFromString
310

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

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

    
344
        return docid;
345
    }
346

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

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

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

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

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

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

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

    
532
        // Create a calendar to get the date formatted properly
533
        String[] ids = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000);
534
        SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids[0]);
535
        pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
536
        pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
537
        Calendar calendar = new GregorianCalendar(pdt);
538
        Date trialTime = new Date();
539
        calendar.setTime(trialTime);
540
        // using yyyymmddhhmmssmmm by convention (zero padding to preserve places)
541
        // will help with looking at logs and especially database tables.
542
        // for each millisecond we can support up to 99 before resetting to 0
543
        // NOTE: if you make it larger, docid is too big for a Long 
544
        if (documentIdCounter > 100) {
545
        	documentIdCounter = 0;
546
        }
547
        docid.append(String.format("%04d%02d%02d%02d%02d%02d%03d%02d",
548
        calendar.get(Calendar.YEAR),
549
        calendar.get(Calendar.MONTH) + 1,  // adjust 0-11 range to 1-12
550
        calendar.get(Calendar.DAY_OF_MONTH),
551
        calendar.get(Calendar.HOUR_OF_DAY),
552
        calendar.get(Calendar.MINUTE),
553
        calendar.get(Calendar.SECOND),
554
        calendar.get(Calendar.MILLISECOND),
555
        documentIdCounter++)
556
        );
557
        if (revision > 0) {
558
            docid.append(".").append(revision);
559
        }
560
        return docid.toString();
561
    }
562
}
(4-4/16)