Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *  Copyright: 2000 Regents of the University of California and the
4
 *              National Center for Ecological Analysis and Synthesis
5
 *
6
 *   '$Author: leinfelder $'
7
 *     '$Date: 2011-02-04 06:17:53 -0800 (Fri, 04 Feb 2011) $'
8
 * '$Revision: 5914 $'
9
 *
10
 * This program is free software; you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation; either version 2 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program; if not, write to the Free Software
22
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23
 */
24

    
25
package edu.ucsb.nceas.metacat.client;
26

    
27
import java.io.BufferedInputStream;
28
import java.io.BufferedOutputStream;
29
import java.io.FileOutputStream;
30
import java.io.InputStream;
31
import java.io.InputStreamReader;
32
import java.io.StringReader;
33
import java.io.IOException;
34
import java.io.StringWriter;
35
import java.io.Reader;
36
import java.nio.charset.Charset;
37
import java.util.ArrayList;
38
import java.util.Enumeration;
39
import java.util.List;
40
import java.util.Properties;
41
import java.util.Vector;
42
import javax.servlet.http.HttpServletRequest;
43

    
44
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
import org.w3c.dom.Node;
61
import org.w3c.dom.NodeList;
62

    
63
import edu.ucsb.nceas.utilities.IOUtil;
64
import edu.ucsb.nceas.utilities.XMLUtilities;
65
import java.io.File;
66

    
67

    
68
/**
69
 *  This interface provides methods for initializing and logging in to a
70
 *  Metacat server, and then querying, reading, transforming, inserting,
71
 *  updating and deleting documents from that server.
72
 */
