Project

General

Profile

1 1780 jones
/**
2
 *  '$RCSfile$'
3
 *  Copyright: 2000 Regents of the University of California and the
4
 *              National Center for Ecological Analysis and Synthesis
5
 *
6
 *   '$Author$'
7
 *     '$Date$'
8
 * '$Revision$'
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 5066 leinfelder
import java.io.BufferedInputStream;
28
import java.io.BufferedOutputStream;
29
import java.io.FileOutputStream;
30 1780 jones
import java.io.InputStream;
31 1783 jones
import java.io.InputStreamReader;
32 2981 jones
import java.io.StringReader;
33 1784 jones
import java.io.IOException;
34 1783 jones
import java.io.StringWriter;
35 1780 jones
import java.io.Reader;
36
import java.net.URL;
37
import java.util.Properties;
38 3141 berkley
import java.util.Vector;
39 3300 barteau
import javax.servlet.http.HttpServletRequest;
40 1780 jones
41 2981 jones
import org.w3c.dom.Node;
42 3141 berkley
import org.w3c.dom.NodeList;
43 2981 jones
44 1780 jones
import edu.ucsb.nceas.utilities.HttpMessage;
45 1788 jones
import edu.ucsb.nceas.utilities.IOUtil;
46 2981 jones
import edu.ucsb.nceas.utilities.XMLUtilities;
47 2240 sgarg
import java.io.File;
48 1780 jones
49 5066 leinfelder
50 1780 jones
/**
51 2240 sgarg
 *  This interface provides methods for initializing and logging in to a
52
 *  Metacat server, and then querying, reading, transforming, inserting,
53 1780 jones
 *  updating and deleting documents from that server.
54
 */
