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: 2014-04-24 13:28:01 -0700 (Thu, 24 Apr 2014) $'
8
 * '$Revision: 8748 $'
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.AbstractContentBody;
54
import org.apache.http.entity.mime.content.ByteArrayBody;
55
import org.apache.http.entity.mime.content.FileBody;
56
import org.apache.http.entity.mime.content.InputStreamBody;
57
import org.apache.http.entity.mime.content.StringBody;
58
import org.apache.http.impl.client.DefaultHttpClient;
59
import org.apache.http.message.BasicNameValuePair;
60
import org.apache.http.params.CoreProtocolPNames;
61
import org.apache.http.util.EntityUtils;
62
import org.w3c.dom.Node;
63
import org.w3c.dom.NodeList;
64

    
65
import edu.ucsb.nceas.utilities.IOUtil;
66
import edu.ucsb.nceas.utilities.XMLUtilities;
67
import java.io.File;
68

    
69

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

    
94
            int c = r.read();
95
            while(c != -1)
96
            {
97
              bfos.write(c);
98
              c = r.read();
99
            }
100
            bfos.flush();
101
            bfos.close();
102
            fos.flush();
103
            fos.close();
104
    	} catch (Exception e) {
105
    		e.printStackTrace();
106
    	}
107
    }
108
    
109
    /**
110
     * Constructor to create a new instance. Protected because instances
111
     * should only be created by the factory MetacatFactory.
112
     */
113
    protected MetacatClient() {
114
        this.metacatUrl = null;
115
        this.sessionId = null;
116
    }
117
    
118
    /**
119
     *  Method used to log in to a metacat server. Implementations will need
120
     *  to cache a cookie value to make the session persistent.  Each time a
121
     *  call is made to one of the other methods (e.g., read), the cookie will
122
     *  need to be passed back to the metacat server along with the request.
123
     *
124
     *  @param username   the username of the user, like an LDAP DN
125
     *  @param password   the password for that user for authentication
126
     *  @return the response string from metacat in XML format
127
     *  @throws MetacatAuthException when the username/password could
128
     *                    not be authenticated
129
     */
130
    public String login(String username, String password)
131
    throws MetacatAuthException, MetacatInaccessibleException {
132
        Properties prop = new Properties();
133
        prop.put("action", "login");
134
        prop.put("qformat", "xml");
135
        prop.put("username", username);
136
        prop.put("password", password);
137
//        if (this.sessionId != null) {
138
//        	prop.put("sessionid", sessionId);
139
//        }
140
        
141
        String response = null;
142
        try {
143
        	InputStream result = sendParameters(prop);
144
            response = IOUtils.toString(result, encoding);
145
        } catch (Exception e) {
146
            throw new MetacatInaccessibleException(e.getMessage());
147
        }
148
        
149
        if (response.indexOf("<login>") == -1) {
150
            setSessionId("");
151
            throw new MetacatAuthException(response);
152
        } else {
153
            int start = response.indexOf("<sessionId>") + 11;
154
            int end = response.indexOf("</sessionId>");
155
            if ((start != -1) && (end != -1)) {
156
                setSessionId(response.substring(start,end));
157
            }
158
        }
159
        return response;
160
    }
161
    
162
    /**
163
     *  Method used to log in to a metacat server. Implementations will need
164
     *  to cache a cookie value to make the session persistent.  Each time a
165
     *  call is made to one of the other methods (e.g., read), the cookie will
166
     *  need to be passed back to the metacat server along with the request.
167
     *
168
     *  @param username   the username of the user, like an LDAP DN
169
     *  @param password   the password for that user for authentication
170
     *  @return the response string from metacat in XML format
171
     *  @throws MetacatAuthException when the username/password could
172
     *                    not be authenticated
173
     */
174
    public String getloggedinuserinfo() throws MetacatInaccessibleException {
175
        Properties prop = new Properties();
176
        prop.put("action", "getloggedinuserinfo");
177
        prop.put("qformat", "xml");
178
        
179
        String response = null;
180
        try {
181
        	InputStream result = sendParameters(prop);
182
            response = IOUtils.toString(result, encoding);
183
        } catch (Exception e) {
184
            throw new MetacatInaccessibleException(e.getMessage());
185
        }
186
        
187
        return response;
188
    }
189
    
190
    /**
191
     *  Method used to log out a metacat server. The Metacat server will end
192
     *  the session when this call is invoked.
193
     *
194
     *  @return the response string from metacat in XML format
195
     *  @throws MetacatInaccessibleException when the metacat server can not be
196
     *                                    reached or does not respond
197
     */
198
    public String logout() throws MetacatInaccessibleException, MetacatException {
199
        Properties prop = new Properties();
200
        prop.put("action", "logout");
201
        prop.put("qformat", "xml");
202
        if (this.sessionId != null) {
203
        	prop.put("sessionid", sessionId);
204
        }
205
        
206
        String response = null;
207
        try {
208
        	InputStream result = sendParameters(prop);
209
            response = IOUtils.toString(result, encoding);
210
        } catch (Exception e) {
211
            throw new MetacatInaccessibleException(e.getMessage());
212
        }
213
        
214
        if (response.indexOf("<logout>") == -1) {
215
            throw new MetacatException(response);
216
        }
217
        setSessionId("");
218
        return response;
219
    }
220
    
