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

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

    
103

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

    
126

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

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

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

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

    
166

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

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

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

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

    
206

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

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

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

    
249
	/**
250
	 * Put (Insert/Update) an XML document into the repository.
251
	 *
252
	 * @param docid the docid to insert the document
253
	 * @param xmlDocument a Reader for accessing the XML document to be inserted
254
	 * @param isInsert whether the operation is update or insert
255
	 * 
256
	 * 
257
	 * @return the metacat response message
258
	 * @throws InsufficientKarmaException when the user has insufficent rights
259
	 *                                    for the operation
260
	 * @throws MetacatInaccessibleException when the metacat server can not be
261
	 *                                    reached or does not respond
262
	 * @throws MetacatException when the metacat server generates another error
263
	 * @throws IOException when there is an error reading the xml document
264
	 */
265
	public String putObject(String docid, Reader xmlDocument, boolean isInsert)
266
	throws InsufficientKarmaException, MetacatException, IOException, MetacatInaccessibleException{
267
		String resource = RESOURCE_OBJECTS+"/"+docid;
268
		String urlParams = "sessionid="+sessionId+"&";
269

    
270
		if (isInsert)
271
			urlParams += FUNCTION_KEYWORD+"="+FUNCTION_NAME_INSERT;
272
		else
273
			urlParams += FUNCTION_KEYWORD+"="+FUNCTION_NAME_UPDATE;
274

    
275
		String response = null;
276
		try{
277
			response = sendData(resource, PUT, urlParams, null, "text/xml", xmlDocument, null);
278
		} catch (Exception e) {
279
			e.printStackTrace();
280
			throw new MetacatInaccessibleException(e.getMessage());
281
		}
282

    
283
		// Check for an error condition
284
		if (response.indexOf("<error>") != -1) {
285
			if (response.indexOf("does not have permission") != -1) {
286
				throw new InsufficientKarmaException(response);
287
			} else {
288
				throw new MetacatException(response);
289
			}
290
		}	
291
		return response;
292
	}
293

    
294
	/**
295
	 * Delete an XML document in the repository.
296
	 *
297
	 * @param docid the docid to delete
298
	 * @return the metacat response message
299
	 * @throws InsufficientKarmaException when the user has insufficent rights
300
	 *                                    for the operation
301
	 * @throws MetacatInaccessibleException when the metacat server can not be
302
	 *                                    reached or does not respond
303
	 * @throws MetacatException when the metacat server generates another error
304
	 */
305
	public String deleteObject(String docid)
306
	throws InsufficientKarmaException, MetacatException,MetacatInaccessibleException {
307
		String resource = RESOURCE_OBJECTS+"/"+docid;
308
		String urlParams = "sessionid="+sessionId+"&";
309
		String response = null;
310
		try{
311
			response = sendData(resource, DELETE, urlParams, null, null, null, null);
312
		} catch (Exception e) {
313
			e.printStackTrace();
314
			throw new MetacatInaccessibleException(e.getMessage());
315
		}
316

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

    
328

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

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

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

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

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

    
381
			Reader responseReader = new StringReader(response);
382
			Node root =
383
				XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
384
			Node docidNode =
385
				XMLUtilities.getNodeWithXPath(root, "/next-revision");
386
			rev = Integer.parseInt(docidNode.getFirstChild().getNodeValue());                        
387

    
388
			// Check for an error condition            
389
			if (response.indexOf("<error>") != -1 ) {
390
				throw new MetacatException(response);
391
			}
392

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

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

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

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

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

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

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

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

    
496
	}
497

    
498

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

    
503

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

    
508
	/**
509
	 * Send request to metacat REST API. 
510
	 * @param resource Resource name to be accessed
511
	 * @param method HTTP verb, shoudl be one of GET,POST,DELETE,PUT
512
	 * @param urlParameters QueryString to be added to the end of server url
513
	 * @param postData QueryString to be printed to output stream
514
	 * @param contentType Content Type of the data to be posted. eg: "text/xml" or "application/x-www-form-urlencoded"
515
	 * @param postFileReader Reader of file to be posted
516
	 * @param outputFile File name to be saved returning from API
517
	 */
518
	private String sendData(String resource, String method, String urlParamaters,String postData, String contentType,
519
			Reader postFileReader, String outputFile) throws IOException {
520
		HttpURLConnection connection = null ;
521

    
522
		String restURL = contextRootUrl+resource;
523

    
524
		if (urlParamaters != null) {
525
			if (restURL.indexOf("?") == -1)				
526
				restURL += "?";
527
			restURL += urlParamaters; 
528
		}
529

    
530
		URL u = new URL(restURL);
531
		System.out.println("url:"+restURL+ " postData:"+postData);
532
		URLConnection uc = u.openConnection();
533
		connection= (HttpURLConnection) uc;
534

    
535
		if (contentType!=null)
536
			connection.setRequestProperty("Content-Type",contentType);
537

    
538
		connection.setDoOutput(true);
539
		connection.setDoInput(true);
540
		connection.setRequestMethod(method);
541

    
542
		if (!method.equals(GET)) {
543
			if (postFileReader != null) {
544
				postData = IOUtil.getAsString(postFileReader, true);
545
			}
546
			if (postData != null){
547
				OutputStream out = connection.getOutputStream();
548
				Writer wout = new OutputStreamWriter(out);		
549
				wout.write(postData); 
550
				wout.flush();
551
				wout.close();
552
			}			
553
		}
554
		return readStream(connection.getInputStream(),outputFile);
555
	}
556
	
557
	/**
558
	 * 
559
	 * Reads Input stream and return readed data, optionaly write the data to specified file 
560
	 * */
561
	private String readStream(InputStream is, String writeFile) throws IOException{
562
		BufferedReader in = new BufferedReader(
563
				new InputStreamReader(
564
						is));
565

    
566
		String inputLine;
567
		StringBuffer b = new StringBuffer();
568
		FileWriter writer = null;
569
		if (writeFile!=null)
570
			writer =  new FileWriter(writeFile);
571
		while ((inputLine = in.readLine()) != null) { 
572
			//System.out.println(inputLine+"\n");
573
			b.append(inputLine+"\n");
574
			if (writeFile!=null)
575
				writer.write(inputLine);
576
		}
577
		if (writeFile!=null) {
578
			writer.flush();
579
			writer.close();			
580
		}
581
		in.close();
582
		return b.toString();
583
	}
584

    
585
}
(2-2/2)