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: daigle $'
7
 *     '$Date: 2008-08-22 16:23:02 -0700 (Fri, 22 Aug 2008) $'
8
 * '$Revision: 4296 $'
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.HashMap;
36
import java.util.Properties;
37
import java.util.Vector;
38
import javax.servlet.http.HttpServletRequest;
39
import javax.xml.xpath.XPath;
40
import javax.xml.xpath.XPathFactory;
41
import org.w3c.dom.Document;
42

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

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

    
51
/**
52
 *  This interface provides methods for initializing and logging in to a
53
 *  Metacat server, and then querying, reading, transforming, inserting,
54
 *  updating and deleting documents from that server.
55
 */
56
public class MetacatClient implements Metacat {
57
    /** The URL string for the metacat server */
58
    private String metacatUrl;
59
    
60
    /** The session identifier for the session */
61
    private String sessionId;
62
    
63
    /**
64
     * Constructor to create a new instance. Protected because instances
65
     * should only be created by the factory MetacatFactory.
66
     */
67
    protected MetacatClient() {
68
        this.metacatUrl = null;
69
        this.sessionId = null;
70
    }
71
    
72
    /**
73
     *  Method used to log in to a metacat server. Implementations will need
74
     *  to cache a cookie value to make the session persistent.  Each time a
75
     *  call is made to one of the other methods (e.g., read), the cookie will
76
     *  need to be passed back to the metacat server along with the request.
77
     *
78
     *  @param username   the username of the user, like an LDAP DN
79
     *  @param password   the password for that user for authentication
80
     *  @return the response string from metacat in XML format
81
     *  @throws MetacatAuthException when the username/password could
82
     *                    not be authenticated
83
     */
84
    public String login(String username, String password)
85
    throws MetacatAuthException, MetacatInaccessibleException {
86
        Properties prop = new Properties();
87
        prop.put("action", "login");
88
        prop.put("qformat", "xml");
89
        prop.put("username", username);
90
        prop.put("password", password);
91
        
92
        String response = null;
93
        try {
94
            response = sendDataForString(prop, null, null, 0);
95
        } catch (Exception e) {
96
            throw new MetacatInaccessibleException(e.getMessage());
97
        }
98
        
99
        if (response.indexOf("<login>") == -1) {
100
            setSessionId("");
101
            throw new MetacatAuthException(response);
102
        } else {
103
            int start = response.indexOf("<sessionId>") + 11;
104
            int end = response.indexOf("</sessionId>");
105
            if ((start != -1) && (end != -1)) {
106
                setSessionId(response.substring(start,end));
107
            }
108
        }
109
        return response;
110
    }
111
    
112
    /**
113
     *  Method used to log in to a metacat server. Implementations will need
114
     *  to cache a cookie value to make the session persistent.  Each time a
115
     *  call is made to one of the other methods (e.g., read), the cookie will
116
     *  need to be passed back to the metacat server along with the request.
117
     *
118
     *  @param username   the username of the user, like an LDAP DN
119
     *  @param password   the password for that user for authentication
120
     *  @return the response string from metacat in XML format
121
     *  @throws MetacatAuthException when the username/password could
122
     *                    not be authenticated
123
     */
124
    public String getloggedinuserinfo() throws MetacatInaccessibleException {
125
        Properties prop = new Properties();
126
        prop.put("action", "getloggedinuserinfo");
127
        prop.put("qformat", "xml");
128
        
129
        String response = null;
130
        try {
131
            response = sendDataForString(prop, null, null, 0);
132
        } catch (Exception e) {
133
            throw new MetacatInaccessibleException(e.getMessage());
134
        }
135
        
136
        return response;
137
    }
138
    
139
    /**
140
     *  Method used to log out a metacat server. The Metacat server will end
141
     *  the session when this call is invoked.
142
     *
143
     *  @return the response string from metacat in XML format
144
     *  @throws MetacatInaccessibleException when the metacat server can not be
145
     *                                    reached or does not respond
146
     */
147
    public String logout() throws MetacatInaccessibleException, MetacatException {
148
        Properties prop = new Properties();
149
        prop.put("action", "logout");
150
        prop.put("qformat", "xml");
151
        
152
        String response = null;
153
        try {
154
            response = sendDataForString(prop, null, null, 0);
155
        } catch (Exception e) {
156
            throw new MetacatInaccessibleException(e.getMessage());
157
        }
158
        
159
        if (response.indexOf("<logout>") == -1) {
160
            throw new MetacatException(response);
161
        }
162
        setSessionId("");
163
        return response;
164
    }
165
    
166
    /**
167
     * Read an XML document from the metacat server session, accessed by docid,
168
     * and returned as a Reader.
169
     *
170
     * @param docid the identifier of the document to be read
171
     * @return a Reader for accessing the document
172
     * @throws InsufficientKarmaException when the user has insufficent rights
173
     *                                    for the operation
174
     * @throws MetacatInaccessibleException when the metacat server can not be
175
     *                                    reached or does not respond
176
     * @throws MetacatException when the metacat server generates another error
177
     */
178
    public Reader read(String docid) throws InsufficientKarmaException,
179
            MetacatInaccessibleException, MetacatException, DocumentNotFoundException {
180
        PushbackReader pbr = null;
181
        
182
        Properties prop = new Properties();
183
        prop.put("action", "read");
184
        prop.put("qformat", "xml");
185
        prop.put("docid", docid);
186
        InputStream response = null;
187
        try {
188
            response = sendData(prop, null, null, 0);
189
        } catch (Exception e) {
190
            throw new MetacatInaccessibleException(e.getMessage());
191
        }
192
        pbr = new PushbackReader(new InputStreamReader(response), 512);
193
        try {
194
            char[] characters = new char[512];
195
            int len = pbr.read(characters, 0, 512);
196
            StringWriter sw = new StringWriter();
197
            sw.write(characters, 0, len);
198
            String message = sw.toString();
199
            sw.close();
200
            pbr.unread(characters, 0, len);
201
            if (message.indexOf("<error>") != -1) {
202
                if (message.indexOf("does not have permission") != -1) {
203
                    throw new InsufficientKarmaException(message);
204
                } else if(message.indexOf("does not exist") != -1) {
205
                    throw new DocumentNotFoundException(message);
206
                } else {
207
                    throw new MetacatException(message);
208
                }
209
            }
210
        } catch (IOException ioe) {
211
            throw new MetacatException(
212
                    "MetacatClient: Error converting Reader to String."
213
                    + ioe.getMessage());
214
        }
215
        return pbr;
216
    }
217
    
218
    
219
    /**
220
     * Read inline data from the metacat server session, accessed by
221
     * inlinedataid and returned as a Reader.
222
     *
223
     * @param inlinedataid the identifier of the data to be read
224
     * @return a Reader for accessing the document
225
     * @throws InsufficientKarmaException when the user has insufficent rights
226
     *                                    for the operation
227
     * @throws MetacatInaccessibleException when the metacat server can not be
228
     *                                    reached or does not respond
229
     * @throws MetacatException when the metacat server generates another error
230
     */
231
    public Reader readInlineData(String inlinedataid)
232
    throws InsufficientKarmaException,
233
            MetacatInaccessibleException, MetacatException {
234
        PushbackReader pbr = null;
235
        
236
        Properties prop = new Properties();
237
        prop.put("action", "readinlinedata");
238
        prop.put("inlinedataid", inlinedataid);
239
        
240
        InputStream response = null;
241
        try {
242
            response = sendData(prop, null, null, 0);
243
        } catch (Exception e) {
244
            throw new MetacatInaccessibleException(e.getMessage());
245
        }
246
        
247
        pbr = new PushbackReader(new InputStreamReader(response), 512);
248
        try {
249
            char[] characters = new char[512];
250
            int len = pbr.read(characters, 0, 512);
251
            StringWriter sw = new StringWriter();
252
            sw.write(characters, 0, len);
253
            String message = sw.toString();
254
            sw.close();
255
            pbr.unread(characters, 0, len);
256
            
257
            if (message.indexOf("<error>") != -1) {
258
                if (message.indexOf("does not have permission") != -1) {
259
                    throw new InsufficientKarmaException(message);
260
                } else {
261
                    throw new MetacatException(message);
262
                }
263
            }
264
        } catch (IOException ioe) {
265
            throw new MetacatException(
266
                    "MetacatClient: Error converting Reader to String."
267
                    + ioe.getMessage());
268
        }
269
        
270
        return pbr;
271
    }
272
    
273
    /**
274
     * Query the metacat document store with the given metacat-compatible
275
     * query document and default qformat xml, and return the result set as a Reader.
276
     *
277
     * @param xmlQuery a Reader for accessing the XML version of the query
278
     * @return a Reader for accessing the result set
279
     */
280
    public Reader query(Reader xmlQuery) throws MetacatInaccessibleException,
281
            IOException {
282
        String qformat = "xml";
283
        return query(xmlQuery, qformat);
284
    }
285
    
286
    /**
287
     * Query the metacat document store with the given metacat-compatible
288
     * query document and qformat, and return the result set as a Reader.
289
     *
290
     * @param xmlQuery a Reader for accessing the XML version of the query
291
     * @param qformat the format of return doc. It can be xml, knb, lter and etal.
292
     * @return a Reader for accessing the result set
293
     */
294
    public Reader query(Reader xmlQuery, String qformat) throws MetacatInaccessibleException,
295
            IOException {
296
        Reader reader = null;
297
        String query = null;
298
        try {
299
            query = IOUtil.getAsString(xmlQuery, true);
300
        } catch (IOException ioE) {
301
            throw ioE;
302
        }
303
        
304
        //set up properties
305
        Properties prop = new Properties();
306
        prop.put("action", "squery");
307
        prop.put("qformat", qformat);
308
        prop.put("query", query);
309
        
310
        InputStream response = null;
311
        try {
312
            response = sendData(prop, null, null, 0);
313
        } catch (Exception e) {
314
            throw new MetacatInaccessibleException(e.getMessage());
315
        }
316
        reader = new InputStreamReader(response);
317
        return reader;
318
    }
319
    
320
    /**
321
     * Insert an XML document into the repository.
322
     *
323
     * @param docid the docid to insert the document
324
     * @param xmlDocument a Reader for accessing the XML document to be inserted
325
     * @param schema a Reader for accessing the DTD or XML Schema for
326
     *               the document
327
     * @return the metacat response message
328
     * @throws InsufficientKarmaException when the user has insufficent rights
329
     *                                    for the operation
330
     * @throws MetacatInaccessibleException when the metacat server can not be
331
     *                                    reached or does not respond
332
     * @throws MetacatException when the metacat server generates another error
333
     * @throws IOException when there is an error reading the xml document
334
     */
335
    public String insert(String docid, Reader xmlDocument, Reader schema)
336
    	throws InsufficientKarmaException, MetacatException, IOException,
337
            MetacatInaccessibleException {
338

    
339
        Reader reader = null;
340
        String doctext = null;
341
        String schematext = null;
342
        try {
343
            doctext = IOUtil.getAsString(xmlDocument, true);
344
            if (schema != null) {
345
                schematext = IOUtil.getAsString(schema, true);
346
            }
347
        } catch (IOException ioE) {
348
            throw ioE;
349
        }
350
        
351
        //set up properties
352
        Properties prop = new Properties();
353
        prop.put("action", "insert");
354
        prop.put("docid", docid);
355
        prop.put("doctext", doctext);
356
        if (schematext != null) {
357
            prop.put("dtdtext", schematext);
358
        }
359

    
360
        if (sessionId != null) {
361
            prop.put("sessionid", sessionId);
362
        }
363
        
364
        String response = null;
365
        try {
366
            response = sendDataForString(prop, null, null, 0);
367
        } catch (Exception e) {
368
            throw new MetacatInaccessibleException(e.getMessage());
369
        }
370
        
371
        // Check for an error condition
372
        if (response.indexOf("<error>") != -1) {
373
            if (response.indexOf("does not have permission") != -1) {
374
                throw new InsufficientKarmaException(response);
375
            } else {
376
                throw new MetacatException(response);
377
            }
378
        }
379
        
380
        return response;
381
    }
382
    
383
    /**
384
     * Update an XML document in the repository.
385
     *
386
     * @param docid the docid to update
387
     * @param xmlDocument a Reader for accessing the XML text to be updated
388
     * @param schema a Reader for accessing the DTD or XML Schema for
389
     *               the document
390
     * @return the metacat response message
391
     * @throws InsufficientKarmaException when the user has insufficent rights
392
     *                                    for the operation
393
     * @throws MetacatInaccessibleException when the metacat server can not be
394
     *                                    reached or does not respond
395
     * @throws MetacatException when the metacat server generates another error
396
     * @throws IOException when there is an error reading the xml document
397
     */
398
    public String update(String docid, Reader xmlDocument, Reader schema)
399
    throws InsufficientKarmaException, MetacatException, IOException,
400
            MetacatInaccessibleException {
401
        Reader reader = null;
402
        String doctext = null;
403
        String schematext = null;
404
        try {
405
            doctext = IOUtil.getAsString(xmlDocument, true);
406
            if (schema != null) {
407
                schematext = IOUtil.getAsString(schema, true);
408
            }
409
        } catch (IOException ioE) {
410
            throw ioE;
411
        }
412
        
413
        //set up properties
414
        Properties prop = new Properties();
415
        prop.put("action", "update");
416
        prop.put("docid", docid);
417
        prop.put("doctext", doctext);
418
        if (schematext != null) {
419
            prop.put("dtdtext", schematext);
420
        }
421
        
422
        String response = null;
423
        try {
424
            response = sendDataForString(prop, null, null, 0);
425
        } catch (Exception e) {
426
            throw new MetacatInaccessibleException(e.getMessage());
427
        }
428
        
429
        // Check for an error condition
430
        if (response.indexOf("<error>") != -1) {
431
            if (response.indexOf("does not have permission") != -1) {
432
                throw new InsufficientKarmaException(response);
433
            } else {
434
                throw new MetacatException(response);
435
            }
436
        }
437
        
438
        return response;
439
    }
440
    
441
    /**
442
     * Upload a data document into the repository. Data files are stored on 
443
     * metacat and may be in any format (binary or text), but they are all
444
     * treated as if they were binary.  Data files are not searched by the
445
     * query() methods because they are not loaded into the XML store because
446
     * they are not XML documents.  The File parameter is used to determine a
447
     * name for the uploaded document.
448
     *
449
     * @param docid the identifier to be used for the document
450
     * @param file the File to be uploaded
451
     * @param document a InputStream containing the data to be uploaded
452
     * @return the metacat response message
453
     * @throws InsufficientKarmaException when the user has insufficent rights
454
     *                                    for the operation
455
     * @throws MetacatInaccessibleException when the metacat server can not be
456
     *                                    reached or does not respond
457
     * @throws MetacatException when the metacat server generates another error
458
     * @throws IOException when there is an error reading the xml document
459
     */
460
    public String upload(String docid, File file)
461
    throws InsufficientKarmaException, MetacatException, IOException,
462
            MetacatInaccessibleException {
463
        
464
        URL url = new URL(metacatUrl.trim());
465
        HttpMessage msg = new HttpMessage(url);
466
        //set up properties
467
        Properties arg = new Properties();
468
        arg.put("action", "upload");
469
        arg.put("docid", docid);
470
        
471
        Properties filenames = new Properties();
472
        String filename = file.getAbsolutePath();
473
        filenames.put("datafile", filename);
474
        
475
        String response = null;
476
        try {
477
            response = sendDataForString(arg, filenames, null, 0);
478
        } catch (Exception e) {
479
            throw new MetacatInaccessibleException(e.getMessage());
480
        }
481
        
482
        // Check for an error condition
483
        if (response.indexOf("<error>") != -1) {
484
            if (response.indexOf("does not have permission") != -1) {
485
                throw new InsufficientKarmaException(response);
486
            } else {
487
                throw new MetacatException(response);
488
            }
489
        }
490
        
491
        return response;
492
    }
493
    
494
    /**
495
     * Upload a data document into the repository. Data files are stored on 
496
     * metacat and may be in any format (binary or text), but they are all
497
     * treated as if they were binary.  Data files are not searched by the
498
     * query() methods because they are not loaded into the XML store because
499
     * they are not XML documents. The name for the document is set explicitly
500
     * using the filename parameter.
501
     *
502
     * @param docid the identifier to be used for the document
503
     * @param filename the name to be used in the MIME description of the uploaded file
504
     * @param document a InputStream containing the data to be uploaded
505
     * @return the metacat response message
506
     * @throws InsufficientKarmaException when the user has insufficent rights
507
     *                                    for the operation
508
     * @throws MetacatInaccessibleException when the metacat server can not be
509
     *                                    reached or does not respond
510
     * @throws MetacatException when the metacat server generates another error
511
     * @throws IOException when there is an error reading the xml document
512
     */
513
    public String upload(String docid, String filename, InputStream fileData,
514
            int size)
515
            throws InsufficientKarmaException, MetacatException, IOException,
516
            MetacatInaccessibleException {
517
        
518
        URL url = new URL(metacatUrl.trim());
519
        HttpMessage msg = new HttpMessage(url);
520
        //set up properties
521
        Properties arg = new Properties();
522
        arg.put("action", "upload");
523
        arg.put("docid", docid);
524
        
525
        Properties filenames = new Properties();
526
        filenames.put("datafile", filename);
527
        
528
        String response = null;
529
        try {
530
            response = sendDataForString(arg, filenames, fileData, size);
531
        } catch (Exception e) {
532
            throw new MetacatInaccessibleException(e.getMessage());
533
        }
534
        
535
        // Check for an error condition
536
        if (response.indexOf("<error>") != -1) {
537
            if (response.indexOf("does not have permission") != -1) {
538
                throw new InsufficientKarmaException(response);
539
            } else {
540
                throw new MetacatException(response);
541
            }
542
        }
543
        
544
        return response;
545
    }
546
    
547
    /**
548
     * Delete an XML document in the repository.
549
     *
550
     * @param docid the docid to delete
551
     * @return the metacat response message
552
     * @throws InsufficientKarmaException when the user has insufficent rights
553
     *                                    for the operation
554
     * @throws MetacatInaccessibleException when the metacat server can not be
555
     *                                    reached or does not respond
556
     * @throws MetacatException when the metacat server generates another error
557
     */
558
    public String delete(String docid)
559
    throws InsufficientKarmaException, MetacatException,
560
            MetacatInaccessibleException {
561
        //set up properties
562
        Properties prop = new Properties();
563
        prop.put("action", "delete");
564
        prop.put("docid", docid);
565
        
566
        String response = null;
567
        try {
568
            response = sendDataForString(prop, null, null, 0);
569
        } catch (Exception e) {
570
            throw new MetacatInaccessibleException(e.getMessage());
571
        }
572
        
573
        // Check for an error condition
574
        if (response.indexOf("<error>") != -1) {
575
            if (response.indexOf("does not have permission") != -1) {
576
                throw new InsufficientKarmaException(response);
577
            } else {
578
                throw new MetacatException(response);
579
            }
580
        }
581
        return response;
582
    }
583
    
584
    
585
    /**
586
     * set the access on an XML document in the repository.
587
     *
588
     * @param _docid the docid of the document for which the access should be applied.
589
     *
590
     * @param _principal the document's principal
591
     *
592
     * @param _permission the access permission to be applied to the docid
593
     *  {e.g. read,write,all}
594
     *
595
     * @param _permType the permission type to be applied to the document
596
     *  {e.g. allow or deny}
597
     *
598
     * @param _permOrder the order that the document's permissions should be
599
     *  processed {e.g. denyFirst or allowFirst}
600
     *
601
     *
602
     * @return the metacat response message
603
     *
604
     * @throws InsufficientKarmaException when the user has insufficent rights
605
     *                                    for the operation
606
     * @throws MetacatInaccessibleException when the metacat server can not be
607
     *                                    reached or does not respond
608
     * @throws MetacatException when the metacat server generates another error
609
     */
610
    public String setAccess(String _docid, String _principal, String
611
            _permission, String _permType,
612
            String _permOrder )
613
            throws InsufficientKarmaException, MetacatException,
614
            MetacatInaccessibleException {
615
        //set up properties
616
        Properties prop = new Properties();
617
        prop.put("action", "setaccess");
618
        prop.put("docid", _docid);
619
        prop.put("principal", _principal);
620
        prop.put("permission", _permission);
621
        prop.put("permType", _permType);
622
        prop.put("permOrder", _permOrder);
623
        
624
        String response = null;
625
        try {
626
            response = sendDataForString(prop, null, null, 0);
627
        } catch (Exception e) {
628
            throw new MetacatInaccessibleException(e.getMessage());
629
        }
630
        
631
        // Check for an error condition
632
        if (response.indexOf("<error>") != -1) {
633
            if (response.indexOf("does not have permission") != -1) {
634
                throw new InsufficientKarmaException(response);
635
            } else {
636
                throw new MetacatException(response);
637
            }
638
        }
639
        return response;
640
    }
641
    
642
    /**
643
     * When the MetacatFactory creates an instance it needs to set the
644
     * MetacatUrl to which connections should be made.
645
     *
646
     * @param metacatUrl the URL for the metacat server
647
     */
648
    public void setMetacatUrl(String metacatUrl) {
649
        this.metacatUrl = metacatUrl;
650
    }
651
    
652
    /**
653
     * Get the session identifier for this session.  This is only valid if
654
     * the login methods has been called successfully for this Metacat object
655
     * beforehand.
656
     *
657
     * @returns the sessionId as a String, or null if the session is invalid
658
     */
659
    public String getSessionId() {
660
        return this.sessionId;
661
    }
662
    
663
    /**
664
     * Set the session identifier for this session.  This identifier was
665
     * previously established with a call to login.  To continue to use the
666
     * same session, set the session id before making a call to one of the
667
     * metacat access methods (e.g., read, query, insert, etc.).
668
     *
669
     * @param String the sessionId from a previously established session
670
     */
671
    public void setSessionId(String sessionId) {
672
        this.sessionId = sessionId;
673
    }
674
    
675
    /**
676
     * The method will return the latest revision in metacat server
677
     * for a given document id. If some error happens, this method will throw
678
     * an exception.
679
     * @param docId String  the given docid you want to use. the docid it self
680
     *                      can have or haven't revision number
681
     * @throws MetacatException
682
     */
683
    public int getNewestDocRevision(String docId) throws MetacatException {
684
        int rev = 0;
685
        //set up properties
686
        Properties prop = new Properties();
687
        prop.put("action", "getrevisionanddoctype");
688
        prop.put("docid", docId);
689
        
690
        String response = null;
691
        try {
692
            response = sendDataForString(prop, null, null, 0);
693
            //parseRevisionResponse will return null if there is an
694
            //error that it can't handle
695
            String revStr = parserRevisionResponse(response);
696
            Integer revObj = new Integer(revStr);
697
            rev = revObj.intValue();
698
            // Check for an error condition
699
            if (response.indexOf("<error>") != -1 && revStr == null) {
700
                throw new MetacatException(response);
701
            }
702
        } catch (Exception e) {
703
            throw new MetacatException(e.getMessage());
704
        }
705
        return rev;
706
    }
707
    
708
    /**
709
     * Return the highest document id for a given scope.  This is used by
710
     * clients to make it easier to determine the next free identifier in a
711
     * sequence for a given scope.
712
     * @param scope String  the scope to use for looking up the latest id
713
     * @throws MetacatException when an error occurs
714
     */
715
    public String getLastDocid(String scope) throws MetacatException {
716
        String lastIdentifier = "";
717
        //set up properties
718
        Properties prop = new Properties();
719
        prop.put("action", "getlastdocid");
720
        prop.put("scope", scope);
721
        
722
        String response = null;
723
        try {
724
            response = sendDataForString(prop, null, null, 0);
725
            // Check for an error condition
726
            if (response.indexOf("<error>") != -1) {
727
                throw new MetacatException(response);
728
            } else {
729
                Reader responseReader = new StringReader(response);
730
                Node root =
731
                        XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
732
                Node docidNode =
733
                        XMLUtilities.getNodeWithXPath(root, "/lastDocid/docid");
734
                lastIdentifier = docidNode.getFirstChild().getNodeValue();
735
            }
736
        } catch (Exception e) {
737
            throw new MetacatException(e.getMessage());
738
        }
739
        return lastIdentifier;
740
    }
741
    
742
    /**
743
     * return a list of all docids that match a given scope.  if scope is null
744
     * return all docids registered in the system
745
     * @param scope String  the scope to use to limit the docid query
746
     * @throws MetacatException when an error occurs
747
     */
748
    public Vector getAllDocids(String scope) throws MetacatException {
749
        Vector resultVec = new Vector();
750
        //set up properties
751
        Properties prop = new Properties();
752
        prop.put("action", "getalldocids");
753
        if(scope != null) {
754
            prop.put("scope", scope);
755
        }
756
        
757
        String response = null;
758
        try {
759
            response = sendDataForString(prop, null, null, 0);
760
            // Check for an error condition
761
            if (response.indexOf("<error>") != -1) {
762
                throw new MetacatException(response);
763
            } else {
764
                Reader responseReader = new StringReader(response);
765
                Node root =
766
                        XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
767
                NodeList nlist = root.getChildNodes();
768
                for(int i=0; i<nlist.getLength(); i++) {
769
                    Node n = nlist.item(i);
770
                    if(n.getNodeName().equals("docid")) {
771
                        //add the content to the return vector
772
                        String nodeVal = n.getFirstChild().getNodeValue();
773
                        resultVec.addElement(nodeVal);
774
                    }
775
                }
776
                
777
            }
778
        } catch (Exception e) {
779
            throw new MetacatException(e.getMessage());
780
        }
781
        return resultVec;
782
    }
783
    
784
    /**
785
     * return true of the given docid is registered, false if not
786
     * @param scope String  the scope to use to limit the docid query
787
     * @throws MetacatException when an error occurs
788
     */
789
    public boolean isRegistered(String docid) throws MetacatException {
790
        Vector resultVec = new Vector();
791
        //set up properties
792
        Properties prop = new Properties();
793
        prop.put("action", "isregistered");
794
        if(docid == null) {
795
            throw new MetacatException("<error>Cannot check if a null docid " +
796
                    "is registered.</error>");
797
        }
798
        prop.put("docid", docid);
799
        
800
        String response = null;
801
        try {
802
            response = sendDataForString(prop, null, null, 0);
803
            // Check for an error condition
804
            if (response.indexOf("<error>") != -1) {
805
                throw new MetacatException(response);
806
            } else {
807
                Reader responseReader = new StringReader(response);
808
                StringBuffer sb = new StringBuffer();
809
                char[] c = new char[1024];
810
                int numread = responseReader.read(c, 0, 1024);
811
                while(numread != -1) {
812
                    sb.append(new String(c, 0, numread));
813
                    numread = responseReader.read(c, 0, 1024);
814
                }
815
                
816
                String responseStr = sb.toString();
817
                if(responseStr.indexOf("true") != -1) {
818
                    return true;
819
                }
820
                return false;
821
            }
822
        } catch (Exception e) {
823
            throw new MetacatException(e.getMessage());
824
        }
825
    }
826
    
827
    /**
828
     * Send a request to Metacat.  An alternative to the sentData method.
829
     * Allows for sending multiple parameters with the same name, 
830
     * different names, or any combo.  Send properties where the entry 
831
     * key contains the "param value", 
832
     * and the entry value contains the "param name".  
833
     * Constraint: param values must be unique.
834
     *
835
     * @return InputStream as returned by Metacat
836
     * @param args Properties of the parameters to be sent to Metacat, where,
837
     *      key = param value
838
     *      value = param name
839
     * @throws java.lang.Exception thrown
840
     */
841
    synchronized public InputStream sendParameters(Properties args) throws Exception {
842
        InputStream                     result = null;
843
        URL                             url;
844
        HttpMessage                     httpMsg;
845
        
846
        url = new URL(metacatUrl);
847
        httpMsg = new HttpMessage(url);
848
        httpMsg.setCookie("JSESSIONID="+this.sessionId);
849
        result = httpMsg.sendPostParameters(args);
850
        return(result);
851
    }
852

    
853
    /************************************************************************
854
     * PRIVATE METHODS
855
     ************************************************************************/
856
    
857
    /**
858
     * Send a request to metacat.
859
     *
860
     * @param prop the properties to be URL encoded and sent
861
     * @param filename  the properties to be sent to Metacat
862
     *                  in case of upload, otherwise null
863
     * @param fileData  the inputStream for the file data to be sent to Metacat
864
     *                  in case of upload, otherwise null
865
     * @param size      the size of the data being sent to Metacat
866
     *                  in case of upload, otherwise 0
867
     */
868
    synchronized private InputStream sendDataOnce(Properties args,
869
            Properties filename,
870
            InputStream fileData,
871
            int size)
872
            throws Exception {
873
        InputStream returnStream = null;
874
        URL url = new URL(metacatUrl);
875
        HttpMessage msg = new HttpMessage(url);
876
        msg.setCookie("JSESSIONID="+this.sessionId);
877
        if (filename == null){
878
            returnStream = msg.sendPostData(args);
879
        } else if (fileData == null){
880
            returnStream = msg.sendPostData(args, filename);
881
        } else if (size > 0) {
882
            returnStream = msg.sendPostData(args, filename, fileData, size);
883
        } else {
884
            throw new MetacatException("Invalid size specified for " +
885
                    "the input stream being passed");
886
        }
887
        return returnStream;
888
    }
889
    
890
    /**
891
     * Send a request to Metacat
892
     *
893
     * @param args  the properties to be sent to Metacat
894
     * @param filename  the properties to be sent to Metacat
895
     *                  in case of upload, otherwise null
896
     * @param fileData  the inputStream for the file data to be sent to Metacat
897
     *                  in case of upload, otherwise null
898
     * @param size      the size of the data being sent to Metacat
899
     *                  in case of upload, otherwise 0
900
     * @return      InputStream as returned by Metacat
901
     */
902
    synchronized public InputStream sendData(Properties args,
903
            Properties filename,
904
            InputStream fileData,
905
            int size)
906
            throws Exception {
907
        InputStream returnStream = null;
908
        /*
909
            Note:  The reason that there are three try statements all executing
910
            the same code is that there is a problem with the initial connection
911
            using the HTTPClient protocol handler.  These try statements make
912
            sure that a connection is made because it gives each connection a
913
            2nd and 3rd chance to work before throwing an error.
914
            THIS IS A TOTAL HACK.  THIS NEEDS TO BE LOOKED INTO AFTER THE BETA1
915
            RELEASE OF MORPHO!!!  cwb (7/24/01)
916
         */
917
        try {
918
            return sendDataOnce(args, filename, fileData, size);
919
        } catch (Exception e) {
920
            try {
921
                return sendDataOnce(args, filename, fileData, size);
922
            } catch (Exception e2) {
923
                try {
924
                    return sendDataOnce(args, filename, fileData, size);
925
                } catch (Exception e3) {
926
                    System.err.println(
927
                            "Failed to send data to metacat 3 times: " + e3.getMessage());
928
                    System.err.println("metacaturl: " + metacatUrl);
929
                    throw e3;
930
                }
931
            }
932
        }
933
    }
934
    
935
    /**
936
     * Send a request to Metacat
937
     *
938
     * @param args      the properties to be sent to Metacat
939
     * @param filename  the properties to be sent to Metacat
940
     *                  in case of upload, otherwise null
941
     * @param fileData  the inputStream for the file data to be sent to Metacat
942
     *                  in case of upload, otherwise null
943
     * @param size      the size of the data being sent to Metacat
944
     *                  in case of upload, otherwise 0
945
     * @return          a string as returned by Metacat
946
     */
947
    synchronized private String sendDataForString(Properties args,
948
            Properties filename,
949
            InputStream fileData,
950
            int size)
951
            throws Exception {
952
        String response = null;
953
        
954
        try {
955
            InputStreamReader returnStream =
956
                    new InputStreamReader(sendData(args, filename,
957
                    fileData, size));
958
            StringWriter sw = new StringWriter();
959
            int len;
960
            char[] characters = new char[512];
961
            while ((len = returnStream.read(characters, 0, 512)) != -1) {
962
                sw.write(characters, 0, len);
963
            }
964
            returnStream.close();
965
            response = sw.toString();
966
            sw.close();
967
        } catch (Exception e) {
968
            throw e;
969
        }
970
        return response;
971
    }
972
    
973
    /*
974
     * "getversionanddoctype" action will return a string from metacat server.
975
     * The string format is "revision;doctype"(This is bad idea, we should use xml)
976
     * This method will get revision string from the response string
977
     */
978
    private String parserRevisionResponse(String response) throws Exception {
979
        String revision = null;
980
        if (response != null) {
981
            if(response.indexOf("<error>") != -1) {
982
                if(response.indexOf("There is not record") != -1) {
983
                    return "0";
984
                } else {
985
                    return null;
986
                }
987
            } else {
988
                int firstSemiCol = response.indexOf(";");
989
                revision = response.substring(0, firstSemiCol);
990
            }
991
        }
992
        return revision;
993
    }
994
    
995
    /**
996
     * JSP API: This is a convenience method to reduce the amount of code in a Metacat Client
997
     * JSP.  It handles creating/reusing an instance of a MetacatClient.
998
     * @param request Since this is intended to be used by a JSP, it is passed the
999
     * available "request" variable (the HttpServletRequest).
1000
     * @throws edu.ucsb.nceas.metacat.client.MetacatInaccessibleException Received by MetacatFactory.
1001
     * @return MetacatClient instance.
1002
     */
1003
    public static MetacatClient getMetacatClient(HttpServletRequest request) throws MetacatInaccessibleException {
1004
        MetacatClient                       result;
1005
        String                              metacatPath = "http://%1$s%2$s/metacat";
1006
        String                              host, context;
1007
        javax.servlet.http.HttpSession      session;
1008
        
1009
        session = request.getSession();
1010
        result = (MetacatClient) session.getAttribute("MetacatClient");
1011
        if (result == null) {
1012
            host = request.getHeader("host");
1013
            context = request.getContextPath();
1014
            metacatPath = metacatPath.replaceFirst("%1$s", host);
1015
            metacatPath = metacatPath.replaceFirst("%2$s", context);
1016
            result = (MetacatClient) MetacatFactory.createMetacatConnection(metacatPath);
1017
            session.setAttribute("MetacatClient", result);
1018
        }
1019
        return(result);
1020
    }
1021
    
1022
}
(5-5/8)