221
    /**
222
     *  Method used to log in to a metacat server. Implementations will need
223
     *  to cache a cookie value to make the session persistent.  Each time a
224
     *  call is made to one of the other methods (e.g., read), the cookie will
225
     *  need to be passed back to the metacat server along with the request.
226
     *
227
     *  @param username   the username of the user, like an LDAP DN
228
     *  @param password   the password for that user for authentication
229
     *  @return the response string from metacat in XML format
230
     *  @throws MetacatAuthException when the username/password could
231
     *                    not be authenticated
232
     */
233
    public String validateSession(String sessionId)
234
    		throws MetacatAuthException, MetacatInaccessibleException {
235
    	
236
        Properties prop = new Properties();
237
        prop.put("action", "validatesession");
238
        prop.put("sessionid", sessionId);
239
        
240
        String response = null;
241
        try {
242
        	InputStream result = sendParameters(prop);
243
            response = IOUtils.toString(result, encoding);
244
        } catch (Exception e) {
245
            throw new MetacatInaccessibleException(e.getMessage());
246
        }
247
        
248
        if (response.indexOf("<validateSession><status>") == -1) {
249
            setSessionId("");
250
            throw new MetacatAuthException(response);
251
        } 
252
        
253
        return response;
254
    }
255
    
256
   
257

    
258
	/**
259
     *  Method used to log in to a metacat server. Implementations will need
260
     *  to cache a cookie value to make the session persistent.  Each time a
261
     *  call is made to one of the other methods (e.g., read), the cookie will
262
     *  need to be passed back to the metacat server along with the request.
263
     *
264
     *  @param username   the username of the user, like an LDAP DN
265
     *  @param password   the password for that user for authentication
266
     *  @return the response string from metacat in XML format
267
     *  @throws MetacatAuthException when the username/password could
268
     *                    not be authenticated
269
     */
270
    public String isAuthorized(String resourceLsid, String permission, String sessionId)
271
    		throws MetacatAuthException, MetacatInaccessibleException {
272
    	
273
        Properties prop = new Properties();
274
        prop.put("action", "isauthorized");
275
        prop.put("resourceLsid", resourceLsid);
276
        prop.put("permission", permission);
277
        prop.put("sessionId", sessionId);
278
        
279
        String response = null;
280
        try {
281
        	InputStream result = sendParameters(prop);
282
            response = IOUtils.toString(result, encoding);
283
        } catch (Exception e) {
284
            throw new MetacatInaccessibleException(e.getMessage());
285
        }
286
        
287
        if (response.indexOf("<resourceAuthorization>") == -1) {
288
        	System.out.println("invalid response: " + response);
289
            throw new MetacatAuthException(response);
290
        } 
291
        
292
        return response;
293
    }
294
    
295
    /**
296
     * Read an XML document from the metacat server session, accessed by docid,
297
     * and returned as a Reader.
298
     *
299
     * @param docid the identifier of the document to be read
300
     * @return a Reader for accessing the document
301
     * @throws InsufficientKarmaException when the user has insufficent rights
302
     *                                    for the operation
303
     * @throws MetacatInaccessibleException when the metacat server can not be
304
     *                                    reached or does not respond
305
     * @throws MetacatException when the metacat server generates another error
306
     */
307
    public InputStream read(String docid) throws InsufficientKarmaException,
308
            MetacatInaccessibleException, MetacatException, DocumentNotFoundException {
309
    	Reader r = null;
310
        
311
        Properties prop = new Properties();
312
        prop.put("action", "read");
313
        prop.put("qformat", "xml");
314
        prop.put("docid", docid);
315
        InputStream response = null;
316
        try {
317
            response = sendParameters(prop);
318
        } catch (Exception e) {
319
            throw new MetacatInaccessibleException(e.getMessage());
320
        }
321
        BufferedInputStream bis = new BufferedInputStream(response);
322
        r = new InputStreamReader(bis);
323
        try {
324
        	bis.mark(512);
325
            char[] characters = new char[512];
326
            int len = r.read(characters, 0, 512);
327
            StringWriter sw = new StringWriter();
328
            sw.write(characters, 0, len);
329
            String message = sw.toString();
330
            sw.close();
331
            bis.reset();
332
            if (message.indexOf("<error>") != -1) {
333
                if (message.indexOf("does not have permission") != -1) {
334
                    throw new InsufficientKarmaException(message);
335
                } else if(message.indexOf("does not exist") != -1) {
336
                    throw new DocumentNotFoundException(message);
337
                } else {
338
                    throw new MetacatException(message);
339
                }
340
            }
341
        } catch (IOException ioe) {
342
            throw new MetacatException(
343
                    "MetacatClient: Error converting Reader to String."
344
                    + ioe.getMessage());
345
        }
346
        return bis;
347
    }
348
    
349
    
350
    /**
351
     * Read inline data from the metacat server session, accessed by
352
     * inlinedataid and returned as a Reader.
353
     *
354
     * @param inlinedataid the identifier of the data to be read
355
     * @return a Reader for accessing the document
356
     * @throws InsufficientKarmaException when the user has insufficent rights
357
     *                                    for the operation
358
     * @throws MetacatInaccessibleException when the metacat server can not be
359
     *                                    reached or does not respond
360
     * @throws MetacatException when the metacat server generates another error
361
     */
362
    public InputStream readInlineData(String inlinedataid)
363
    throws InsufficientKarmaException,
