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 6680 leinfelder
    	InputStreamBody content = null;
680
    	if (size < 0) {
681
        	content = new InputStreamBody(fileData, filename);
682
    	} else {
683
    		content = new InputStreamKnownSizeBody(fileData, filename, size);
684
    	}
685 5914 leinfelder
    	entity.addPart("datafile", content);
686
687 3285 barteau
        //set up properties
688 5914 leinfelder
        Properties prop = new Properties();
689
        prop.put("action", "upload");
690
        prop.put("docid", docid);
691 3285 barteau
692 5914 leinfelder
        // For usual String parameters
693
        Enumeration<Object> keys = prop.keys();
694
        while (keys.hasMoreElements()) {
695
        	String key = (String) keys.nextElement();
696
        	String value = prop.getProperty(key);
697
        	entity.addPart(key, new StringBody(value, Charset.forName(encoding)));
698
        }
699
700
        post.setHeader("Cookie", "JSESSIONID="+ this.sessionId);
701
        post.setEntity(entity);
702
703 3285 barteau
        String response = null;
704
        try {
705 5914 leinfelder
        	response = EntityUtils.toString(httpclient.execute(post).getEntity(), encoding);
706
        	httpclient.getConnectionManager().shutdown();
707 3285 barteau
        } catch (Exception e) {
708 2264 sgarg
            throw new MetacatInaccessibleException(e.getMessage());
709 3285 barteau
        }
710
711
        // Check for an error condition
712
        if (response.indexOf("<error>") != -1) {
713 2264 sgarg
            if (response.indexOf("does not have permission") != -1) {
714 3285 barteau
                throw new InsufficientKarmaException(response);
715 2264 sgarg
            } else {
716 3285 barteau
                throw new MetacatException(response);
717 2264 sgarg
            }
718 3285 barteau
        }
719
720
        return response;
721
    }
722
723 2240 sgarg
    /**
724 1780 jones
     * Delete an XML document in the repository.
725
     *
726
     * @param docid the docid to delete
727 1795 jones
     * @return the metacat response message
728 2240 sgarg
     * @throws InsufficientKarmaException when the user has insufficent rights
729 1780 jones
     *                                    for the operation
730 1795 jones
     * @throws MetacatInaccessibleException when the metacat server can not be
731
     *                                    reached or does not respond
732
     * @throws MetacatException when the metacat server generates another error
733 1780 jones
     */
734 1795 jones
    public String delete(String docid)
735 3285 barteau
    throws InsufficientKarmaException, MetacatException,
736
            MetacatInaccessibleException {
737 1795 jones
        //set up properties
738
        Properties prop = new Properties();
739
        prop.put("action", "delete");
740
        prop.put("docid", docid);
741 3285 barteau
742 1795 jones
        String response = null;
743
        try {
744 5914 leinfelder
        	InputStream result = sendParameters(prop);
745
            response = IOUtils.toString(result, encoding);
746 1795 jones
        } catch (Exception e) {
747
            throw new MetacatInaccessibleException(e.getMessage());
748
        }
749 3285 barteau
750 1795 jones
        // Check for an error condition
751
        if (response.indexOf("<error>") != -1) {
752
            if (response.indexOf("does not have permission") != -1) {
753
                throw new InsufficientKarmaException(response);
754
            } else {
755
                throw new MetacatException(response);
756
            }
757
        }
758 2326 harris
        return response;
759
    }
760 3285 barteau
761 5112 daigle
    /**
762
     * get the access control info for a given document id.
763
     *
764
     * @param _docid the docid of the document for which the access should be applied.
765
     *
766
     * @return the metacat access xml
767
     */
768
    public String getAccessControl(String docid)
769
    	throws InsufficientKarmaException, MetacatException,MetacatInaccessibleException {
770
        //set up properties
771
        Properties prop = new Properties();
772
        prop.put("action", "getaccesscontrol");
773
        prop.put("docid", docid);
774
775
        String response = null;
776
        try {
777 5914 leinfelder
        	InputStream result = sendParameters(prop);
778
            response = IOUtils.toString(result, encoding);
779 5112 daigle
        } catch (Exception e) {
780
            throw new MetacatInaccessibleException(e.getMessage());
781
        }
782
783
        // Check for an error condition
784
        if (response.indexOf("<error>") != -1) {
785
            if (response.indexOf("does not have permission") != -1) {
786
                throw new InsufficientKarmaException(response);
787
            } else {
788
                throw new MetacatException(response);
789
            }
790
        }
791
        return response;
792
    }
