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: barteau $'
7
 *     '$Date: 2007-05-14 16:35:05 -0700 (Mon, 14 May 2007) $'
8
 * '$Revision: 3285 $'
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 com.oreilly.servlet.multipart.FilePart;
28
import com.oreilly.servlet.multipart.MultipartParser;
29
import com.oreilly.servlet.multipart.ParamPart;
30
import com.oreilly.servlet.multipart.Part;
31
import edu.ucsb.nceas.metacat.MetaCatUtil;
32
import java.io.BufferedInputStream;
33
import java.io.BufferedReader;
34
import java.io.InputStream;
35
import java.io.InputStreamReader;
36
import java.io.PushbackReader;
37
import java.io.StringReader;
38
import java.io.IOException;
39
import java.io.StringWriter;
40
import java.io.Reader;
41
import java.net.URL;
42
import java.util.HashMap;
43
import java.util.Iterator;
44
import java.util.Properties;
45
import java.util.Vector;
46
import javax.xml.xpath.XPath;
47
import javax.xml.xpath.XPathFactory;
48
import org.w3c.dom.Document;
49
import org.w3c.dom.DocumentType;
50
import org.w3c.dom.Element;
51

    
52
import org.w3c.dom.Node;
53
import org.w3c.dom.NodeList;
54

    
55
import edu.ucsb.nceas.utilities.HttpMessage;
56
import edu.ucsb.nceas.utilities.IOUtil;
57
import edu.ucsb.nceas.utilities.XMLUtilities;
58
import java.io.File;
59
import javax.xml.xpath.XPathConstants;
60
import javax.xml.xpath.XPathExpressionException;
61

    
62

    
63
/**
64
 *  This interface provides methods for initializing and logging in to a
65
 *  Metacat server, and then querying, reading, transforming, inserting,
66
 *  updating and deleting documents from that server.
67
 */
