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-11-21 11:21:10 -0800 (Mon, 21 Nov 2011) $'
8
 * '$Revision: 6680 $'
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 = null;
680
    	if (size < 0) {
681
        	content = new InputStreamBody(fileData, filename);
682
    	} else {
683
    		content = new InputStreamKnownSizeBody(fileData, filename, size);
684
    	}    	
685
    	entity.addPart("datafile", content);
686
    	
687
        //set up properties
688
        Properties prop = new Properties();
689
        prop.put("action", "upload");
690
        prop.put("docid", docid);
691
        
692
        // 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
        String response = null;
704
        try {
705
        	response = EntityUtils.toString(httpclient.execute(post).getEntity(), encoding);
706
        	httpclient.getConnectionManager().shutdown();
707
        } catch (Exception e) {
708
            throw new MetacatInaccessibleException(e.getMessage());
709
        }
710
        
711
        // Check for an error condition
712
        if (response.indexOf("<error>") != -1) {
713
            if (response.indexOf("does not have permission") != -1) {
714
                throw new InsufficientKarmaException(response);
715
            } else {
716
                throw new MetacatException(response);
717
            }
718
        }
719
        
720
        return response;
721
    }
722
    
723
    /**
724
     * Delete an XML document in the repository.
725
     *
726
     * @param docid the docid to delete
727
     * @return the metacat response message
728
     * @throws InsufficientKarmaException when the user has insufficent rights
729
     *                                    for the operation
730
     * @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
     */
734
    public String delete(String docid)
735
    throws InsufficientKarmaException, MetacatException,
736
            MetacatInaccessibleException {
737
        //set up properties
738
        Properties prop = new Properties();
739
        prop.put("action", "delete");
740
        prop.put("docid", docid);
741
        
742
        String response = null;
743
        try {
744
        	InputStream result = sendParameters(prop);
745
            response = IOUtils.toString(result, encoding);
746
        } catch (Exception e) {
747
            throw new MetacatInaccessibleException(e.getMessage());
748
        }
749
        
750
        // 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
        return response;
759
    }
760
    
761
    /**
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
        	InputStream result = sendParameters(prop);
778
            response = IOUtils.toString(result, encoding);
779
        } 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
    
794
    /**
795
     * set the access on an XML document in the repository.
796
     *
797
     * @param _docid the docid of the document for which the access should be applied.
798
     *
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
    public String setAccess(String docid, String principal, String
820
            permission, String permType, String permOrder )
821
            throws InsufficientKarmaException, MetacatException,
822
            MetacatInaccessibleException {
823
        //set up properties
824
        Properties prop = new Properties();
825
        prop.put("action", "setaccess");
826
        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
        
832
        String response = null;
833
        try {
834
        	InputStream result = sendParameters(prop);
835
            response = IOUtils.toString(result, encoding);
836
        } catch (Exception e) {
837
            throw new MetacatInaccessibleException(e.getMessage());
838
        }
839
        
840
        // 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
        return response;
849
    }
850
    
851
    /**
852
	 * 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
        	InputStream result = sendParameters(prop);
874
            response = IOUtils.toString(result, encoding);
875
        } 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
     * 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
    public void setMetacatUrl(String metacatUrl) {
897
        this.metacatUrl = metacatUrl;
898
    }
899
    
900
    /**
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
    public String getSessionId() {
908
        return this.sessionId;
909
    }
910
    
911
    /**
912
     * Set the session identifier for this session.  This identifier was
913
     * previously established with a call to login.  To continue to use the
914
     * 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
    public void setSessionId(String sessionId) {
920
        this.sessionId = sessionId;
921
    }
922
    
923
    /**
924
     * The method will return the latest revision in metacat server
925
     * for a given document id. If some error happens, this method will throw
926
     * an exception.
927
     * @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
    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
        	InputStream result = sendParameters(prop);
941
            response = IOUtils.toString(result, encoding);
942
            //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
    /**
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
     * sequence for a given scope.
961
     * @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
        
971
        String response = null;
972
        try {
973
        	InputStream result = sendParameters(prop);
974
            response = IOUtils.toString(result, encoding);
975
            // Check for an error condition
976
            if (response.indexOf("<error>") != -1) {
977
                throw new MetacatException(response);
978
            } else {
979
                Reader responseReader = new StringReader(response);
980
                Node root =
981
                        XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
982
                Node docidNode =
983
                        XMLUtilities.getNodeWithXPath(root, "/lastDocid/docid");
984
                lastIdentifier = docidNode.getFirstChild().getNodeValue();
985
            }
986
        } catch (Exception e) {
987
            throw new MetacatException(e.getMessage());
988
        }
989
        return lastIdentifier;
990
    }
991
    
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
        if(scope != null) {
1004
            prop.put("scope", scope);
1005
        }
1006
        
1007
        String response = null;
1008
        try {
1009
        	InputStream result = sendParameters(prop);
1010
            response = IOUtils.toString(result, encoding);
1011
            // Check for an error condition
1012
            if (response.indexOf("<error>") != -1) {
1013
                throw new MetacatException(response);
1014
            } else {
1015
                Reader responseReader = new StringReader(response);
1016
                Node root =
1017
                        XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
1018
                NodeList nlist = root.getChildNodes();
1019
                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
                }
1027
                
1028
            }
1029
        } catch (Exception e) {
1030
            throw new MetacatException(e.getMessage());
1031
        }
1032
        return resultVec;
1033
    }
1034
    
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
        if(docid == null) {
1046
            throw new MetacatException("<error>Cannot check if a null docid " +
1047
                    "is registered.</error>");
1048
        }
1049
        prop.put("docid", docid);
1050
        
1051
        String response = null;
1052
        try {
1053
        	InputStream result = sendParameters(prop);
1054
            response = IOUtils.toString(result, encoding);
1055
            // Check for an error condition
1056
            if (response.indexOf("<error>") != -1) {
1057
                throw new MetacatException(response);
1058
            } else {
1059
                if (response.indexOf("true") != -1) {
1060
                    return true;
1061
                }
1062
                return false;
1063
            }
1064
        } catch (Exception e) {
1065
            throw new MetacatException(e.getMessage());
1066
        }
1067
    }
1068
    
1069
    /**
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
    synchronized public InputStream sendParameters(Properties prop) throws Exception {
1084
        InputStream result = null;
1085
        try {
1086
        	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
            }
1103
            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
        } catch (Exception e) {
1109
            throw new MetacatInaccessibleException(e.getMessage());
1110
        }
1111
        return result;
1112
    }
1113
    
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
    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
        }
1133
        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
    public static MetacatClient getMetacatClient(HttpServletRequest request) throws MetacatInaccessibleException {
1145
        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
            metacatPath = metacatPath.replaceFirst("%1$s", host);
1156
            metacatPath = metacatPath.replaceFirst("%2$s", context);
1157
            result = (MetacatClient) MetacatFactory.createMetacatConnection(metacatPath);
1158
            session.setAttribute("MetacatClient", result);
1159
        }
1160
        return(result);
1161
    }
1162

    
1163
	public String getEncoding() {
1164
		return encoding;
1165
	}
1166

    
1167
	public void setEncoding(String encoding) {
1168
		this.encoding = encoding;
1169
	}
1170
    
1171
}
1172

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