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: 2009-11-06 14:47:55 -0800 (Fri, 06 Nov 2009) $'
8
 * '$Revision: 5112 $'
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
    		Metacat mc = 
65
    			MetacatFactory.createMetacatConnection(args[0]);
66
    		
67
    		InputStream r = mc.read(args[1]);
68
    		FileOutputStream fos = new FileOutputStream(args[2]);
69
    		BufferedOutputStream bfos = new BufferedOutputStream(fos);
70

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

    
231
	/**
232
     *  Method used to log in to a metacat server. Implementations will need
233
     *  to cache a cookie value to make the session persistent.  Each time a
234
     *  call is made to one of the other methods (e.g., read), the cookie will
235
     *  need to be passed back to the metacat server along with the request.
236
     *
237
     *  @param username   the username of the user, like an LDAP DN
238
     *  @param password   the password for that user for authentication
239
     *  @return the response string from metacat in XML format
240
     *  @throws MetacatAuthException when the username/password could
241
     *                    not be authenticated
242
     */
243
    public String isAuthorized(String resourceLsid, String permission, String sessionId)
244
    		throws MetacatAuthException, MetacatInaccessibleException {
245
    	
246
        Properties prop = new Properties();
247
        prop.put("action", "isauthorized");
248
        prop.put("resourceLsid", resourceLsid);
249
        prop.put("permission", permission);
250
        prop.put("sessionId", sessionId);
251
        
252
        String response = null;
253
        try {
254
            response = sendDataForString(prop, null, null, 0);
255
        } catch (Exception e) {
256
            throw new MetacatInaccessibleException(e.getMessage());
257
        }
258
        
259
        if (response.indexOf("<resourceAuthorization>") == -1) {
260
        	System.out.println("invalid response: " + response);
261
            throw new MetacatAuthException(response);
262
        } 
263
        
264
        return response;
265
    }
266
    
267
    /**
268
     * Read an XML document from the metacat server session, accessed by docid,
269
     * and returned as a Reader.
270
     *
271
     * @param docid the identifier of the document to be read
272
     * @return a Reader for accessing the document
273
     * @throws InsufficientKarmaException when the user has insufficent rights
274
     *                                    for the operation
275
     * @throws MetacatInaccessibleException when the metacat server can not be
276
     *                                    reached or does not respond
277
     * @throws MetacatException when the metacat server generates another error
278
     */
279
    public InputStream read(String docid) throws InsufficientKarmaException,
280
            MetacatInaccessibleException, MetacatException, DocumentNotFoundException {
281
    	Reader r = null;
282
        
283
        Properties prop = new Properties();
284
        prop.put("action", "read");
285
        prop.put("qformat", "xml");
286
        prop.put("docid", docid);
287
        InputStream response = null;
288
        try {
289
            response = sendData(prop, null, null, 0);
290
        } catch (Exception e) {
291
            throw new MetacatInaccessibleException(e.getMessage());
292
        }
293
        BufferedInputStream bis = new BufferedInputStream(response);
294
        r = new InputStreamReader(bis);
295
        try {
296
        	bis.mark(512);
297
            char[] characters = new char[512];
298
            int len = r.read(characters, 0, 512);
299
            StringWriter sw = new StringWriter();
300
            sw.write(characters, 0, len);
301
            String message = sw.toString();
302
            sw.close();
303
            bis.reset();
304
            if (message.indexOf("<error>") != -1) {
305
                if (message.indexOf("does not have permission") != -1) {
306
                    throw new InsufficientKarmaException(message);
307
                } else if(message.indexOf("does not exist") != -1) {
308
                    throw new DocumentNotFoundException(message);
309
                } else {
310
                    throw new MetacatException(message);
311
                }
312
            }
313
        } catch (IOException ioe) {
314
            throw new MetacatException(
315
                    "MetacatClient: Error converting Reader to String."
316
                    + ioe.getMessage());
317
        }
318
        return bis;
319
    }
320
    