55 3285 barteau
public class MetacatClient implements Metacat {
56 1780 jones
    /** The URL string for the metacat server */
57
    private String metacatUrl;
58 3285 barteau
59 1822 jones
    /** The session identifier for the session */
60
    private String sessionId;
61 3285 barteau
62 5066 leinfelder
    public static void main(String[] args) {
63
    	try {
64 5069 leinfelder
    		Metacat mc =
65
    			MetacatFactory.createMetacatConnection(args[0]);
66 5066 leinfelder
67 5069 leinfelder
    		InputStream r = mc.read(args[1]);
68
    		FileOutputStream fos = new FileOutputStream(args[2]);
69
    		BufferedOutputStream bfos = new BufferedOutputStream(fos);
70 5066 leinfelder
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 3300 barteau
    /**
87 1780 jones
     * Constructor to create a new instance. Protected because instances
88
     * should only be created by the factory MetacatFactory.
89
     */
90 3285 barteau
    protected MetacatClient() {
91 1822 jones
        this.metacatUrl = null;
92
        this.sessionId = null;
93 1780 jones
    }
94 3285 barteau
95 1780 jones
    /**
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 1822 jones
     *  @return the response string from metacat in XML format
104 1780 jones
     *  @throws MetacatAuthException when the username/password could
105
     *                    not be authenticated
106
     */
107 2240 sgarg
    public String login(String username, String password)
108 3285 barteau
    throws MetacatAuthException, MetacatInaccessibleException {
109 1783 jones
        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 5072 daigle
//        if (this.sessionId != null) {
115
//        	prop.put("sessionid", sessionId);
116
//        }
117 3285 barteau
118 1783 jones
        String response = null;
119
        try {
120 2264 sgarg
            response = sendDataForString(prop, null, null, 0);
121 1783 jones
        } catch (Exception e) {
122
            throw new MetacatInaccessibleException(e.getMessage());
123
        }
124 3285 barteau
125 1783 jones
        if (response.indexOf("<login>") == -1) {
126 1828 jones
            setSessionId("");
127 1783 jones
            throw new MetacatAuthException(response);
128 1822 jones
        } else {
129 1825 jones
            int start = response.indexOf("<sessionId>") + 11;
130 1822 jones
            int end = response.indexOf("</sessionId>");
131
            if ((start != -1) && (end != -1)) {
132 1828 jones
                setSessionId(response.substring(start,end));
133 1822 jones
            }
134 1783 jones
        }
135 1822 jones
        return response;
136 1780 jones
    }
137 2683 sgarg
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 3285 barteau
    public String getloggedinuserinfo() throws MetacatInaccessibleException {
151 2683 sgarg
        Properties prop = new Properties();
152
        prop.put("action", "getloggedinuserinfo");
153
        prop.put("qformat", "xml");
154 3285 barteau
155 2683 sgarg
        String response = null;
156
        try {
157
            response = sendDataForString(prop, null, null, 0);
158
        } catch (Exception e) {
159
            throw new MetacatInaccessibleException(e.getMessage());
160
        }
161 3285 barteau
162 2683 sgarg
        return response;
163
    }
164 3285 barteau
165 1780 jones
    /**
166 1822 jones
     *  Method used to log out a metacat server. The Metacat server will end
167
     *  the session when this call is invoked.
168 1798 tao
     *
169 1822 jones
     *  @return the response string from metacat in XML format
170 1798 tao
     *  @throws MetacatInaccessibleException when the metacat server can not be
171
     *                                    reached or does not respond
172
     */
173 3285 barteau
    public String logout() throws MetacatInaccessibleException, MetacatException {
174 1798 tao
        Properties prop = new Properties();
175
        prop.put("action", "logout");
176 2240 sgarg
        prop.put("qformat", "xml");
177 5072 daigle
        if (this.sessionId != null) {
178
        	prop.put("sessionid", sessionId);
179
        }
180 3285 barteau
181 1798 tao
        String response = null;
182
        try {
183 2264 sgarg
            response = sendDataForString(prop, null, null, 0);
184 1798 tao
        } catch (Exception e) {
185
            throw new MetacatInaccessibleException(e.getMessage());
186
        }
187 3285 barteau
188 1798 tao
        if (response.indexOf("<logout>") == -1) {
189
            throw new MetacatException(response);
190
        }
191 1828 jones
        setSessionId("");
192 1822 jones
        return response;
193 1798 tao
    }
194 3285 barteau
195 1798 tao
    /**
196 5057 daigle
     *  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 5066 leinfelder
230
231
	/**
232 5072 daigle
     *  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 1780 jones
     * 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 2240 sgarg
     * @throws InsufficientKarmaException when the user has insufficent rights
274 1780 jones
     *                                    for the operation
275 1784 jones
     * @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 1780 jones
     */
279 5066 leinfelder
    public InputStream read(String docid) throws InsufficientKarmaException,
280 3285 barteau
            MetacatInaccessibleException, MetacatException, DocumentNotFoundException {
281 5066 leinfelder
    	Reader r = null;
282 3285 barteau
283 1784 jones
        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 2264 sgarg
            response = sendData(prop, null, null, 0);
290 1784 jones
        } catch (Exception e) {
291
            throw new MetacatInaccessibleException(e.getMessage());
292
        }
293 5066 leinfelder
        BufferedInputStream bis = new BufferedInputStream(response);
294
        r = new InputStreamReader(bis);
295 1784 jones
        try {
296 5066 leinfelder
        	bis.mark(512);
297 1784 jones
            char[] characters = new char[512];
298 5066 leinfelder
            int len = r.read(characters, 0, 512);
299 1784 jones
            StringWriter sw = new StringWriter();
300
            sw.write(characters, 0, len);
301
            String message = sw.toString();
302
            sw.close();
303 5066 leinfelder
            bis.reset();
304 1784 jones
            if (message.indexOf("<error>") != -1) {
305
                if (message.indexOf("does not have permission") != -1) {
306
                    throw new InsufficientKarmaException(message);
307 2989 berkley
                } else if(message.indexOf("does not exist") != -1) {
308
                    throw new DocumentNotFoundException(message);
309 1784 jones
                } else {
310
                    throw new MetacatException(message);
311
                }
312
            }
313
        } catch (IOException ioe) {
314
            throw new MetacatException(
315 2240 sgarg
                    "MetacatClient: Error converting Reader to String."
316 1784 jones
                    + ioe.getMessage());
317
        }
318 5066 leinfelder
        return bis;
319 1780 jones
    }
320 3285 barteau
321
322 1780 jones
    /**
323 3285 barteau
     * 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 5066 leinfelder
    public InputStream readInlineData(String inlinedataid)
335 3285 barteau
    throws InsufficientKarmaException,
336
            MetacatInaccessibleException, MetacatException {
337 5066 leinfelder
        Reader r = null;
338 3285 barteau
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 5066 leinfelder
        BufferedInputStream bis = new BufferedInputStream(response);
350
        r = new InputStreamReader(bis);
351 3285 barteau
        try {
352 5066 leinfelder
        	bis.mark(512);
353 3285 barteau
            char[] characters = new char[512];
354 5066 leinfelder
            int len = r.read(characters, 0, 512);
355 3285 barteau
            StringWriter sw = new StringWriter();
356
            sw.write(characters, 0, len);
357
            String message = sw.toString();
358
            sw.close();
359 5066 leinfelder
            bis.reset();
360 3285 barteau
            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 5066 leinfelder
        return bis;
374 3285 barteau
    }
375
376 2261 sgarg
    /**
377 2240 sgarg
     * Query the metacat document store with the given metacat-compatible
378 3464 tao
     * query document and default qformat xml, and return the result set as a Reader.
379 1780 jones
     *
380
     * @param xmlQuery a Reader for accessing the XML version of the query
381
     * @return a Reader for accessing the result set
382
     */
383 1786 tao
    public Reader query(Reader xmlQuery) throws MetacatInaccessibleException,
384 3285 barteau
            IOException {
385 3464 tao
        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 1786 tao
        Reader reader = null;
400
        String query = null;
401 1788 jones
        try {
402 3285 barteau
            query = IOUtil.getAsString(xmlQuery, true);
403 1788 jones
        } catch (IOException ioE) {
404 3285 barteau
            throw ioE;
405 1786 tao
        }
406 3285 barteau
407 1786 tao
        //set up properties
408
        Properties prop = new Properties();
409
        prop.put("action", "squery");
410 3464 tao
        prop.put("qformat", qformat);
411 1786 tao
        prop.put("query", query);
412 3285 barteau
413 1786 tao
        InputStream response = null;
414
        try {
415 2264 sgarg
            response = sendData(prop, null, null, 0);
416 1786 tao
        } catch (Exception e) {
417
            throw new MetacatInaccessibleException(e.getMessage());
418
        }
419
        reader = new InputStreamReader(response);
420
        return reader;
421 1780 jones
    }
422 3285 barteau
423 1780 jones
    /**
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 2240 sgarg
     * @param schema a Reader for accessing the DTD or XML Schema for
429 1780 jones
     *               the document
430 1789 jones
     * @return the metacat response message
431 2240 sgarg
     * @throws InsufficientKarmaException when the user has insufficent rights
432 1780 jones
     *                                    for the operation
433 1789 jones
     * @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 1780 jones
     */
438 1789 jones
    public String insert(String docid, Reader xmlDocument, Reader schema)
439 4296 daigle
    	throws InsufficientKarmaException, MetacatException, IOException,
440 3285 barteau
            MetacatInaccessibleException {
441 4296 daigle
442 1789 jones
        Reader reader = null;
443
        String doctext = null;
444
        String schematext = null;
445
        try {
446 3285 barteau
            doctext = IOUtil.getAsString(xmlDocument, true);
447
            if (schema != null) {
448
                schematext = IOUtil.getAsString(schema, true);
449
            }
450 1789 jones
        } catch (IOException ioE) {
451 3285 barteau
            throw ioE;
452 1789 jones
        }
453 3285 barteau
454 1789 jones
        //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 4296 daigle
463
        if (sessionId != null) {
464
            prop.put("sessionid", sessionId);
465
        }
466 3285 barteau
467 1789 jones
        String response = null;
468
        try {
469 2264 sgarg
            response = sendDataForString(prop, null, null, 0);
470 1789 jones
        } catch (Exception e) {
471
            throw new MetacatInaccessibleException(e.getMessage());
472
        }
473 3285 barteau
474 1789 jones
        // 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 3285 barteau
483 1789 jones
        return response;
484 1780 jones
    }
485 3285 barteau
486 1780 jones
    /**
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 2240 sgarg
     * @param schema a Reader for accessing the DTD or XML Schema for
492 1780 jones
     *               the document
493 1795 jones
     * @return the metacat response message
494 2240 sgarg
     * @throws InsufficientKarmaException when the user has insufficent rights
495 1780 jones
     *                                    for the operation
496 1795 jones
     * @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 1780 jones
     */
501 1795 jones
    public String update(String docid, Reader xmlDocument, Reader schema)
502 3285 barteau
    throws InsufficientKarmaException, MetacatException, IOException,
503
            MetacatInaccessibleException {
504 1795 jones
        Reader reader = null;
505
        String doctext = null;
506
        String schematext = null;
507
        try {
508 3285 barteau
            doctext = IOUtil.getAsString(xmlDocument, true);
509
            if (schema != null) {
510
                schematext = IOUtil.getAsString(schema, true);
511
            }
512 1795 jones
        } catch (IOException ioE) {
513 3285 barteau
            throw ioE;
514 1795 jones
        }
515 3285 barteau
516 1795 jones
        //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 3285 barteau
525 1795 jones
        String response = null;
526
        try {
527 2264 sgarg
            response = sendDataForString(prop, null, null, 0);
528 1795 jones
        } catch (Exception e) {
529
            throw new MetacatInaccessibleException(e.getMessage());
530
        }
531 3285 barteau
532 1795 jones
        // 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 3285 barteau
541 1795 jones
        return response;
542 1780 jones
    }
543 3285 barteau
544 1780 jones
    /**
545 3721 jones
     * 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 3285 barteau
     *
552 3721 jones
     * @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 3285 barteau
     * @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 2264 sgarg
            response = sendDataForString(arg, filenames, null, 0);
581 3285 barteau
        } catch (Exception e) {
582 2240 sgarg
            throw new MetacatInaccessibleException(e.getMessage());
583 3285 barteau
        }
584
585
        // Check for an error condition
586
        if (response.indexOf("<error>") != -1) {
587 2240 sgarg
            if (response.indexOf("does not have permission") != -1) {
588 3285 barteau
                throw new InsufficientKarmaException(response);
589 2240 sgarg
            } else {
590 3285 barteau
                throw new MetacatException(response);
591 2240 sgarg
            }
592 3285 barteau
        }
593
594
        return response;
595
    }
596
597
    /**
598 3721 jones
     * 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 3285 barteau
     *
605 3721 jones
     * @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 3285 barteau
     * @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 2264 sgarg
            response = sendDataForString(arg, filenames, fileData, size);
634 3285 barteau
        } catch (Exception e) {
635 2264 sgarg
            throw new MetacatInaccessibleException(e.getMessage());
636 3285 barteau
        }
637
638
        // Check for an error condition
639
        if (response.indexOf("<error>") != -1) {
640 2264 sgarg
            if (response.indexOf("does not have permission") != -1) {
641 3285 barteau
                throw new InsufficientKarmaException(response);
642 2264 sgarg
            } else {
643 3285 barteau
                throw new MetacatException(response);
644 2264 sgarg
            }
645 3285 barteau
        }
646
647
        return response;
648
    }
649
650 2240 sgarg
    /**
651 1780 jones
     * Delete an XML document in the repository.
652
     *
653
     * @param docid the docid to delete
654 1795 jones
     * @return the metacat response message
655 2240 sgarg
     * @throws InsufficientKarmaException when the user has insufficent rights
656 1780 jones
     *                                    for the operation
657 1795 jones
     * @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 1780 jones
     */
661 1795 jones
    public String delete(String docid)
662 3285 barteau
    throws InsufficientKarmaException, MetacatException,
663
            MetacatInaccessibleException {
664 1795 jones
        //set up properties
665
        Properties prop = new Properties();
666
        prop.put("action", "delete");
667
        prop.put("docid", docid);
668 3285 barteau
669 1795 jones
        String response = null;
670
        try {
671 2264 sgarg
            response = sendDataForString(prop, null, null, 0);
672 1795 jones
        } catch (Exception e) {
673
            throw new MetacatInaccessibleException(e.getMessage());
674
        }
675 3285 barteau
676 1795 jones
        // 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 2326 harris
        return response;
685
    }
686 3285 barteau
687
688 2326 harris
    /**
689
     * set the access on an XML document in the repository.
690
     *
691 2327 harris
     * @param _docid the docid of the document for which the access should be applied.
692 2326 harris
     *
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 5098 daigle
    public String setAccess(String docid, String principal, String
714
            permission, String permType, String permOrder )
715 3285 barteau
            throws InsufficientKarmaException, MetacatException,
716
            MetacatInaccessibleException {
717 2326 harris
        //set up properties
718
        Properties prop = new Properties();
719
        prop.put("action", "setaccess");
720 5098 daigle
        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 3285 barteau
726 2326 harris
        String response = null;
727
        try {
728
            response = sendDataForString(prop, null, null, 0);
729
        } catch (Exception e) {
730
            throw new MetacatInaccessibleException(e.getMessage());
731
        }
732 3285 barteau
733 2326 harris
        // 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 1795 jones
        return response;
742 1780 jones
    }
743 3285 barteau
744 1780 jones
    /**
745 5098 daigle
	 * 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 1780 jones
     * 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 3285 barteau
    public void setMetacatUrl(String metacatUrl) {
789 1783 jones
        this.metacatUrl = metacatUrl;
790 1780 jones
    }
791 3285 barteau
792 1822 jones
    /**
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 3285 barteau
    public String getSessionId() {
800 1822 jones
        return this.sessionId;
801
    }
802 3285 barteau
803 1826 jones
    /**
804 2240 sgarg
     * Set the session identifier for this session.  This identifier was
805
     * previously established with a call to login.  To continue to use the
806 1826 jones
     * 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 3285 barteau
    public void setSessionId(String sessionId) {
812 1826 jones
        this.sessionId = sessionId;
813
    }
814 2337 tao
815
    /**
816 3285 barteau
     * The method will return the latest revision in metacat server
817 2981 jones
     * for a given document id. If some error happens, this method will throw
818 3285 barteau
     * an exception.
819 2337 tao
     * @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 3285 barteau
    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 2981 jones
    /**
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 3285 barteau
     * sequence for a given scope.
852 2981 jones
     * @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 3285 barteau
862 2981 jones
        String response = null;
863
        try {
864 2337 tao
            response = sendDataForString(prop, null, null, 0);
865
            // Check for an error condition
866 2981 jones
            if (response.indexOf("<error>") != -1) {
867 3285 barteau
                throw new MetacatException(response);
868 2981 jones
            } else {
869
                Reader responseReader = new StringReader(response);
870 3285 barteau
                Node root =
871
                        XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
872
                Node docidNode =
873
                        XMLUtilities.getNodeWithXPath(root, "/lastDocid/docid");
874 2986 jones
                lastIdentifier = docidNode.getFirstChild().getNodeValue();
875 2981 jones
            }
876
        } catch (Exception e) {
877 2337 tao
            throw new MetacatException(e.getMessage());
878
        }
879 2981 jones
        return lastIdentifier;
880
    }
881 3141 berkley
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 3285 barteau
        if(scope != null) {
894
            prop.put("scope", scope);
895 3141 berkley
        }
896 3285 barteau
897 3141 berkley
        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 3285 barteau
                throw new MetacatException(response);
903 3141 berkley
            } else {
904
                Reader responseReader = new StringReader(response);
905 3285 barteau
                Node root =
906
                        XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
907 3141 berkley
                NodeList nlist = root.getChildNodes();
908 3285 barteau
                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 3141 berkley
                }
916
917
            }
918
        } catch (Exception e) {
919
            throw new MetacatException(e.getMessage());
920
        }
921
        return resultVec;
922
    }
923 3143 berkley
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 3285 barteau
        if(docid == null) {
935
            throw new MetacatException("<error>Cannot check if a null docid " +
936
                    "is registered.</error>");
937 3143 berkley
        }
938
        prop.put("docid", docid);
939 3285 barteau
940 3143 berkley
        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 3285 barteau
                throw new MetacatException(response);
946 3143 berkley
            } 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 3285 barteau
                while(numread != -1) {
952
                    sb.append(new String(c, 0, numread));
953
                    numread = responseReader.read(c, 0, 1024);
954 3143 berkley
                }
955
956
                String responseStr = sb.toString();
957 3285 barteau
                if(responseStr.indexOf("true") != -1) {
958
                    return true;
959 3143 berkley
                }
960
                return false;
961
            }
962
        } catch (Exception e) {
963
            throw new MetacatException(e.getMessage());
964
        }
965
    }
966 3285 barteau
967 3481 barteau
    /**
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 1780 jones
    /************************************************************************
994
     * PRIVATE METHODS
995
     ************************************************************************/
996 3285 barteau
997 1783 jones
    /**
998
     * Send a request to metacat.
999
     *
1000
     * @param prop the properties to be URL encoded and sent
1001 2264 sgarg
     * @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 1783 jones
     */
1008 2240 sgarg
    synchronized private InputStream sendDataOnce(Properties args,
1009 3285 barteau
            Properties filename,
1010
            InputStream fileData,
1011
            int size)
1012
            throws Exception {
1013 1780 jones
        InputStream returnStream = null;
1014
        URL url = new URL(metacatUrl);
1015
        HttpMessage msg = new HttpMessage(url);
1016 1828 jones
        msg.setCookie("JSESSIONID="+this.sessionId);
1017 2264 sgarg
        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 2240 sgarg
        } else {
1024 2264 sgarg
            throw new MetacatException("Invalid size specified for " +
1025 3285 barteau
                    "the input stream being passed");
1026 2240 sgarg
        }
1027 1780 jones
        return returnStream;
1028
    }
1029 3285 barteau
1030 1780 jones
    /**
1031
     * Send a request to Metacat
1032
     *
1033 2264 sgarg
     * @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 1780 jones
     * @return      InputStream as returned by Metacat
1041
     */
1042 3316 barteau
    synchronized public InputStream sendData(Properties args,
1043 3285 barteau
            Properties filename,
1044
            InputStream fileData,
1045
            int size)
1046
            throws Exception {
1047 1780 jones
        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 2240 sgarg
            using the HTTPClient protocol handler.  These try statements make
1052
            sure that a connection is made because it gives each connection a
1053 1780 jones
            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 3285 barteau
         */
1057 1780 jones
        try {
1058 3285 barteau
            return sendDataOnce(args, filename, fileData, size);
1059 1780 jones
        } catch (Exception e) {
1060
            try {
1061 2264 sgarg
                return sendDataOnce(args, filename, fileData, size);
1062 1780 jones
            } catch (Exception e2) {
1063
                try {
1064 2264 sgarg
                    return sendDataOnce(args, filename, fileData, size);
1065 1780 jones
                } catch (Exception e3) {
1066
                    System.err.println(
1067 3196 berkley
                            "Failed to send data to metacat 3 times: " + e3.getMessage());
1068
                    System.err.println("metacaturl: " + metacatUrl);
1069 1780 jones
                    throw e3;
1070
                }
1071
            }
1072
        }
1073
    }
1074 3285 barteau
1075 1783 jones
    /**
1076
     * Send a request to Metacat
1077
     *
1078 2264 sgarg
     * @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 1783 jones
     */
1087 2240 sgarg
    synchronized private String sendDataForString(Properties args,
1088 3285 barteau
            Properties filename,
1089
            InputStream fileData,
1090
            int size)
1091
            throws Exception {
1092 1783 jones
        String response = null;
1093 3285 barteau
1094 1783 jones
        try {
1095
            InputStreamReader returnStream =
1096 2264 sgarg
                    new InputStreamReader(sendData(args, filename,
1097 3285 barteau
                    fileData, size));
1098 1783 jones
            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 2337 tao
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 3285 barteau
    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 2992 berkley
        }
1132 3285 barteau
        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 3316 barteau
    public static MetacatClient getMetacatClient(HttpServletRequest request) throws MetacatInaccessibleException {
1144 3285 barteau
        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 3362 barteau
            metacatPath = metacatPath.replaceFirst("%1$s", host);
1155
            metacatPath = metacatPath.replaceFirst("%2$s", context);
1156 3285 barteau
            result = (MetacatClient) MetacatFactory.createMetacatConnection(metacatPath);
1157
            session.setAttribute("MetacatClient", result);
1158
        }
1159
        return(result);
1160
    }
1161
1162 1780 jones
}