364
            MetacatInaccessibleException, MetacatException {
365
        Reader r = null;
366
        
367
        Properties prop = new Properties();
368
        prop.put("action", "readinlinedata");
369
        prop.put("inlinedataid", inlinedataid);
370
        
371
        InputStream response = null;
372
        try {
373
            response = sendParameters(prop);
374
        } catch (Exception e) {
375
            throw new MetacatInaccessibleException(e.getMessage());
376
        }
377
        BufferedInputStream bis = new BufferedInputStream(response);
378
        r = new InputStreamReader(bis);
379
        try {
380
        	bis.mark(512);
381
            char[] characters = new char[512];
382
            int len = r.read(characters, 0, 512);
383
            StringWriter sw = new StringWriter();
384
            sw.write(characters, 0, len);
385
            String message = sw.toString();
386
            sw.close();
387
            bis.reset();
388
            if (message.indexOf("<error>") != -1) {
389
                if (message.indexOf("does not have permission") != -1) {
390
                    throw new InsufficientKarmaException(message);
391
                } else {
392
                    throw new MetacatException(message);
393
                }
394
            }
395
        } catch (IOException ioe) {
396
            throw new MetacatException(
397
                    "MetacatClient: Error converting Reader to String."
398
                    + ioe.getMessage());
399
        }
400
        
401
        return bis;
402
    }
403
    
404
    /**
405
     * Query the metacat document store with the given metacat-compatible
406
     * query document and default qformat xml, and return the result set as a Reader.
407
     *
408
     * @param xmlQuery a Reader for accessing the XML version of the query
409
     * @return a Reader for accessing the result set
410
     */
411
    public Reader query(Reader xmlQuery) throws MetacatInaccessibleException,
412
            IOException {
413
        String qformat = "xml";
414
        return query(xmlQuery, qformat);
415
    }
416
    
417
    /**
418
     * Query the metacat document store with the given metacat-compatible
419
     * query document and qformat, and return the result set as a Reader.
420
     *
421
     * @param xmlQuery a Reader for accessing the XML version of the query
422
     * @param qformat the format of return doc. It can be xml, knb, lter and etal.
423
     * @return a Reader for accessing the result set
424
     */
425
    public Reader query(Reader xmlQuery, String qformat) throws MetacatInaccessibleException,
426
            IOException {
427
        Reader reader = null;
428
        String query = null;
429
        try {
430
            query = IOUtil.getAsString(xmlQuery, true);
431
        } catch (IOException ioE) {
432
            throw ioE;
433
        }
434
        
435
        //set up properties
436
        Properties prop = new Properties();
437
        prop.put("action", "squery");
438
        prop.put("qformat", qformat);
439
        prop.put("query", query);
440
        
441
        InputStream response = null;
442
        try {
443
            response = sendParameters(prop);
444
        } catch (Exception e) {
445
            throw new MetacatInaccessibleException(e.getMessage());
446
        }
447
        reader = new InputStreamReader(response);
448
        return reader;
449
    }
450
    
451
    /**
452
     * Insert an XML document into the repository.
453
     *
454
     * @param docid the docid to insert the document
455
     * @param xmlDocument a Reader for accessing the XML document to be inserted
456
     * @param schema a Reader for accessing the DTD or XML Schema for
457
     *               the document
458
     * @return the metacat response message
459
     * @throws InsufficientKarmaException when the user has insufficent rights
460
     *                                    for the operation
461
     * @throws MetacatInaccessibleException when the metacat server can not be
462
     *                                    reached or does not respond
463
     * @throws MetacatException when the metacat server generates another error
464
     * @throws IOException when there is an error reading the xml document
465
     */
466
    public String insert(String docid, Reader xmlDocument, Reader schema)
467
    	throws InsufficientKarmaException, MetacatException, IOException,
468
            MetacatInaccessibleException {
469

    
470
        String doctext = null;
471
        String schematext = null;
472
        try {
473
            doctext = IOUtil.getAsString(xmlDocument, true);
474
            if (schema != null) {
475
                schematext = IOUtil.getAsString(schema, true);
476
            }
477
        } catch (IOException ioE) {
478
            throw ioE;
479
        }
480
        
481
        //set up properties
482
        Properties prop = new Properties();
483
        prop.put("action", "insert");
484
        prop.put("docid", docid);
485
        prop.put("doctext", doctext);
486
        if (schematext != null) {
487
            prop.put("dtdtext", schematext);
488
        }
489

    
490
//        if (sessionId != null) {
491
//            prop.put("sessionid", sessionId);
492
//        }
493
        
494
        String response = null;
495
        try {
496
        	InputStream result = sendParameters(prop);
497
            response = IOUtils.toString(result, encoding);
498
        } catch (Exception e) {
499
            throw new MetacatInaccessibleException(e.getMessage());
500
        }
501
        
502
        // Check for an error condition
503
        if (response.indexOf("<error>") != -1) {
504
            if (response.indexOf("does not have permission") != -1) {
505
                throw new InsufficientKarmaException(response);
506
            } else {
507
                throw new MetacatException(response);
508
            }
509
        }
510
        
511
        return response;
512
    }
513
    
514
    /**
515
     * Update an XML document in the repository.
516
     *
517
     * @param docid the docid to update
518
     * @param xmlDocument a Reader for accessing the XML text to be updated
519
     * @param schema a Reader for accessing the DTD or XML Schema for
520
     *               the document
521
     * @return the metacat response message
522
     * @throws InsufficientKarmaException when the user has insufficent rights
523
     *                                    for the operation
524
     * @throws MetacatInaccessibleException when the metacat server can not be
525
     *                                    reached or does not respond
526
     * @throws MetacatException when the metacat server generates another error
527
     * @throws IOException when there is an error reading the xml document
528
     */
