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
	    String urlParams = FUNCTION_KEYWORD+"="+FUNCTION_NAME_LOGIN;
82
		String postData = "username="+username+"&password="+password;		
83
		String response = null;
84
		
85

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

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

    
104

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

    
127

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

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

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

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

    
167

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

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

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

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

    
207

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

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

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

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

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

    
326

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
494
	}
495

    
496

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

    
501

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

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

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

    
564
		String restURL = contextRootUrl+resource;
565

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

    
572
		URL u = new URL(restURL);
573
		URLConnection uc = u.openConnection();
574
		connection= (HttpURLConnection) uc;
575

    
576
		if (contentType!=null)
577
			connection.setRequestProperty("Content-Type",contentType);
578

    
579
		connection.setDoOutput(true);
580
		connection.setDoInput(true);
581
		connection.setRequestMethod(method);
582

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

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

    
626
}
(2-2/2)