Project

General

Profile

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

    
25
package edu.ucsb.nceas.metacat.client;
26

    
27
import java.io.InputStream;
28
import java.io.InputStreamReader;
29
import java.io.PushbackReader;
30
import java.io.StringReader;
31
import java.io.IOException;
32
import java.io.StringWriter;
33
import java.io.Reader;
34
import java.net.URL;
35
import java.util.Properties;
36
import java.util.Vector;
37
import javax.servlet.http.HttpServletRequest;
38
import javax.xml.xpath.XPath;
39
import javax.xml.xpath.XPathFactory;
40
import org.w3c.dom.Document;
41

    
42
import org.w3c.dom.Node;
43
import org.w3c.dom.NodeList;
44

    
45
import edu.ucsb.nceas.utilities.HttpMessage;
46
import edu.ucsb.nceas.utilities.IOUtil;
47
import edu.ucsb.nceas.utilities.XMLUtilities;
48
import java.io.File;
49

    
50
/**
51
 *  This interface provides methods for initializing and logging in to a
52
 *  Metacat server, and then querying, reading, transforming, inserting,
53
 *  updating and deleting documents from that server.
54
 */
55
public class MetacatClient implements Metacat {
56
    /** The URL string for the metacat server */
57
    private String metacatUrl;
58
    
59
    /** The session identifier for the session */
60
    private String sessionId;
61
    
62
    /**
63
     * The Login cookie name.
64
     */
65
    public final static String                    LOGIN_COOOKIE = "cookie";
66
    
67
    /**
68
     * Constructor to create a new instance. Protected because instances
69
     * should only be created by the factory MetacatFactory.
70
     */
71
    protected MetacatClient() {
72
        this.metacatUrl = null;
73
        this.sessionId = null;
74
    }
75
    
76
    /**
77
     *  Method used to log in to a metacat server. Implementations will need
78
     *  to cache a cookie value to make the session persistent.  Each time a
79
     *  call is made to one of the other methods (e.g., read), the cookie will
80
     *  need to be passed back to the metacat server along with the request.
81
     *
82
     *  @param username   the username of the user, like an LDAP DN
83
     *  @param password   the password for that user for authentication
84
     *  @return the response string from metacat in XML format
85
     *  @throws MetacatAuthException when the username/password could
86
     *                    not be authenticated
87
     */
88
    public String login(String username, String password)
89
    throws MetacatAuthException, MetacatInaccessibleException {
90
        Properties prop = new Properties();
91
        prop.put("action", "login");
92
        prop.put("qformat", "xml");
93
        prop.put("username", username);
94
        prop.put("password", password);
95
        
96
        String response = null;
97
        try {
98
            response = sendDataForString(prop, null, null, 0);
99
        } catch (Exception e) {
100
            throw new MetacatInaccessibleException(e.getMessage());
101
        }
102
        
103
        if (response.indexOf("<login>") == -1) {
104
            setSessionId("");
105
            throw new MetacatAuthException(response);
106
        } else {
107
            int start = response.indexOf("<sessionId>") + 11;
108
            int end = response.indexOf("</sessionId>");
109
            if ((start != -1) && (end != -1)) {
110
                setSessionId(response.substring(start,end));
111
            }
112
        }
113
        return response;
114
    }
115
    
116
    /**
117
     *  Method used to log in to a metacat server. Implementations will need
118
     *  to cache a cookie value to make the session persistent.  Each time a
119
     *  call is made to one of the other methods (e.g., read), the cookie will
120
     *  need to be passed back to the metacat server along with the request.
121
     *
122
     *  @param username   the username of the user, like an LDAP DN
123
     *  @param password   the password for that user for authentication
124
     *  @return the response string from metacat in XML format
125
     *  @throws MetacatAuthException when the username/password could
126
     *                    not be authenticated
127
     */
128
    public String getloggedinuserinfo() throws MetacatInaccessibleException {
129
        Properties prop = new Properties();
130
        prop.put("action", "getloggedinuserinfo");
131
        prop.put("qformat", "xml");
132
        
133
        String response = null;
134
        try {
135
            response = sendDataForString(prop, null, null, 0);
136
        } catch (Exception e) {
137
            throw new MetacatInaccessibleException(e.getMessage());
138
        }
139
        
140
        return response;
141
    }
142
    
143
    /**
144
     *  Method used to log out a metacat server. The Metacat server will end
145
     *  the session when this call is invoked.
146
     *
147
     *  @return the response string from metacat in XML format
148
     *  @throws MetacatInaccessibleException when the metacat server can not be
149
     *                                    reached or does not respond
150
     */
151
    public String logout() throws MetacatInaccessibleException, MetacatException {
152
        Properties prop = new Properties();
153
        prop.put("action", "logout");
154
        prop.put("qformat", "xml");
155
        
156
        String response = null;
157
        try {
158
            response = sendDataForString(prop, null, null, 0);
159
        } catch (Exception e) {
160
            throw new MetacatInaccessibleException(e.getMessage());
161
        }
162
        
163
        if (response.indexOf("<logout>") == -1) {
164
            throw new MetacatException(response);
165
        }
166
        setSessionId("");
167
        return response;
168
    }
169
    
170
    /**
171
     * Read an XML document from the metacat server session, accessed by docid,
172
     * and returned as a Reader.
173
     *
174
     * @param docid the identifier of the document to be read
175
     * @return a Reader for accessing the document
176
     * @throws InsufficientKarmaException when the user has insufficent rights
177
     *                                    for the operation
178
     * @throws MetacatInaccessibleException when the metacat server can not be
179
     *                                    reached or does not respond
180
     * @throws MetacatException when the metacat server generates another error
181
     */
182
    public Reader read(String docid) throws InsufficientKarmaException,
183
            MetacatInaccessibleException, MetacatException, DocumentNotFoundException {
184
        PushbackReader pbr = null;
185
        
186
        Properties prop = new Properties();
187
        prop.put("action", "read");
188
        prop.put("qformat", "xml");
189
        prop.put("docid", docid);
190
        InputStream response = null;
191
        try {
192
            response = sendData(prop, null, null, 0);
193
        } catch (Exception e) {
194
            throw new MetacatInaccessibleException(e.getMessage());
195
        }
196
        pbr = new PushbackReader(new InputStreamReader(response), 512);
197
        try {
198
            char[] characters = new char[512];
199
            int len = pbr.read(characters, 0, 512);
200
            StringWriter sw = new StringWriter();
201
            sw.write(characters, 0, len);
202
            String message = sw.toString();
203
            sw.close();
204
            pbr.unread(characters, 0, len);
205
            if (message.indexOf("<error>") != -1) {
206
                if (message.indexOf("does not have permission") != -1) {
207
                    throw new InsufficientKarmaException(message);
208
                } else if(message.indexOf("does not exist") != -1) {
209
                    throw new DocumentNotFoundException(message);
210
                } else {
211
                    throw new MetacatException(message);
212
                }
213
            }
214
        } catch (IOException ioe) {
215
            throw new MetacatException(
216
                    "MetacatClient: Error converting Reader to String."
217
                    + ioe.getMessage());
218
        }
219
        return pbr;
220
    }
221
    
222
    
223
    /**
224
     * Read inline data from the metacat server session, accessed by
225
     * inlinedataid and returned as a Reader.
226
     *
227
     * @param inlinedataid the identifier of the data to be read
228
     * @return a Reader for accessing the document
229
     * @throws InsufficientKarmaException when the user has insufficent rights
230
     *                                    for the operation
231
     * @throws MetacatInaccessibleException when the metacat server can not be
232
     *                                    reached or does not respond
233
     * @throws MetacatException when the metacat server generates another error
234
     */
235
    public Reader readInlineData(String inlinedataid)
236
    throws InsufficientKarmaException,
237
            MetacatInaccessibleException, MetacatException {
238
        PushbackReader pbr = null;
239
        
240
        Properties prop = new Properties();
241
        prop.put("action", "readinlinedata");
242
        prop.put("inlinedataid", inlinedataid);
243
        
244
        InputStream response = null;
245
        try {
246
            response = sendData(prop, null, null, 0);
247
        } catch (Exception e) {
248
            throw new MetacatInaccessibleException(e.getMessage());
249
        }
250
        
251
        pbr = new PushbackReader(new InputStreamReader(response), 512);
252
        try {
253
            char[] characters = new char[512];
254
            int len = pbr.read(characters, 0, 512);
255
            StringWriter sw = new StringWriter();
256
            sw.write(characters, 0, len);
257
            String message = sw.toString();
258
            sw.close();
259
            pbr.unread(characters, 0, len);
260
            
261
            if (message.indexOf("<error>") != -1) {
262
                if (message.indexOf("does not have permission") != -1) {
263
                    throw new InsufficientKarmaException(message);
264
                } else {
265
                    throw new MetacatException(message);
266
                }
267
            }
268
        } catch (IOException ioe) {
269
            throw new MetacatException(
270
                    "MetacatClient: Error converting Reader to String."
271
                    + ioe.getMessage());
272
        }
273
        
274
        return pbr;
275
    }
276
    
277
    /**
278
     * Query the metacat document store with the given metacat-compatible
279
     * query document and default qformat xml, and return the result set as a Reader.
280
     *
281
     * @param xmlQuery a Reader for accessing the XML version of the query
282
     * @return a Reader for accessing the result set
283
     */
284
    public Reader query(Reader xmlQuery) throws MetacatInaccessibleException,
285
            IOException {
286
        String qformat = "xml";
287
        return query(xmlQuery, qformat);
288
    }
289
    
290
    /**
291
     * Query the metacat document store with the given metacat-compatible
292
     * query document and qformat, and return the result set as a Reader.
293
     *
294
     * @param xmlQuery a Reader for accessing the XML version of the query
295
     * @param qformat the format of return doc. It can be xml, knb, lter and etal.
296
     * @return a Reader for accessing the result set
297
     */
298
    public Reader query(Reader xmlQuery, String qformat) throws MetacatInaccessibleException,
299
            IOException {
300
        Reader reader = null;
301
        String query = null;
302
        try {
303
            query = IOUtil.getAsString(xmlQuery, true);
304
        } catch (IOException ioE) {
305
            throw ioE;
306
        }
307
        
308
        //set up properties
309
        Properties prop = new Properties();
310
        prop.put("action", "squery");
311
        prop.put("qformat", qformat);
312
        prop.put("query", query);
313
        
314
        InputStream response = null;
315
        try {
316
            response = sendData(prop, null, null, 0);
317
        } catch (Exception e) {
318
            throw new MetacatInaccessibleException(e.getMessage());
319
        }
320
        reader = new InputStreamReader(response);
321
        return reader;
322
    }
323
    
324
    /**
325
     * Insert an XML document into the repository.
326
     *
327
     * @param docid the docid to insert the document
328
     * @param xmlDocument a Reader for accessing the XML document to be inserted
329
     * @param schema a Reader for accessing the DTD or XML Schema for
330
     *               the document
331
     * @return the metacat response message
332
     * @throws InsufficientKarmaException when the user has insufficent rights
333
     *                                    for the operation
334
     * @throws MetacatInaccessibleException when the metacat server can not be
335
     *                                    reached or does not respond
336
     * @throws MetacatException when the metacat server generates another error
337
     * @throws IOException when there is an error reading the xml document
338
     */
339
    public String insert(String docid, Reader xmlDocument, Reader schema)
340
    throws InsufficientKarmaException, MetacatException, IOException,
341
            MetacatInaccessibleException {
342
        Reader reader = null;
343
        String doctext = null;
344
        String schematext = null;
345
        try {
346
            doctext = IOUtil.getAsString(xmlDocument, true);
347
            if (schema != null) {
348
                schematext = IOUtil.getAsString(schema, true);
349
            }
350
        } catch (IOException ioE) {
351
            throw ioE;
352
        }
353
        
354
        //set up properties
355
        Properties prop = new Properties();
356
        prop.put("action", "insert");
357
        prop.put("docid", docid);
358
        prop.put("doctext", doctext);
359
        if (schematext != null) {
360
            prop.put("dtdtext", schematext);
361
        }
362
        
363
        String response = null;
364
        try {
365
            response = sendDataForString(prop, null, null, 0);
366
        } catch (Exception e) {
367
            throw new MetacatInaccessibleException(e.getMessage());
368
        }
369
        
370
        // Check for an error condition
371
        if (response.indexOf("<error>") != -1) {
372
            if (response.indexOf("does not have permission") != -1) {
373
                throw new InsufficientKarmaException(response);
374
            } else {
375
                throw new MetacatException(response);
376
            }
377
        }
378
        
379
        return response;
380
    }
381
    
382
    /**
383
     * Update an XML document in the repository.
384
     *
385
     * @param docid the docid to update
386
     * @param xmlDocument a Reader for accessing the XML text to be updated
387
     * @param schema a Reader for accessing the DTD or XML Schema for
388
     *               the document
389
     * @return the metacat response message
390
     * @throws InsufficientKarmaException when the user has insufficent rights
391
     *                                    for the operation
392
     * @throws MetacatInaccessibleException when the metacat server can not be
393
     *                                    reached or does not respond
394
     * @throws MetacatException when the metacat server generates another error
395
     * @throws IOException when there is an error reading the xml document
396
     */
397
    public String update(String docid, Reader xmlDocument, Reader schema)
398
    throws InsufficientKarmaException, MetacatException, IOException,
399
            MetacatInaccessibleException {
400
        Reader reader = null;
401
        String doctext = null;
402
        String schematext = null;
403
        try {
404
            doctext = IOUtil.getAsString(xmlDocument, true);
405
            if (schema != null) {
406
                schematext = IOUtil.getAsString(schema, true);
407
            }
408
        } catch (IOException ioE) {
409
            throw ioE;
410
        }
411
        
412
        //set up properties
413
        Properties prop = new Properties();
414
        prop.put("action", "update");
415
        prop.put("docid", docid);
416
        prop.put("doctext", doctext);
417
        if (schematext != null) {
418
            prop.put("dtdtext", schematext);
419
        }
420
        
421
        String response = null;
422
        try {
423
            response = sendDataForString(prop, null, null, 0);
424
        } catch (Exception e) {
425
            throw new MetacatInaccessibleException(e.getMessage());
426
        }
427
        
428
        // Check for an error condition
429
        if (response.indexOf("<error>") != -1) {
430
            if (response.indexOf("does not have permission") != -1) {
431
                throw new InsufficientKarmaException(response);
432
            } else {
433
                throw new MetacatException(response);
434
            }
435
        }
436
        
437
        return response;
438
    }
439
    
440
    /**
441
     * Upload a data document into the repository.
442
     *
443
     * @param docid the docid to insert the document
444
     * @param document a Reader for accessing the document to be uploaded
445
     * @return the metacat response message
446
     * @throws InsufficientKarmaException when the user has insufficent rights
447
     *                                    for the operation
448
     * @throws MetacatInaccessibleException when the metacat server can not be
449
     *                                    reached or does not respond
450
     * @throws MetacatException when the metacat server generates another error
451
     * @throws IOException when there is an error reading the xml document
452
     */
453
    public String upload(String docid, File file)
454
    throws InsufficientKarmaException, MetacatException, IOException,
455
            MetacatInaccessibleException {
456
        
457
        URL url = new URL(metacatUrl.trim());
458
        HttpMessage msg = new HttpMessage(url);
459
        //set up properties
460
        Properties arg = new Properties();
461
        arg.put("action", "upload");
462
        arg.put("docid", docid);
463
        
464
        Properties filenames = new Properties();
465
        String filename = file.getAbsolutePath();
466
        filenames.put("datafile", filename);
467
        
468
        String response = null;
469
        try {
470
            response = sendDataForString(arg, filenames, null, 0);
471
        } catch (Exception e) {
472
            throw new MetacatInaccessibleException(e.getMessage());
473
        }
474
        
475
        // Check for an error condition
476
        if (response.indexOf("<error>") != -1) {
477
            if (response.indexOf("does not have permission") != -1) {
478
                throw new InsufficientKarmaException(response);
479
            } else {
480
                throw new MetacatException(response);
481
            }
482
        }
483
        
484
        return response;
485
    }
486
    
487
    /**
488
     * Upload a data document into the repository.
489
     *
490
     * @param docid the docid to insert the document
491
     * @param document a Reader for accessing the document to be uploaded
492
     * @return the metacat response message
493
     * @throws InsufficientKarmaException when the user has insufficent rights
494
     *                                    for the operation
495
     * @throws MetacatInaccessibleException when the metacat server can not be
496
     *                                    reached or does not respond
497
     * @throws MetacatException when the metacat server generates another error
498
     * @throws IOException when there is an error reading the xml document
499
     */
500
    
501
    
502
    public String upload(String docid, String filename, InputStream fileData,
503
            int size)
504
            throws InsufficientKarmaException, MetacatException, IOException,
505
            MetacatInaccessibleException {
506
        
507
        URL url = new URL(metacatUrl.trim());
508
        HttpMessage msg = new HttpMessage(url);
509
        //set up properties
510
        Properties arg = new Properties();
511
        arg.put("action", "upload");
512
        arg.put("docid", docid);
513
        
514
        Properties filenames = new Properties();
515
        filenames.put("datafile", filename);
516
        
517
        String response = null;
518
        try {
519
            response = sendDataForString(arg, filenames, fileData, size);
520
        } catch (Exception e) {
521
            throw new MetacatInaccessibleException(e.getMessage());
522
        }
523
        
524
        // Check for an error condition
525
        if (response.indexOf("<error>") != -1) {
526
            if (response.indexOf("does not have permission") != -1) {
527
                throw new InsufficientKarmaException(response);
528
            } else {
529
                throw new MetacatException(response);
530
            }
531
        }
532
        
533
        return response;
534
    }
535
    
536
    /**
537
     * Delete an XML document in the repository.
538
     *
539
     * @param docid the docid to delete
540
     * @return the metacat response message
541
     * @throws InsufficientKarmaException when the user has insufficent rights
542
     *                                    for the operation
543
     * @throws MetacatInaccessibleException when the metacat server can not be
544
     *                                    reached or does not respond
545
     * @throws MetacatException when the metacat server generates another error
546
     */
547
    public String delete(String docid)
548
    throws InsufficientKarmaException, MetacatException,
549
            MetacatInaccessibleException {
550
        //set up properties
551
        Properties prop = new Properties();
552
        prop.put("action", "delete");
553
        prop.put("docid", docid);
554
        
555
        String response = null;
556
        try {
557
            response = sendDataForString(prop, null, null, 0);
558
        } catch (Exception e) {
559
            throw new MetacatInaccessibleException(e.getMessage());
560
        }
561
        
562
        // Check for an error condition
563
        if (response.indexOf("<error>") != -1) {
564
            if (response.indexOf("does not have permission") != -1) {
565
                throw new InsufficientKarmaException(response);
566
            } else {
567
                throw new MetacatException(response);
568
            }
569
        }
570
        return response;
571
    }
572
    
573
    
574
    /**
575
     * set the access on an XML document in the repository.
576
     *
577
     * @param _docid the docid of the document for which the access should be applied.
578
     *
579
     * @param _principal the document's principal
580
     *
581
     * @param _permission the access permission to be applied to the docid
582
     *  {e.g. read,write,all}
583
     *
584
     * @param _permType the permission type to be applied to the document
585
     *  {e.g. allow or deny}
586
     *
587
     * @param _permOrder the order that the document's permissions should be
588
     *  processed {e.g. denyFirst or allowFirst}
589
     *
590
     *
591
     * @return the metacat response message
592
     *
593
     * @throws InsufficientKarmaException when the user has insufficent rights
594
     *                                    for the operation
595
     * @throws MetacatInaccessibleException when the metacat server can not be
596
     *                                    reached or does not respond
597
     * @throws MetacatException when the metacat server generates another error
598
     */
599
    public String setAccess(String _docid, String _principal, String
600
            _permission, String _permType,
601
            String _permOrder )
602
            throws InsufficientKarmaException, MetacatException,
603
            MetacatInaccessibleException {
604
        //set up properties
605
        Properties prop = new Properties();
606
        prop.put("action", "setaccess");
607
        prop.put("docid", _docid);
608
        prop.put("principal", _principal);
609
        prop.put("permission", _permission);
610
        prop.put("permType", _permType);
611
        prop.put("permOrder", _permOrder);
612
        
613
        String response = null;
614
        try {
615
            response = sendDataForString(prop, null, null, 0);
616
        } catch (Exception e) {
617
            throw new MetacatInaccessibleException(e.getMessage());
618
        }
619
        
620
        // Check for an error condition
621
        if (response.indexOf("<error>") != -1) {
622
            if (response.indexOf("does not have permission") != -1) {
623
                throw new InsufficientKarmaException(response);
624
            } else {
625
                throw new MetacatException(response);
626
            }
627
        }
628
        return response;
629
    }
630
    
631
    /**
632
     * When the MetacatFactory creates an instance it needs to set the
633
     * MetacatUrl to which connections should be made.
634
     *
635
     * @param metacatUrl the URL for the metacat server
636
     */
637
    public void setMetacatUrl(String metacatUrl) {
638
        this.metacatUrl = metacatUrl;
639
    }
640
    
641
    /**
642
     * Get the session identifier for this session.  This is only valid if
643
     * the login methods has been called successfully for this Metacat object
644
     * beforehand.
645
     *
646
     * @returns the sessionId as a String, or null if the session is invalid
647
     */
648
    public String getSessionId() {
649
        return this.sessionId;
650
    }
651
    
652
    /**
653
     * Set the session identifier for this session.  This identifier was
654
     * previously established with a call to login.  To continue to use the
655
     * same session, set the session id before making a call to one of the
656
     * metacat access methods (e.g., read, query, insert, etc.).
657
     *
658
     * @param String the sessionId from a previously established session
659
     */
660
    public void setSessionId(String sessionId) {
661
        this.sessionId = sessionId;
662
    }
663
    
664
    /**
665
     * The method will return the latest revision in metacat server
666
     * for a given document id. If some error happens, this method will throw
667
     * an exception.
668
     * @param docId String  the given docid you want to use. the docid it self
669
     *                      can have or haven't revision number
670
     * @throws MetacatException
671
     */
672
    public int getNewestDocRevision(String docId) throws MetacatException {
673
        int rev = 0;
674
        //set up properties
675
        Properties prop = new Properties();
676
        prop.put("action", "getrevisionanddoctype");
677
        prop.put("docid", docId);
678
        
679
        String response = null;
680
        try {
681
            response = sendDataForString(prop, null, null, 0);
682
            //parseRevisionResponse will return null if there is an
683
            //error that it can't handle
684
            String revStr = parserRevisionResponse(response);
685
            Integer revObj = new Integer(revStr);
686
            rev = revObj.intValue();
687
            // Check for an error condition
688
            if (response.indexOf("<error>") != -1 && revStr == null) {
689
                throw new MetacatException(response);
690
            }
691
        } catch (Exception e) {
692
            throw new MetacatException(e.getMessage());
693
        }
694
        return rev;
695
    }
696
    
697
    /**
698
     * Return the highest document id for a given scope.  This is used by
699
     * clients to make it easier to determine the next free identifier in a
700
     * sequence for a given scope.
701
     * @param scope String  the scope to use for looking up the latest id
702
     * @throws MetacatException when an error occurs
703
     */
704
    public String getLastDocid(String scope) throws MetacatException {
705
        String lastIdentifier = "";
706
        //set up properties
707
        Properties prop = new Properties();
708
        prop.put("action", "getlastdocid");
709
        prop.put("scope", scope);
710
        
711
        String response = null;
712
        try {
713
            response = sendDataForString(prop, null, null, 0);
714
            // Check for an error condition
715
            if (response.indexOf("<error>") != -1) {
716
                throw new MetacatException(response);
717
            } else {
718
                Reader responseReader = new StringReader(response);
719
                Node root =
720
                        XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
721
                Node docidNode =
722
                        XMLUtilities.getNodeWithXPath(root, "/lastDocid/docid");
723
                lastIdentifier = docidNode.getFirstChild().getNodeValue();
724
            }
725
        } catch (Exception e) {
726
            throw new MetacatException(e.getMessage());
727
        }
728
        return lastIdentifier;
729
    }
730
    
731
    /**
732
     * return a list of all docids that match a given scope.  if scope is null
733
     * return all docids registered in the system
734
     * @param scope String  the scope to use to limit the docid query
735
     * @throws MetacatException when an error occurs
736
     */
737
    public Vector getAllDocids(String scope) throws MetacatException {
738
        Vector resultVec = new Vector();
739
        //set up properties
740
        Properties prop = new Properties();
741
        prop.put("action", "getalldocids");
742
        if(scope != null) {
743
            prop.put("scope", scope);
744
        }
745
        
746
        String response = null;
747
        try {
748
            response = sendDataForString(prop, null, null, 0);
749
            // Check for an error condition
750
            if (response.indexOf("<error>") != -1) {
751
                throw new MetacatException(response);
752
            } else {
753
                Reader responseReader = new StringReader(response);
754
                Node root =
755
                        XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
756
                NodeList nlist = root.getChildNodes();
757
                for(int i=0; i<nlist.getLength(); i++) {
758
                    Node n = nlist.item(i);
759
                    if(n.getNodeName().equals("docid")) {
760
                        //add the content to the return vector
761
                        String nodeVal = n.getFirstChild().getNodeValue();
762
                        resultVec.addElement(nodeVal);
763
                    }
764
                }
765
                
766
            }
767
        } catch (Exception e) {
768
            throw new MetacatException(e.getMessage());
769
        }
770
        return resultVec;
771
    }
772
    
773
    /**
774
     * return true of the given docid is registered, false if not
775
     * @param scope String  the scope to use to limit the docid query
776
     * @throws MetacatException when an error occurs
777
     */
778
    public boolean isRegistered(String docid) throws MetacatException {
779
        Vector resultVec = new Vector();
780
        //set up properties
781
        Properties prop = new Properties();
782
        prop.put("action", "isregistered");
783
        if(docid == null) {
784
            throw new MetacatException("<error>Cannot check if a null docid " +
785
                    "is registered.</error>");
786
        }
787
        prop.put("docid", docid);
788
        
789
        String response = null;
790
        try {
791
            response = sendDataForString(prop, null, null, 0);
792
            // Check for an error condition
793
            if (response.indexOf("<error>") != -1) {
794
                throw new MetacatException(response);
795
            } else {
796
                Reader responseReader = new StringReader(response);
797
                StringBuffer sb = new StringBuffer();
798
                char[] c = new char[1024];
799
                int numread = responseReader.read(c, 0, 1024);
800
                while(numread != -1) {
801
                    sb.append(new String(c, 0, numread));
802
                    numread = responseReader.read(c, 0, 1024);
803
                }
804
                
805
                String responseStr = sb.toString();
806
                if(responseStr.indexOf("true") != -1) {
807
                    return true;
808
                }
809
                return false;
810
            }
811
        } catch (Exception e) {
812
            throw new MetacatException(e.getMessage());
813
        }
814
    }
815
    
816
    /************************************************************************
817
     * PRIVATE METHODS
818
     ************************************************************************/
819
    
820
    /**
821
     * Send a request to metacat.
822
     *
823
     * @param prop the properties to be URL encoded and sent
824
     * @param filename  the properties to be sent to Metacat
825
     *                  in case of upload, otherwise null
826
     * @param fileData  the inputStream for the file data to be sent to Metacat
827
     *                  in case of upload, otherwise null
828
     * @param size      the size of the data being sent to Metacat
829
     *                  in case of upload, otherwise 0
830
     */
831
    synchronized private InputStream sendDataOnce(Properties args,
832
            Properties filename,
833
            InputStream fileData,
834
            int size)
835
            throws Exception {
836
        InputStream returnStream = null;
837
        URL url = new URL(metacatUrl);
838
        HttpMessage msg = new HttpMessage(url);
839
        msg.setCookie("JSESSIONID="+this.sessionId);
840
        if (filename == null){
841
            returnStream = msg.sendPostData(args);
842
        } else if (fileData == null){
843
            returnStream = msg.sendPostData(args, filename);
844
        } else if (size > 0) {
845
            returnStream = msg.sendPostData(args, filename, fileData, size);
846
        } else {
847
            throw new MetacatException("Invalid size specified for " +
848
                    "the input stream being passed");
849
        }
850
        return returnStream;
851
    }
852
    
853
    /**
854
     * Send a request to Metacat
855
     *
856
     * @param args  the properties to be sent to Metacat
857
     * @param filename  the properties to be sent to Metacat
858
     *                  in case of upload, otherwise null
859
     * @param fileData  the inputStream for the file data to be sent to Metacat
860
     *                  in case of upload, otherwise null
861
     * @param size      the size of the data being sent to Metacat
862
     *                  in case of upload, otherwise 0
863
     * @return      InputStream as returned by Metacat
864
     */
865
    synchronized public InputStream sendData(Properties args,
866
            Properties filename,
867
            InputStream fileData,
868
            int size)
869
            throws Exception {
870
        InputStream returnStream = null;
871
        /*
872
            Note:  The reason that there are three try statements all executing
873
            the same code is that there is a problem with the initial connection
874
            using the HTTPClient protocol handler.  These try statements make
875
            sure that a connection is made because it gives each connection a
876
            2nd and 3rd chance to work before throwing an error.
877
            THIS IS A TOTAL HACK.  THIS NEEDS TO BE LOOKED INTO AFTER THE BETA1
878
            RELEASE OF MORPHO!!!  cwb (7/24/01)
879
         */
880
        try {
881
            return sendDataOnce(args, filename, fileData, size);
882
        } catch (Exception e) {
883
            try {
884
                return sendDataOnce(args, filename, fileData, size);
885
            } catch (Exception e2) {
886
                try {
887
                    return sendDataOnce(args, filename, fileData, size);
888
                } catch (Exception e3) {
889
                    System.err.println(
890
                            "Failed to send data to metacat 3 times: " + e3.getMessage());
891
                    System.err.println("metacaturl: " + metacatUrl);
892
                    throw e3;
893
                }
894
            }
895
        }
896
    }
897
    
898
    /**
899
     * Send a request to Metacat
900
     *
901
     * @param args      the properties to be sent to Metacat
902
     * @param filename  the properties to be sent to Metacat
903
     *                  in case of upload, otherwise null
904
     * @param fileData  the inputStream for the file data to be sent to Metacat
905
     *                  in case of upload, otherwise null
906
     * @param size      the size of the data being sent to Metacat
907
     *                  in case of upload, otherwise 0
908
     * @return          a string as returned by Metacat
909
     */
910
    synchronized private String sendDataForString(Properties args,
911
            Properties filename,
912
            InputStream fileData,
913
            int size)
914
            throws Exception {
915
        String response = null;
916
        
917
        try {
918
            InputStreamReader returnStream =
919
                    new InputStreamReader(sendData(args, filename,
920
                    fileData, size));
921
            StringWriter sw = new StringWriter();
922
            int len;
923
            char[] characters = new char[512];
924
            while ((len = returnStream.read(characters, 0, 512)) != -1) {
925
                sw.write(characters, 0, len);
926
            }
927
            returnStream.close();
928
            response = sw.toString();
929
            sw.close();
930
        } catch (Exception e) {
931
            throw e;
932
        }
933
        return response;
934
    }
935
    
936
    /*
937
     * "getversionanddoctype" action will return a string from metacat server.
938
     * The string format is "revision;doctype"(This is bad idea, we should use xml)
939
     * This method will get revision string from the response string
940
     */
941
    private String parserRevisionResponse(String response) throws Exception {
942
        String revision = null;
943
        if (response != null) {
944
            if(response.indexOf("<error>") != -1) {
945
                if(response.indexOf("There is not record") != -1) {
946
                    return "0";
947
                } else {
948
                    return null;
949
                }
950
            } else {
951
                int firstSemiCol = response.indexOf(";");
952
                revision = response.substring(0, firstSemiCol);
953
            }
954
        }
955
        return revision;
956
    }
957
    
958
    /**
959
     * JSP API: This is a convenience method to reduce the amount of code in a Metacat Client
960
     * JSP.  It handles creating/reusing an instance of a MetacatClient.
961
     * @param request Since this is intended to be used by a JSP, it is passed the
962
     * available "request" variable (the HttpServletRequest).
963
     * @throws edu.ucsb.nceas.metacat.client.MetacatInaccessibleException Received by MetacatFactory.
964
     * @return MetacatClient instance.
965
     */
966
    public static MetacatClient getMetacatClient(HttpServletRequest request) throws MetacatInaccessibleException {
967
        MetacatClient                       result;
968
        String                              metacatPath = "http://%1$s%2$s/metacat";
969
        String                              host, context;
970
        javax.servlet.http.HttpSession      session;
971
        
972
        session = request.getSession();
973
        result = (MetacatClient) session.getAttribute("MetacatClient");
974
        if (result == null) {
975
            host = request.getHeader("host");
976
            context = request.getContextPath();
977
            metacatPath = metacatPath.replaceFirst("%1$s", host);
978
            metacatPath = metacatPath.replaceFirst("%2$s", context);
979
            result = (MetacatClient) MetacatFactory.createMetacatConnection(metacatPath);
980
            session.setAttribute("MetacatClient", result);
981
        }
982
        return(result);
983
    }
984
    
985
}
(5-5/8)