793 3285 barteau
794 2326 harris
    /**
795
     * set the access on an XML document in the repository.
796
     *
797 2327 harris
     * @param _docid the docid of the document for which the access should be applied.
798 2326 harris
     *
799
     * @param _principal the document's principal
800
     *
801
     * @param _permission the access permission to be applied to the docid
802
     *  {e.g. read,write,all}
803
     *
804
     * @param _permType the permission type to be applied to the document
805
     *  {e.g. allow or deny}
806
     *
807
     * @param _permOrder the order that the document's permissions should be
808
     *  processed {e.g. denyFirst or allowFirst}
809
     *
810
     *
811
     * @return the metacat response message
812
     *
813
     * @throws InsufficientKarmaException when the user has insufficent rights
814
     *                                    for the operation
815
     * @throws MetacatInaccessibleException when the metacat server can not be
816
     *                                    reached or does not respond
817
     * @throws MetacatException when the metacat server generates another error
818
     */
819 5098 daigle
    public String setAccess(String docid, String principal, String
820
            permission, String permType, String permOrder )
821 3285 barteau
            throws InsufficientKarmaException, MetacatException,
822
            MetacatInaccessibleException {
823 2326 harris
        //set up properties
824
        Properties prop = new Properties();
825
        prop.put("action", "setaccess");
826 5098 daigle
        prop.put("docid", docid);
827
        prop.put("principal", principal);
828
        prop.put("permission", permission);
829
        prop.put("permType", permType);
830
        prop.put("permOrder", permOrder);
831 3285 barteau
832 2326 harris
        String response = null;
833
        try {
834 5914 leinfelder
        	InputStream result = sendParameters(prop);
835
            response = IOUtils.toString(result, encoding);
836 2326 harris
        } catch (Exception e) {
837
            throw new MetacatInaccessibleException(e.getMessage());
838
        }
839 3285 barteau
840 2326 harris
        // Check for an error condition
841
        if (response.indexOf("<error>") != -1) {
842
            if (response.indexOf("does not have permission") != -1) {
843
                throw new InsufficientKarmaException(response);
844
            } else {
845
                throw new MetacatException(response);
846
            }
847
        }
848 1795 jones
        return response;
849 1780 jones
    }
850 3285 barteau
851 1780 jones
    /**
852 5098 daigle
	 * Set access for a given doc id. The access is represented in an access
853
	 * block of xml. All existing access will be replaced with the access
854
	 * provided in the access block.
855
	 *
856
	 * @param docid
857
	 *            the doc id for the doc we want to update
858
	 * @param accessBlock
859
	 *            the xml access block. This is the same structure as that
860
	 *            returned by the getdocumentinfo action in metacat.
861
	 * @return a string holding the response xml
862
	 */
863
    public String setAccess(String docid, String accessBlock)
864
            throws InsufficientKarmaException, MetacatException, MetacatInaccessibleException {
865
        //set up properties
866
        Properties prop = new Properties();
867
        prop.put("action", "setaccess");
868
        prop.put("docid", docid);
869
        prop.put("accessBlock", accessBlock);
870
871
        String response = null;
872
        try {
873 5914 leinfelder
        	InputStream result = sendParameters(prop);
874
            response = IOUtils.toString(result, encoding);
875 5098 daigle
        } catch (Exception e) {
876
            throw new MetacatInaccessibleException(e.getMessage());
877
        }
878
879
        // Check for an error condition
880
        if (response.indexOf("<error>") != -1) {
881
            if (response.indexOf("does not have permission") != -1) {
882
                throw new InsufficientKarmaException(response);
883
            } else {
884
                throw new MetacatException(response);
885
            }
886
        }
887
        return response;
888
    }
889
890
    /**
891 1780 jones
     * When the MetacatFactory creates an instance it needs to set the
892
     * MetacatUrl to which connections should be made.
893
     *
894
     * @param metacatUrl the URL for the metacat server
895
     */