68
public class MetacatClient implements Metacat {
69
    /** The URL string for the metacat server */
70
    private String metacatUrl;
71
    
72
    /** The session identifier for the session */
73
    private String sessionId;
74
    
75
    public static final String              FGDC_SYSTEM_ID = "http://www.fgdc.gov/metadata/fgdc-std-001-1998.dtd";
76
    private static XPath                    xpath = XPathFactory.newInstance().newXPath();
77
    private Document                        loginResponse = null, metadataDoc = null;
78
    private String                          user = null;
79
    
80
    /**
81
     * The Login cookie name.
82
     */
83
    public final static String                    LOGIN_COOOKIE = "cookie";
84
    
85
    /**
86
     * Constructor to create a new instance. Protected because instances
87
     * should only be created by the factory MetacatFactory.
88
     */
89
    protected MetacatClient() {
90
        this.metacatUrl = null;
91
        this.sessionId = null;
92
    }
93
    
94
    /**
95
     *  Method used to log in to a metacat server. Implementations will need
96
     *  to cache a cookie value to make the session persistent.  Each time a
97
     *  call is made to one of the other methods (e.g., read), the cookie will
98
     *  need to be passed back to the metacat server along with the request.
99
     *
100
     *  @param username   the username of the user, like an LDAP DN
101
     *  @param password   the password for that user for authentication
102
     *  @return the response string from metacat in XML format
103
     *  @throws MetacatAuthException when the username/password could
104
     *                    not be authenticated
105
     */
106
    public String login(String username, String password)
107
    throws MetacatAuthException, MetacatInaccessibleException {
108
        Properties prop = new Properties();
109
        prop.put("action", "login");
110
        prop.put("qformat", "xml");
111
        prop.put("username", username);
112
        prop.put("password", password);
113
        
114
        String response = null;
115
        try {
116
            response = sendDataForString(prop, null, null, 0);
117
        } catch (Exception e) {
118
            throw new MetacatInaccessibleException(e.getMessage());
119
        }
120
        
121
        if (response.indexOf("<login>") == -1) {
122
            setSessionId("");
123
            throw new MetacatAuthException(response);
124
        } else {
125
            int start = response.indexOf("<sessionId>") + 11;
126
            int end = response.indexOf("</sessionId>");
127
            if ((start != -1) && (end != -1)) {
128
                setSessionId(response.substring(start,end));
129
            }
130
        }
131
        return response;
132
    }
133
    
134
    /**
135
     *  Method used to log in to a metacat server. Implementations will need
136
     *  to cache a cookie value to make the session persistent.  Each time a
137
     *  call is made to one of the other methods (e.g., read), the cookie will
138
     *  need to be passed back to the metacat server along with the request.
139
     *
140
     *  @param username   the username of the user, like an LDAP DN
141
     *  @param password   the password for that user for authentication
142
     *  @return the response string from metacat in XML format
143
     *  @throws MetacatAuthException when the username/password could
144
     *                    not be authenticated
145
     */
146
    public String getloggedinuserinfo() throws MetacatInaccessibleException {
147
        Properties prop = new Properties();
148
        prop.put("action", "getloggedinuserinfo");
149
        prop.put("qformat", "xml");
150
        
151
        String response = null;
152
        try {
153
            response = sendDataForString(prop, null, null, 0);
154
        } catch (Exception e) {
155
            throw new MetacatInaccessibleException(e.getMessage());
156
        }
157
        
158
        return response;
159
    }
160
    
161
    /**
162
     *  Method used to log out a metacat server. The Metacat server will end
163
     *  the session when this call is invoked.
164
     *
165
     *  @return the response string from metacat in XML format
166
     *  @throws MetacatInaccessibleException when the metacat server can not be
167
     *                                    reached or does not respond
168
     */
169
    public String logout() throws MetacatInaccessibleException, MetacatException {
170
        Properties prop = new Properties();
171
        prop.put("action", "logout");
172
        prop.put("qformat", "xml");
173
        
174
        String response = null;
175
        try {
176
            response = sendDataForString(prop, null, null, 0);
177
        } catch (Exception e) {
178
            throw new MetacatInaccessibleException(e.getMessage());
179
        }
180
        
181
        if (response.indexOf("<logout>") == -1) {
182
            throw new MetacatException(response);
183
        }
184
        setSessionId("");
185
        return response;
186
    }
187
    
188
    /**
189
     * Read an XML document from the metacat server session, accessed by docid,
190
     * and returned as a Reader.
191
     *
192
     * @param docid the identifier of the document to be read
193
     * @return a Reader for accessing the document
194
     * @throws InsufficientKarmaException when the user has insufficent rights
195
     *                                    for the operation
196
     * @throws MetacatInaccessibleException when the metacat server can not be
197
     *                                    reached or does not respond
198
     * @throws MetacatException when the metacat server generates another error
199
     */
200
    public Reader read(String docid) throws InsufficientKarmaException,
201
            MetacatInaccessibleException, MetacatException, DocumentNotFoundException {
202
        PushbackReader pbr = null;
203
        
204
        Properties prop = new Properties();
205
        prop.put("action", "read");
206
        prop.put("qformat", "xml");
207
        prop.put("docid", docid);
208
        InputStream response = null;
209
        try {
210
            response = sendData(prop, null, null, 0);
211
        } catch (Exception e) {
212
            throw new MetacatInaccessibleException(e.getMessage());
213
        }
214
        pbr = new PushbackReader(new InputStreamReader(response), 512);
215
        try {
216
            char[] characters = new char[512];
217
            int len = pbr.read(characters, 0, 512);
218
            StringWriter sw = new StringWriter();
219
            sw.write(characters, 0, len);
220
            String message = sw.toString();
221
            sw.close();
222
            pbr.unread(characters, 0, len);
223
            if (message.indexOf("<error>") != -1) {
224
                if (message.indexOf("does not have permission") != -1) {
225
                    throw new InsufficientKarmaException(message);
226
                } else if(message.indexOf("does not exist") != -1) {
227
                    throw new DocumentNotFoundException(message);
228
                } else {
229
                    throw new MetacatException(message);
230
                }
231
            }
232
        } catch (IOException ioe) {
233
            throw new MetacatException(
234
                    "MetacatClient: Error converting Reader to String."
235
                    + ioe.getMessage());
236
        }
237
        return pbr;
238
    }
239
    
240
    
241
    /**
242
     * Read inline data from the metacat server session, accessed by
243
     * inlinedataid and returned as a Reader.
244
     *
245
     * @param inlinedataid the identifier of the data to be read
246
     * @return a Reader for accessing the document
247
     * @throws InsufficientKarmaException when the user has insufficent rights
248
     *                                    for the operation
249
     * @throws MetacatInaccessibleException when the metacat server can not be
250
     *                                    reached or does not respond
251
     * @throws MetacatException when the metacat server generates another error
252
     */
253
    public Reader readInlineData(String inlinedataid)
254
    throws InsufficientKarmaException,
255
            MetacatInaccessibleException, MetacatException {
256
        PushbackReader pbr = null;
257
        
258
        Properties prop = new Properties();
259
        prop.put("action", "readinlinedata");
260
        prop.put("inlinedataid", inlinedataid);
261
        
262
        InputStream response = null;
263
        try {
264
            response = sendData(prop, null, null, 0);
265
        } catch (Exception e) {
266
            throw new MetacatInaccessibleException(e.getMessage());
267
        }
268
        
269
        pbr = new PushbackReader(new InputStreamReader(response), 512);
270
        try {
271
            char[] characters = new char[512];
272
            int len = pbr.read(characters, 0, 512);
273
            StringWriter sw = new StringWriter();
274
            sw.write(characters, 0, len);
275
            String message = sw.toString();
276
            sw.close();
277
            pbr.unread(characters, 0, len);
278
            
279
            if (message.indexOf("<error>") != -1) {
280
                if (message.indexOf("does not have permission") != -1) {
281
                    throw new InsufficientKarmaException(message);
282
                } else {
283
                    throw new MetacatException(message);
284
                }
285
            }
286
        } catch (IOException ioe) {
287
            throw new MetacatException(
288
                    "MetacatClient: Error converting Reader to String."
289
                    + ioe.getMessage());
290
        }
291
        
292
        return pbr;
293
    }
294
    
295
    /**
296
     * Query the metacat document store with the given metacat-compatible
297
     * query document, and return the result set as a Reader.
298
     *
299
     * @param xmlQuery a Reader for accessing the XML version of the query
300
     * @return a Reader for accessing the result set
301
     */
302
    public Reader query(Reader xmlQuery) throws MetacatInaccessibleException,
303
            IOException {
304
        Reader reader = null;
305
        String query = null;
306
        try {
307
            query = IOUtil.getAsString(xmlQuery, true);
308
        } catch (IOException ioE) {
309
            throw ioE;
310
        }
311
        
312
        //set up properties
313
        Properties prop = new Properties();
314
        prop.put("action", "squery");
315
        prop.put("qformat", "xml");
316
        prop.put("query", query);
317
        
318
        InputStream response = null;
319
        try {
320
            response = sendData(prop, null, null, 0);
321
        } catch (Exception e) {
322
            throw new MetacatInaccessibleException(e.getMessage());
323
        }
324
        reader = new InputStreamReader(response);
325
        return reader;
326
    }
327
    
328
    /**
329
     * Insert an XML document into the repository.
330
     *
331
     * @param docid the docid to insert the document
332
     * @param xmlDocument a Reader for accessing the XML document to be inserted
333
     * @param schema a Reader for accessing the DTD or XML Schema for
334
     *               the document
335
     * @return the metacat response message
336
     * @throws InsufficientKarmaException when the user has insufficent rights
337
     *                                    for the operation
338
     * @throws MetacatInaccessibleException when the metacat server can not be
339
     *                                    reached or does not respond
340
     * @throws MetacatException when the metacat server generates another error
341
     * @throws IOException when there is an error reading the xml document
342
     */
343
    public String insert(String docid, Reader xmlDocument, Reader schema)
344
    throws InsufficientKarmaException, MetacatException, IOException,
345
            MetacatInaccessibleException {
346
        Reader reader = null;
347
        String doctext = null;
348
        String schematext = null;
349
        try {
350
            doctext = IOUtil.getAsString(xmlDocument, true);
351
            if (schema != null) {
352
                schematext = IOUtil.getAsString(schema, true);
353
            }
354
        } catch (IOException ioE) {
355
            throw ioE;
356
        }
357
        
358
        //set up properties
359
        Properties prop = new Properties();
360
        prop.put("action", "insert");
361
        prop.put("docid", docid);
362
        prop.put("doctext", doctext);
363
        if (schematext != null) {
364
            prop.put("dtdtext", schematext);
365
        }
366
        
367
        String response = null;
368
        try {
369
            response = sendDataForString(prop, null, null, 0);
370
        } catch (Exception e) {
371
            throw new MetacatInaccessibleException(e.getMessage());
372
        }
373
        
374
        // Check for an error condition
375
        if (response.indexOf("<error>") != -1) {
376
            if (response.indexOf("does not have permission") != -1) {
377
                throw new InsufficientKarmaException(response);
378
            } else {
379
                throw new MetacatException(response);
380
            }
381
        }
382
        
383
        return response;
384
    }
385
    
386
    /**
387
     * Update an XML document in the repository.
388
     *
389
     * @param docid the docid to update
390
     * @param xmlDocument a Reader for accessing the XML text to be updated
391
     * @param schema a Reader for accessing the DTD or XML Schema for
392
     *               the document
393
     * @return the metacat response message
394
     * @throws InsufficientKarmaException when the user has insufficent rights
395
     *                                    for the operation
396
     * @throws MetacatInaccessibleException when the metacat server can not be
397
     *                                    reached or does not respond
398
     * @throws MetacatException when the metacat server generates another error
399
     * @throws IOException when there is an error reading the xml document
400
     */
401
    public String update(String docid, Reader xmlDocument, Reader schema)
402
    throws InsufficientKarmaException, MetacatException, IOException,
403
            MetacatInaccessibleException {
404
        Reader reader = null;
405
        String doctext = null;
406
        String schematext = null;
407
        try {
408
            doctext = IOUtil.getAsString(xmlDocument, true);
409
            if (schema != null) {
410
                schematext = IOUtil.getAsString(schema, true);
411
            }
412
        } catch (IOException ioE) {
413
            throw ioE;
414
        }
415
        
416
        //set up properties
417
        Properties prop = new Properties();
418
        prop.put("action", "update");
419
        prop.put("docid", docid);
420
        prop.put("doctext", doctext);
421
        if (schematext != null) {
422
            prop.put("dtdtext", schematext);
423
        }
424
        
425
        String response = null;
426
        try {
427
            response = sendDataForString(prop, null, null, 0);
428
        } catch (Exception e) {
429
            throw new MetacatInaccessibleException(e.getMessage());
430
        }
431
        
432
        // Check for an error condition
433
        if (response.indexOf("<error>") != -1) {
434
            if (response.indexOf("does not have permission") != -1) {
435
                throw new InsufficientKarmaException(response);
436
            } else {
437
                throw new MetacatException(response);
438
            }
439
        }
440
        
441
        return response;
442
    }
443
    
444
    /**
445
     * Upload a data document into the repository.
446
     *
447
     * @param docid the docid to insert the document
448
     * @param document a Reader for accessing the document to be uploaded
449
     * @return the metacat response message
450
     * @throws InsufficientKarmaException when the user has insufficent rights
451
     *                                    for the operation
452
     * @throws MetacatInaccessibleException when the metacat server can not be
453
     *                                    reached or does not respond
454
     * @throws MetacatException when the metacat server generates another error
455
     * @throws IOException when there is an error reading the xml document
456
     */
457
    public String upload(String docid, File file)
458
    throws InsufficientKarmaException, MetacatException, IOException,
459
            MetacatInaccessibleException {
460
        
461
        URL url = new URL(metacatUrl.trim());
462
        HttpMessage msg = new HttpMessage(url);
463
        //set up properties
464
        Properties arg = new Properties();
465
        arg.put("action", "upload");
466
        arg.put("docid", docid);
467
        
468
        Properties filenames = new Properties();
469
        String filename = file.getAbsolutePath();
470
        filenames.put("datafile", filename);
471
        
472
        String response = null;
473
        try {
474
            response = sendDataForString(arg, filenames, null, 0);
475
        } catch (Exception e) {
476
            throw new MetacatInaccessibleException(e.getMessage());
477
        }
478
        
479
        // Check for an error condition
480
        if (response.indexOf("<error>") != -1) {
481
            if (response.indexOf("does not have permission") != -1) {
482
                throw new InsufficientKarmaException(response);
483
            } else {
484
                throw new MetacatException(response);
485
            }
486
        }
487
        
488
        return response;
489
    }
490
    
491
    /**
492
     * Upload a data document into the repository.
493
     *
494
     * @param docid the docid to insert the document
495
     * @param document a Reader for accessing the document to be uploaded
496
     * @return the metacat response message
497
     * @throws InsufficientKarmaException when the user has insufficent rights
498
     *                                    for the operation
499
     * @throws MetacatInaccessibleException when the metacat server can not be
500
     *                                    reached or does not respond
501
     * @throws MetacatException when the metacat server generates another error
502
     * @throws IOException when there is an error reading the xml document
503
     */
504
    
505
    
506
    public String upload(String docid, String filename, InputStream fileData,
507
            int size)
508
            throws InsufficientKarmaException, MetacatException, IOException,
509
            MetacatInaccessibleException {
510
        
511
        URL url = new URL(metacatUrl.trim());
512
        HttpMessage msg = new HttpMessage(url);
513
        //set up properties
514
        Properties arg = new Properties();
515
        arg.put("action", "upload");
516
        arg.put("docid", docid);
517
        
518
        Properties filenames = new Properties();
519
        filenames.put("datafile", filename);
520
        
521
        String response = null;
522
        try {
523
            response = sendDataForString(arg, filenames, fileData, size);
524
        } catch (Exception e) {
525
            throw new MetacatInaccessibleException(e.getMessage());
526
        }
527
        
528
        // Check for an error condition
529
        if (response.indexOf("<error>") != -1) {
530
            if (response.indexOf("does not have permission") != -1) {
531
                throw new InsufficientKarmaException(response);
532
            } else {
533
                throw new MetacatException(response);
534
            }
535
        }
536
        
537
        return response;
538
    }
539
    
540
    /**
541
     * Delete an XML document in the repository.
542
     *
543
     * @param docid the docid to delete
544
     * @return the metacat response message
545
     * @throws InsufficientKarmaException when the user has insufficent rights
546
     *                                    for the operation
547
     * @throws MetacatInaccessibleException when the metacat server can not be
548
     *                                    reached or does not respond
549
     * @throws MetacatException when the metacat server generates another error
550
     */
551
    public String delete(String docid)
552
    throws InsufficientKarmaException, MetacatException,
553
            MetacatInaccessibleException {
554
        //set up properties
555
        Properties prop = new Properties();
556
        prop.put("action", "delete");
557
        prop.put("docid", docid);
558
        
559
        String response = null;
560
        try {
561
            response = sendDataForString(prop, null, null, 0);
562
        } catch (Exception e) {
563
            throw new MetacatInaccessibleException(e.getMessage());
564
        }
565
        
566
        // Check for an error condition
567
        if (response.indexOf("<error>") != -1) {
568
            if (response.indexOf("does not have permission") != -1) {
569
                throw new InsufficientKarmaException(response);
570
            } else {
571
                throw new MetacatException(response);
572
            }
573
        }
574
        return response;
575
    }
576
    
577
    
578
    /**
579
     * set the access on an XML document in the repository.
580
     *
581
     * @param _docid the docid of the document for which the access should be applied.
582
     *
583
     * @param _principal the document's principal
584
     *
585
     * @param _permission the access permission to be applied to the docid
586
     *  {e.g. read,write,all}
587
     *
588
     * @param _permType the permission type to be applied to the document
589
     *  {e.g. allow or deny}
590
     *
591
     * @param _permOrder the order that the document's permissions should be
592
     *  processed {e.g. denyFirst or allowFirst}
593
     *
594
     *
595
     * @return the metacat response message
596
     *
597
     * @throws InsufficientKarmaException when the user has insufficent rights
598
     *                                    for the operation
599
     * @throws MetacatInaccessibleException when the metacat server can not be
600
     *                                    reached or does not respond
601
     * @throws MetacatException when the metacat server generates another error
602
     */
603
    public String setAccess(String _docid, String _principal, String
604
            _permission, String _permType,
605
            String _permOrder )
606
            throws InsufficientKarmaException, MetacatException,
607
            MetacatInaccessibleException {
608
        //set up properties
609
        Properties prop = new Properties();
610
        prop.put("action", "setaccess");
611
        prop.put("docid", _docid);
612
        prop.put("principal", _principal);
613
        prop.put("permission", _permission);
614
        prop.put("permType", _permType);
615
        prop.put("permOrder", _permOrder);
616
        
617
        String response = null;
618
        try {
619
            response = sendDataForString(prop, null, null, 0);
620
        } catch (Exception e) {
621
            throw new MetacatInaccessibleException(e.getMessage());
622
        }
623
        
624
        // Check for an error condition
625
        if (response.indexOf("<error>") != -1) {
626
            if (response.indexOf("does not have permission") != -1) {
627
                throw new InsufficientKarmaException(response);
628
            } else {
629
                throw new MetacatException(response);
630
            }
631
        }
632
        return response;
633
    }
634
    
635
    /**
636
     * When the MetacatFactory creates an instance it needs to set the
637
     * MetacatUrl to which connections should be made.
638
     *
639
     * @param metacatUrl the URL for the metacat server
640
     */
641
    public void setMetacatUrl(String metacatUrl) {
642
        this.metacatUrl = metacatUrl;
643
    }
644
    
645
    /**
646
     * Get the session identifier for this session.  This is only valid if
647
     * the login methods has been called successfully for this Metacat object
648
     * beforehand.
649
     *
650
     * @returns the sessionId as a String, or null if the session is invalid
651
     */
652
    public String getSessionId() {
653
        return this.sessionId;
654
    }
655
    
656
    /**
657
     * Set the session identifier for this session.  This identifier was
658
     * previously established with a call to login.  To continue to use the
659
     * same session, set the session id before making a call to one of the
660
     * metacat access methods (e.g., read, query, insert, etc.).
661
     *
662
     * @param String the sessionId from a previously established session
663
     */
664
    public void setSessionId(String sessionId) {
665
        this.sessionId = sessionId;
666
    }
667
    
668
    /**
669
     * The method will return the latest revision in metacat server
670
     * for a given document id. If some error happens, this method will throw
671
     * an exception.
672
     * @param docId String  the given docid you want to use. the docid it self
673
     *                      can have or haven't revision number
674
     * @throws MetacatException
675
     */
676
    public int getNewestDocRevision(String docId) throws MetacatException {
677
        int rev = 0;
678
        //set up properties
679
        Properties prop = new Properties();
680
        prop.put("action", "getrevisionanddoctype");
681
        prop.put("docid", docId);
682
        
683
        String response = null;
684
        try {
685
            response = sendDataForString(prop, null, null, 0);
686
            //parseRevisionResponse will return null if there is an
687
            //error that it can't handle
688
            String revStr = parserRevisionResponse(response);
689
            Integer revObj = new Integer(revStr);
690
            rev = revObj.intValue();
691
            // Check for an error condition
692
            if (response.indexOf("<error>") != -1 && revStr == null) {
693
                throw new MetacatException(response);
694
            }
695
        } catch (Exception e) {
696
            throw new MetacatException(e.getMessage());
697
        }
698
        return rev;
699
    }
700
    
701
    /**
702
     * Return the highest document id for a given scope.  This is used by
703
     * clients to make it easier to determine the next free identifier in a
704
     * sequence for a given scope.
705
     * @param scope String  the scope to use for looking up the latest id
706
     * @throws MetacatException when an error occurs
707
     */
708
    public String getLastDocid(String scope) throws MetacatException {
709
        String lastIdentifier = "";
710
        //set up properties
711
        Properties prop = new Properties();
712
        prop.put("action", "getlastdocid");
713
        prop.put("scope", scope);
714
        
715
        String response = null;
716
        try {
717
            response = sendDataForString(prop, null, null, 0);
718
            // Check for an error condition
719
            if (response.indexOf("<error>") != -1) {
720
                throw new MetacatException(response);
721
            } else {
722
                Reader responseReader = new StringReader(response);
723
                Node root =
724
                        XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
725
                Node docidNode =
726
                        XMLUtilities.getNodeWithXPath(root, "/lastDocid/docid");
727
                lastIdentifier = docidNode.getFirstChild().getNodeValue();
728
            }
729
        } catch (Exception e) {
730
            throw new MetacatException(e.getMessage());
731
        }
732
        return lastIdentifier;
733
    }
734
    
735
    /**
736
     * return a list of all docids that match a given scope.  if scope is null
737
     * return all docids registered in the system
738
     * @param scope String  the scope to use to limit the docid query
739
     * @throws MetacatException when an error occurs
740
     */
741
    public Vector getAllDocids(String scope) throws MetacatException {
742
        Vector resultVec = new Vector();
743
        //set up properties
744
        Properties prop = new Properties();
745
        prop.put("action", "getalldocids");
746
        if(scope != null) {
747
            prop.put("scope", scope);
748
        }
749
        
750
        String response = null;
751
        try {
752
            response = sendDataForString(prop, null, null, 0);
753
            // Check for an error condition
754
            if (response.indexOf("<error>") != -1) {
755
                throw new MetacatException(response);
756
            } else {
757
                Reader responseReader = new StringReader(response);
758
                Node root =
759
                        XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader);
760
                NodeList nlist = root.getChildNodes();
761
                for(int i=0; i<nlist.getLength(); i++) {
762
                    Node n = nlist.item(i);
763
                    if(n.getNodeName().equals("docid")) {
764
                        //add the content to the return vector
765
                        String nodeVal = n.getFirstChild().getNodeValue();
766
                        resultVec.addElement(nodeVal);
767
                    }
768
                }
769
                
770
            }
771
        } catch (Exception e) {
772
            throw new MetacatException(e.getMessage());
773
        }
774
        return resultVec;
775
    }
