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: leinfelder $'
7
 *     '$Date: 2009-10-01 12:12:08 -0700 (Thu, 01 Oct 2009) $'
8
 * '$Revision: 5066 $'
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.BufferedInputStream;
28
import java.io.BufferedOutputStream;
29
import java.io.FileOutputStream;
30
import java.io.InputStream;
31
import java.io.InputStreamReader;
32
import java.io.StringReader;
33
import java.io.IOException;
34
import java.io.StringWriter;
35
import java.io.Reader;
36
import java.net.URL;
37
import java.util.Properties;
38
import java.util.Vector;
39
import javax.servlet.http.HttpServletRequest;
40

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

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

    
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
    public static void main(String[] args) {
63
    	try {
64
    		MetacatClient mc = (MetacatClient) MetacatFactory.createMetacatConnection("http://fred.msi.ucsb.edu:8080/knb/metacat");
65
    		//InputStream r = mc.read("zip.1.1");
66
    		InputStream r = mc.read("jlee.2808.2");
67
    		
68
    		//FileOutputStream fos = new FileOutputStream("test.zip");
69
    		FileOutputStream fos = new FileOutputStream("jlee.xml");
70
            BufferedOutputStream bfos = new BufferedOutputStream(fos);
71

    
72
            int c = r.read();
73
            while(c != -1)
74
            {
75
              bfos.write(c);
76
              c = r.read();
77
            }
78
            bfos.flush();
79
            bfos.close();
80
            fos.flush();
81
            fos.close();
82
    	} catch (Exception e) {
83
    		e.printStackTrace();
84
    	}
85
    }
86
    
87
    /**
88
     * Constructor to create a new instance. Protected because instances
89
     * should only be created by the factory MetacatFactory.
90
     */
91
    protected MetacatClient() {
92
        this.metacatUrl = null;
93
        this.sessionId = null;
94
    }
95
    
96
    /**
97
     *  Method used to log in to a metacat server. Implementations will need
98
     *  to cache a cookie value to make the session persistent.  Each time a
99
     *  call is made to one of the other methods (e.g., read), the cookie will
100
     *  need to be passed back to the metacat server along with the request.
101
     *
102
     *  @param username   the username of the user, like an LDAP DN
103
     *  @param password   the password for that user for authentication
104
     *  @return the response string from metacat in XML format
105
     *  @throws MetacatAuthException when the username/password could
106
     *                    not be authenticated
107
     */
108
    public String login(String username, String password)
109
    throws MetacatAuthException, MetacatInaccessibleException {
110
        Properties prop = new Properties();
111
        prop.put("action", "login");
112
        prop.put("qformat", "xml");
113
        prop.put("username", username);
114
        prop.put("password", password);
115
        
116
        String response = null;
117
        try {
118
            response = sendDataForString(prop, null, null, 0);
119
        } catch (Exception e) {
120
            throw new MetacatInaccessibleException(e.getMessage());
121
        }
122
        
123
        if (response.indexOf("<login>") == -1) {
124
            setSessionId("");
125
            throw new MetacatAuthException(response);
126
        } else {
127
            int start = response.indexOf("<sessionId>") + 11;
128
            int end = response.indexOf("</sessionId>");
129
            if ((start != -1) && (end != -1)) {
130
                setSessionId(response.substring(start,end));
131
            }
132
        }
133
        return response;
134
    }
135
    
136
    /**
137
     *  Method used to log in to a metacat server. Implementations will need
138
     *  to cache a cookie value to make the session persistent.  Each time a
139
     *  call is made to one of the other methods (e.g., read), the cookie will
140
     *  need to be passed back to the metacat server along with the request.
141
     *
142
     *  @param username   the username of the user, like an LDAP DN
143
     *  @param password   the password for that user for authentication
144
     *  @return the response string from metacat in XML format
145
     *  @throws MetacatAuthException when the username/password could
146
     *                    not be authenticated
147
     */
