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-10-30 15:39:35 -0700 (Fri, 30 Oct 2009) $'
8
 * '$Revision: 5098 $'
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
    /**
689
     * set the access on an XML document in the repository.
690
     *
691
     * @param _docid the docid of the document for which the access should be applied.
692
     *
693
     * @param _principal the document's principal
694
     *
695
     * @param _permission the access permission to be applied to the docid
696
     *  {e.g. read,write,all}
697
     *
698
     * @param _permType the permission type to be applied to the document
699
     *  {e.g. allow or deny}
700
     *
701
     * @param _permOrder the order that the document's permissions should be
702
     *  processed {e.g. denyFirst or allowFirst}
703
     *
704
     *
705
     * @return the metacat response message
706
     *
707
     * @throws InsufficientKarmaException when the user has insufficent rights
708
     *                                    for the operation
709
     * @throws MetacatInaccessibleException when the metacat server can not be
710
     *                                    reached or does not respond
711
     * @throws MetacatException when the metacat server generates another error
712
     */
713
    public String setAccess(String docid, String principal, String
714
            permission, String permType, String permOrder )
715
            throws InsufficientKarmaException, MetacatException,
716
            MetacatInaccessibleException {
717
        //set up properties
718
        Properties prop = new Properties();
719
        prop.put("action", "setaccess");
720
        prop.put("docid", docid);
721
        prop.put("principal", principal);
722
        prop.put("permission", permission);
723
        prop.put("permType", permType);
724
        prop.put("permOrder", permOrder);
725
        
726
        String response = null;
727
        try {
728
            response = sendDataForString(prop, null, null, 0);
729
        } catch (Exception e) {
730
            throw new MetacatInaccessibleException(e.getMessage());
731
        }
732
        
733
        // Check for an error condition
734
        if (response.indexOf("<error>") != -1) {
735
            if (response.indexOf("does not have permission") != -1) {
736
                throw new InsufficientKarmaException(response);
737
            } else {
738
                throw new MetacatException(response);
739
            }
740
        }
741
        return response;
742
    }
743
    
744
    /**
745
	 * Set access for a given doc id. The access is represented in an access
746
	 * block of xml. All existing access will be replaced with the access
747
	 * provided in the access block.
748
	 * 
749
	 * @param docid
750
	 *            the doc id for the doc we want to update
751
	 * @param accessBlock
752
	 *            the xml access block. This is the same structure as that
753
	 *            returned by the getdocumentinfo action in metacat.
754
	 * @return a string holding the response xml
755
	 */
756
    public String setAccess(String docid, String accessBlock)
757
            throws InsufficientKarmaException, MetacatException, MetacatInaccessibleException {
758
        //set up properties
759
        Properties prop = new Properties();
760
        prop.put("action", "setaccess");
761
        prop.put("docid", docid);
762
        prop.put("accessBlock", accessBlock);
763
        
764
        String response = null;
765
        try {
766
            response = sendDataForString(prop, null, null, 0);
767
        } catch (Exception e) {
768
            throw new MetacatInaccessibleException(e.getMessage());
769
        }
770
        
771
        // Check for an error condition
772
        if (response.indexOf("<error>") != -1) {
773
            if (response.indexOf("does not have permission") != -1) {
774
                throw new InsufficientKarmaException(response);
775
            } else {
776
                throw new MetacatException(response);
777
            }
778
        }
779
        return response;
780
    }
781
    
782
    /**
783
     * When the MetacatFactory creates an instance it needs to set the
784
     * MetacatUrl to which connections should be made.
785
     *
786
     * @param metacatUrl the URL for the metacat server
787
     */
788
    public void setMetacatUrl(String metacatUrl) {
789
        this.metacatUrl = metacatUrl;
790
    }
791
    
792
    /**
793
     * Get the session identifier for this session.  This is only valid if
794
     * the login methods has been called successfully for this Metacat object
795
     * beforehand.
796
     *
797
     * @returns the sessionId as a String, or null if the session is invalid
798
     */
799
    public String getSessionId() {
800
        return this.sessionId;
801
    }
802
    
803
    /**
804
     * Set the session identifier for this session.  This identifier was
805
     * previously established with a call to login.  To continue to use the
806
     * same session, set the session id before making a call to one of the
807
     * metacat access methods (e.g., read, query, insert, etc.).
808
     *
809
     * @param String the sessionId from a previously established session
810
     */
811
    public void setSessionId(String sessionId) {
812
        this.sessionId = sessionId;
813
    }
814
    
815
    /**
816
     * The method will return the latest revision in metacat server
817
     * for a given document id. If some error happens, this method will throw
818
     * an exception.
819
     * @param docId String  the given docid you want to use. the docid it self
820
     *                      can have or haven't revision number
821
     * @throws MetacatException
822
     */
823
    public int getNewestDocRevision(String docId) throws MetacatException {
824
        int rev = 0;
825
        //set up properties
826
        Properties prop = new Properties();
827
        prop.put("action", "getrevisionanddoctype");
828
        prop.put("docid", docId);
829
        
830
        String response = null;
831
        try {
832
            response = sendDataForString(prop, null, null, 0);
833
            //parseRevisionResponse will return null if there is an
834
            //error that it can't handle
835
            String revStr = parserRevisionResponse(response);
836
            Integer revObj = new Integer(revStr);
837
            rev = revObj.intValue();
838
            // Check for an error condition
839
            if (response.indexOf("<error>") != -1 && revStr == null) {
840
                throw new MetacatException(response);
841
            }
842
        } catch (Exception e) {
843
            throw new MetacatException(e.getMessage());
844
        }
845
        return rev;
846
    }