776
    
777
    /**
778
     * return true of the given docid is registered, false if not
779
     * @param scope String  the scope to use to limit the docid query
780
     * @throws MetacatException when an error occurs
781
     */
782
    public boolean isRegistered(String docid) throws MetacatException {
783
        Vector resultVec = new Vector();
784
        //set up properties
785
        Properties prop = new Properties();
786
        prop.put("action", "isregistered");
787
        if(docid == null) {
788
            throw new MetacatException("<error>Cannot check if a null docid " +
789
                    "is registered.</error>");
790
        }
791
        prop.put("docid", docid);
792
        
793
        String response = null;
794
        try {
795
            response = sendDataForString(prop, null, null, 0);
796
            // Check for an error condition
797
            if (response.indexOf("<error>") != -1) {
798
                throw new MetacatException(response);
799
            } else {
800
                Reader responseReader = new StringReader(response);
801
                StringBuffer sb = new StringBuffer();
802
                char[] c = new char[1024];
803
                int numread = responseReader.read(c, 0, 1024);
804
                while(numread != -1) {
805
                    sb.append(new String(c, 0, numread));
806
                    numread = responseReader.read(c, 0, 1024);
807
                }
808
                
809
                String responseStr = sb.toString();
810
                if(responseStr.indexOf("true") != -1) {
811
                    return true;
812
                }
813
                return false;
814
            }
815
        } catch (Exception e) {
816
            throw new MetacatException(e.getMessage());
817
        }
818
    }