529
    public String update(String docid, Reader xmlDocument, Reader schema)
530
    throws InsufficientKarmaException, MetacatException, IOException,
531
            MetacatInaccessibleException {
532
        String doctext = null;
533
        String schematext = null;
534
        try {
535
            doctext = IOUtil.getAsString(xmlDocument, true);
536
            if (schema != null) {
537
                schematext = IOUtil.getAsString(schema, true);
538
            }
539
        } catch (IOException ioE) {
540
            throw ioE;
541
        }
542
        
543
        //set up properties
544
        Properties prop = new Properties();
545
        prop.put("action", "update");
546
        prop.put("docid", docid);
547
        prop.put("doctext", doctext);
548
        if (schematext != null) {
549
            prop.put("dtdtext", schematext);
550
        }
551
        
552
        String response = null;
553
        try {
554
        	InputStream result = sendParameters(prop);
555
            response = IOUtils.toString(result, encoding);
556
        } catch (Exception e) {
557
            throw new MetacatInaccessibleException(e.getMessage());
558
        }
559
        
560
        // Check for an error condition
561
        if (response.indexOf("<error>") != -1) {
562
            if (response.indexOf("does not have permission") != -1) {
563
                throw new InsufficientKarmaException(response);
564
            } else {
565
                throw new MetacatException(response);
566
            }
567
        }
568
        
569
        return response;
570
    }
571
    
572
    /**
573
     * Upload a data document into the repository. Data files are stored on 
574
     * metacat and may be in any format (binary or text), but they are all
575
     * treated as if they were binary.  Data files are not searched by the
576
     * query() methods because they are not loaded into the XML store because
577
     * they are not XML documents.  The File parameter is used to determine a
578
     * name for the uploaded document.
579
     *
580
     * @param docid the identifier to be used for the document
581
     * @param file the File to be uploaded
582
     * @param document a InputStream containing the data to be uploaded
583
     * @return the metacat response message
584
     * @throws InsufficientKarmaException when the user has insufficent rights
585
     *                                    for the operation
586
     * @throws MetacatInaccessibleException when the metacat server can not be
587
     *                                    reached or does not respond
588
     * @throws MetacatException when the metacat server generates another error
589
     * @throws IOException when there is an error reading the xml document
590
     */
591
    public String upload(String docid, File file)
592
    throws InsufficientKarmaException, MetacatException, IOException,
593
            MetacatInaccessibleException {
594
        
595
    	HttpClient httpclient = new DefaultHttpClient();
596
        httpclient.getParams().setParameter(
597
        		CoreProtocolPNames.PROTOCOL_VERSION, 
598
        	    HttpVersion.HTTP_1_1);
599
    	httpclient.getParams().setParameter(
600
    			CoreProtocolPNames.HTTP_CONTENT_CHARSET, 
601
    			encoding);
602
    	 
603
    	HttpPost post = new HttpPost(metacatUrl);
604
    	MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
605
    	 
606
    	// For File parameters
607
    	entity.addPart("datafile", new FileBody(file));
608
    	
609
        //set up properties
610
        Properties prop = new Properties();
611
        prop.put("action", "upload");
612
        prop.put("docid", docid);
613
        
614
        // For usual String parameters
615
        Enumeration<Object> keys = prop.keys();
616
        while (keys.hasMoreElements()) {
617
        	String key = (String) keys.nextElement();
618
        	String value = prop.getProperty(key);
619
        	entity.addPart(key, new StringBody(value, Charset.forName(encoding)));
620
        }
621
        
622
        post.setHeader("Cookie", "JSESSIONID="+ this.sessionId);
623
        post.setEntity(entity);
624
    	
625
        String response = null;
626
        try {
627
        	response = EntityUtils.toString(httpclient.execute(post).getEntity(), encoding);
628
        	httpclient.getConnectionManager().shutdown();
629
        } catch (Exception e) {
630
            throw new MetacatInaccessibleException(e.getMessage());
631
        }
632
        
633
        // Check for an error condition
634
        if (response.indexOf("<error>") != -1) {
635
            if (response.indexOf("does not have permission") != -1) {
636
                throw new InsufficientKarmaException(response);
637
            } else {
638
                throw new MetacatException(response);
639
            }
640
        }
641
        
642
        return response;
643
    }
644
    
645
    /**
646
     * Upload a data document into the repository. Data files are stored on 
647
     * metacat and may be in any format (binary or text), but they are all
648
     * treated as if they were binary.  Data files are not searched by the
649
     * query() methods because they are not loaded into the XML store because
650
     * they are not XML documents. The name for the document is set explicitly
651
     * using the filename parameter.
652
     *
653
     * @param docid the identifier to be used for the document
654
     * @param filename the name to be used in the MIME description of the uploaded file
655
     * @param document a InputStream containing the data to be uploaded
656
     * @return the metacat response message
657
     * @throws InsufficientKarmaException when the user has insufficent rights
658
     *                                    for the operation
659
     * @throws MetacatInaccessibleException when the metacat server can not be
660
     *                                    reached or does not respond
661
     * @throws MetacatException when the metacat server generates another error
662
     * @throws IOException when there is an error reading the xml document
663
     */