148
    public String getloggedinuserinfo() throws MetacatInaccessibleException {
149
        Properties prop = new Properties();
150
        prop.put("action", "getloggedinuserinfo");
151
        prop.put("qformat", "xml");
152
        
153
        String response = null;
154
        try {
155
            response = sendDataForString(prop, null, null, 0);
156
        } catch (Exception e) {
157
            throw new MetacatInaccessibleException(e.getMessage());
158
        }
159
        
160
        return response;
161
    }
162
    
163
    /**
164
     *  Method used to log out a metacat server. The Metacat server will end
165
     *  the session when this call is invoked.
166
     *
167
     *  @return the response string from metacat in XML format
168
     *  @throws MetacatInaccessibleException when the metacat server can not be
169
     *                                    reached or does not respond
170
     */
171
    public String logout() throws MetacatInaccessibleException, MetacatException {
172
        Properties prop = new Properties();
173
        prop.put("action", "logout");
174
        prop.put("qformat", "xml");
175
        
176
        String response = null;
177
        try {
178
            response = sendDataForString(prop, null, null, 0);
179
        } catch (Exception e) {
180
            throw new MetacatInaccessibleException(e.getMessage());
181
        }
182
        
183
        if (response.indexOf("<logout>") == -1) {
184
            throw new MetacatException(response);
185
        }
186
        setSessionId("");
187
        return response;
188
    }
189
    
190
    /**
191
     *  Method used to log in to a metacat server. Implementations will need
192
     *  to cache a cookie value to make the session persistent.  Each time a
193
     *  call is made to one of the other methods (e.g., read), the cookie will
194
     *  need to be passed back to the metacat server along with the request.
195
     *
196
     *  @param username   the username of the user, like an LDAP DN
197
     *  @param password   the password for that user for authentication
198
     *  @return the response string from metacat in XML format
199
     *  @throws MetacatAuthException when the username/password could
200
     *                    not be authenticated
201
     */
202
    public String validateSession(String sessionId)
203
    		throws MetacatAuthException, MetacatInaccessibleException {
204
    	
205
        Properties prop = new Properties();
206
        prop.put("action", "validatesession");
207
        prop.put("sessionid", sessionId);
208
        
209
        String response = null;
210
        try {
211
            response = sendDataForString(prop, null, null, 0);
212
        } catch (Exception e) {
213
            throw new MetacatInaccessibleException(e.getMessage());
214
        }
215
        
216
        if (response.indexOf("<validateSession><status>") == -1) {
217
            setSessionId("");
218
            throw new MetacatAuthException(response);
219
        } 
220
        
221
        return response;
222
    }
223
    
224
   
225

    
226
	/**
227
     * Read an XML document from the metacat server session, accessed by docid,
228
     * and returned as a Reader.
229
     *
230
     * @param docid the identifier of the document to be read
231
     * @return a Reader for accessing the document
232
     * @throws InsufficientKarmaException when the user has insufficent rights
233
     *                                    for the operation
234
     * @throws MetacatInaccessibleException when the metacat server can not be
235
     *                                    reached or does not respond
236
     * @throws MetacatException when the metacat server generates another error
237
     */
238
    public InputStream read(String docid) throws InsufficientKarmaException,
