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