664
    public String upload(String docid, String filename, InputStream fileData,
665
            int size)
666
            throws InsufficientKarmaException, MetacatException, IOException,
667
            MetacatInaccessibleException {
668
        
669
    	HttpClient httpclient = new DefaultHttpClient();
670
        httpclient.getParams().setParameter(
671
        		CoreProtocolPNames.PROTOCOL_VERSION, 
672
        	    HttpVersion.HTTP_1_1);
673
    	httpclient.getParams().setParameter(
674
    			CoreProtocolPNames.HTTP_CONTENT_CHARSET, 
675
    			encoding);
676
    	 
677
    	HttpPost post = new HttpPost(metacatUrl);
678
    	MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
679
    	
680
    	// For File parameters
681
    	AbstractContentBody content = null;
682
    	if (size < 0) {
683
        	content = new InputStreamBody(fileData, filename);
684
        	//content = new ByteArrayBody(IOUtils.toByteArray(fileData),  filename);
685
    	} else {
686
    		content = new InputStreamKnownSizeBody(fileData, filename, size);
687
    	}    	
688
    	entity.addPart("datafile", content);
689
    	
690
        //set up properties
691
        Properties prop = new Properties();
692
        prop.put("action", "upload");
693
        prop.put("docid", docid);
694
        
695
        // For usual String parameters
696
        Enumeration<Object> keys = prop.keys();
697
        while (keys.hasMoreElements()) {
698
        	String key = (String) keys.nextElement();
699
        	String value = prop.getProperty(key);
700
        	entity.addPart(key, new StringBody(value, Charset.forName(encoding)));
701
        }
702
    
703
        post.setHeader("Cookie", "JSESSIONID="+ this.sessionId);
704
        post.setEntity(entity);
705
    	
706
        String response = null;
707
        try {
708
        	response = EntityUtils.toString(httpclient.execute(post).getEntity(), encoding);
709
        	httpclient.getConnectionManager().shutdown();
710
        } catch (Exception e) {
711
            throw new MetacatInaccessibleException(e.getMessage());
712
        }
713
        
714
        // Check for an error condition
715
        if (response.indexOf("<error>") != -1) {
716
            if (response.indexOf("does not have permission") != -1) {
717
                throw new InsufficientKarmaException(response);
718
            } else {
719
                throw new MetacatException(response);
720
            }
721
        }
722
        
723
        return response;
724
    }
725
    
726
    /**
727
     * Delete an XML document in the repository.
728
     *
729
     * @param docid the docid to delete
730
     * @return the metacat response message
731
     * @throws InsufficientKarmaException when the user has insufficent rights
732
     *                                    for the operation
733
     * @throws MetacatInaccessibleException when the metacat server can not be
734
     *                                    reached or does not respond
735
     * @throws MetacatException when the metacat server generates another error
736
     */
737
    public String delete(String docid)
738
    throws InsufficientKarmaException, MetacatException,
739
            MetacatInaccessibleException {
740
        //set up properties
741
        Properties prop = new Properties();
742
        prop.put("action", "delete");
743
        prop.put("docid", docid);
744
        
745
        String response = null;
746
        try {
747
        	InputStream result = sendParameters(prop);
748
            response = IOUtils.toString(result, encoding);
749
        } catch (Exception e) {
750
            throw new MetacatInaccessibleException(e.getMessage());
751
        }
752
        
753
        // Check for an error condition
754
        if (response.indexOf("<error>") != -1) {
755
            if (response.indexOf("does not have permission") != -1) {
756
                throw new InsufficientKarmaException(response);
757
            } else {
758
                throw new MetacatException(response);
759
            }
760
        }
761
        return response;
762
    }
763
    
764
    /**
765
     * get the access control info for a given document id.
766
     *
767
     * @param _docid the docid of the document for which the access should be applied.
768
     *
769
     * @return the metacat access xml
770
     */
771
    public String getAccessControl(String docid) 
772
    	throws InsufficientKarmaException, MetacatException,MetacatInaccessibleException {
773
        //set up properties
774
        Properties prop = new Properties();
775
        prop.put("action", "getaccesscontrol");
776
        prop.put("docid", docid);
777
       
778
        String response = null;
779
        try {
780
        	InputStream result = sendParameters(prop);
781
            response = IOUtils.toString(result, encoding);
782
        } catch (Exception e) {
783
            throw new MetacatInaccessibleException(e.getMessage());
784
        }
785
        
786
        // Check for an error condition
787
        if (response.indexOf("<error>") != -1) {
788
            if (response.indexOf("does not have permission") != -1) {
789
                throw new InsufficientKarmaException(response);
790
            } else {
791
                throw new MetacatException(response);
792
            }
793
        }
794
        return response;
795
    }
796
    
797
    /**
798
     * set the access on an XML document in the repository.
799
     *
800
     * @param _docid the docid of the document for which the access should be applied.
801
     *
802
     * @param _principal the document's principal
803
     *
804
     * @param _permission the access permission to be applied to the docid
805
     *  {e.g. read,write,all}
806
     *
807
     * @param _permType the permission type to be applied to the document
808
     *  {e.g. allow or deny}
809
     *
810
     * @param _permOrder the order that the document's permissions should be
811
     *  processed {e.g. denyFirst or allowFirst}
812
     *
813
     *
814
     * @return the metacat response message
815
     *
816
     * @throws InsufficientKarmaException when the user has insufficent rights
817
     *                                    for the operation
818
     * @throws MetacatInaccessibleException when the metacat server can not be
819
     *                                    reached or does not respond
820
     * @throws MetacatException when the metacat server generates another error
821
     */