239
            MetacatInaccessibleException, MetacatException, DocumentNotFoundException {
240
    	Reader r = null;
241
        
242
        Properties prop = new Properties();
243
        prop.put("action", "read");
244
        prop.put("qformat", "xml");
245
        prop.put("docid", docid);
246
        InputStream response = null;
247
        try {
248
            response = sendData(prop, null, null, 0);
249
        } catch (Exception e) {
250
            throw new MetacatInaccessibleException(e.getMessage());
251
        }
252
        BufferedInputStream bis = new BufferedInputStream(response);
253
        r = new InputStreamReader(bis);
254
        try {
255
        	bis.mark(512);
256
            char[] characters = new char[512];
257
            int len = r.read(characters, 0, 512);
258
            StringWriter sw = new StringWriter();
259
            sw.write(characters, 0, len);
260
            String message = sw.toString();
261
            sw.close();
262
            bis.reset();
263
            if (message.indexOf("<error>") != -1) {
264
                if (message.indexOf("does not have permission") != -1) {
265
                    throw new InsufficientKarmaException(message);
266
                } else if(message.indexOf("does not exist") != -1) {
267
                    throw new DocumentNotFoundException(message);
268
                } else {
269
                    throw new MetacatException(message);
270
                }
271
            }
272
        } catch (IOException ioe) {
273
            throw new MetacatException(
274
                    "MetacatClient: Error converting Reader to String."
275
                    + ioe.getMessage());
276
        }
277
        return bis;
278
    }
279
    
280
    
281
    /**
282
     * Read inline data from the metacat server session, accessed by
283
     * inlinedataid and returned as a Reader.
284
     *
285
     * @param inlinedataid the identifier of the data to be read
286
     * @return a Reader for accessing the document
287
     * @throws InsufficientKarmaException when the user has insufficent rights
288
     *                                    for the operation
289
     * @throws MetacatInaccessibleException when the metacat server can not be
290
     *                                    reached or does not respond
291
     * @throws MetacatException when the metacat server generates another error
292
     */
293
    public InputStream readInlineData(String inlinedataid)
294
    throws InsufficientKarmaException,
295
            MetacatInaccessibleException, MetacatException {
296
        Reader r = null;
297
        
298
        Properties prop = new Properties();
299
        prop.put("action", "readinlinedata");
300
        prop.put("inlinedataid", inlinedataid);
301
        
302
        InputStream response = null;
303
        try {
304
            response = sendData(prop, null, null, 0);
305
        } catch (Exception e) {
306
            throw new MetacatInaccessibleException(e.getMessage());
307
        }
308
        BufferedInputStream bis = new BufferedInputStream(response);
309
        r = new InputStreamReader(bis);
310
        try {
311
        	bis.mark(512);
312
            char[] characters = new char[512];
313
            int len = r.read(characters, 0, 512);
314
            StringWriter sw = new StringWriter();
315
            sw.write(characters, 0, len);
316
            String message = sw.toString();
317
            sw.close();
318
            bis.reset();
319
            if (message.indexOf("<error>") != -1) {
320
                if (message.indexOf("does not have permission") != -1) {
321
                    throw new InsufficientKarmaException(message);
322
                } else {
323
                    throw new MetacatException(message);
324
                }
325
            }
326
        } catch (IOException ioe) {
327
            throw new MetacatException(
328
                    "MetacatClient: Error converting Reader to String."
329
                    + ioe.getMessage());
330
        }
331
        
332
        return bis;
333
    }
334
    
335
    /**
336
     * Query the metacat document store with the given metacat-compatible
337
     * query document and default qformat xml, and return the result set as a Reader.
338
     *
339
     * @param xmlQuery a Reader for accessing the XML version of the query
340
     * @return a Reader for accessing the result set
341
     */
342
    public Reader query(Reader xmlQuery) throws MetacatInaccessibleException,
343
            IOException {
344
        String qformat = "xml";
345
        return query(xmlQuery, qformat);
346
    }
347
    
348
    /**
349
     * Query the metacat document store with the given metacat-compatible
350
     * query document and qformat, and return the result set as a Reader.
351
     *
352
     * @param xmlQuery a Reader for accessing the XML version of the query
353
     * @param qformat the format of return doc. It can be xml, knb, lter and etal.
354
     * @return a Reader for accessing the result set
355
     */
356
    public Reader query(Reader xmlQuery, String qformat) throws MetacatInaccessibleException,