819
    
820
    /************************************************************************
821
     * PRIVATE METHODS
822
     ************************************************************************/
823
    
824
    /**
825
     * Send a request to metacat.
826
     *
827
     * @param prop the properties to be URL encoded and sent
828
     * @param filename  the properties to be sent to Metacat
829
     *                  in case of upload, otherwise null
830
     * @param fileData  the inputStream for the file data to be sent to Metacat
831
     *                  in case of upload, otherwise null
832
     * @param size      the size of the data being sent to Metacat
833
     *                  in case of upload, otherwise 0
834
     */
835
    synchronized private InputStream sendDataOnce(Properties args,
836
            Properties filename,
837
            InputStream fileData,
838
            int size)
839
            throws Exception {
840
        InputStream returnStream = null;
841
        URL url = new URL(metacatUrl);
842
        HttpMessage msg = new HttpMessage(url);
843
        msg.setCookie("JSESSIONID="+this.sessionId);
844
        if (filename == null){
845
            returnStream = msg.sendPostData(args);
846
        } else if (fileData == null){
847
            returnStream = msg.sendPostData(args, filename);
848
        } else if (size > 0) {
849
            returnStream = msg.sendPostData(args, filename, fileData, size);
850
        } else {
851
            throw new MetacatException("Invalid size specified for " +
852
                    "the input stream being passed");
853
        }
854
        return returnStream;
855
    }