321
    
322
    /**
323
     * Read inline data from the metacat server session, accessed by
324
     * inlinedataid and returned as a Reader.
325
     *
326
     * @param inlinedataid the identifier of the data to be read
327
     * @return a Reader for accessing the document
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
     */
334
    public InputStream readInlineData(String inlinedataid)
335
    throws InsufficientKarmaException,
336
            MetacatInaccessibleException, MetacatException {
337
        Reader r = null;
338
        
339
        Properties prop = new Properties();
340
        prop.put("action", "readinlinedata");
341
        prop.put("inlinedataid", inlinedataid);
342
        
343
        InputStream response = null;
344
        try {
345
            response = sendData(prop, null, null, 0);
346
        } catch (Exception e) {
347
            throw new MetacatInaccessibleException(e.getMessage());
348
        }
349
        BufferedInputStream bis = new BufferedInputStream(response);
350
        r = new InputStreamReader(bis);
351
        try {
352
        	bis.mark(512);
353
            char[] characters = new char[512];
354
            int len = r.read(characters, 0, 512);
355
            StringWriter sw = new StringWriter();
356
            sw.write(characters, 0, len);
357
            String message = sw.toString();
358
            sw.close();
359
            bis.reset();
360
            if (message.indexOf("<error>") != -1) {
361
                if (message.indexOf("does not have permission") != -1) {
362
                    throw new InsufficientKarmaException(message);
363
                } else {
364
                    throw new MetacatException(message);
365
                }
366
            }
367
        } catch (IOException ioe) {
368
            throw new MetacatException(
369
                    "MetacatClient: Error converting Reader to String."
370
                    + ioe.getMessage());
371
        }
372
        
373
        return bis;
374
    }
375
    
376
    /**
377
     * Query the metacat document store with the given metacat-compatible
378
     * query document and default qformat xml, and return the result set as a Reader.
379
     *
380
     * @param xmlQuery a Reader for accessing the XML version of the query
381
     * @return a Reader for accessing the result set
382
     */
383
    public Reader query(Reader xmlQuery) throws MetacatInaccessibleException,
384
            IOException {
385
        String qformat = "xml";
386
        return query(xmlQuery, qformat);
387
    }
388
    
389
    /**
390
     * Query the metacat document store with the given metacat-compatible
391
     * query document and qformat, and return the result set as a Reader.
392
     *
393
     * @param xmlQuery a Reader for accessing the XML version of the query
394
     * @param qformat the format of return doc. It can be xml, knb, lter and etal.
395
     * @return a Reader for accessing the result set
396
     */
397
    public Reader query(Reader xmlQuery, String qformat) throws MetacatInaccessibleException,
398
            IOException {
399
        Reader reader = null;
400
        String query = null;
401
        try {
402
            query = IOUtil.getAsString(xmlQuery, true);
403
        } catch (IOException ioE) {
404
            throw ioE;
405
        }
406
        
407
        //set up properties
408
        Properties prop = new Properties();
409
        prop.put("action", "squery");
410
        prop.put("qformat", qformat);
411
        prop.put("query", query);
412
        
413
        InputStream response = null;
414
        try {
415
            response = sendData(prop, null, null, 0);
416
        } catch (Exception e) {
417
            throw new MetacatInaccessibleException(e.getMessage());
418
        }
419
        reader = new InputStreamReader(response);
420
        return reader;
421
    }
422
    
423
    /**
424
     * Insert an XML document into the repository.
425
     *
426
     * @param docid the docid to insert the document
427
     * @param xmlDocument a Reader for accessing the XML document to be inserted
428
     * @param schema a Reader for accessing the DTD or XML Schema for
429
     *               the document
430
     * @return the metacat response message
431
     * @throws InsufficientKarmaException when the user has insufficent rights
432
     *                                    for the operation
433
     * @throws MetacatInaccessibleException when the metacat server can not be
434
     *                                    reached or does not respond
435
     * @throws MetacatException when the metacat server generates another error
436
     * @throws IOException when there is an error reading the xml document
437
     */