896 3285 barteau
    public void setMetacatUrl(String metacatUrl) {
897 1783 jones
        this.metacatUrl = metacatUrl;
898 1780 jones
    }
899 3285 barteau
900 1822 jones
    /**
901
     * Get the session identifier for this session.  This is only valid if
902
     * the login methods has been called successfully for this Metacat object
903
     * beforehand.
904
     *
905
     * @returns the sessionId as a String, or null if the session is invalid
906
     */
907 3285 barteau
    public String getSessionId() {
908 1822 jones
        return this.sessionId;
909
    }
910 3285 barteau
911 1826 jones
    /**
912 2240 sgarg
     * Set the session identifier for this session.  This identifier was
913
     * previously established with a call to login.  To continue to use the
914 1826 jones
     * same session, set the session id before making a call to one of the
915
     * metacat access methods (e.g., read, query, insert, etc.).
916
     *
917
     * @param String the sessionId from a previously established session
918
     */
919 3285 barteau
    public void setSessionId(String sessionId) {
920 1826 jones
        this.sessionId = sessionId;
921
    }
922 2337 tao
923
    /**
924 3285 barteau
     * The method will return the latest revision in metacat server
925 2981 jones
     * for a given document id. If some error happens, this method will throw
926 3285 barteau
     * an exception.
927 2337 tao
     * @param docId String  the given docid you want to use. the docid it self
928
     *                      can have or haven't revision number
929
     * @throws MetacatException
930
     */
931 3285 barteau
    public int getNewestDocRevision(String docId) throws MetacatException {
932
        int rev = 0;
933
        //set up properties
934
        Properties prop = new Properties();
935
        prop.put("action", "getrevisionanddoctype");
936
        prop.put("docid", docId);
937
938
        String response = null;
939
        try {
940 5914 leinfelder
        	InputStream result = sendParameters(prop);
941
            response = IOUtils.toString(result, encoding);
942 3285 barteau
            //parseRevisionResponse will return null if there is an
943
            //error that it can't handle
944
            String revStr = parserRevisionResponse(response);
945
            Integer revObj = new Integer(revStr);
946
            rev = revObj.intValue();
947
            // Check for an error condition
948
            if (response.indexOf("<error>") != -1 && revStr == null) {
949
                throw new MetacatException(response);
950
            }
951
        } catch (Exception e) {
952
            throw new MetacatException(e.getMessage());
953
        }
954
        return rev;
955
    }
956
957 2981 jones
    /**
958
     * Return the highest document id for a given scope.  This is used by
959
     * clients to make it easier to determine the next free identifier in a
960 3285 barteau
     * sequence for a given scope.
961 2981 jones
     * @param scope String  the scope to use for looking up the latest id
962
     * @throws MetacatException when an error occurs
963
     */
964
    public String getLastDocid(String scope) throws MetacatException {
965
        String lastIdentifier = "";
966
        //set up properties
967
        Properties prop = new Properties();
968
        prop.put("action", "getlastdocid");
969
        prop.put("scope", scope);
970 3285 barteau
971 2981 jones
        String response = null;
972
        try {
973 5914 leinfelder
        	InputStream result = sendParameters(prop);
974
            response = IOUtils.toString(result, encoding);
975 2337 tao
            // Check for an error condition
976 2981 jones
            if (response.indexOf("<error>") != -1) {
977 3285 barteau
                throw new MetacatException(response);
978 2981 jones
            } else {
979
                Reader responseReader = new StringReader(response);
980 3285 barteau
                Node root =
981
                        XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
982
                Node docidNode =
983
                        XMLUtilities.getNodeWithXPath(root, "/lastDocid/docid");
984 2986 jones
                lastIdentifier = docidNode.getFirstChild().getNodeValue();
985 2981 jones
            }
986
        } catch (Exception e) {
987 2337 tao
            throw new MetacatException(e.getMessage());
988
        }
989 2981 jones
        return lastIdentifier;
990
    }
991 3141 berkley
992
    /**
993
     * return a list of all docids that match a given scope.  if scope is null
994
     * return all docids registered in the system
995
     * @param scope String  the scope to use to limit the docid query
996
     * @throws MetacatException when an error occurs
997
     */