856
    
857
    /**
858
     * Send a request to Metacat
859
     *
860
     * @param args  the properties to be sent to Metacat
861
     * @param filename  the properties to be sent to Metacat
862
     *                  in case of upload, otherwise null
863
     * @param fileData  the inputStream for the file data to be sent to Metacat
864
     *                  in case of upload, otherwise null
865
     * @param size      the size of the data being sent to Metacat
866
     *                  in case of upload, otherwise 0
867
     * @return      InputStream as returned by Metacat
868
     */
869
    synchronized private InputStream sendData(Properties args,
870
            Properties filename,
871
            InputStream fileData,
872
            int size)
873
            throws Exception {
874
        InputStream returnStream = null;
875
        /*
876
            Note:  The reason that there are three try statements all executing
877
            the same code is that there is a problem with the initial connection
878
            using the HTTPClient protocol handler.  These try statements make
879
            sure that a connection is made because it gives each connection a
880
            2nd and 3rd chance to work before throwing an error.
881
            THIS IS A TOTAL HACK.  THIS NEEDS TO BE LOOKED INTO AFTER THE BETA1
882
            RELEASE OF MORPHO!!!  cwb (7/24/01)
883
         */
884
        try {
885
            return sendDataOnce(args, filename, fileData, size);
886
        } catch (Exception e) {
887
            try {
888
                return sendDataOnce(args, filename, fileData, size);
889
            } catch (Exception e2) {
890
                try {
891
                    return sendDataOnce(args, filename, fileData, size);
892
                } catch (Exception e3) {
893
                    System.err.println(
894
                            "Failed to send data to metacat 3 times: " + e3.getMessage());
895
                    System.err.println("metacaturl: " + metacatUrl);
896
                    throw e3;
897
                }
898
            }
899
        }
900
    }
901
    
902
    /**
903
     * Send a request to Metacat
904
     *
905
     * @param args      the properties to be sent to Metacat
906
     * @param filename  the properties to be sent to Metacat
907
     *                  in case of upload, otherwise null
908
     * @param fileData  the inputStream for the file data to be sent to Metacat
909
     *                  in case of upload, otherwise null
910
     * @param size      the size of the data being sent to Metacat
911
     *                  in case of upload, otherwise 0
912
     * @return          a string as returned by Metacat
913
     */
914
    synchronized private String sendDataForString(Properties args,
915
            Properties filename,
916
            InputStream fileData,
917
            int size)
