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: Serhan AKIN $'
7
 *     '$Date: 2009-07-15 10:54:27 +0300  $'
8
 *
9
 * This program is free software; you can redistribute it and/or modify
10
 * it under the terms of the GNU General Public License as published by
11
 * the Free Software Foundation; either version 2 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program; if not, write to the Free Software
21
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
 */
23
package edu.ucsb.nceas.metacat.client.rest;
24

    
25
import java.io.BufferedReader;
26
import java.io.FileWriter;
27
import java.io.IOException;
28
import java.io.InputStream;
29
import java.io.InputStreamReader;
30
import java.io.OutputStream;
31
import java.io.OutputStreamWriter;
32
import java.io.Reader;
33
import java.io.StringReader;
34
import java.io.Writer;
35
import java.net.HttpURLConnection;
36
import java.net.URL;
37
import java.net.URLConnection;
38
import java.util.Vector;
39

    
40
import org.w3c.dom.Node;
41
import org.w3c.dom.NodeList;
42

    
43
import edu.ucsb.nceas.metacat.client.DocumentNotFoundException;
44
import edu.ucsb.nceas.metacat.client.InsufficientKarmaException;
45
import edu.ucsb.nceas.metacat.client.MetacatAuthException;
46
import edu.ucsb.nceas.metacat.client.MetacatException;
47
import edu.ucsb.nceas.metacat.client.MetacatInaccessibleException;
48
import edu.ucsb.nceas.utilities.IOUtil;
49
import edu.ucsb.nceas.utilities.XMLUtilities;
50

    
51

    
52
public class MetacatRestClient implements MetacatRest {
53
    
54
	/** The session identifier for the session */
55
	private String sessionId;
56
	
57
	/** The URL string for the metacat REST API*/
58
	private String contextRootUrl;
59

    
60
    /**
61
     * Constructor to create a new instance. 
62
     */ 
63
	public MetacatRestClient(String contextRootUrl){
64
		setContextRootUrl(contextRootUrl);
65
	}
66

    
67
    /**
68
     *  Method used to log in to a metacat server through REST API. Implementations will need
69
     *  to cache a cookie value to make the session persistent.  Each time a
70
     *  call is made to one of the other methods (e.g., read), the cookie will
71
     *  need to be passed back to the metacat server along with the request.
72
     *
73
     *  @param username   the username of the user, like an LDAP DN
74
     *  @param password   the password for that user for authentication
75
     *  @return the response string from metacat in XML format
76
     *  @throws MetacatAuthException when the username/password could
77
     *                    not be authenticated
78
     */
79
	public String login(String username, String password)
80
	throws MetacatAuthException, MetacatInaccessibleException {
81
		System.out.println("in login");
82
	    String urlParams = FUNCTION_KEYWORD+"="+FUNCTION_NAME_LOGIN;
83
		String postData = "username="+username+"&password="+password;		
84
		String response = null;
85
		
86

    
87
		try {
88
			response = sendData(RESOURCE_SESSION, POST, urlParams, postData, "application/x-www-form-urlencoded", null, null);
89
		} catch (Exception e) {
90
			throw new MetacatInaccessibleException(e.getMessage());
91
		}
92

    
93
		if (response.indexOf("<login>") == -1) {
94
			setSessionId("");
95
			throw new MetacatAuthException(response);
96
		} else {
97
			int start = response.indexOf("<sessionId>") + 11;
98
			int end = response.indexOf("</sessionId>");
99
			if ((start != -1) && (end != -1)) {
100
				setSessionId(response.substring(start,end));
101
			}
102
		}
103
		return response;
104

    
105

    
106
	}
107
	
108
    /**
109
     *  Method used to log out a metacat server. The Metacat server will end
110
     *  the session when this call is invoked.
111
     *
112
     *  @return the response string from metacat in XML format
113
     *  @throws MetacatInaccessibleException when the metacat server can not be
114
     *                                    reached or does not respond
115
     */
116
	public String logout()throws MetacatInaccessibleException,MetacatException {
117
		String urlParams = FUNCTION_KEYWORD+"="+FUNCTION_NAME_LOGOUT ;
118
		String postData = "sessionid="+sessionId;
119
		String response;
120
		try {
121
			response = sendData(RESOURCE_SESSION, POST, urlParams, postData,"application/x-www-form-urlencoded", null, null);
122
		} catch (Exception e) {
123
			throw new MetacatInaccessibleException(e.getMessage());
124
		}
125
		return response;
126
	}
127

    
128

    
129
    /**
130
     * Read a public XML document , accessed by docid, and returned as a Reader.
131
     *
132
     * @param docid the identifier of the document to be read
133
     * @param outputFile name of the file to be written to local (optional)
134
     * @return a Reader for accessing the document
135
     * @throws InsufficientKarmaException when the user has insufficent rights
136
     *                                    for the operation
137
     * @throws MetacatInaccessibleException when the metacat server can not be
138
     *                                    reached or does not respond
139
     * @throws MetacatException when the metacat server generates another error
140
     */
141
	public Reader getObject(String docid, String outFile) throws InsufficientKarmaException,
142
	MetacatInaccessibleException, DocumentNotFoundException, MetacatException{
143
		String resource = RESOURCE_OBJECTS+"/"+docid; 
144

    
145
		try {
146
			String response = sendData(resource, GET, null, null, null, null, outFile);
147

    
148
			if (response != null ) {
149
				if (response != null && response.indexOf("<error>") != -1) {
150
					if (response.indexOf("does not have permission") != -1) {
151
						throw new InsufficientKarmaException(response);
152
					} else if(response.indexOf("does not exist") != -1) {
153
						throw new DocumentNotFoundException(response);
154
					} else {
155
						throw new MetacatException(response);                	
156
					} 
157
				} else {
158
					return new StringReader(response);
159
				}
160
			} else 
161
				throw new MetacatException(response);
162

    
163
		} catch(IOException ioe){
164
			throw new MetacatInaccessibleException(ioe.getMessage());
165
		}	
166
	}
167

    
168

    
169
    /**
170
     * Read XML document from server session, accessed by docid, and returned as a Reader.
171
     *
172
     * @param docid the identifier of the document to be read
173
     * @param outputFile name of the file to be written to local (optional)
174
     * @return a Reader for accessing the document
175
     * @throws InsufficientKarmaException when the user has insufficent rights
176
     *                                    for the operation
177
     * @throws MetacatInaccessibleException when the metacat server can not be
178
     *                                    reached or does not respond
179
     * @throws MetacatException when the metacat server generates another error
180
     */ 
181
	public Reader authenticatedGetObject(String docid, String outFile) throws InsufficientKarmaException,
182
	MetacatInaccessibleException, DocumentNotFoundException, MetacatException{
183
		String resource = RESOURCE_OBJECTS+"/"+docid; 
184

    
185
		try {
186
			String response = sendData(resource, GET, "sessionid="+sessionId, null, null, null, outFile);
187

    
188
			if (response != null ) {
189
				if (response != null && response.indexOf("<error>") != -1) {
190
					if (response.indexOf("does not have permission") != -1) {
191
						throw new InsufficientKarmaException(response);
192
					} else if(response.indexOf("does not exist") != -1) {
193
						throw new DocumentNotFoundException(response);
194
					} else {
195
						throw new MetacatException(response);                	
196
					} 
197
				} else {
198
					return new StringReader(response);
199
				}
200
			} else 
201
				throw new MetacatException(response);
202

    
203
		} catch(IOException ioe){
204
			throw new MetacatInaccessibleException(ioe.getMessage());
205
		}	
206
	}
207

    
208

    
209
    /**
210
     * Query the metacat document store with the given Ecogrid-compatible
211
     * query document and return the Ecogrid result set as a Reader.
212
     *
213
     * @param xmlQuery a Reader for accessing the XML version of the query
214
     * @return a Reader for accessing the result set
215
     */
216
	
217
	public Reader query(Reader xmlQuery) throws MetacatInaccessibleException,IOException {
218
		String response = null;
219

    
220
		try{	
221
			response = sendData(RESOURCE_OBJECTS, POST, null, null, "text/xml", xmlQuery, null);
222
		} catch (Exception e) {
223
			e.printStackTrace();
224
			throw new MetacatInaccessibleException(e.getMessage());
225
		}
226
		if (response != null)
227
			return new StringReader(response);
228
		return null;
229
	}
230

    
231
    /**
232
     * Query (as an authenticated user) the metacat document store with the given Ecogrid-compatible
233
     * query document and return the Ecogrid result set as a Reader.
234
     *
235
     * @param xmlQuery a Reader for accessing the XML version of the query
236
     * @return a Reader for accessing the result set
237
     */
238
	public Reader authenticatedQuery(Reader xmlQuery) throws MetacatInaccessibleException,IOException {
239
		String response = null;
240
		try{
241
			response = sendData(RESOURCE_OBJECTS, POST, "sessionid="+sessionId, null, "text/xml", xmlQuery, null);
242
		} catch (Exception e) {
243
			e.printStackTrace();
244
			throw new MetacatInaccessibleException(e.getMessage());
245
		}
246
		if (response != null)
247
			return new StringReader(response);		
248
		return null;
249
	}
250

    
251
	/**
252
     * Create an XML document in the repository.
253
     *
254
     * @param docid the docid to insert the document
255
     * @param xmlDocument a Reader for accessing the XML document to be inserted
256
     * @param isInsert whether the operation is update or insert
257
     * 
258
     * 
259
     * @return the metacat response message
260
     * @throws InsufficientKarmaException when the user has insufficent rights
261
     *                                    for the operation
262
     * @throws MetacatInaccessibleException when the metacat server can not be
263
     *                                    reached or does not respond
264
     * @throws MetacatException when the metacat server generates another error
265
     * @throws IOException when there is an error reading the xml document
266
     */
267
    public String create(String docid, Reader xmlDocument)
268
    throws InsufficientKarmaException, MetacatException, IOException, MetacatInaccessibleException {
269
        return putObject(docid, xmlDocument, true);
270
    }
271
    
272
    /**
273
     * Update an XML document in the repository, replacing an existing document.
274
     *
275
     * @param docid the docid to insert the document
276
     * @param xmlDocument a Reader for accessing the XML document to be inserted
277
     * @param isInsert whether the operation is update or insert
278
     * 
279
     * 
280
     * @return the metacat response message
281
     * @throws InsufficientKarmaException when the user has insufficent rights
282
     *                                    for the operation
283
     * @throws MetacatInaccessibleException when the metacat server can not be
284
     *                                    reached or does not respond
285
     * @throws MetacatException when the metacat server generates another error
286
     * @throws IOException when there is an error reading the xml document
287
     */
288
    public String update(String docid, Reader xmlDocument)
289
    throws InsufficientKarmaException, MetacatException, IOException, MetacatInaccessibleException {
290
        return putObject(docid, xmlDocument, false);
291
    }
292
    
293
	/**
294
	 * Delete an XML document in the repository.
295
	 *
296
	 * @param docid the docid to delete
297
	 * @return the metacat response message
298
	 * @throws InsufficientKarmaException when the user has insufficent rights
299
	 *                                    for the operation
300
	 * @throws MetacatInaccessibleException when the metacat server can not be
301
	 *                                    reached or does not respond
302
	 * @throws MetacatException when the metacat server generates another error
303
	 */
304
	public String deleteObject(String docid)
305
	throws InsufficientKarmaException, MetacatException,MetacatInaccessibleException {
306
		String resource = RESOURCE_OBJECTS+"/"+docid;
307
		String urlParams = "sessionid="+sessionId+"&";
308
		String response = null;
309
		try{
310
			response = sendData(resource, DELETE, urlParams, null, null, null, null);
311
		} catch (Exception e) {
312
			e.printStackTrace();
313
			throw new MetacatInaccessibleException(e.getMessage());
314
		}
315

    
316
		// Check for an error condition
317
		if (response.indexOf("<error>") != -1) {
318
			if (response.indexOf("does not have permission") != -1) {
319
				throw new InsufficientKarmaException(response);
320
			} else {
321
				throw new MetacatException(response);
322
			}
323
		}	
324
		return response;
325
	}
326

    
327

    
328
	/**
329
	 * Return the highest document id for a given scope.  This is used by
330
	 * clients to make it easier to determine the next free identifier in a
331
	 * sequence for a given scope.
332
	 * @param scope String  the scope to use for looking up the latest id
333
	 * @throws MetacatException when an error occurs
334
	 */
335

    
336
	public String getNextObject(String scope) throws MetacatException {
337
		String lastIdentifier = "";
338
		String resource = RESOURCE_IDENTIFIER;
339
		String urlParams = FUNCTION_KEYWORD+"="+FUNCTION_NAME_GETNEXTOBJ;
340
		if (scope != null)
341
			urlParams += "&scope="+scope; 
342
		String response = null;
343
		try {
344
			response = sendData(resource, GET, urlParams, null, null, null, null);
345
			// Check for an error condition
346
			if (response.indexOf("<error>") != -1) {
347
				throw new MetacatException(response);
348
			} else {
349
				Reader responseReader = new StringReader(response);
350
				Node root =
351
					XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
352
				Node docidNode =
353
					XMLUtilities.getNodeWithXPath(root, "/lastDocid/docid");
354
				lastIdentifier = docidNode.getFirstChild().getNodeValue();
355
			}
356
		} catch (Exception e) {
357
			throw new MetacatException(e.getMessage());
358
		}
359
		return lastIdentifier;
360
	}
361

    
362
	/**
363
	 * The method will return the latest revision in metacat server
364
	 * for a given document id. If some error happens, this method will throw
365
	 * an exception.
366
	 * @param identifierId String  the given docid you want to use. the docid it self
367
	 *                      can have or haven't revision number
368
	 * @throws MetacatException
369
	 */
370
	public int getNextRevision(String identifierId) throws MetacatException {
371
		int rev = 0;
372

    
373
		String resource = RESOURCE_IDENTIFIER+"/"+identifierId;
374
		String urlParams = FUNCTION_KEYWORD+"="+FUNCTION_NAME_GETNEXTREV;
375

    
376
		String response = null;
377
		try {
378
			response = sendData(resource, GET, urlParams, null, null, null, null);
379

    
380
	         // Check for an error condition            
381
            if (response.indexOf("<error>") != -1 ) {
382
                throw new MetacatException(response);
383
            }
384
            
385
			Reader responseReader = new StringReader(response);
386
			Node root =
387
				XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
388
			Node docidNode =
389
				XMLUtilities.getNodeWithXPath(root, "/next-revision");
390
			rev = Integer.parseInt(docidNode.getFirstChild().getNodeValue());                        
391

    
392
		} catch (Exception e) {
393
			e.printStackTrace();
394
			throw new MetacatException(e.getMessage());
395
		}
396
		return rev;
397
	}
398

    
399
	/**
400
	 * return a list of all docids that match a given scope.  if scope is null
401
	 * return all docids registered in the system
402
	 * @param scope String  the scope to use to limit the docid query
403
	 * @throws MetacatException when an error occurs
404
	 */
405
	public Vector<String> getAllDocids(String scope) throws MetacatException {
406
		Vector<String> resultVec = new Vector<String>();
407
		String resource = RESOURCE_IDENTIFIER;
408
		String urlParams = FUNCTION_KEYWORD+"="+FUNCTION_NAME_GETALLDOCS;
409
		if (scope != null)
410
			urlParams += "&scope="+scope; 
411
		String response = null;
412
		try {
413
			response = sendData(resource, GET, urlParams, null, null, null, null);
414
			// Check for an error condition
415
			if (response.indexOf("<error>") != -1) {
416
				throw new MetacatException(response);
417
			} else {
418
				Reader responseReader = new StringReader(response);
419
				Node root =
420
					XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
421
				NodeList nlist = root.getChildNodes();
422
				for(int i=0; i<nlist.getLength(); i++) {
423
					Node n = nlist.item(i);
424
					if(n.getNodeName().equals("docid")) {
425
						//add the content to the return vector
426
						String nodeVal = n.getFirstChild().getNodeValue();
427
						resultVec.addElement(nodeVal);
428
					}
429
				}
430

    
431
			}
432
		} catch (Exception e) {
433
			throw new MetacatException(e.getMessage());
434
		}
435
		return resultVec;
436
	}
437

    
438
	/**
439
	 * return true of the given docid is registered, false if not
440
	 * @param scope String  the scope to use to limit the docid query
441
	 * @throws MetacatException when an error occurs
442
	 */
443
	public boolean isRegistered(String identifierId) throws MetacatException {
444
		String resource = RESOURCE_IDENTIFIER+"/"+identifierId;
445
		String urlParams = FUNCTION_KEYWORD+"="+FUNCTION_NAME_ISREGISTERED;
446

    
447
		String response = null;
448
		try {
449
			response = sendData(resource, GET, urlParams, null, null, null, null);
450
			// Check for an error condition
451
			if (response.indexOf("<error>") != -1) {
452
				throw new MetacatException(response);
453
			} else {
454
				Reader responseReader = new StringReader(response);
455
				StringBuffer sb = new StringBuffer();
456
				char[] c = new char[1024];
457
				int numread = responseReader.read(c, 0, 1024);
458
				while(numread != -1) {
459
					sb.append(new String(c, 0, numread));
460
					numread = responseReader.read(c, 0, 1024);
461
				}
462

    
463
				String responseStr = sb.toString();
464
				if(responseStr.indexOf("true") != -1) {
465
					return true;
466
				}
467
				return false;
468
			}
469
		} catch (Exception e) {
470
			throw new MetacatException(e.getMessage());
471
		}
472
	}
473

    
474
	/**
475
	 * Adds identifierId
476
	 * @param identifierId String  the given docid you want to use.
477
	 * @throws MetacatException when an error occurs
478
	 */
479
	public String addLSID(String identifierId) throws MetacatException {
480
		String resource = RESOURCE_IDENTIFIER+"/"+identifierId;
481
		String response = null;
482
		try {
483
			response = sendData(resource, PUT, null, null, null, null, null);
484
		} catch (Exception e) {
485
			throw new MetacatException(e.getMessage());
486
		}	
487
		return response;
488
	}
489

    
490
	public void setContextRootUrl(String contextRootUrl) {
491
		if (!contextRootUrl.endsWith("/"))
492
			contextRootUrl += "/";
493
		this.contextRootUrl = contextRootUrl;
494

    
495
	}
496

    
497

    
498
	public String getSessionId() {
499
		return sessionId;
500
	}
501

    
502

    
503
	public void setSessionId(String sessionId) {
504
		this.sessionId = sessionId;
505
	}
506

    
507
	/**
508
     * Put (Insert/Update) an XML document into the repository.
509
     *
510
     * @param docid the docid to insert the document
511
     * @param xmlDocument a Reader for accessing the XML document to be inserted
512
     * @param isInsert whether the operation is update or insert
513
     * 
514
     * @return the metacat response message
515
     * @throws InsufficientKarmaException when the user has insufficent rights
516
     *                                    for the operation
517
     * @throws MetacatInaccessibleException when the metacat server can not be
518
     *                                    reached or does not respond
519
     * @throws MetacatException when the metacat server generates another error
520
     * @throws IOException when there is an error reading the xml document
521
     */
522
    private String putObject(String docid, Reader xmlDocument, boolean isInsert)
523
    throws InsufficientKarmaException, MetacatException, IOException, MetacatInaccessibleException {
524
    	String resource = RESOURCE_OBJECTS+"/"+docid;
525
    	String urlParams = "sessionid="+sessionId+"&";
526
    
527
    	if (isInsert)
528
    		urlParams += FUNCTION_KEYWORD+"="+FUNCTION_NAME_INSERT;
529
    	else
530
    		urlParams += FUNCTION_KEYWORD+"="+FUNCTION_NAME_UPDATE;
531
    
532
    	String response = null;
533
    	try{
534
    		response = sendData(resource, PUT, urlParams, null, "text/xml", xmlDocument, null);
535
    	} catch (Exception e) {
536
    		e.printStackTrace();
537
    		throw new MetacatInaccessibleException(e.getMessage());
538
    	}
539
    
540
    	// Check for an error condition
541
    	if (response.indexOf("<error>") != -1) {
542
    		if (response.indexOf("does not have permission") != -1) {
543
    			throw new InsufficientKarmaException(response);
544
    		} else {
545
    			throw new MetacatException(response);
546
    		}
547
    	}	
548
    	return response;
549
    }
550

    
551
    /**
552
	 * Send request to metacat REST API. 
553
	 * @param resource Resource name to be accessed
554
	 * @param method HTTP verb, shoudl be one of GET,POST,DELETE,PUT
555
	 * @param urlParameters QueryString to be added to the end of server url
556
	 * @param postData QueryString to be printed to output stream
557
	 * @param contentType Content Type of the data to be posted. eg: "text/xml" or "application/x-www-form-urlencoded"
558
	 * @param postFileReader Reader of file to be posted
559
	 * @param outputFile File name to be saved returning from API
560
	 */
561
	private String sendData(String resource, String method, String urlParamaters,String postData, String contentType,
562
			Reader postFileReader, String outputFile) throws IOException {
563
		HttpURLConnection connection = null ;
564

    
565
		String restURL = contextRootUrl+resource;
566
		System.out.println("restURL: " + restURL);
567

    
568
		if (urlParamaters != null) {
569
			if (restURL.indexOf("?") == -1)				
570
				restURL += "?";
571
			restURL += urlParamaters; 
572
		}
573

    
574
		URL u = new URL(restURL);
575
		System.out.println("url:"+restURL+ " postData:"+postData);
576
		URLConnection uc = u.openConnection();
577
		connection= (HttpURLConnection) uc;
578

    
579
		if (contentType!=null)
580
			connection.setRequestProperty("Content-Type",contentType);
581

    
582
		connection.setDoOutput(true);
583
		connection.setDoInput(true);
584
		connection.setRequestMethod(method);
585

    
586
		if (!method.equals(GET)) {
587
			if (postFileReader != null) {
588
				postData = IOUtil.getAsString(postFileReader, true);
589
			}
590
			if (postData != null){
591
				OutputStream out = connection.getOutputStream();
592
				Writer wout = new OutputStreamWriter(out);		
593
				wout.write(postData); 
594
				wout.flush();
595
				wout.close();
596
			}			
597
		}
598
		return readStream(connection.getInputStream(),outputFile);
599
	}
600
	
601
	/**
602
	 * 
603
	 * Reads Input stream and return readed data, optionaly write the data to specified file 
604
	 * */
605
	private String readStream(InputStream is, String writeFile) throws IOException{
606
		BufferedReader in = new BufferedReader(
607
				new InputStreamReader(
608
						is));
609

    
610
		String inputLine;
611
		StringBuffer b = new StringBuffer();
612
		FileWriter writer = null;
613
		if (writeFile!=null)
614
			writer =  new FileWriter(writeFile);
615
		while ((inputLine = in.readLine()) != null) { 
616
			//System.out.println(inputLine+"\n");
617
			b.append(inputLine+"\n");
618
			if (writeFile!=null)
619
				writer.write(inputLine);
620
		}
621
		if (writeFile!=null) {
622
			writer.flush();
623
			writer.close();			
624
		}
625
		in.close();
626
		return b.toString();
627
	}
628

    
629
}
(2-2/2)