847
    
848
    /**
849
     * Return the highest document id for a given scope.  This is used by
850
     * clients to make it easier to determine the next free identifier in a
851
     * sequence for a given scope.
852
     * @param scope String  the scope to use for looking up the latest id
853
     * @throws MetacatException when an error occurs
854
     */
855
    public String getLastDocid(String scope) throws MetacatException {
856
        String lastIdentifier = "";
857
        //set up properties
858
        Properties prop = new Properties();
859
        prop.put("action", "getlastdocid");
860
        prop.put("scope", scope);
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
                Node root =
871
                        XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
872
                Node docidNode =
873
                        XMLUtilities.getNodeWithXPath(root, "/lastDocid/docid");
874
                lastIdentifier = docidNode.getFirstChild().getNodeValue();
875
            }
876
        } catch (Exception e) {
877
            throw new MetacatException(e.getMessage());
878
        }
879
        return lastIdentifier;
880
    }
881
    
882
    /**
883
     * return a list of all docids that match a given scope.  if scope is null
884
     * return all docids registered in the system
885
     * @param scope String  the scope to use to limit the docid query
886
     * @throws MetacatException when an error occurs
887
     */
888
    public Vector getAllDocids(String scope) throws MetacatException {
889
        Vector resultVec = new Vector();
890
        //set up properties
891
        Properties prop = new Properties();
892
        prop.put("action", "getalldocids");
893
        if(scope != null) {
894
            prop.put("scope", scope);
895
        }
896
        
897
        String response = null;
898
        try {
899
            response = sendDataForString(prop, null, null, 0);
900
            // Check for an error condition
901
            if (response.indexOf("<error>") != -1) {
902
                throw new MetacatException(response);
903
            } else {
904
                Reader responseReader = new StringReader(response);
905
                Node root =
906
                        XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
907
                NodeList nlist = root.getChildNodes();
908
                for(int i=0; i<nlist.getLength(); i++) {
909
                    Node n = nlist.item(i);
910
                    if(n.getNodeName().equals("docid")) {
911
                        //add the content to the return vector
912
                        String nodeVal = n.getFirstChild().getNodeValue();
913
                        resultVec.addElement(nodeVal);
914
                    }
915
                }
916
                
917
            }
918
        } catch (Exception e) {
919
            throw new MetacatException(e.getMessage());
920
        }
921
        return resultVec;
922
    }
923
    
924
    /**
925
     * return true of the given docid is registered, false if not
926
     * @param scope String  the scope to use to limit the docid query
927
     * @throws MetacatException when an error occurs
928
     */
929
    public boolean isRegistered(String docid) throws MetacatException {
930
        Vector resultVec = new Vector();
931
        //set up properties
932
        Properties prop = new Properties();
933
        prop.put("action", "isregistered");
934
        if(docid == null) {
935
            throw new MetacatException("<error>Cannot check if a null docid " +
936
                    "is registered.</error>");
937
        }
938
        prop.put("docid", docid);
939
        
940
        String response = null;
941
        try {
942
            response = sendDataForString(prop, null, null, 0);
943
            // Check for an error condition
944
            if (response.indexOf("<error>") != -1) {
945
                throw new MetacatException(response);
946
            } else {
947
                Reader responseReader = new StringReader(response);
948
                StringBuffer sb = new StringBuffer();
949
                char[] c = new char[1024];
950
                int numread = responseReader.read(c, 0, 1024);
951
                while(numread != -1) {
952
                    sb.append(new String(c, 0, numread));
953
                    numread = responseReader.read(c, 0, 1024);
954
                }
955
                
956
                String responseStr = sb.toString();
957
                if(responseStr.indexOf("true") != -1) {
958
                    return true;
959
                }
960
                return false;
961
            }
962
        } catch (Exception e) {
963
            throw new MetacatException(e.getMessage());
964
        }
965
    }
966
    
967
    /**
968
     * Send a request to Metacat.  An alternative to the sentData method.
969
     * Allows for sending multiple parameters with the same name, 
970
     * different names, or any combo.  Send properties where the entry 
971
     * key contains the "param value", 
972
     * and the entry value contains the "param name".  
973
     * Constraint: param values must be unique.
974
     *
975
     * @return InputStream as returned by Metacat
976
     * @param args Properties of the parameters to be sent to Metacat, where,
977
     *      key = param value
978
     *      value = param name
979
     * @throws java.lang.Exception thrown
980
     */
981
    synchronized public InputStream sendParameters(Properties args) throws Exception {
982
        InputStream                     result = null;
983
        URL                             url;
984
        HttpMessage                     httpMsg;
985
        
986
        url = new URL(metacatUrl);
987
        httpMsg = new HttpMessage(url);
988
        httpMsg.setCookie("JSESSIONID="+this.sessionId);
989
        result = httpMsg.sendPostParameters(args);
990
        return(result);
991
    }
992

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