918
            throws Exception {
919
        String response = null;
920
        
921
        try {
922
            InputStreamReader returnStream =
923
                    new InputStreamReader(sendData(args, filename,
924
                    fileData, size));
925
            StringWriter sw = new StringWriter();
926
            int len;
927
            char[] characters = new char[512];
928
            while ((len = returnStream.read(characters, 0, 512)) != -1) {
929
                sw.write(characters, 0, len);
930
            }
931
            returnStream.close();
932
            response = sw.toString();
933
            sw.close();
934
        } catch (Exception e) {
935
            throw e;
936
        }
937
        return response;
938
    }
939
    
940
    /*
941
     * "getversionanddoctype" action will return a string from metacat server.
942
     * The string format is "revision;doctype"(This is bad idea, we should use xml)
943
     * This method will get revision string from the response string
944
     */
945
    private String parserRevisionResponse(String response) throws Exception {
946
        String revision = null;
947
        if (response != null) {
948
            if(response.indexOf("<error>") != -1) {
949
                if(response.indexOf("There is not record") != -1) {
950
                    return "0";
951
                } else {
952
                    return null;
953
                }
954
            } else {
955
                int firstSemiCol = response.indexOf(";");
956
                revision = response.substring(0, firstSemiCol);
957
            }
958
        }
959
        return revision;
960
    }
961
    
962
    /**
963
     * JSP API: This is a convenience method to reduce the amount of code in a Metacat Client
964
     * JSP.  It handles creating/reusing an instance of a MetacatClient.
965
     * @param request Since this is intended to be used by a JSP, it is passed the
966
     * available "request" variable (the HttpServletRequest).
967
     * @throws edu.ucsb.nceas.metacat.client.MetacatInaccessibleException Received by MetacatFactory.
968
     * @return MetacatClient instance.
969
     */
970
    public static MetacatClient getMetacatClient(javax.servlet.http.HttpServletRequest request) throws MetacatInaccessibleException {
971
        MetacatClient                       result;
972
        String                              metacatPath = "http://%1$s%2$s/metacat";
973
        String                              host, context;
974
        javax.servlet.http.HttpSession      session;
975
        
976
        session = request.getSession();
977
        result = (MetacatClient) session.getAttribute("MetacatClient");
978
        if (result == null) {
979
            host = request.getHeader("host");
980
            context = request.getContextPath();
981
            metacatPath = String.format(metacatPath, host, context);
982
            result = (MetacatClient) MetacatFactory.createMetacatConnection(metacatPath);
983
            session.setAttribute("MetacatClient", result);
984
        }
985
        return(result);
986
    }
987
    
988
    /**
989
     * JSP API: When the user logs in, the server will send back a string containing XML.  Calling
990
     * this method with the string will allow other methods to work, such as isLoggIn()
991
     * and getLoginResponseElement().
992
     * @param xmlString XML in String format.
993
     * @throws java.io.IOException Input/Output exception.
994
     */
995
    public void setLoginResponse(String xmlString) throws IOException {
996
        if (xmlString != null) {
997
            loginResponse = XMLUtilities.getXMLReaderAsDOMDocument(new StringReader(xmlString));
998
        }
999
    }
1000
    
1001
    private void setMetadataDoc(InputStream ioStream) throws IOException {
1002
        BufferedReader                          buffy;
1003
        
1004
        if (ioStream != null) {
1005
            buffy = new BufferedReader(new InputStreamReader(ioStream));
1006
            metadataDoc = XMLUtilities.getXMLReaderAsDOMDocument(buffy);
1007
        }
1008
    }
1009
    
1010
    /**
1011
     * JSP API: A convenient and efficient method to retrieve info from the "login response".
1012
     * @param elementName String of the elementName.
1013
     * NOTE: setLoginResponse() must have been called first,
1014
     * otherwise it will always return null.
1015
     * @throws javax.xml.xpath.XPathExpressionException XPath error.
1016
     * @return String containing the text content of the element, or null.
1017
     */
1018
    public String getLoginResponseElement(String elementName) throws XPathExpressionException {
1019
        String                      result = null;
1020
        
1021
        if (loginResponse != null) {
1022
            result = (String) xpath.evaluate(elementName, loginResponse.getDocumentElement(), XPathConstants.STRING);
1023
            if (result != null)
1024
                result = result.trim();
1025
        }
1026
        return(result);
1027
    }
1028
    
1029
    
1030
    /**
1031
     * JSP API: Easy way to get info from an uploaded metadata XML file.
1032
     * Note:  doMetadataUpload() must have been called first.
1033
     * @param elementName String containing the elemement name
1034
     * @throws javax.xml.xpath.XPathExpressionException Thrown by XPath
1035
     * @return String text content of the named element
1036
     */
1037
    public String getMetadataDocElement(String elementName) throws XPathExpressionException {
1038
        String                      result = null;
1039
        
1040
        if (metadataDoc != null) {
1041
            result = (String) xpath.evaluate(elementName, metadataDoc.getDocumentElement(), XPathConstants.STRING);
1042
            result = result.trim();
1043
        }
1044
        return(result);
1045
    }
1046
    
1047
    /**
1048
     * JSP API: A convenience method to be used by JSP or any other client code that requires
1049
     * the user to be logged in.  NOTE: setUser() must have been called first,
1050
     * otherwise it will always return false.
1051
     * @return boolean  true if user has logged in for this session, false otherwise.
1052
     */
1053
    public boolean isLoggedIn() {
1054
        return(user != null);
1055
    }
1056
    
1057
    /**
1058
     * JSP API: After calling "login(ldapUserName, pwd)", call this with the username
1059
     * and servers response message.  You can than use isLoggedIn() to determine if
1060
     * the user is logged in, getLoginResponseElement(), etc.  The user name will also
1061
     * used by calls to doMetadataUpload() for Document Id creation (scope).
1062
     * @param userName User name
1063
     * @param serverResponse XML login response sent from Metacat.
1064
     */
1065
    public void setUser(String userName, String serverResponse) {
1066
        if (serverResponse != null && serverResponse.contains("login"))
1067
            user = userName;
1068
        else
1069
            user = null;
1070
    }
1071
    