998
    public Vector getAllDocids(String scope) throws MetacatException {
999
        Vector resultVec = new Vector();
1000
        //set up properties
1001
        Properties prop = new Properties();
1002
        prop.put("action", "getalldocids");
1003 3285 barteau
        if(scope != null) {
1004
            prop.put("scope", scope);
1005 3141 berkley
        }
1006 3285 barteau
1007 3141 berkley
        String response = null;
1008
        try {
1009 5914 leinfelder
        	InputStream result = sendParameters(prop);
1010
            response = IOUtils.toString(result, encoding);
1011 3141 berkley
            // Check for an error condition
1012
            if (response.indexOf("<error>") != -1) {
1013 3285 barteau
                throw new MetacatException(response);
1014 3141 berkley
            } else {
1015
                Reader responseReader = new StringReader(response);
1016 3285 barteau
                Node root =
1017
                        XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
1018 3141 berkley
                NodeList nlist = root.getChildNodes();
1019 3285 barteau
                for(int i=0; i<nlist.getLength(); i++) {
1020
                    Node n = nlist.item(i);
1021
                    if(n.getNodeName().equals("docid")) {
1022
                        //add the content to the return vector
1023
                        String nodeVal = n.getFirstChild().getNodeValue();
1024
                        resultVec.addElement(nodeVal);
1025
                    }
1026 3141 berkley
                }
1027
1028
            }
1029
        } catch (Exception e) {
1030
            throw new MetacatException(e.getMessage());
1031
        }
1032
        return resultVec;
1033
    }
1034 3143 berkley
1035
    /**
1036
     * return true of the given docid is registered, false if not
1037
     * @param scope String  the scope to use to limit the docid query
1038
     * @throws MetacatException when an error occurs
1039
     */
1040
    public boolean isRegistered(String docid) throws MetacatException {
1041
        Vector resultVec = new Vector();
1042
        //set up properties
1043
        Properties prop = new Properties();
1044
        prop.put("action", "isregistered");
1045 3285 barteau
        if(docid == null) {
1046
            throw new MetacatException("<error>Cannot check if a null docid " +
1047
                    "is registered.</error>");
1048 3143 berkley
        }
1049
        prop.put("docid", docid);
1050 3285 barteau
1051 3143 berkley
        String response = null;
1052
        try {
1053 5914 leinfelder
        	InputStream result = sendParameters(prop);
1054
            response = IOUtils.toString(result, encoding);
1055 3143 berkley
            // Check for an error condition
1056
            if (response.indexOf("<error>") != -1) {
1057 3285 barteau
                throw new MetacatException(response);
1058 3143 berkley
            } else {
1059 5914 leinfelder
                if (response.indexOf("true") != -1) {
1060 3285 barteau
                    return true;
1061 3143 berkley
                }
1062
                return false;
1063
            }
1064
        } catch (Exception e) {
1065
            throw new MetacatException(e.getMessage());
1066
        }
1067
    }
1068 3285 barteau
1069 3481 barteau
    /**
1070
     * Send a request to Metacat.  An alternative to the sentData method.
1071
     * Allows for sending multiple parameters with the same name,
1072
     * different names, or any combo.  Send properties where the entry
1073
     * key contains the "param value",
1074
     * and the entry value contains the "param name".
1075
     * Constraint: param values must be unique.
1076
     *
1077
     * @return InputStream as returned by Metacat
1078
     * @param args Properties of the parameters to be sent to Metacat, where,
1079
     *      key = param value
1080
     *      value = param name
1081
     * @throws java.lang.Exception thrown
1082
     */