357
            IOException {
358
        Reader reader = null;
359
        String query = null;
360
        try {
361
            query = IOUtil.getAsString(xmlQuery, true);
362
        } catch (IOException ioE) {
363
            throw ioE;
364
        }
365
        
366
        //set up properties
367
        Properties prop = new Properties();
368
        prop.put("action", "squery");
369
        prop.put("qformat", qformat);
370
        prop.put("query", query);
371
        
372
        InputStream response = null;
373
        try {
374
            response = sendData(prop, null, null, 0);
375
        } catch (Exception e) {
376
            throw new MetacatInaccessibleException(e.getMessage());
377
        }
378
        reader = new InputStreamReader(response);
379
        return reader;
380
    }
381
    
382
    /**
383
     * Insert an XML document into the repository.
384
     *
385
     * @param docid the docid to insert the document
386
     * @param xmlDocument a Reader for accessing the XML document to be inserted
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 insert(String docid, Reader xmlDocument, Reader schema)
398
    	throws InsufficientKarmaException, MetacatException, IOException,
399
            MetacatInaccessibleException {
400

    
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", "insert");
416
        prop.put("docid", docid);
417
        prop.put("doctext", doctext);
418
        if (schematext != null) {
419
            prop.put("dtdtext", schematext);
420
        }
421

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

    
915
    /************************************************************************
916
     * PRIVATE METHODS
917
     ************************************************************************/
918
    
919
    /**
920
     * Send a request to metacat.
921
     *
922
     * @param prop the properties to be URL encoded and sent
923
     * @param filename  the properties to be sent to Metacat
924
     *                  in case of upload, otherwise null
925
     * @param fileData  the inputStream for the file data to be sent to Metacat
926
     *                  in case of upload, otherwise null
927
     * @param size      the size of the data being sent to Metacat
928
     *                  in case of upload, otherwise 0
929
     */
930
    synchronized private InputStream sendDataOnce(Properties args,
931
            Properties filename,
932
            InputStream fileData,
933
            int size)
934
            throws Exception {
935
        InputStream returnStream = null;
936
        URL url = new URL(metacatUrl);
937
        HttpMessage msg = new HttpMessage(url);
938
        msg.setCookie("JSESSIONID="+this.sessionId);
939
        if (filename == null){
940
            returnStream = msg.sendPostData(args);
941
        } else if (fileData == null){
942
            returnStream = msg.sendPostData(args, filename);
943
        } else if (size > 0) {
944
            returnStream = msg.sendPostData(args, filename, fileData, size);
945
        } else {
946
            throw new MetacatException("Invalid size specified for " +
947
                    "the input stream being passed");
948
        }
949
        return returnStream;
950
    }
951
    
952
    /**
953
     * Send a request to Metacat
954
     *
955
     * @param args  the properties to be sent to Metacat
956
     * @param filename  the properties to be sent to Metacat
957
     *                  in case of upload, otherwise null
958
     * @param fileData  the inputStream for the file data to be sent to Metacat
959
     *                  in case of upload, otherwise null
960
     * @param size      the size of the data being sent to Metacat
961
     *                  in case of upload, otherwise 0
962
     * @return      InputStream as returned by Metacat
963
     */
964
    synchronized public InputStream sendData(Properties args,
965
            Properties filename,
966
            InputStream fileData,
967
            int size)
968
            throws Exception {
969
        InputStream returnStream = null;
970
        /*
971
            Note:  The reason that there are three try statements all executing
972
            the same code is that there is a problem with the initial connection
973
            using the HTTPClient protocol handler.  These try statements make
974
            sure that a connection is made because it gives each connection a
975
            2nd and 3rd chance to work before throwing an error.
976
            THIS IS A TOTAL HACK.  THIS NEEDS TO BE LOOKED INTO AFTER THE BETA1
977
            RELEASE OF MORPHO!!!  cwb (7/24/01)
978
         */
979
        try {
980
            return sendDataOnce(args, filename, fileData, size);
981
        } catch (Exception e) {
982
            try {
983
                return sendDataOnce(args, filename, fileData, size);
984
            } catch (Exception e2) {
985
                try {
986
                    return sendDataOnce(args, filename, fileData, size);
987
                } catch (Exception e3) {
988
                    System.err.println(
989
                            "Failed to send data to metacat 3 times: " + e3.getMessage());
990
                    System.err.println("metacaturl: " + metacatUrl);
991
                    throw e3;
992
                }
993
            }
994
        }
995
    }