1072
    /**
1073
     * JSP API:  Handles metadata file and data file uploads for inserting new
1074
     * Metacat data packages.  Note: if content type is not "multipart/form-data",
1075
     * nothing will happen; thus, it's safe to be (unintentionally) called by other
1076
     * types of form submissions.
1077
     * @param request HTTP request.
1078
     * @return A 1-line status message for the user.
1079
     */
1080
    public String doMetadataUpload(javax.servlet.http.HttpServletRequest request) {
1081
        String                      result = "", contentType, formatType;
1082
        String                      lastDocId, nextDocId, metaDocId;
1083
        StringBuilder               fileName = new StringBuilder();
1084
        Reader                      reader;
1085
        int                         sizeLimit;
1086
        MultipartParser             multipartParser;
1087
        InputStream                 inputStream;
1088
        Node                        newBranch, metaRootNode;
1089
        HashMap                     dataDocIDs;
1090
        
1091
        //*** Only process request if a file upload.
1092
        contentType = request.getContentType();
1093
        if (isLoggedIn() && contentType != null && contentType.contains("multipart/form-data")) {
1094
            try {
1095
                //*** Init the MultipartParser.
1096
                sizeLimit = (new Integer(MetaCatUtil.getOption("datafilesizelimit"))).intValue();
1097
                multipartParser = new MultipartParser(request, sizeLimit * 1024 * 1024);
1098
                
1099
                //*** Get the First file, which should be the metadata file.
1100
                inputStream = getNextInputStream(multipartParser, fileName);
1101
                if (fileName.toString().toLowerCase().endsWith(".xml")) {
1102
                    setMetadataDoc(inputStream);
1103
                    
1104
                    //*** Get the Metadata File's DOC ID.
1105
                    lastDocId = getLastDocid(user);
1106
                    metaDocId = lastDocId = nextDocId(lastDocId);
1107
                    
1108
                    if (isFGDC()) {
1109
                        //*** Loop thru all of the data files, get fileName and inputStream.
1110
                        dataDocIDs = new HashMap();
1111
                        fileName = new StringBuilder();
1112
                        while ((inputStream = getNextInputStream(multipartParser, fileName)) != null) {
1113
                            //*** Get the data file's DOC ID.
1114
                            nextDocId = nextDocId(lastDocId);
1115
                            //*** Set the file format (just using file extension for now).
1116
                            formatType = fileName.substring(fileName.lastIndexOf(".")+1).toUpperCase();
1117
                            dataDocIDs.put(nextDocId, formatType);
1118
                            //*** Upload the data file to metacat.
1119
                            upload(nextDocId, fileName.toString(), inputStream, sizeLimit);
1120
                            
1121
                            lastDocId = nextDocId;
1122
                            fileName = new StringBuilder();
1123
                        }
1124
                        
1125
                        //*** Store the User Name and Doc Id in the FGDC document.
1126
                        newBranch = getFGDCdisinfo(getLoginResponseElement("name"), metaDocId, dataDocIDs);
1127
                        System.out.println("MetacatClient.doMetadataUpload: " + XMLUtilities.getDOMTreeAsString(newBranch));
1128
                        metaRootNode = addDistInfoToFGDC(newBranch);
1129
                        
1130
                        //*** Upload the metadata file to metacat.
1131
                        reader = XMLUtilities.getDOMTreeAsReader(metadataDoc.getDocumentElement(), false);
1132
                        insert(metaDocId, reader, null);
1133
                        
1134
                        result = "MetaCat Package Inserted:  Metadata Doc ID #" + metaDocId;
1135
                        reader.close();
1136
                    } else {
1137
                        System.out.println("MetacatClient.doUpload: not an FGDC file = " + fileName);
1138
                        result = fileName + " is not an FGDC file.  Files not uploaded.";
1139
                        //TODO add other types of metadata grammars here...
1140
                    }
1141
                } else {
1142
                    result = "The first file must be an XML Metadata file.  Files not uploaded.";
1143
                }
1144
                if (inputStream != null)
1145
                    inputStream.close();
1146
            } catch (MetacatException ex)  {
1147
                result = ex.getMessage();
1148
                System.out.println("MetacatClient.doUpload: MetacatException = " + result);
1149
            } catch (IOException ex)  {
1150
                System.out.println("MetacatClient.doUpload: " + ex);
1151
            } catch (Exception ex) {
1152
                System.out.println("MetacatClient.doUpload: " + ex);
1153
            } catch (Error err) {
1154
                System.out.println("MetacatClient.doUpload: ERR - " + err.getCause());
1155
                result = "ERR: " + err.getMessage();
1156
            }
1157
        }
1158
        return(result);
1159
    }
1160
    
1161
    private InputStream getNextInputStream(MultipartParser multipartParser, StringBuilder fileName) throws IOException {
1162
        InputStream                     result = null;
1163
        Part                            part;
1164
        String                          parmName = null, value = null, fnam;
1165
        
1166
        while ((part = multipartParser.readNextPart()) != null) {
1167
            if (part.isParam()) {
1168
                parmName = part.getName();
1169
                value = ((ParamPart) part).getStringValue();
1170
                System.out.println("MetacatClient.doUpload: parmName = " + parmName + "  value = " + value);
1171
                
1172
            } else if (part.isFile()) {
1173
                fnam = ((FilePart) part).getFileName();
1174
                if (fnam != null && !fnam.equals("")) {
1175
                    //*** File name is passed back via StringBuilder fileName param.
1176
                    fileName.append(fnam);
1177
                    result = ((FilePart) part).getInputStream();
1178
                    System.out.println("MetacatClient.doUpload: fileName = " + fileName + "  inputStream = " + result.toString());
1179
                    break;
1180
                }
1181
            }
1182
        }
1183
        return(result);
1184
    }
1185
    
1186
    private String nextDocId(String lastDocId) {
1187
        String                      result = null, tokens[];
1188
        int                         vers;
1189
        String                      template = user.toLowerCase() + ".%1$d.%2$d";
1190
        
1191
        if(lastDocId != null && lastDocId.contains(".")) {
1192
            lastDocId = lastDocId.replace('.','~'); //*** This is necessary for the split to work.
1193
            tokens = lastDocId.split("~");
1194
            if(tokens.length > 1 && !tokens[1].equals("")) {
1195
                try {
1196
                    vers = Integer.parseInt(tokens[1]);
1197
                    result = String.format(template, 1 + vers, 1);
1198
                } catch (NumberFormatException ex) {
1199
                    //*** In case the lastDocId has something other than a number.
1200
                    result = String.format(template, 1, 1);
1201
                }
1202
            } else {
1203
                //*** In case the lastDocId ends with a '.'
1204
                result = String.format(template, 1, 1);
1205
            }
1206
        } else {
1207
            //*** In case there isn't any doc Id's with the user name.
1208
            result = String.format(template, 1, 1);
1209
        }
1210
        return(result);
1211
    }