438
    public String insert(String docid, Reader xmlDocument, Reader schema)
439
    	throws InsufficientKarmaException, MetacatException, IOException,
440
            MetacatInaccessibleException {
441

    
442
        Reader reader = null;
443
        String doctext = null;
444
        String schematext = null;
445
        try {
446
            doctext = IOUtil.getAsString(xmlDocument, true);
447
            if (schema != null) {
448
                schematext = IOUtil.getAsString(schema, true);
449
            }
450
        } catch (IOException ioE) {
451
            throw ioE;
452
        }
453
        
454
        //set up properties
455
        Properties prop = new Properties();
456
        prop.put("action", "insert");
457
        prop.put("docid", docid);
458
        prop.put("doctext", doctext);
459
        if (schematext != null) {
460
            prop.put("dtdtext", schematext);
461
        }
462

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

    
1024
    /************************************************************************
1025
     * PRIVATE METHODS
1026
     ************************************************************************/
1027
    
1028
    /**
1029
     * Send a request to metacat.
1030
     *
1031
     * @param prop the properties to be URL encoded and sent
1032
     * @param filename  the properties to be sent to Metacat
1033
     *                  in case of upload, otherwise null
1034
     * @param fileData  the inputStream for the file data to be sent to Metacat
1035
     *                  in case of upload, otherwise null
1036
     * @param size      the size of the data being sent to Metacat
1037
     *                  in case of upload, otherwise 0
1038
     */
1039
    synchronized private InputStream sendDataOnce(Properties args,
1040
            Properties filename,
1041
            InputStream fileData,
1042
            int size)
1043
            throws Exception {
1044
        InputStream returnStream = null;
1045
        URL url = new URL(metacatUrl);
1046
        HttpMessage msg = new HttpMessage(url);
1047
        msg.setCookie("JSESSIONID="+this.sessionId);
1048
        if (filename == null){
1049
            returnStream = msg.sendPostData(args);
1050
        } else if (fileData == null){
1051
            returnStream = msg.sendPostData(args, filename);
1052
        } else if (size > 0) {
1053
            returnStream = msg.sendPostData(args, filename, fileData, size);
1054
        } else {
1055
            throw new MetacatException("Invalid size specified for " +
1056
                    "the input stream being passed");
1057
        }
1058
        return returnStream;
1059
    }
1060
    
1061
    /**
1062
     * Send a request to Metacat
1063
     *
1064
     * @param args  the properties to be sent to Metacat
1065
     * @param filename  the properties to be sent to Metacat
1066
     *                  in case of upload, otherwise null
1067
     * @param fileData  the inputStream for the file data to be sent to Metacat
1068
     *                  in case of upload, otherwise null
1069
     * @param size      the size of the data being sent to Metacat
1070
     *                  in case of upload, otherwise 0
1071
     * @return      InputStream as returned by Metacat
1072
     */
1073
    synchronized public InputStream sendData(Properties args,
1074
            Properties filename,
1075
            InputStream fileData,
1076
            int size)
1077
            throws Exception {
1078
        InputStream returnStream = null;
1079
        /*
1080
            Note:  The reason that there are three try statements all executing
1081
            the same code is that there is a problem with the initial connection
1082
            using the HTTPClient protocol handler.  These try statements make
1083
            sure that a connection is made because it gives each connection a
1084
            2nd and 3rd chance to work before throwing an error.
1085
            THIS IS A TOTAL HACK.  THIS NEEDS TO BE LOOKED INTO AFTER THE BETA1
1086
            RELEASE OF MORPHO!!!  cwb (7/24/01)
1087
         */
1088
        try {
1089
            return sendDataOnce(args, filename, fileData, size);
1090
        } catch (Exception e) {
1091
            try {
1092
                return sendDataOnce(args, filename, fileData, size);
1093
            } catch (Exception e2) {
1094
                try {
1095
                    return sendDataOnce(args, filename, fileData, size);
1096
                } catch (Exception e3) {
1097
                    System.err.println(
1098
                            "Failed to send data to metacat 3 times: " + e3.getMessage());
1099
                    System.err.println("metacaturl: " + metacatUrl);
1100
                    throw e3;
1101
                }
1102
            }
1103
        }
1104
    }
1105
    
1106
    /**
1107
     * Send a request to Metacat
1108
     *
1109
     * @param args      the properties to be sent to Metacat
1110
     * @param filename  the properties to be sent to Metacat
1111
     *                  in case of upload, otherwise null
1112
     * @param fileData  the inputStream for the file data to be sent to Metacat
1113
     *                  in case of upload, otherwise null
1114
     * @param size      the size of the data being sent to Metacat
1115
     *                  in case of upload, otherwise 0
1116
     * @return          a string as returned by Metacat
1117
     */
1118
    synchronized private String sendDataForString(Properties args,
1119
            Properties filename,
1120
            InputStream fileData,
1121
            int size)
1122
            throws Exception {
1123
        String response = null;
1124
        
1125
        try {
1126
            InputStreamReader returnStream =
1127
                    new InputStreamReader(sendData(args, filename,
1128
                    fileData, size));
1129
            StringWriter sw = new StringWriter();
1130
            int len;
1131
            char[] characters = new char[512];
1132
            while ((len = returnStream.read(characters, 0, 512)) != -1) {
1133
                sw.write(characters, 0, len);
1134
            }
1135
            returnStream.close();
1136
            response = sw.toString();
1137
            sw.close();
1138
        } catch (Exception e) {
1139
            throw e;
1140
        }
1141
        return response;
1142
    }
1143
    
1144
    /*
1145
     * "getversionanddoctype" action will return a string from metacat server.
1146
     * The string format is "revision;doctype"(This is bad idea, we should use xml)
1147
     * This method will get revision string from the response string
1148
     */
1149
    private String parserRevisionResponse(String response) throws Exception {
1150
        String revision = null;
1151
        if (response != null) {
1152
            if(response.indexOf("<error>") != -1) {
1153
                if(response.indexOf("There is not record") != -1) {
1154
                    return "0";
1155
                } else {
1156
                    return null;
1157
                }
1158
            } else {
1159
                int firstSemiCol = response.indexOf(";");
1160
                revision = response.substring(0, firstSemiCol);
1161
            }
1162
        }
1163
        return revision;
1164
    }
1165
    
1166
    /**
1167
     * JSP API: This is a convenience method to reduce the amount of code in a Metacat Client
1168
     * JSP.  It handles creating/reusing an instance of a MetacatClient.
1169
     * @param request Since this is intended to be used by a JSP, it is passed the
1170
     * available "request" variable (the HttpServletRequest).
1171
     * @throws edu.ucsb.nceas.metacat.client.MetacatInaccessibleException Received by MetacatFactory.
1172
     * @return MetacatClient instance.
1173
     */
1174
    public static MetacatClient getMetacatClient(HttpServletRequest request) throws MetacatInaccessibleException {
1175
        MetacatClient                       result;
1176
        String                              metacatPath = "http://%1$s%2$s/metacat";
1177
        String                              host, context;
1178
        javax.servlet.http.HttpSession      session;
1179
        
1180
        session = request.getSession();
1181
        result = (MetacatClient) session.getAttribute("MetacatClient");
1182
        if (result == null) {
1183
            host = request.getHeader("host");
1184
            context = request.getContextPath();
1185
            metacatPath = metacatPath.replaceFirst("%1$s", host);
1186
            metacatPath = metacatPath.replaceFirst("%2$s", context);
1187
            result = (MetacatClient) MetacatFactory.createMetacatConnection(metacatPath);
1188
            session.setAttribute("MetacatClient", result);
1189
        }
1190
        return(result);
1191
    }
1192
    
1193
}
(5-5/8)