996
    
997
    /**
998
     * Send a request to Metacat
999
     *
1000
     * @param args      the properties to be sent to Metacat
1001
     * @param filename  the properties to be sent to Metacat
1002
     *                  in case of upload, otherwise null
1003
     * @param fileData  the inputStream for the file data to be sent to Metacat
1004
     *                  in case of upload, otherwise null
1005
     * @param size      the size of the data being sent to Metacat
1006
     *                  in case of upload, otherwise 0
1007
     * @return          a string as returned by Metacat
1008
     */
1009
    synchronized private String sendDataForString(Properties args,
1010
            Properties filename,
1011
            InputStream fileData,
1012
            int size)
1013
            throws Exception {
1014
        String response = null;
1015
        
1016
        try {
1017
            InputStreamReader returnStream =
1018
                    new InputStreamReader(sendData(args, filename,
1019
                    fileData, size));
1020
            StringWriter sw = new StringWriter();
1021
            int len;
1022
            char[] characters = new char[512];
1023
            while ((len = returnStream.read(characters, 0, 512)) != -1) {
1024
                sw.write(characters, 0, len);
1025
            }
1026
            returnStream.close();
1027
            response = sw.toString();
1028
            sw.close();
1029
        } catch (Exception e) {
1030
            throw e;
1031
        }
1032
        return response;
1033
    }
1034
    
1035
    /*
1036
     * "getversionanddoctype" action will return a string from metacat server.
1037
     * The string format is "revision;doctype"(This is bad idea, we should use xml)
1038
     * This method will get revision string from the response string
1039
     */
1040
    private String parserRevisionResponse(String response) throws Exception {
1041
        String revision = null;
1042
        if (response != null) {
1043
            if(response.indexOf("<error>") != -1) {
1044
                if(response.indexOf("There is not record") != -1) {
1045
                    return "0";
1046
                } else {
1047
                    return null;
1048
                }
1049
            } else {
1050
                int firstSemiCol = response.indexOf(";");
1051
                revision = response.substring(0, firstSemiCol);
1052
            }
1053
        }
1054
        return revision;
1055
    }
1056
    
1057
    /**
1058
     * JSP API: This is a convenience method to reduce the amount of code in a Metacat Client
1059
     * JSP.  It handles creating/reusing an instance of a MetacatClient.
1060
     * @param request Since this is intended to be used by a JSP, it is passed the
1061
     * available "request" variable (the HttpServletRequest).
1062
     * @throws edu.ucsb.nceas.metacat.client.MetacatInaccessibleException Received by MetacatFactory.
1063
     * @return MetacatClient instance.
1064
     */
1065
    public static MetacatClient getMetacatClient(HttpServletRequest request) throws MetacatInaccessibleException {
1066
        MetacatClient                       result;
1067
        String                              metacatPath = "http://%1$s%2$s/metacat";
1068
        String                              host, context;
1069
        javax.servlet.http.HttpSession      session;
1070
        
1071
        session = request.getSession();
1072
        result = (MetacatClient) session.getAttribute("MetacatClient");
1073
        if (result == null) {
1074
            host = request.getHeader("host");
1075
            context = request.getContextPath();
1076
            metacatPath = metacatPath.replaceFirst("%1$s", host);
1077
            metacatPath = metacatPath.replaceFirst("%2$s", context);
1078
            result = (MetacatClient) MetacatFactory.createMetacatConnection(metacatPath);
1079
            session.setAttribute("MetacatClient", result);
1080
        }
1081
        return(result);
1082
    }
1083
    
1084
}
(5-5/8)