1083 5914 leinfelder
    synchronized public InputStream sendParameters(Properties prop) throws Exception {
1084
        InputStream result = null;
1085 1780 jones
        try {
1086 5914 leinfelder
        	HttpClient httpclient = new DefaultHttpClient();
1087
            httpclient.getParams().setParameter(
1088
            		CoreProtocolPNames.PROTOCOL_VERSION,
1089
            	    HttpVersion.HTTP_1_1);
1090
        	httpclient.getParams().setParameter(
1091
        			CoreProtocolPNames.HTTP_CONTENT_CHARSET,
1092
        			encoding);
1093
            HttpPost post = new HttpPost(metacatUrl);
1094
            //set the params
1095
            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
1096
            Enumeration<Object> keys = prop.keys();
1097
            while (keys.hasMoreElements()) {
1098
            	String key = (String) keys.nextElement();
1099
            	String value = prop.getProperty(key);
1100
            	NameValuePair nvp = new BasicNameValuePair(key, value);
1101
            	nameValuePairs.add(nvp);
1102 1780 jones
            }
1103 5914 leinfelder
            post.setEntity(new UrlEncodedFormEntity(nameValuePairs, encoding));
1104
            post.setHeader("Cookie", "JSESSIONID="+ this.sessionId);
1105
            HttpResponse httpResponse = httpclient.execute(post);
1106
            result = httpResponse.getEntity().getContent();
1107
            //httpclient.getConnectionManager().shutdown();
1108 1783 jones
        } catch (Exception e) {
1109 5914 leinfelder
            throw new MetacatInaccessibleException(e.getMessage());
1110 1783 jones
        }
1111 5914 leinfelder
        return result;
1112 1783 jones
    }
1113 2337 tao
1114
    /*
1115
     * "getversionanddoctype" action will return a string from metacat server.
1116
     * The string format is "revision;doctype"(This is bad idea, we should use xml)
1117
     * This method will get revision string from the response string
1118
     */
1119 3285 barteau
    private String parserRevisionResponse(String response) throws Exception {
1120
        String revision = null;
1121
        if (response != null) {
1122
            if(response.indexOf("<error>") != -1) {
1123
                if(response.indexOf("There is not record") != -1) {
1124
                    return "0";
1125
                } else {
1126
                    return null;
1127
                }
1128
            } else {
1129
                int firstSemiCol = response.indexOf(";");
1130
                revision = response.substring(0, firstSemiCol);
1131
            }
1132 2992 berkley
        }
1133 3285 barteau
        return revision;
1134
    }
1135
1136
    /**
1137
     * JSP API: This is a convenience method to reduce the amount of code in a Metacat Client
1138
     * JSP.  It handles creating/reusing an instance of a MetacatClient.
1139
     * @param request Since this is intended to be used by a JSP, it is passed the
1140
     * available "request" variable (the HttpServletRequest).
1141
     * @throws edu.ucsb.nceas.metacat.client.MetacatInaccessibleException Received by MetacatFactory.
1142
     * @return MetacatClient instance.
1143
     */
1144 3316 barteau
    public static MetacatClient getMetacatClient(HttpServletRequest request) throws MetacatInaccessibleException {
1145 3285 barteau
        MetacatClient                       result;
1146
        String                              metacatPath = "http://%1$s%2$s/metacat";
1147
        String                              host, context;
1148
        javax.servlet.http.HttpSession      session;
1149
1150
        session = request.getSession();
1151
        result = (MetacatClient) session.getAttribute("MetacatClient");
1152
        if (result == null) {
1153
            host = request.getHeader("host");
1154
            context = request.getContextPath();
1155 3362 barteau
            metacatPath = metacatPath.replaceFirst("%1$s", host);
1156
            metacatPath = metacatPath.replaceFirst("%2$s", context);
1157 3285 barteau
            result = (MetacatClient) MetacatFactory.createMetacatConnection(metacatPath);
1158
            session.setAttribute("MetacatClient", result);
1159
        }
1160
        return(result);
1161
    }
1162 5914 leinfelder
1163
	public String getEncoding() {
1164
		return encoding;
1165
	}
1166
1167
	public void setEncoding(String encoding) {
1168
		this.encoding = encoding;
1169
	}
1170 3285 barteau
1171 1780 jones
}
1172 5914 leinfelder
1173
class InputStreamKnownSizeBody extends InputStreamBody {
1174
	private int length;
1175
1176
	public InputStreamKnownSizeBody(
1177
			final InputStream in,
1178
			final String filename,
1179
			final int length) {
1180
		super(in, filename);
1181
		this.length = length;
1182
	}
1183
1184
	@Override
1185
	public long getContentLength() {
1186
		return this.length;
1187
	}
1188
}