822
    public String setAccess(String docid, String principal, String
823
            permission, String permType, String permOrder )
824
            throws InsufficientKarmaException, MetacatException,
825
            MetacatInaccessibleException {
826
        //set up properties
827
        Properties prop = new Properties();
828
        prop.put("action", "setaccess");
829
        prop.put("docid", docid);
830
        prop.put("principal", principal);
831
        prop.put("permission", permission);
832
        prop.put("permType", permType);
833
        prop.put("permOrder", permOrder);
834
        
835
        String response = null;
836
        try {
837
        	InputStream result = sendParameters(prop);
838
            response = IOUtils.toString(result, encoding);
839
        } catch (Exception e) {
840
            throw new MetacatInaccessibleException(e.getMessage());
841
        }
842
        
843
        // Check for an error condition
844
        if (response.indexOf("<error>") != -1) {
845
            if (response.indexOf("does not have permission") != -1) {
846
                throw new InsufficientKarmaException(response);
847
            } else {
848
                throw new MetacatException(response);
849
            }
850
        }
851
        return response;
852
    }
853
    
854
    /**
855
	 * Set access for a given doc id. The access is represented in an access
856
	 * block of xml. All existing access will be replaced with the access
857
	 * provided in the access block.
858
	 * 
859
	 * @param docid
860
	 *            the doc id for the doc we want to update
861
	 * @param accessBlock
862
	 *            the xml access block. This is the same structure as that
863
	 *            returned by the getdocumentinfo action in metacat.
864
	 * @return a string holding the response xml
865
	 */
866
    public String setAccess(String docid, String accessBlock)
867
            throws InsufficientKarmaException, MetacatException, MetacatInaccessibleException {
868
        //set up properties
869
        Properties prop = new Properties();
870
        prop.put("action", "setaccess");
871
        prop.put("docid", docid);
872
        prop.put("accessBlock", accessBlock);
873
        
874
        String response = null;
875
        try {
876
        	InputStream result = sendParameters(prop);
877
            response = IOUtils.toString(result, encoding);
878
        } catch (Exception e) {
879
            throw new MetacatInaccessibleException(e.getMessage());
880
        }
881
        
882
        // Check for an error condition
883
        if (response.indexOf("<error>") != -1) {
884
            if (response.indexOf("does not have permission") != -1) {
885
                throw new InsufficientKarmaException(response);
886
            } else {
887
                throw new MetacatException(response);
888
            }
889
        }
890
        return response;
891
    }
892
    
893
    /**
894
     * When the MetacatFactory creates an instance it needs to set the
895
     * MetacatUrl to which connections should be made.
896
     *
897
     * @param metacatUrl the URL for the metacat server
898
     */
899
    public void setMetacatUrl(String metacatUrl) {
900
        this.metacatUrl = metacatUrl;
901
    }
902
    
903
    /**
904
     * Get the session identifier for this session.  This is only valid if
905
     * the login methods has been called successfully for this Metacat object
906
     * beforehand.
907
     *
908
     * @returns the sessionId as a String, or null if the session is invalid
909
     */
910
    public String getSessionId() {
911
        return this.sessionId;
912
    }
913
    
914
    /**
915
     * Set the session identifier for this session.  This identifier was
916
     * previously established with a call to login.  To continue to use the
917
     * same session, set the session id before making a call to one of the
918
     * metacat access methods (e.g., read, query, insert, etc.).
919
     *
920
     * @param String the sessionId from a previously established session
921
     */
922
    public void setSessionId(String sessionId) {
923
        this.sessionId = sessionId;
924
    }
925
    
926
    /**
927
     * The method will return the latest revision in metacat server
928
     * for a given document id. If some error happens, this method will throw
929
     * an exception.
930
     * @param docId String  the given docid you want to use. the docid it self
931
     *                      can have or haven't revision number
932
     * @throws MetacatException
933
     */
934
    public int getNewestDocRevision(String docId) throws MetacatException {
935
        int rev = 0;
936
        //set up properties
937
        Properties prop = new Properties();
938
        prop.put("action", "getrevisionanddoctype");
939
        prop.put("docid", docId);
940
        
941
        String response = null;
942
        try {
943
        	InputStream result = sendParameters(prop);
944
            response = IOUtils.toString(result, encoding);
945
            //parseRevisionResponse will return null if there is an
946
            //error that it can't handle
947
            String revStr = parserRevisionResponse(response);
948
            Integer revObj = new Integer(revStr);
949
            rev = revObj.intValue();
950
            // Check for an error condition
951
            if (response.indexOf("<error>") != -1 && revStr == null) {
952
                throw new MetacatException(response);
953
            }
954
        } catch (Exception e) {
955
            throw new MetacatException(e.getMessage());
956
        }
957
        return rev;
958
    }
959
    
960
    /**
961
     * Return the highest document id for a given scope.  This is used by
962
     * clients to make it easier to determine the next free identifier in a
963
     * sequence for a given scope.
964
     * @param scope String  the scope to use for looking up the latest id
965
     * @throws MetacatException when an error occurs
966
     */