73
public class MetacatClient implements Metacat {
74
    /** The URL string for the metacat server */
75
    private String metacatUrl;
76
    
77
    /** The session identifier for the session */
78
    private String sessionId;
79
    
80
    /** The default character encoding, can be changed by client */
81
    private String encoding = "UTF-8";
82
    
83
    public static void main(String[] args) {
84
    	try {
85
    		Metacat mc = 
86
    			MetacatFactory.createMetacatConnection(args[0]);
87
    		
88
    		InputStream r = mc.read(args[1]);
89
    		FileOutputStream fos = new FileOutputStream(args[2]);
90
    		BufferedOutputStream bfos = new BufferedOutputStream(fos);
91

    
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
    /**
108
     * Constructor to create a new instance. Protected because instances
109
     * should only be created by the factory MetacatFactory.
110
     */
111
    protected MetacatClient() {
112
        this.metacatUrl = null;
113
        this.sessionId = null;
114
    }
115
    
116
    /**
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
     *  @return the response string from metacat in XML format
125
     *  @throws MetacatAuthException when the username/password could
126
     *                    not be authenticated
127
     */
128
    public String login(String username, String password)
129
    throws MetacatAuthException, MetacatInaccessibleException {
130
        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
//        if (this.sessionId != null) {
136
//        	prop.put("sessionid", sessionId);
137
//        }
138
        
139
        String response = null;
140
        try {
141
        	InputStream result = sendParameters(prop);
142
            response = IOUtils.toString(result, encoding);
143
        } catch (Exception e) {
144
            throw new MetacatInaccessibleException(e.getMessage());
145
        }
146
        
147
        if (response.indexOf("<login>") == -1) {
148
            setSessionId("");
149
            throw new MetacatAuthException(response);
150
        } else {
151
            int start = response.indexOf("<sessionId>") + 11;
152
            int end = response.indexOf("</sessionId>");
153
            if ((start != -1) && (end != -1)) {
154
                setSessionId(response.substring(start,end));
155
            }
156
        }
157
        return response;
158
    }
159
    
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
    public String getloggedinuserinfo() throws MetacatInaccessibleException {
173
        Properties prop = new Properties();
174
        prop.put("action", "getloggedinuserinfo");
175
        prop.put("qformat", "xml");
176
        
177
        String response = null;
178
        try {
179
        	InputStream result = sendParameters(prop);
180
            response = IOUtils.toString(result, encoding);
181
        } catch (Exception e) {
182
            throw new MetacatInaccessibleException(e.getMessage());
183
        }
184
        
185
        return response;
186
    }
187
    
188
    /**
189
     *  Method used to log out a metacat server. The Metacat server will end
190
     *  the session when this call is invoked.
191
     *
192
     *  @return the response string from metacat in XML format
193
     *  @throws MetacatInaccessibleException when the metacat server can not be
194
     *                                    reached or does not respond
195
     */
196
    public String logout() throws MetacatInaccessibleException, MetacatException {
197
        Properties prop = new Properties();
198
        prop.put("action", "logout");
199
        prop.put("qformat", "xml");
200
        if (this.sessionId != null) {
201
        	prop.put("sessionid", sessionId);
202
        }
203
        
204
        String response = null;
205
        try {
206
        	InputStream result = sendParameters(prop);
207
            response = IOUtils.toString(result, encoding);
208
        } catch (Exception e) {
209
            throw new MetacatInaccessibleException(e.getMessage());
210
        }
211
        
212
        if (response.indexOf("<logout>") == -1) {
213
            throw new MetacatException(response);
214
        }
215
        setSessionId("");
216
        return response;
217
    }
218
    
219
    /**
220
     *  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
        	InputStream result = sendParameters(prop);
241
            response = IOUtils.toString(result, encoding);
242
        } 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
   
255

    
256
	/**
257
     *  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
        	InputStream result = sendParameters(prop);
280
            response = IOUtils.toString(result, encoding);
281
        } 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
     * 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
     * @throws InsufficientKarmaException when the user has insufficent rights
300
     *                                    for the operation
301
     * @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
     */
305
    public InputStream read(String docid) throws InsufficientKarmaException,
306
            MetacatInaccessibleException, MetacatException, DocumentNotFoundException {
307
    	Reader r = null;
308
        
309
        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
            response = sendParameters(prop);
316
        } catch (Exception e) {
317
            throw new MetacatInaccessibleException(e.getMessage());
318
        }
319
        BufferedInputStream bis = new BufferedInputStream(response);
320
        r = new InputStreamReader(bis);
321
        try {
322
        	bis.mark(512);
323
            char[] characters = new char[512];
324
            int len = r.read(characters, 0, 512);
325
            StringWriter sw = new StringWriter();
326
            sw.write(characters, 0, len);
327
            String message = sw.toString();
328
            sw.close();
329
            bis.reset();
330
            if (message.indexOf("<error>") != -1) {
331
                if (message.indexOf("does not have permission") != -1) {
332
                    throw new InsufficientKarmaException(message);
333
                } else if(message.indexOf("does not exist") != -1) {
334
                    throw new DocumentNotFoundException(message);
335
                } else {
336
                    throw new MetacatException(message);
337
                }
338
            }
339
        } catch (IOException ioe) {
340
            throw new MetacatException(
341
                    "MetacatClient: Error converting Reader to String."
342
                    + ioe.getMessage());
343
        }
344
        return bis;
345
    }
346
    
347
    
348
    /**
349
     * 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
    public InputStream readInlineData(String inlinedataid)
361
    throws InsufficientKarmaException,
362
            MetacatInaccessibleException, MetacatException {
363
        Reader r = null;
364
        
365
        Properties prop = new Properties();
366
        prop.put("action", "readinlinedata");
367
        prop.put("inlinedataid", inlinedataid);
368
        
369
        InputStream response = null;
370
        try {
371
            response = sendParameters(prop);
372
        } catch (Exception e) {
373
            throw new MetacatInaccessibleException(e.getMessage());
374
        }
375
        BufferedInputStream bis = new BufferedInputStream(response);
376
        r = new InputStreamReader(bis);
377
        try {
378
        	bis.mark(512);
379
            char[] characters = new char[512];
380
            int len = r.read(characters, 0, 512);
381
            StringWriter sw = new StringWriter();
382
            sw.write(characters, 0, len);
383
            String message = sw.toString();
384
            sw.close();
385
            bis.reset();
386
            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
        return bis;
400
    }
401
    
402
    /**
403
     * Query the metacat document store with the given metacat-compatible
404
     * query document and default qformat xml, and return the result set as a Reader.
405
     *
406
     * @param xmlQuery a Reader for accessing the XML version of the query
407
     * @return a Reader for accessing the result set
408
     */
409
    public Reader query(Reader xmlQuery) throws MetacatInaccessibleException,
410
            IOException {
411
        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
        Reader reader = null;
426
        String query = null;
427
        try {
428
            query = IOUtil.getAsString(xmlQuery, true);
429
        } catch (IOException ioE) {
430
            throw ioE;
431
        }
432
        
433
        //set up properties
434
        Properties prop = new Properties();
435
        prop.put("action", "squery");
436
        prop.put("qformat", qformat);
437
        prop.put("query", query);
438
        
439
        InputStream response = null;
440
        try {
441
            response = sendParameters(prop);
442
        } catch (Exception e) {
443
            throw new MetacatInaccessibleException(e.getMessage());
444
        }
445
        reader = new InputStreamReader(response);
446
        return reader;
447
    }
448
    
449
    /**
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
     * @param schema a Reader for accessing the DTD or XML Schema for
455
     *               the document
456
     * @return the metacat response message
457
     * @throws InsufficientKarmaException when the user has insufficent rights
458
     *                                    for the operation
459
     * @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
     */
464
    public String insert(String docid, Reader xmlDocument, Reader schema)
465
    	throws InsufficientKarmaException, MetacatException, IOException,
466
            MetacatInaccessibleException {
467

    
468
        String doctext = null;
469
        String schematext = null;
470
        try {
471
            doctext = IOUtil.getAsString(xmlDocument, true);
472
            if (schema != null) {
473
                schematext = IOUtil.getAsString(schema, true);
474
            }
475
        } catch (IOException ioE) {
476
            throw ioE;
477
        }
478
        
479
        //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

    
488
//        if (sessionId != null) {
489
//            prop.put("sessionid", sessionId);
490
//        }
491
        
492
        String response = null;
493
        try {
494
        	InputStream result = sendParameters(prop);
495
            response = IOUtils.toString(result, encoding);
496
        } catch (Exception e) {
497
            throw new MetacatInaccessibleException(e.getMessage());
498
        }
499
        
500
        // 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
        
509
        return response;
510
    }
511
    
512
    /**
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
     * @param schema a Reader for accessing the DTD or XML Schema for
518
     *               the document
519
     * @return the metacat response message
520
     * @throws InsufficientKarmaException when the user has insufficent rights
521
     *                                    for the operation
522
     * @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
     */
527
    public String update(String docid, Reader xmlDocument, Reader schema)
528
    throws InsufficientKarmaException, MetacatException, IOException,
529
            MetacatInaccessibleException {
530
        String doctext = null;
531
        String schematext = null;
532
        try {
533
            doctext = IOUtil.getAsString(xmlDocument, true);
534
            if (schema != null) {
535
                schematext = IOUtil.getAsString(schema, true);
536
            }
537
        } catch (IOException ioE) {
538
            throw ioE;
539
        }
540
        
541
        //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
        
550
        String response = null;
551
        try {
552
        	InputStream result = sendParameters(prop);
553
            response = IOUtils.toString(result, encoding);
554
        } catch (Exception e) {
555
            throw new MetacatInaccessibleException(e.getMessage());
556
        }
557
        
558
        // 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
        
567
        return response;
568
    }
569
    
570
    /**
571
     * 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
     *
578
     * @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
     * @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
    	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
        //set up properties
608
        Properties prop = new Properties();
609
        prop.put("action", "upload");
610
        prop.put("docid", docid);
611
        
612
        // 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
        
620
        post.setHeader("Cookie", "JSESSIONID="+ this.sessionId);
621
        post.setEntity(entity);
622
    	
623
        String response = null;
624
        try {
625
        	response = EntityUtils.toString(httpclient.execute(post).getEntity(), encoding);
626
        	httpclient.getConnectionManager().shutdown();
627
        } catch (Exception e) {
628
            throw new MetacatInaccessibleException(e.getMessage());
629
        }
630
        
631
        // Check for an error condition
632
        if (response.indexOf("<error>") != -1) {
633
            if (response.indexOf("does not have permission") != -1) {
634
                throw new InsufficientKarmaException(response);
635
            } else {
636
                throw new MetacatException(response);
637
            }
638
        }
639
        
640
        return response;
641
    }
642
    
643
    /**
644
     * 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
     *
651
     * @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
     * @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
    	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
        //set up properties
683
        Properties prop = new Properties();
684
        prop.put("action", "upload");
685
        prop.put("docid", docid);
686
        
687
        // 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
        String response = null;
699
        try {
700
        	response = EntityUtils.toString(httpclient.execute(post).getEntity(), encoding);
701
        	httpclient.getConnectionManager().shutdown();
702
        } catch (Exception e) {
703
            throw new MetacatInaccessibleException(e.getMessage());
704
        }
705
        
706
        // Check for an error condition
707
        if (response.indexOf("<error>") != -1) {
708
            if (response.indexOf("does not have permission") != -1) {
709
                throw new InsufficientKarmaException(response);
710
            } else {
711
                throw new MetacatException(response);
712
            }
713
        }
714
        
715
        return response;
716
    }
717
    
718
    /**
719
     * Delete an XML document in the repository.
720
     *
721
     * @param docid the docid to delete
722
     * @return the metacat response message
723
     * @throws InsufficientKarmaException when the user has insufficent rights
724
     *                                    for the operation
725
     * @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
     */
729
    public String delete(String docid)
730
    throws InsufficientKarmaException, MetacatException,
731
            MetacatInaccessibleException {
732
        //set up properties
733
        Properties prop = new Properties();
734
        prop.put("action", "delete");
735
        prop.put("docid", docid);
736
        
737
        String response = null;
738
        try {
739
        	InputStream result = sendParameters(prop);
740
            response = IOUtils.toString(result, encoding);
741
        } catch (Exception e) {
742
            throw new MetacatInaccessibleException(e.getMessage());
743
        }
744
        
745
        // 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
        return response;
754
    }
755
    
756
    /**
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
        	InputStream result = sendParameters(prop);
773
            response = IOUtils.toString(result, encoding);
774
        } 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
    
789
    /**
790
     * set the access on an XML document in the repository.
791
     *
792
     * @param _docid the docid of the document for which the access should be applied.
793
     *
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
    public String setAccess(String docid, String principal, String
815
            permission, String permType, String permOrder )
816
            throws InsufficientKarmaException, MetacatException,
817
            MetacatInaccessibleException {
818
        //set up properties
819
        Properties prop = new Properties();
820
        prop.put("action", "setaccess");
821
        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
        
827
        String response = null;
828
        try {
829
        	InputStream result = sendParameters(prop);
830
            response = IOUtils.toString(result, encoding);
831
        } catch (Exception e) {
832
            throw new MetacatInaccessibleException(e.getMessage());
833
        }
834
        
835
        // 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
        return response;
844
    }
845
    
846
    /**
847
	 * 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
        	InputStream result = sendParameters(prop);
869
            response = IOUtils.toString(result, encoding);
870
        } 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
     * 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
    public void setMetacatUrl(String metacatUrl) {
892
        this.metacatUrl = metacatUrl;
893
    }
894
    
895
    /**
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
    public String getSessionId() {
903
        return this.sessionId;
904
    }
905
    
906
    /**
907
     * Set the session identifier for this session.  This identifier was
908
     * previously established with a call to login.  To continue to use the
909
     * 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
    public void setSessionId(String sessionId) {
915
        this.sessionId = sessionId;
916
    }
917
    
918
    /**
919
     * The method will return the latest revision in metacat server
920
     * for a given document id. If some error happens, this method will throw
921
     * an exception.
922
     * @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
    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
        	InputStream result = sendParameters(prop);
936
            response = IOUtils.toString(result, encoding);
937
            //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
    /**
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
     * sequence for a given scope.
956
     * @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
        
966
        String response = null;
967
        try {
968
        	InputStream result = sendParameters(prop);
969
            response = IOUtils.toString(result, encoding);
970
            // Check for an error condition
971
            if (response.indexOf("<error>") != -1) {
972
                throw new MetacatException(response);
973
            } else {
974
                Reader responseReader = new StringReader(response);
975
                Node root =
976
                        XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
977
                Node docidNode =
978
                        XMLUtilities.getNodeWithXPath(root, "/lastDocid/docid");
979
                lastIdentifier = docidNode.getFirstChild().getNodeValue();
980
            }
981
        } catch (Exception e) {
982
            throw new MetacatException(e.getMessage());
983
        }
984
        return lastIdentifier;
985
    }
986
    
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
        if(scope != null) {
999
            prop.put("scope", scope);
1000
        }
1001
        
1002
        String response = null;
1003
        try {
1004
        	InputStream result = sendParameters(prop);
1005
            response = IOUtils.toString(result, encoding);
1006
            // Check for an error condition
1007
            if (response.indexOf("<error>") != -1) {
1008
                throw new MetacatException(response);
1009
            } else {
1010
                Reader responseReader = new StringReader(response);
1011
                Node root =
1012
                        XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
1013
                NodeList nlist = root.getChildNodes();
1014
                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
                }
1022
                
1023
            }
1024
        } catch (Exception e) {
1025
            throw new MetacatException(e.getMessage());
1026
        }
1027
        return resultVec;
1028
    }
1029
    
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
        if(docid == null) {
1041
            throw new MetacatException("<error>Cannot check if a null docid " +
1042
                    "is registered.</error>");
1043
        }
1044
        prop.put("docid", docid);
1045
        
1046
        String response = null;
1047
        try {
1048
        	InputStream result = sendParameters(prop);
1049
            response = IOUtils.toString(result, encoding);
1050
            // Check for an error condition
1051
            if (response.indexOf("<error>") != -1) {
1052
                throw new MetacatException(response);
1053
            } else {
1054
                if (response.indexOf("true") != -1) {
1055
                    return true;
1056
                }
1057
                return false;
1058
            }
1059
        } catch (Exception e) {
1060
            throw new MetacatException(e.getMessage());
1061
        }
1062
    }
1063
    
1064
    /**
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
    synchronized public InputStream sendParameters(Properties prop) throws Exception {
1079
        InputStream result = null;
1080
        try {
1081
        	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
            }
1098
            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
        } catch (Exception e) {
1104
            throw new MetacatInaccessibleException(e.getMessage());
1105
        }
1106
        return result;
1107
    }
1108
    
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
    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
        }
1128
        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
    public static MetacatClient getMetacatClient(HttpServletRequest request) throws MetacatInaccessibleException {
1140
        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
            metacatPath = metacatPath.replaceFirst("%1$s", host);
1151
            metacatPath = metacatPath.replaceFirst("%2$s", context);
1152
            result = (MetacatClient) MetacatFactory.createMetacatConnection(metacatPath);
1153
            session.setAttribute("MetacatClient", result);
1154
        }
1155
        return(result);
1156
    }
1157

    
1158
	public String getEncoding() {
1159
		return encoding;
1160
	}
1161

    
1162
	public void setEncoding(String encoding) {
1163
		this.encoding = encoding;
1164
	}
1165
    
1166
}
1167

    
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
}
(5-5/8)