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 5914 leinfelder
import java.nio.charset.Charset;
37
import java.util.ArrayList;
38
import java.util.Enumeration;
39
import java.util.List;
40 1780 jones
import java.util.Properties;
41 3141 berkley
import java.util.Vector;
42 3300 barteau
import javax.servlet.http.HttpServletRequest;
43 1780 jones
44 5914 leinfelder
import org.apache.commons.io.IOUtils;
45
import org.apache.http.HttpResponse;
46
import org.apache.http.HttpVersion;
47
import org.apache.http.NameValuePair;
48
import org.apache.http.client.HttpClient;
49
import org.apache.http.client.entity.UrlEncodedFormEntity;
50
import org.apache.http.client.methods.HttpPost;
51
import org.apache.http.entity.mime.HttpMultipartMode;
52
import org.apache.http.entity.mime.MultipartEntity;
53
import org.apache.http.entity.mime.content.FileBody;
54
import org.apache.http.entity.mime.content.InputStreamBody;
55
import org.apache.http.entity.mime.content.StringBody;
56
import org.apache.http.impl.client.DefaultHttpClient;
57
import org.apache.http.message.BasicNameValuePair;
58
import org.apache.http.params.CoreProtocolPNames;
59
import org.apache.http.util.EntityUtils;
60 2981 jones
import org.w3c.dom.Node;
61 3141 berkley
import org.w3c.dom.NodeList;
62 2981 jones
63 1788 jones
import edu.ucsb.nceas.utilities.IOUtil;
64 2981 jones
import edu.ucsb.nceas.utilities.XMLUtilities;
65 2240 sgarg
import java.io.File;
66 1780 jones
67 5066 leinfelder
68 1780 jones
/**
69 2240 sgarg
 *  This interface provides methods for initializing and logging in to a
70
 *  Metacat server, and then querying, reading, transforming, inserting,
71 1780 jones
 *  updating and deleting documents from that server.
72
 */