967
    public String getLastDocid(String scope) throws MetacatException {
968
        String lastIdentifier = "";
969
        //set up properties
970
        Properties prop = new Properties();
971
        prop.put("action", "getlastdocid");
972
        prop.put("scope", scope);
973
        
974
        String response = null;
975
        try {
976
        	InputStream result = sendParameters(prop);
977
            response = IOUtils.toString(result, encoding);
978
            // Check for an error condition
979
            if (response.indexOf("<error>") != -1) {
980
                throw new MetacatException(response);
981
            } else {
982
                Reader responseReader = new StringReader(response);
983
                Node root =
984
                        XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
985
                Node docidNode =
986
                        XMLUtilities.getNodeWithXPath(root, "/lastDocid/docid");
987
                lastIdentifier = docidNode.getFirstChild().getNodeValue();
988
            }
989
        } catch (Exception e) {
990
            throw new MetacatException(e.getMessage());
991
        }
992
        return lastIdentifier;
993
    }
994
    
995
    /**
996
     * return a list of all docids that match a given scope.  if scope is null
997
     * return all docids registered in the system
998
     * @param scope String  the scope to use to limit the docid query
999
     * @throws MetacatException when an error occurs
1000
     */
1001
    public Vector getAllDocids(String scope) throws MetacatException {
1002
        Vector resultVec = new Vector();
1003
        //set up properties
1004
        Properties prop = new Properties();
1005
        prop.put("action", "getalldocids");
1006
        if(scope != null) {
1007
            prop.put("scope", scope);
1008
        }
1009
        
1010
        String response = null;
1011
        try {
1012
        	InputStream result = sendParameters(prop);
1013
            response = IOUtils.toString(result, encoding);
1014
            // Check for an error condition
1015
            if (response.indexOf("<error>") != -1) {
1016
                throw new MetacatException(response);
1017
            } else {
1018
                Reader responseReader = new StringReader(response);
1019
                Node root =
1020
                        XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
1021
                NodeList nlist = root.getChildNodes();
1022
                for(int i=0; i<nlist.getLength(); i++) {
1023
                    Node n = nlist.item(i);
1024
                    if(n.getNodeName().equals("docid")) {
1025
                        //add the content to the return vector
1026
                        String nodeVal = n.getFirstChild().getNodeValue();
1027
                        resultVec.addElement(nodeVal);
1028
                    }
1029
                }
1030
                
1031
            }
1032
        } catch (Exception e) {
1033
            throw new MetacatException(e.getMessage());
1034
        }
1035
        return resultVec;
1036
    }
1037
    
1038
    /**
1039
     * return true of the given docid is registered, false if not
1040
     * @param scope String  the scope to use to limit the docid query
1041
     * @throws MetacatException when an error occurs
1042
     */
1043
    public boolean isRegistered(String docid) throws MetacatException {
1044
        Vector resultVec = new Vector();
1045
        //set up properties
1046
        Properties prop = new Properties();
1047
        prop.put("action", "isregistered");
1048
        if(docid == null) {
1049
            throw new MetacatException("<error>Cannot check if a null docid " +
1050
                    "is registered.</error>");
1051
        }
1052
        prop.put("docid", docid);
1053
        
1054
        String response = null;
1055
        try {
1056
        	InputStream result = sendParameters(prop);
1057
            response = IOUtils.toString(result, encoding);
1058
            // Check for an error condition
1059
            if (response.indexOf("<error>") != -1) {
1060
                throw new MetacatException(response);
1061
            } else {
1062
                if (response.indexOf("true") != -1) {
1063
                    return true;
1064
                }
1065
                return false;
1066
            }
1067
        } catch (Exception e) {
1068
            throw new MetacatException(e.getMessage());
1069
        }
1070
    }
1071
    
1072
    /**
1073
     * Send a request to Metacat.  An alternative to the sentData method.
1074
     * Allows for sending multiple parameters with the same name, 
1075
     * different names, or any combo.  Send properties where the entry 
1076
     * key contains the "param key", 
1077
     * and the entry value contains the "param value".  
1078
     * Constraint: no multi-valued parameters are supported
1079
     *
1080
     * @return InputStream as returned by Metacat
1081
     * @param args Properties of the parameters to be sent to Metacat, where,
1082
     *      key = param key
1083
     *      value = param value
1084
     * @throws java.lang.Exception thrown
1085
     */
1086
    synchronized public InputStream sendParameters(Properties prop) throws Exception {
1087
        InputStream result = null;
1088
        try {
1089
        	HttpClient httpclient = new DefaultHttpClient();
1090
            httpclient.getParams().setParameter(
1091
            		CoreProtocolPNames.PROTOCOL_VERSION, 
1092
            	    HttpVersion.HTTP_1_1);
1093
        	httpclient.getParams().setParameter(
1094
        			CoreProtocolPNames.HTTP_CONTENT_CHARSET, 
1095
        			encoding);
1096
            HttpPost post = new HttpPost(metacatUrl);
1097
            //set the params
1098
            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
1099
            Enumeration<Object> keys = prop.keys();
1100
            while (keys.hasMoreElements()) {
1101
            	String key = (String) keys.nextElement();
1102
            	String value = prop.getProperty(key);
1103
            	NameValuePair nvp = new BasicNameValuePair(key, value);
1104
            	nameValuePairs.add(nvp);
1105
            }
1106
            post.setEntity(new UrlEncodedFormEntity(nameValuePairs, encoding));
1107
            post.setHeader("Cookie", "JSESSIONID="+ this.sessionId);
1108
            HttpResponse httpResponse = httpclient.execute(post);
1109
            result = httpResponse.getEntity().getContent();
1110
            //httpclient.getConnectionManager().shutdown();
1111
        } catch (Exception e) {
1112
            throw new MetacatInaccessibleException(e.getMessage());
1113
        }
1114
        return result;
1115
    }