1212
    
1213
    private boolean isFGDC() {
1214
        boolean                     result = false;
1215
        DocumentType                docType;
1216
        String                      sysId, title = null;
1217
        final String                FGDC_TEST_EXPRESSION = "/metadata/idinfo/citation/citeinfo/title";
1218
        
1219
        //*** First, try the rigid proper way of determining it.
1220
        if (metadataDoc != null) {
1221
            docType = metadataDoc.getDoctype();
1222
            if (docType != null) {
1223
                sysId = docType.getSystemId();
1224
                if (sysId != null)
1225
                    result = sysId.contains(FGDC_SYSTEM_ID);
1226
            }
1227
        }
1228
        //*** It might not have a doc type line, so try another method.
1229
        if (!result) {
1230
            try {
1231
                title = getMetadataDocElement(FGDC_TEST_EXPRESSION);
1232
            } catch (XPathExpressionException ex) {
1233
                ex.printStackTrace();
1234
            }
1235
            result = (title != null && !title.equals(""));
1236
        }
1237
        return(result);
1238
    }
1239
    
1240
    private Node getFGDCdisinfo(String contactName, String resourceDescription, HashMap dataDocIDs) throws IOException {
1241
        Node                        result = null, node, digformBranch, formname, stdorder;
1242
        Document                    doc;
1243
        Iterator                    iterIt;
1244
        String                      key, value;
1245
        
1246
        //*** This is a valid/minimal FGDC "distinfo" branch.
1247
        final String XML = "<distinfo>"
1248
                + "    <distrib>"
1249
                + "        <cntinfo>"
1250
                + "            <cntperp>"
1251
                + "                <cntper></cntper>"
1252
                + "            </cntperp>"
1253
                + "            <cntaddr>"
1254
                + "                <addrtype></addrtype>"
1255
                + "                <address></address>"
1256
                + "                <city></city>"
1257
                + "                <state></state>"
1258
                + "                <postal></postal>"
1259
                + "                <country></country>"
1260
                + "            </cntaddr>"
1261
                + "            <cntvoice></cntvoice>"
1262
                + "        </cntinfo>"
1263
                + "    </distrib>"
1264
                + "    <resdesc></resdesc>"
1265
                + "    <distliab></distliab>"
1266
                + "    <stdorder>"
1267
                + "        <digform>"
1268
                + "            <digtinfo>"
1269
                + "                <formname></formname>"
1270
                + "            </digtinfo>"
1271
                + "            <digtopt>"
1272
                + "                <onlinopt>"
1273
                + "                    <computer>"
1274
                + "                        <networka>"
1275
                + "                            <networkr></networkr>"
1276
                + "                        </networka>"
1277
                + "                    </computer>"
1278
                + "                </onlinopt>"
1279
                + "            </digtopt>"
1280
                + "        </digform>"
1281
                + "        <fees></fees>"
1282
                + "    </stdorder>"
1283
                + "</distinfo>";
1284
        
1285
        doc = XMLUtilities.getXMLReaderAsDOMDocument(new StringReader(XML));
1286
        result = doc.getDocumentElement();
1287
        try {
1288
            //*** Set the Contact Person.
1289
            node = (Node) xpath.evaluate("/distinfo/distrib/cntinfo/cntperp/cntper", result, XPathConstants.NODE);
1290
            node.setTextContent(contactName);
1291
            //*** Set the metadata Doc Id.
1292
            node = (Node) xpath.evaluate("/distinfo/resdesc", result, XPathConstants.NODE);
1293
            node.setTextContent(resourceDescription);
1294
            
1295
            //*** Loop thru the files, setting their format and Doc Id.
1296
            stdorder = (Node) xpath.evaluate("/distinfo/stdorder", result, XPathConstants.NODE);
1297
            digformBranch = (Node) xpath.evaluate("/distinfo/stdorder/digform", result, XPathConstants.NODE);
1298
            iterIt = dataDocIDs.keySet().iterator();
1299
            while(iterIt.hasNext()) {
1300
                //*** Save the data file Doc ID (required).
1301
                key = (String) iterIt.next();
1302
                node = (Node) xpath.evaluate("digtopt/onlinopt/computer/networka/networkr", digformBranch, XPathConstants.NODE);
1303
                node.setTextContent(key);
1304
                //*** Save the data file format (optional).
1305
                formname = (Node) xpath.evaluate("digtinfo/formname", digformBranch, XPathConstants.NODE);
1306
                if ((value = (String) dataDocIDs.get(key)) != null && !value.equals("")) {
1307
                    formname.setTextContent(value);
1308
                } else {
1309
                    //*** We did a deep clone of the branch, so clear prior contents.
1310
                    formname.setTextContent("");
1311
                }
1312
                
1313
                //*** Clone branch for next file.
1314
                if (iterIt.hasNext()) {
1315
                    digformBranch = digformBranch.cloneNode(true);
1316
                    stdorder.appendChild(digformBranch);
1317
                }
1318
            }
1319
        } catch (XPathExpressionException ex) {
1320
            ex.printStackTrace();
1321
        }
1322
        return(result);
1323
    }
1324
    
1325
    private Node addDistInfoToFGDC(Node newBranch) {
1326
        Node                        result = null, node;
1327
        
1328
        if (newBranch != null) {
1329
            result = metadataDoc.getDocumentElement();
1330
            try {
1331
                //*** Get a reference to the FGDC required "metainfo" node (only 1 allowed).
1332
                node = (Node) xpath.evaluate("/metadata/metainfo", result, XPathConstants.NODE);
1333
                if (node != null) {
1334
                    newBranch = metadataDoc.importNode(newBranch, true);
1335
                    //*** Add the new "distinfo" before it.
1336
                    result.insertBefore(newBranch, node);
1337
                }
1338
            } catch (XPathExpressionException ex) {
1339
                ex.printStackTrace();
1340
            }
1341
        }
1342
        return(result);
1343
    }
1344
    
1345
}
(5-5/8)