73 3285 barteau
public class MetacatClient implements Metacat {
74 1780 jones
    /** The URL string for the metacat server */
75
    private String metacatUrl;
76 3285 barteau
77 1822 jones
    /** The session identifier for the session */
78
    private String sessionId;
79 3285 barteau
80 5914 leinfelder
    /** The default character encoding, can be changed by client */
81
    private String encoding = "UTF-8";
82
83 5066 leinfelder
    public static void main(String[] args) {
84
    	try {
85 5069 leinfelder
    		Metacat mc =
86
    			MetacatFactory.createMetacatConnection(args[0]);
87 5066 leinfelder
88 5069 leinfelder
    		InputStream r = mc.read(args[1]);
89
    		FileOutputStream fos = new FileOutputStream(args[2]);
90
    		BufferedOutputStream bfos = new BufferedOutputStream(fos);
91 5066 leinfelder
92
            int c = r.read();
93
            while(c != -1)
94
            {
95
              bfos.write(c);
96
              c = r.read();
97
            }
98
            bfos.flush();
99
            bfos.close();
100
            fos.flush();
101
            fos.close();
102
    	} catch (Exception e) {
103
    		e.printStackTrace();
104
    	}
105
    }
106
107 3300 barteau
    /**
108 1780 jones
     * Constructor to create a new instance. Protected because instances
109
     * should only be created by the factory MetacatFactory.
110
     */
111 3285 barteau
    protected MetacatClient() {
112 1822 jones
        this.metacatUrl = null;
113
        this.sessionId = null;
114 1780 jones
    }
115 3285 barteau
116 1780 jones
    /**
117
     *  Method used to log in to a metacat server. Implementations will need
118
     *  to cache a cookie value to make the session persistent.  Each time a
119
     *  call is made to one of the other methods (e.g., read), the cookie will
120
     *  need to be passed back to the metacat server along with the request.
121
     *
122
     *  @param username   the username of the user, like an LDAP DN
123
     *  @param password   the password for that user for authentication
124 1822 jones
     *  @return the response string from metacat in XML format
125 1780 jones
     *  @throws MetacatAuthException when the username/password could
126
     *                    not be authenticated
127
     */
128 2240 sgarg
    public String login(String username, String password)
129 3285 barteau
    throws MetacatAuthException, MetacatInaccessibleException {
130 1783 jones
        Properties prop = new Properties();
131
        prop.put("action", "login");
132
        prop.put("qformat", "xml");
133
        prop.put("username", username);
134
        prop.put("password", password);
135 5072 daigle
//        if (this.sessionId != null) {
136
//        	prop.put("sessionid", sessionId);
137
//        }
138 3285 barteau
139 1783 jones
        String response = null;
140
        try {
141 5914 leinfelder
        	InputStream result = sendParameters(prop);
142
            response = IOUtils.toString(result, encoding);
143 1783 jones
        } catch (Exception e) {
144
            throw new MetacatInaccessibleException(e.getMessage());
145
        }
146 3285 barteau
147 1783 jones
        if (response.indexOf("<login>") == -1) {
148 1828 jones
            setSessionId("");
149 1783 jones
            throw new MetacatAuthException(response);
150 1822 jones
        } else {
151 1825 jones
            int start = response.indexOf("<sessionId>") + 11;
152 1822 jones
            int end = response.indexOf("</sessionId>");
153
            if ((start != -1) && (end != -1)) {
154 1828 jones
                setSessionId(response.substring(start,end));
155 1822 jones
            }
156 1783 jones
        }
157 1822 jones
        return response;
158 1780 jones
    }
159 2683 sgarg
160
    /**
161
     *  Method used to log in to a metacat server. Implementations will need
162
     *  to cache a cookie value to make the session persistent.  Each time a
163
     *  call is made to one of the other methods (e.g., read), the cookie will
164
     *  need to be passed back to the metacat server along with the request.
165
     *
166
     *  @param username   the username of the user, like an LDAP DN
167
     *  @param password   the password for that user for authentication
168
     *  @return the response string from metacat in XML format
169
     *  @throws MetacatAuthException when the username/password could
170
     *                    not be authenticated
171
     */
172 3285 barteau
    public String getloggedinuserinfo() throws MetacatInaccessibleException {
173 2683 sgarg
        Properties prop = new Properties();
174
        prop.put("action", "getloggedinuserinfo");
175
        prop.put("qformat", "xml");
176 3285 barteau
177 2683 sgarg
        String response = null;
178
        try {
179 5914 leinfelder
        	InputStream result = sendParameters(prop);
180
            response = IOUtils.toString(result, encoding);
181 2683 sgarg
        } catch (Exception e) {
182
            throw new MetacatInaccessibleException(e.getMessage());
183
        }
184 3285 barteau
185 2683 sgarg
        return response;
186
    }
187 3285 barteau
188 1780 jones
    /**
189 1822 jones
     *  Method used to log out a metacat server. The Metacat server will end
190
     *  the session when this call is invoked.
191 1798 tao
     *
192 1822 jones
     *  @return the response string from metacat in XML format
193 1798 tao
     *  @throws MetacatInaccessibleException when the metacat server can not be
194
     *                                    reached or does not respond
195
     */
196 3285 barteau
    public String logout() throws MetacatInaccessibleException, MetacatException {
197 1798 tao
        Properties prop = new Properties();
198
        prop.put("action", "logout");
199 2240 sgarg
        prop.put("qformat", "xml");
200 5072 daigle
        if (this.sessionId != null) {
201
        	prop.put("sessionid", sessionId);
202
        }
203 3285 barteau
204 1798 tao
        String response = null;
205
        try {
206 5914 leinfelder
        	InputStream result = sendParameters(prop);
207
            response = IOUtils.toString(result, encoding);
208 1798 tao
        } catch (Exception e) {
209
            throw new MetacatInaccessibleException(e.getMessage());
210
        }
211 3285 barteau
212 1798 tao
        if (response.indexOf("<logout>") == -1) {
213
            throw new MetacatException(response);
214
        }
215 1828 jones
        setSessionId("");
216 1822 jones
        return response;
217 1798 tao
    }
218 3285 barteau
219 1798 tao
    /**
220 5057 daigle
     *  Method used to log in to a metacat server. Implementations will need
221
     *  to cache a cookie value to make the session persistent.  Each time a
222
     *  call is made to one of the other methods (e.g., read), the cookie will
223
     *  need to be passed back to the metacat server along with the request.
224
     *
225
     *  @param username   the username of the user, like an LDAP DN
226
     *  @param password   the password for that user for authentication
227
     *  @return the response string from metacat in XML format
228
     *  @throws MetacatAuthException when the username/password could
229
     *                    not be authenticated
230
     */
231
    public String validateSession(String sessionId)
232
    		throws MetacatAuthException, MetacatInaccessibleException {
233
234
        Properties prop = new Properties();
235
        prop.put("action", "validatesession");
236
        prop.put("sessionid", sessionId);
237
238
        String response = null;
239
        try {
240 5914 leinfelder
        	InputStream result = sendParameters(prop);
241
            response = IOUtils.toString(result, encoding);
242 5057 daigle
        } catch (Exception e) {
243
            throw new MetacatInaccessibleException(e.getMessage());
244
        }
245
246
        if (response.indexOf("<validateSession><status>") == -1) {
247
            setSessionId("");
248
            throw new MetacatAuthException(response);
249
        }
250
251
        return response;
252
    }
253
254 5066 leinfelder
255
256
	/**
257 5072 daigle
     *  Method used to log in to a metacat server. Implementations will need
258
     *  to cache a cookie value to make the session persistent.  Each time a
259
     *  call is made to one of the other methods (e.g., read), the cookie will
260
     *  need to be passed back to the metacat server along with the request.
261
     *
262
     *  @param username   the username of the user, like an LDAP DN
263
     *  @param password   the password for that user for authentication
264
     *  @return the response string from metacat in XML format
265
     *  @throws MetacatAuthException when the username/password could
266
     *                    not be authenticated
267
     */
268
    public String isAuthorized(String resourceLsid, String permission, String sessionId)
269
    		throws MetacatAuthException, MetacatInaccessibleException {
270
271
        Properties prop = new Properties();
272
        prop.put("action", "isauthorized");
273
        prop.put("resourceLsid", resourceLsid);
274
        prop.put("permission", permission);
275
        prop.put("sessionId", sessionId);
276
277
        String response = null;
278
        try {
279 5914 leinfelder
        	InputStream result = sendParameters(prop);
280
            response = IOUtils.toString(result, encoding);
281 5072 daigle
        } catch (Exception e) {
282
            throw new MetacatInaccessibleException(e.getMessage());
283
        }
284
285
        if (response.indexOf("<resourceAuthorization>") == -1) {
286
        	System.out.println("invalid response: " + response);
287
            throw new MetacatAuthException(response);
288
        }
289
290
        return response;
291
    }
292
293
    /**
294 1780 jones
     * Read an XML document from the metacat server session, accessed by docid,
295
     * and returned as a Reader.
296
     *
297
     * @param docid the identifier of the document to be read
298
     * @return a Reader for accessing the document
299 2240 sgarg
     * @throws InsufficientKarmaException when the user has insufficent rights
300 1780 jones
     *                                    for the operation
301 1784 jones
     * @throws MetacatInaccessibleException when the metacat server can not be
302
     *                                    reached or does not respond
303
     * @throws MetacatException when the metacat server generates another error
304 1780 jones
     */
305 5066 leinfelder
    public InputStream read(String docid) throws InsufficientKarmaException,
306 3285 barteau
            MetacatInaccessibleException, MetacatException, DocumentNotFoundException {
307 5066 leinfelder
    	Reader r = null;
308 3285 barteau
309 1784 jones
        Properties prop = new Properties();
310
        prop.put("action", "read");
311
        prop.put("qformat", "xml");
312
        prop.put("docid", docid);
313
        InputStream response = null;
314
        try {
315 5914 leinfelder
            response = sendParameters(prop);
316 1784 jones
        } catch (Exception e) {
317
            throw new MetacatInaccessibleException(e.getMessage());
318
        }
319 5066 leinfelder
        BufferedInputStream bis = new BufferedInputStream(response);
320
        r = new InputStreamReader(bis);
321 1784 jones
        try {
322 5066 leinfelder
        	bis.mark(512);
323 1784 jones
            char[] characters = new char[512];
324 5066 leinfelder
            int len = r.read(characters, 0, 512);
325 1784 jones
            StringWriter sw = new StringWriter();
326
            sw.write(characters, 0, len);
327
            String message = sw.toString();
328
            sw.close();
329 5066 leinfelder
            bis.reset();
330 1784 jones
            if (message.indexOf("<error>") != -1) {
331
                if (message.indexOf("does not have permission") != -1) {
332
                    throw new InsufficientKarmaException(message);
333 2989 berkley
                } else if(message.indexOf("does not exist") != -1) {
334
                    throw new DocumentNotFoundException(message);
335 1784 jones
                } else {
336
                    throw new MetacatException(message);
337
                }
338
            }
339
        } catch (IOException ioe) {
340
            throw new MetacatException(
341 2240 sgarg
                    "MetacatClient: Error converting Reader to String."
342 1784 jones
                    + ioe.getMessage());
343
        }
344 5066 leinfelder
        return bis;
345 1780 jones
    }
346 3285 barteau
347
348 1780 jones
    /**
349 3285 barteau
     * Read inline data from the metacat server session, accessed by
350
     * inlinedataid and returned as a Reader.
351
     *
352
     * @param inlinedataid the identifier of the data to be read
353
     * @return a Reader for accessing the document
354
     * @throws InsufficientKarmaException when the user has insufficent rights
355
     *                                    for the operation
356
     * @throws MetacatInaccessibleException when the metacat server can not be
357
     *                                    reached or does not respond
358
     * @throws MetacatException when the metacat server generates another error
359
     */
360 5066 leinfelder
    public InputStream readInlineData(String inlinedataid)
361 3285 barteau
    throws InsufficientKarmaException,
362
            MetacatInaccessibleException, MetacatException {
363 5066 leinfelder
        Reader r = null;
364 3285 barteau
365
        Properties prop = new Properties();
366
        prop.put("action", "readinlinedata");
367
        prop.put("inlinedataid", inlinedataid);
368
369
        InputStream response = null;
370
        try {
371 5914 leinfelder
            response = sendParameters(prop);
372 3285 barteau
        } catch (Exception e) {
373
            throw new MetacatInaccessibleException(e.getMessage());
374
        }
375 5066 leinfelder
        BufferedInputStream bis = new BufferedInputStream(response);
376
        r = new InputStreamReader(bis);
377 3285 barteau
        try {
378 5066 leinfelder
        	bis.mark(512);
379 3285 barteau
            char[] characters = new char[512];
380 5066 leinfelder
            int len = r.read(characters, 0, 512);
381 3285 barteau
            StringWriter sw = new StringWriter();
382
            sw.write(characters, 0, len);
383
            String message = sw.toString();
384
            sw.close();
385 5066 leinfelder
            bis.reset();
386 3285 barteau
            if (message.indexOf("<error>") != -1) {
387
                if (message.indexOf("does not have permission") != -1) {
388
                    throw new InsufficientKarmaException(message);
389
                } else {
390
                    throw new MetacatException(message);
391
                }
392
            }
393
        } catch (IOException ioe) {
394
            throw new MetacatException(
395
                    "MetacatClient: Error converting Reader to String."
396
                    + ioe.getMessage());
397
        }
398
399 5066 leinfelder
        return bis;
400 3285 barteau
    }
401
402 2261 sgarg
    /**
403 2240 sgarg
     * Query the metacat document store with the given metacat-compatible
404 3464 tao
     * query document and default qformat xml, and return the result set as a Reader.
405 1780 jones
     *
406
     * @param xmlQuery a Reader for accessing the XML version of the query
407
     * @return a Reader for accessing the result set
408
     */
409 1786 tao
    public Reader query(Reader xmlQuery) throws MetacatInaccessibleException,
410 3285 barteau
            IOException {
411 3464 tao
        String qformat = "xml";
412
        return query(xmlQuery, qformat);
413
    }
414
415
    /**
416
     * Query the metacat document store with the given metacat-compatible
417
     * query document and qformat, and return the result set as a Reader.
418
     *
419
     * @param xmlQuery a Reader for accessing the XML version of the query
420
     * @param qformat the format of return doc. It can be xml, knb, lter and etal.
421
     * @return a Reader for accessing the result set
422
     */
423
    public Reader query(Reader xmlQuery, String qformat) throws MetacatInaccessibleException,
424
            IOException {
425 1786 tao
        Reader reader = null;
426
        String query = null;
427 1788 jones
        try {
428 3285 barteau
            query = IOUtil.getAsString(xmlQuery, true);
429 1788 jones
        } catch (IOException ioE) {
430 3285 barteau
            throw ioE;
431 1786 tao
        }
432 3285 barteau
433 1786 tao
        //set up properties
434
        Properties prop = new Properties();
435
        prop.put("action", "squery");
436 3464 tao
        prop.put("qformat", qformat);
437 1786 tao
        prop.put("query", query);
438 3285 barteau
439 1786 tao
        InputStream response = null;
440
        try {
441 5914 leinfelder
            response = sendParameters(prop);
442 1786 tao
        } catch (Exception e) {
443
            throw new MetacatInaccessibleException(e.getMessage());
444
        }
445
        reader = new InputStreamReader(response);
446
        return reader;
447 1780 jones
    }
448 3285 barteau
449 1780 jones
    /**
450
     * Insert an XML document into the repository.
451
     *
452
     * @param docid the docid to insert the document
453
     * @param xmlDocument a Reader for accessing the XML document to be inserted
454 2240 sgarg
     * @param schema a Reader for accessing the DTD or XML Schema for
455 1780 jones
     *               the document
456 1789 jones
     * @return the metacat response message
457 2240 sgarg
     * @throws InsufficientKarmaException when the user has insufficent rights
458 1780 jones
     *                                    for the operation
459 1789 jones
     * @throws MetacatInaccessibleException when the metacat server can not be
460
     *                                    reached or does not respond
461
     * @throws MetacatException when the metacat server generates another error
462
     * @throws IOException when there is an error reading the xml document
463 1780 jones
     */
464 1789 jones
    public String insert(String docid, Reader xmlDocument, Reader schema)
465 4296 daigle
    	throws InsufficientKarmaException, MetacatException, IOException,
466 3285 barteau
            MetacatInaccessibleException {
467 4296 daigle
468 1789 jones
        String doctext = null;
469
        String schematext = null;
470
        try {
471 3285 barteau
            doctext = IOUtil.getAsString(xmlDocument, true);
472
            if (schema != null) {
473
                schematext = IOUtil.getAsString(schema, true);
474
            }
475 1789 jones
        } catch (IOException ioE) {
476 3285 barteau
            throw ioE;
477 1789 jones
        }
478 3285 barteau
479 1789 jones
        //set up properties
480
        Properties prop = new Properties();
481
        prop.put("action", "insert");
482
        prop.put("docid", docid);
483
        prop.put("doctext", doctext);
484
        if (schematext != null) {
485
            prop.put("dtdtext", schematext);
486
        }
487 4296 daigle
488 5914 leinfelder
//        if (sessionId != null) {
489
//            prop.put("sessionid", sessionId);
490
//        }
491 3285 barteau
492 1789 jones
        String response = null;
493
        try {
494 5914 leinfelder
        	InputStream result = sendParameters(prop);
495
            response = IOUtils.toString(result, encoding);
496 1789 jones
        } catch (Exception e) {
497
            throw new MetacatInaccessibleException(e.getMessage());
498
        }
499 3285 barteau
500 1789 jones
        // Check for an error condition
501
        if (response.indexOf("<error>") != -1) {
502
            if (response.indexOf("does not have permission") != -1) {
503
                throw new InsufficientKarmaException(response);
504
            } else {
505
                throw new MetacatException(response);
506
            }
507
        }
508 3285 barteau
509 1789 jones
        return response;
510 1780 jones
    }
511 3285 barteau
512 1780 jones
    /**
513
     * Update an XML document in the repository.
514
     *
515
     * @param docid the docid to update
516
     * @param xmlDocument a Reader for accessing the XML text to be updated
517 2240 sgarg
     * @param schema a Reader for accessing the DTD or XML Schema for
518 1780 jones
     *               the document
519 1795 jones
     * @return the metacat response message
520 2240 sgarg
     * @throws InsufficientKarmaException when the user has insufficent rights
521 1780 jones
     *                                    for the operation
522 1795 jones
     * @throws MetacatInaccessibleException when the metacat server can not be
523
     *                                    reached or does not respond
524
     * @throws MetacatException when the metacat server generates another error
525
     * @throws IOException when there is an error reading the xml document
526 1780 jones
     */
527 1795 jones
    public String update(String docid, Reader xmlDocument, Reader schema)
528 3285 barteau
    throws InsufficientKarmaException, MetacatException, IOException,
529
            MetacatInaccessibleException {
530 1795 jones
        String doctext = null;
531
        String schematext = null;
532
        try {
533 3285 barteau
            doctext = IOUtil.getAsString(xmlDocument, true);
534
            if (schema != null) {
535
                schematext = IOUtil.getAsString(schema, true);
536
            }
537 1795 jones
        } catch (IOException ioE) {
538 3285 barteau
            throw ioE;
539 1795 jones
        }
540 3285 barteau
541 1795 jones
        //set up properties
542
        Properties prop = new Properties();
543
        prop.put("action", "update");
544
        prop.put("docid", docid);
545
        prop.put("doctext", doctext);
546
        if (schematext != null) {
547
            prop.put("dtdtext", schematext);
548
        }
549 3285 barteau
550 1795 jones
        String response = null;
551
        try {
552 5914 leinfelder
        	InputStream result = sendParameters(prop);
553
            response = IOUtils.toString(result, encoding);
554 1795 jones
        } catch (Exception e) {
555
            throw new MetacatInaccessibleException(e.getMessage());
556
        }
557 3285 barteau
558 1795 jones
        // Check for an error condition
559
        if (response.indexOf("<error>") != -1) {
560
            if (response.indexOf("does not have permission") != -1) {
561
                throw new InsufficientKarmaException(response);
562
            } else {
563
                throw new MetacatException(response);
564
            }
565
        }
566 3285 barteau
567 1795 jones
        return response;
568 1780 jones
    }
569 3285 barteau
570 1780 jones
    /**
571 3721 jones
     * Upload a data document into the repository. Data files are stored on
572
     * metacat and may be in any format (binary or text), but they are all
573
     * treated as if they were binary.  Data files are not searched by the
574
     * query() methods because they are not loaded into the XML store because
575
     * they are not XML documents.  The File parameter is used to determine a
576
     * name for the uploaded document.
577 3285 barteau
     *
578 3721 jones
     * @param docid the identifier to be used for the document
579
     * @param file the File to be uploaded
580
     * @param document a InputStream containing the data to be uploaded
581 3285 barteau
     * @return the metacat response message
582
     * @throws InsufficientKarmaException when the user has insufficent rights
583
     *                                    for the operation
584
     * @throws MetacatInaccessibleException when the metacat server can not be
585
     *                                    reached or does not respond
586
     * @throws MetacatException when the metacat server generates another error
587
     * @throws IOException when there is an error reading the xml document
588
     */
589
    public String upload(String docid, File file)
590
    throws InsufficientKarmaException, MetacatException, IOException,
591
            MetacatInaccessibleException {
592
593 5914 leinfelder
    	HttpClient httpclient = new DefaultHttpClient();
594
        httpclient.getParams().setParameter(
595
        		CoreProtocolPNames.PROTOCOL_VERSION,
596
        	    HttpVersion.HTTP_1_1);
597
    	httpclient.getParams().setParameter(
598
    			CoreProtocolPNames.HTTP_CONTENT_CHARSET,
599
    			encoding);
600
601
    	HttpPost post = new HttpPost(metacatUrl);
602
    	MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
603
604
    	// For File parameters
605
    	entity.addPart("datafile", new FileBody(file));
606
607 3285 barteau
        //set up properties
608 5914 leinfelder
        Properties prop = new Properties();
609
        prop.put("action", "upload");
610
        prop.put("docid", docid);
611 3285 barteau
612 5914 leinfelder
        // For usual String parameters
613
        Enumeration<Object> keys = prop.keys();
614
        while (keys.hasMoreElements()) {
615
        	String key = (String) keys.nextElement();
616
        	String value = prop.getProperty(key);
617
        	entity.addPart(key, new StringBody(value, Charset.forName(encoding)));
618
        }
619 3285 barteau
620 5914 leinfelder
        post.setHeader("Cookie", "JSESSIONID="+ this.sessionId);
621
        post.setEntity(entity);
622
623 3285 barteau
        String response = null;
624
        try {
625 5914 leinfelder
        	response = EntityUtils.toString(httpclient.execute(post).getEntity(), encoding);
626
        	httpclient.getConnectionManager().shutdown();
627 3285 barteau
        } catch (Exception e) {
628 2240 sgarg
            throw new MetacatInaccessibleException(e.getMessage());
629 3285 barteau
        }
630
631
        // Check for an error condition
632
        if (response.indexOf("<error>") != -1) {
633 2240 sgarg
            if (response.indexOf("does not have permission") != -1) {
634 3285 barteau
                throw new InsufficientKarmaException(response);
635 2240 sgarg
            } else {
636 3285 barteau
                throw new MetacatException(response);
637 2240 sgarg
            }
638 3285 barteau
        }
639
640
        return response;
641
    }
642
643
    /**
644 3721 jones
     * Upload a data document into the repository. Data files are stored on
645
     * metacat and may be in any format (binary or text), but they are all
646
     * treated as if they were binary.  Data files are not searched by the
647
     * query() methods because they are not loaded into the XML store because
648
     * they are not XML documents. The name for the document is set explicitly
649
     * using the filename parameter.
650 3285 barteau
     *
651 3721 jones
     * @param docid the identifier to be used for the document
652
     * @param filename the name to be used in the MIME description of the uploaded file
653
     * @param document a InputStream containing the data to be uploaded
654 3285 barteau
     * @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
     * @throws IOException when there is an error reading the xml document
661
     */
662
    public String upload(String docid, String filename, InputStream fileData,
663
            int size)
664
            throws InsufficientKarmaException, MetacatException, IOException,
665
            MetacatInaccessibleException {
666
667 5914 leinfelder
    	HttpClient httpclient = new DefaultHttpClient();
668
        httpclient.getParams().setParameter(
669
        		CoreProtocolPNames.PROTOCOL_VERSION,
670
        	    HttpVersion.HTTP_1_1);
671
    	httpclient.getParams().setParameter(
672
    			CoreProtocolPNames.HTTP_CONTENT_CHARSET,
673
    			encoding);
674
675
    	HttpPost post = new HttpPost(metacatUrl);
676
    	MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
677
678
    	// For File parameters
679
    	InputStreamBody content = new InputStreamKnownSizeBody(fileData, filename, size);
680
    	entity.addPart("datafile", content);
681
682 3285 barteau
        //set up properties
683 5914 leinfelder
        Properties prop = new Properties();
684
        prop.put("action", "upload");
685
        prop.put("docid", docid);
686 3285 barteau
687 5914 leinfelder
        // For usual String parameters
688
        Enumeration<Object> keys = prop.keys();
689
        while (keys.hasMoreElements()) {
690
        	String key = (String) keys.nextElement();
691
        	String value = prop.getProperty(key);
692
        	entity.addPart(key, new StringBody(value, Charset.forName(encoding)));
693
        }
694
695
        post.setHeader("Cookie", "JSESSIONID="+ this.sessionId);
696
        post.setEntity(entity);
697
698 3285 barteau
        String response = null;
699
        try {
700 5914 leinfelder
        	response = EntityUtils.toString(httpclient.execute(post).getEntity(), encoding);
701
        	httpclient.getConnectionManager().shutdown();
702 3285 barteau
        } catch (Exception e) {
703 2264 sgarg
            throw new MetacatInaccessibleException(e.getMessage());
704 3285 barteau
        }
705
706
        // Check for an error condition
707
        if (response.indexOf("<error>") != -1) {
708 2264 sgarg
            if (response.indexOf("does not have permission") != -1) {
709 3285 barteau
                throw new InsufficientKarmaException(response);
710 2264 sgarg
            } else {
711 3285 barteau
                throw new MetacatException(response);
712 2264 sgarg
            }
713 3285 barteau
        }
714
715
        return response;
716
    }
717
718 2240 sgarg
    /**
719 1780 jones
     * Delete an XML document in the repository.
720
     *
721
     * @param docid the docid to delete
722 1795 jones
     * @return the metacat response message
723 2240 sgarg
     * @throws InsufficientKarmaException when the user has insufficent rights
724 1780 jones
     *                                    for the operation
725 1795 jones
     * @throws MetacatInaccessibleException when the metacat server can not be
726
     *                                    reached or does not respond
727
     * @throws MetacatException when the metacat server generates another error
728 1780 jones
     */
729 1795 jones
    public String delete(String docid)
730 3285 barteau
    throws InsufficientKarmaException, MetacatException,
731
            MetacatInaccessibleException {
732 1795 jones
        //set up properties
733
        Properties prop = new Properties();
734
        prop.put("action", "delete");
735
        prop.put("docid", docid);
736 3285 barteau
737 1795 jones
        String response = null;
738
        try {
739 5914 leinfelder
        	InputStream result = sendParameters(prop);
740
            response = IOUtils.toString(result, encoding);
741 1795 jones
        } catch (Exception e) {
742
            throw new MetacatInaccessibleException(e.getMessage());
743
        }
744 3285 barteau
745 1795 jones
        // Check for an error condition
746
        if (response.indexOf("<error>") != -1) {
747
            if (response.indexOf("does not have permission") != -1) {
748
                throw new InsufficientKarmaException(response);
749
            } else {
750
                throw new MetacatException(response);
751
            }
752
        }
753 2326 harris
        return response;
754
    }
755 3285 barteau
756 5112 daigle
    /**
757
     * get the access control info for a given document id.
758
     *
759
     * @param _docid the docid of the document for which the access should be applied.
760
     *
761
     * @return the metacat access xml
762
     */
763
    public String getAccessControl(String docid)
764
    	throws InsufficientKarmaException, MetacatException,MetacatInaccessibleException {
765
        //set up properties
766
        Properties prop = new Properties();
767
        prop.put("action", "getaccesscontrol");
768
        prop.put("docid", docid);
769
770
        String response = null;
771
        try {
772 5914 leinfelder
        	InputStream result = sendParameters(prop);
773
            response = IOUtils.toString(result, encoding);
774 5112 daigle
        } catch (Exception e) {
775
            throw new MetacatInaccessibleException(e.getMessage());
776
        }
777
778
        // Check for an error condition
779
        if (response.indexOf("<error>") != -1) {
780
            if (response.indexOf("does not have permission") != -1) {
781
                throw new InsufficientKarmaException(response);
782
            } else {
783
                throw new MetacatException(response);
784
            }
785
        }
786
        return response;
787
    }
788 3285 barteau
789 2326 harris
    /**
790
     * set the access on an XML document in the repository.
791
     *
792 2327 harris
     * @param _docid the docid of the document for which the access should be applied.
793 2326 harris
     *
794
     * @param _principal the document's principal
795
     *
796
     * @param _permission the access permission to be applied to the docid
797
     *  {e.g. read,write,all}
798
     *
799
     * @param _permType the permission type to be applied to the document
800
     *  {e.g. allow or deny}
801
     *
802
     * @param _permOrder the order that the document's permissions should be
803
     *  processed {e.g. denyFirst or allowFirst}
804
     *
805
     *
806
     * @return the metacat response message
807
     *
808
     * @throws InsufficientKarmaException when the user has insufficent rights
809
     *                                    for the operation
810
     * @throws MetacatInaccessibleException when the metacat server can not be
811
     *                                    reached or does not respond
812
     * @throws MetacatException when the metacat server generates another error
813
     */
814 5098 daigle
    public String setAccess(String docid, String principal, String
815
            permission, String permType, String permOrder )
816 3285 barteau
            throws InsufficientKarmaException, MetacatException,
817
            MetacatInaccessibleException {
818 2326 harris
        //set up properties
819
        Properties prop = new Properties();
820
        prop.put("action", "setaccess");
821 5098 daigle
        prop.put("docid", docid);
822
        prop.put("principal", principal);
823
        prop.put("permission", permission);
824
        prop.put("permType", permType);
825
        prop.put("permOrder", permOrder);
826 3285 barteau
827 2326 harris
        String response = null;
828
        try {
829 5914 leinfelder
        	InputStream result = sendParameters(prop);
830
            response = IOUtils.toString(result, encoding);
831 2326 harris
        } catch (Exception e) {
832
            throw new MetacatInaccessibleException(e.getMessage());
833
        }
834 3285 barteau
835 2326 harris
        // Check for an error condition
836
        if (response.indexOf("<error>") != -1) {
837
            if (response.indexOf("does not have permission") != -1) {
838
                throw new InsufficientKarmaException(response);
839
            } else {
840
                throw new MetacatException(response);
841
            }
842
        }
843 1795 jones
        return response;
844 1780 jones
    }
845 3285 barteau
846 1780 jones
    /**
847 5098 daigle
	 * Set access for a given doc id. The access is represented in an access
848
	 * block of xml. All existing access will be replaced with the access
849
	 * provided in the access block.
850
	 *
851
	 * @param docid
852
	 *            the doc id for the doc we want to update
853
	 * @param accessBlock
854
	 *            the xml access block. This is the same structure as that
855
	 *            returned by the getdocumentinfo action in metacat.
856
	 * @return a string holding the response xml
857
	 */
858
    public String setAccess(String docid, String accessBlock)
859
            throws InsufficientKarmaException, MetacatException, MetacatInaccessibleException {
860
        //set up properties
861
        Properties prop = new Properties();
862
        prop.put("action", "setaccess");
863
        prop.put("docid", docid);
864
        prop.put("accessBlock", accessBlock);
865
866
        String response = null;
867
        try {
868 5914 leinfelder
        	InputStream result = sendParameters(prop);
869
            response = IOUtils.toString(result, encoding);
870 5098 daigle
        } catch (Exception e) {
871
            throw new MetacatInaccessibleException(e.getMessage());
872
        }
873
874
        // Check for an error condition
875
        if (response.indexOf("<error>") != -1) {
876
            if (response.indexOf("does not have permission") != -1) {
877
                throw new InsufficientKarmaException(response);
878
            } else {
879
                throw new MetacatException(response);
880
            }
881
        }
882
        return response;
883
    }
884
885
    /**
886 1780 jones
     * When the MetacatFactory creates an instance it needs to set the
887
     * MetacatUrl to which connections should be made.
888
     *
889
     * @param metacatUrl the URL for the metacat server
890
     */
891 3285 barteau
    public void setMetacatUrl(String metacatUrl) {
892 1783 jones
        this.metacatUrl = metacatUrl;
893 1780 jones
    }
894 3285 barteau
895 1822 jones
    /**
896
     * Get the session identifier for this session.  This is only valid if
897
     * the login methods has been called successfully for this Metacat object
898
     * beforehand.
899
     *
900
     * @returns the sessionId as a String, or null if the session is invalid
901
     */
902 3285 barteau
    public String getSessionId() {
903 1822 jones
        return this.sessionId;
904
    }
905 3285 barteau
906 1826 jones
    /**
907 2240 sgarg
     * Set the session identifier for this session.  This identifier was
908
     * previously established with a call to login.  To continue to use the
909 1826 jones
     * same session, set the session id before making a call to one of the
910
     * metacat access methods (e.g., read, query, insert, etc.).
911
     *
912
     * @param String the sessionId from a previously established session
913
     */
914 3285 barteau
    public void setSessionId(String sessionId) {
915 1826 jones
        this.sessionId = sessionId;
916
    }
917 2337 tao
918
    /**
919 3285 barteau
     * The method will return the latest revision in metacat server
920 2981 jones
     * for a given document id. If some error happens, this method will throw
921 3285 barteau
     * an exception.
922 2337 tao
     * @param docId String  the given docid you want to use. the docid it self
923
     *                      can have or haven't revision number
924
     * @throws MetacatException
925
     */
926 3285 barteau
    public int getNewestDocRevision(String docId) throws MetacatException {
927
        int rev = 0;
928
        //set up properties
929
        Properties prop = new Properties();
930
        prop.put("action", "getrevisionanddoctype");
931
        prop.put("docid", docId);
932
933
        String response = null;
934
        try {
935 5914 leinfelder
        	InputStream result = sendParameters(prop);
936
            response = IOUtils.toString(result, encoding);
937 3285 barteau
            //parseRevisionResponse will return null if there is an
938
            //error that it can't handle
939
            String revStr = parserRevisionResponse(response);
940
            Integer revObj = new Integer(revStr);
941
            rev = revObj.intValue();
942
            // Check for an error condition
943
            if (response.indexOf("<error>") != -1 && revStr == null) {
944
                throw new MetacatException(response);
945
            }
946
        } catch (Exception e) {
947
            throw new MetacatException(e.getMessage());
948
        }
949
        return rev;
950
    }
951
952 2981 jones
    /**
953
     * Return the highest document id for a given scope.  This is used by
954
     * clients to make it easier to determine the next free identifier in a
955 3285 barteau
     * sequence for a given scope.
956 2981 jones
     * @param scope String  the scope to use for looking up the latest id
957
     * @throws MetacatException when an error occurs
958
     */
959
    public String getLastDocid(String scope) throws MetacatException {
960
        String lastIdentifier = "";
961
        //set up properties
962
        Properties prop = new Properties();
963
        prop.put("action", "getlastdocid");
964
        prop.put("scope", scope);
965 3285 barteau
966 2981 jones
        String response = null;
967
        try {
968 5914 leinfelder
        	InputStream result = sendParameters(prop);
969
            response = IOUtils.toString(result, encoding);
970 2337 tao
            // Check for an error condition
971 2981 jones
            if (response.indexOf("<error>") != -1) {
972 3285 barteau
                throw new MetacatException(response);
973 2981 jones
            } else {
974
                Reader responseReader = new StringReader(response);
975 3285 barteau
                Node root =
976
                        XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
977
                Node docidNode =
978
                        XMLUtilities.getNodeWithXPath(root, "/lastDocid/docid");
979 2986 jones
                lastIdentifier = docidNode.getFirstChild().getNodeValue();
980 2981 jones
            }
981
        } catch (Exception e) {
982 2337 tao
            throw new MetacatException(e.getMessage());
983
        }
984 2981 jones
        return lastIdentifier;
985
    }
986 3141 berkley
987
    /**
988
     * return a list of all docids that match a given scope.  if scope is null
989
     * return all docids registered in the system
990
     * @param scope String  the scope to use to limit the docid query
991
     * @throws MetacatException when an error occurs
992
     */
993
    public Vector getAllDocids(String scope) throws MetacatException {
994
        Vector resultVec = new Vector();
995
        //set up properties
996
        Properties prop = new Properties();
997
        prop.put("action", "getalldocids");
998 3285 barteau
        if(scope != null) {
999
            prop.put("scope", scope);
1000 3141 berkley
        }
1001 3285 barteau
1002 3141 berkley
        String response = null;
1003
        try {
1004 5914 leinfelder
        	InputStream result = sendParameters(prop);
1005
            response = IOUtils.toString(result, encoding);
1006 3141 berkley
            // Check for an error condition
1007
            if (response.indexOf("<error>") != -1) {
1008 3285 barteau
                throw new MetacatException(response);
1009 3141 berkley
            } else {
1010
                Reader responseReader = new StringReader(response);
1011 3285 barteau
                Node root =
1012
                        XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
1013 3141 berkley
                NodeList nlist = root.getChildNodes();
1014 3285 barteau
                for(int i=0; i<nlist.getLength(); i++) {
1015
                    Node n = nlist.item(i);
1016
                    if(n.getNodeName().equals("docid")) {
1017
                        //add the content to the return vector
1018
                        String nodeVal = n.getFirstChild().getNodeValue();
1019
                        resultVec.addElement(nodeVal);
1020
                    }
1021 3141 berkley
                }
1022
1023
            }
1024
        } catch (Exception e) {
1025
            throw new MetacatException(e.getMessage());
1026
        }
1027
        return resultVec;
1028
    }
1029 3143 berkley
1030
    /**
1031
     * return true of the given docid is registered, false if not
1032
     * @param scope String  the scope to use to limit the docid query
1033
     * @throws MetacatException when an error occurs
1034
     */
1035
    public boolean isRegistered(String docid) throws MetacatException {
1036
        Vector resultVec = new Vector();
1037
        //set up properties
1038
        Properties prop = new Properties();
1039
        prop.put("action", "isregistered");
1040 3285 barteau
        if(docid == null) {
1041
            throw new MetacatException("<error>Cannot check if a null docid " +
1042
                    "is registered.</error>");
1043 3143 berkley
        }
1044
        prop.put("docid", docid);
1045 3285 barteau
1046 3143 berkley
        String response = null;
1047
        try {
1048 5914 leinfelder
        	InputStream result = sendParameters(prop);
1049
            response = IOUtils.toString(result, encoding);
1050 3143 berkley
            // Check for an error condition
1051
            if (response.indexOf("<error>") != -1) {
1052 3285 barteau
                throw new MetacatException(response);
1053 3143 berkley
            } else {
1054 5914 leinfelder
                if (response.indexOf("true") != -1) {
1055 3285 barteau
                    return true;
1056 3143 berkley
                }
1057
                return false;
1058
            }
1059
        } catch (Exception e) {
1060
            throw new MetacatException(e.getMessage());
1061
        }
1062
    }
1063 3285 barteau
1064 3481 barteau
    /**
1065
     * Send a request to Metacat.  An alternative to the sentData method.
1066
     * Allows for sending multiple parameters with the same name,
1067
     * different names, or any combo.  Send properties where the entry
1068
     * key contains the "param value",
1069
     * and the entry value contains the "param name".
1070
     * Constraint: param values must be unique.
1071
     *
1072
     * @return InputStream as returned by Metacat
1073
     * @param args Properties of the parameters to be sent to Metacat, where,
1074
     *      key = param value
1075
     *      value = param name
1076
     * @throws java.lang.Exception thrown
1077
     */
1078 5914 leinfelder
    synchronized public InputStream sendParameters(Properties prop) throws Exception {
1079
        InputStream result = null;
1080 1780 jones
        try {
1081 5914 leinfelder
        	HttpClient httpclient = new DefaultHttpClient();
1082
            httpclient.getParams().setParameter(
1083
            		CoreProtocolPNames.PROTOCOL_VERSION,
1084
            	    HttpVersion.HTTP_1_1);
1085
        	httpclient.getParams().setParameter(
1086
        			CoreProtocolPNames.HTTP_CONTENT_CHARSET,
1087
        			encoding);
1088
            HttpPost post = new HttpPost(metacatUrl);
1089
            //set the params
1090
            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
1091
            Enumeration<Object> keys = prop.keys();
1092
            while (keys.hasMoreElements()) {
1093
            	String key = (String) keys.nextElement();
1094
            	String value = prop.getProperty(key);
1095
            	NameValuePair nvp = new BasicNameValuePair(key, value);
1096
            	nameValuePairs.add(nvp);
1097 1780 jones
            }
1098 5914 leinfelder
            post.setEntity(new UrlEncodedFormEntity(nameValuePairs, encoding));
1099
            post.setHeader("Cookie", "JSESSIONID="+ this.sessionId);
1100
            HttpResponse httpResponse = httpclient.execute(post);
1101
            result = httpResponse.getEntity().getContent();
1102
            //httpclient.getConnectionManager().shutdown();
1103 1783 jones
        } catch (Exception e) {
1104 5914 leinfelder
            throw new MetacatInaccessibleException(e.getMessage());
1105 1783 jones
        }
1106 5914 leinfelder
        return result;
1107 1783 jones
    }
1108 2337 tao
1109
    /*
1110
     * "getversionanddoctype" action will return a string from metacat server.
1111
     * The string format is "revision;doctype"(This is bad idea, we should use xml)
1112
     * This method will get revision string from the response string
1113
     */
1114 3285 barteau
    private String parserRevisionResponse(String response) throws Exception {
1115
        String revision = null;
1116
        if (response != null) {
1117
            if(response.indexOf("<error>") != -1) {
1118
                if(response.indexOf("There is not record") != -1) {
1119
                    return "0";
1120
                } else {
1121
                    return null;
1122
                }
1123
            } else {
1124
                int firstSemiCol = response.indexOf(";");
1125
                revision = response.substring(0, firstSemiCol);
1126
            }
1127 2992 berkley
        }
1128 3285 barteau
        return revision;
1129
    }
1130
1131
    /**
1132
     * JSP API: This is a convenience method to reduce the amount of code in a Metacat Client
1133
     * JSP.  It handles creating/reusing an instance of a MetacatClient.
1134
     * @param request Since this is intended to be used by a JSP, it is passed the
1135
     * available "request" variable (the HttpServletRequest).
1136
     * @throws edu.ucsb.nceas.metacat.client.MetacatInaccessibleException Received by MetacatFactory.
1137
     * @return MetacatClient instance.
1138
     */
1139 3316 barteau
    public static MetacatClient getMetacatClient(HttpServletRequest request) throws MetacatInaccessibleException {
1140 3285 barteau
        MetacatClient                       result;
1141
        String                              metacatPath = "http://%1$s%2$s/metacat";
1142
        String                              host, context;
1143
        javax.servlet.http.HttpSession      session;
1144
1145
        session = request.getSession();
1146
        result = (MetacatClient) session.getAttribute("MetacatClient");
1147
        if (result == null) {
1148
            host = request.getHeader("host");
1149
            context = request.getContextPath();
1150 3362 barteau
            metacatPath = metacatPath.replaceFirst("%1$s", host);
1151
            metacatPath = metacatPath.replaceFirst("%2$s", context);
1152 3285 barteau
            result = (MetacatClient) MetacatFactory.createMetacatConnection(metacatPath);
1153
            session.setAttribute("MetacatClient", result);
1154
        }
1155
        return(result);
1156
    }
1157 5914 leinfelder
1158
	public String getEncoding() {
1159
		return encoding;
1160
	}
1161
1162
	public void setEncoding(String encoding) {
1163
		this.encoding = encoding;
1164
	}
1165 3285 barteau
1166 1780 jones
}
1167 5914 leinfelder
1168
class InputStreamKnownSizeBody extends InputStreamBody {
1169
	private int length;
1170
1171
	public InputStreamKnownSizeBody(
1172
			final InputStream in,
1173
			final String filename,
1174
			final int length) {
1175
		super(in, filename);
1176
		this.length = length;
1177
	}
1178
1179
	@Override
1180
	public long getContentLength() {
1181
		return this.length;
1182
	}
1183
}