1116
    
1117
    /**
1118
     * Send a request to Metacat.  
1119
     * NOTE: Send properties where the entry 
1120
     * key contains the "param value", 
1121
     * and the entry value contains the "param name".  
1122
     * Constraint: param values must be unique.
1123
     *
1124
     * @return InputStream as returned by Metacat
1125
     * @param args Properties of the parameters to be sent to Metacat, where,
1126
     *      key = param value
1127
     *      value = param name
1128
     * @throws java.lang.Exception thrown
1129
     */
1130
    synchronized public InputStream sendParametersInverted(Properties prop) throws Exception {
1131
        InputStream result = null;
1132
        try {
1133
        	HttpClient httpclient = new DefaultHttpClient();
1134
            httpclient.getParams().setParameter(
1135
            		CoreProtocolPNames.PROTOCOL_VERSION, 
1136
            	    HttpVersion.HTTP_1_1);
1137
        	httpclient.getParams().setParameter(
1138
        			CoreProtocolPNames.HTTP_CONTENT_CHARSET, 
1139
        			encoding);
1140
            HttpPost post = new HttpPost(metacatUrl);
1141
            //set the params
1142
            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
1143
            Enumeration<Object> keys = prop.keys();
1144
            while (keys.hasMoreElements()) {
1145
            	// NOTE: using the value as the key for multi-valued parameters
1146
            	String key = (String) keys.nextElement();
1147
            	String value = prop.getProperty(key);
1148
            	NameValuePair nvp = new BasicNameValuePair(value, key);
1149
            	nameValuePairs.add(nvp);
1150
            }
1151
            post.setEntity(new UrlEncodedFormEntity(nameValuePairs, encoding));
1152
            post.setHeader("Cookie", "JSESSIONID="+ this.sessionId);
1153
            HttpResponse httpResponse = httpclient.execute(post);
1154
            result = httpResponse.getEntity().getContent();
1155
            //httpclient.getConnectionManager().shutdown();
1156
        } catch (Exception e) {
1157
            throw new MetacatInaccessibleException(e.getMessage());
1158
        }
1159
        return result;
1160
    }
1161
    
1162
    /*
1163
     * "getversionanddoctype" action will return a string from metacat server.
1164
     * The string format is "revision;doctype"(This is bad idea, we should use xml)
1165
     * This method will get revision string from the response string
1166
     */
1167
    private String parserRevisionResponse(String response) throws Exception {
1168
        String revision = null;
1169
        if (response != null) {
1170
            if(response.indexOf("<error>") != -1) {
1171
                if(response.indexOf("There is not record") != -1) {
1172
                    return "0";
1173
                } else {
1174
                    return null;
1175
                }
1176
            } else {
1177
                int firstSemiCol = response.indexOf(";");
1178
                revision = response.substring(0, firstSemiCol);
1179
            }
1180
        }
1181
        return revision;
1182
    }
1183
    
1184
    /**
1185
     * JSP API: This is a convenience method to reduce the amount of code in a Metacat Client
1186
     * JSP.  It handles creating/reusing an instance of a MetacatClient.
1187
     * @param request Since this is intended to be used by a JSP, it is passed the
1188
     * available "request" variable (the HttpServletRequest).
1189
     * @throws edu.ucsb.nceas.metacat.client.MetacatInaccessibleException Received by MetacatFactory.
1190
     * @return MetacatClient instance.
1191
     */
1192
    public static MetacatClient getMetacatClient(HttpServletRequest request) throws MetacatInaccessibleException {
1193
        MetacatClient                       result;
1194
        String                              metacatPath = "http://%1$s%2$s/metacat";
1195
        String                              host, context;
1196
        javax.servlet.http.HttpSession      session;
1197
        
1198
        session = request.getSession();
1199
        result = (MetacatClient) session.getAttribute("MetacatClient");
1200
        if (result == null) {
1201
            host = request.getHeader("host");
1202
            context = request.getContextPath();
1203
            metacatPath = metacatPath.replaceFirst("%1$s", host);
1204
            metacatPath = metacatPath.replaceFirst("%2$s", context);
1205
            result = (MetacatClient) MetacatFactory.createMetacatConnection(metacatPath);
1206
            session.setAttribute("MetacatClient", result);
1207
        }
1208
        return(result);
1209
    }
1210

    
1211
	public String getEncoding() {
1212
		return encoding;
1213
	}
1214

    
1215
	public void setEncoding(String encoding) {
1216
		this.encoding = encoding;
1217
	}
1218
    
1219
}
1220

    
1221
class InputStreamKnownSizeBody extends InputStreamBody {
1222
	private int length;
1223

    
1224
	public InputStreamKnownSizeBody(
1225
			final InputStream in, 
1226
			final String filename,
1227
			final int length) {
1228
		super(in, filename);
1229
		this.length = length;
1230
	}
1231

    
1232
	@Override
1233
	public long getContentLength() {
1234
		return this.length;
1235
	}
1236
}
(5-5/8)