Project

General

Profile

1
/*
2
 * ClientViewHelper.java
3
 *
4
 * Created on June 25, 2007, 9:57 AM
5
 *
6
 * To change this template, choose Tools | Template Manager
7
 * and open the template in the editor.
8
 */
9

    
10
package edu.ucsb.nceas.metacat.clientview;
11

    
12
import com.oreilly.servlet.multipart.FilePart;
13
import com.oreilly.servlet.multipart.MultipartParser;
14
import com.oreilly.servlet.multipart.ParamPart;
15
import com.oreilly.servlet.multipart.Part;
16
import edu.ucsb.nceas.metacat.MetaCatUtil;
17
import edu.ucsb.nceas.metacat.client.InsufficientKarmaException;
18
import edu.ucsb.nceas.metacat.client.MetacatClient;
19
import edu.ucsb.nceas.metacat.client.MetacatException;
20
import edu.ucsb.nceas.metacat.client.MetacatFactory;
21
import edu.ucsb.nceas.metacat.client.MetacatInaccessibleException;
22
import edu.ucsb.nceas.utilities.XMLUtilities;
23
import java.io.BufferedReader;
24
import java.io.ByteArrayOutputStream;
25
import java.io.IOException;
26
import java.io.InputStream;
27
import java.io.InputStreamReader;
28
import java.io.Reader;
29
import java.io.StringReader;
30
import java.util.HashMap;
31
import java.util.Iterator;
32
import java.util.Properties;
33
import java.util.Stack;
34
import java.util.TreeMap;
35
import java.util.Vector;
36
import javax.servlet.http.HttpServletRequest;
37
import javax.servlet.http.HttpServletResponse;
38
import javax.servlet.http.HttpSession;
39
import javax.xml.xpath.XPath;
40
import javax.xml.xpath.XPathConstants;
41
import javax.xml.xpath.XPathExpressionException;
42
import javax.xml.xpath.XPathFactory;
43
import org.w3c.dom.DOMException;
44
import org.w3c.dom.Document;
45
import org.w3c.dom.Node;
46
import org.w3c.dom.NodeList;
47
import org.w3c.dom.Text;
48

    
49
/**
50
 *
51
 * @author barteau
52
 */
53
public class ClientViewHelper {
54
    private XPath                                       xpath = XPathFactory.newInstance().newXPath();
55
    private HttpSession                                 clientSession;
56
    private ClientView                                  clientViewBean = null;
57
    private MetacatClient                               metacatClient = null;
58
    private boolean                                     loggedIn = false;
59
    private Document                                    metadataDoc = null;
60
    private int                                         sizeLimit;
61
    private String                                      contactName = "";
62
    
63
    private static final String                         LDAP_TEMPLATE = "uid=%1s,o=%2s,dc=ecoinformatics,dc=org";
64
    
65
    public static final String                          DOWNLOAD_ACTION = "Download";
66
    
67
    public static final String                          PERMISSION_TYPE_ALLOW = "allow";
68
    
69
    public static final String                          PERMISSION_TYPE_DISALLOW = "deny";
70
    
71
    /**
72
     * Creates a new instance of ClientViewHelper, using info in an HttpServletRequest
73
     * for initializing.
74
     * @param request HttpServletRequest, sent from the client browser.
75
     * @throws edu.ucsb.nceas.metacat.client.MetacatInaccessibleException Thrown
76
     */
77
    public ClientViewHelper(HttpServletRequest request) throws MetacatInaccessibleException {
78
        String                              host, context;
79
        
80
        clientSession = request.getSession();
81
        host = request.getHeader("host");
82
        context = request.getContextPath();
83
        init(host, context);
84
    }
85
    
86
    /**
87
     * Creates a new instance of ClientViewHelper, using parameter values
88
     * for initializing.  This constructor is plain java code so it's the portal of
89
     * choice for JUnit testing.
90
     * @param host The host with port (if needed), such as "localhost:8084".
91
     * @param context The application root context.
92
     * @param bean ClientView instance, with pre-populated values.
93
     * @throws edu.ucsb.nceas.metacat.client.MetacatInaccessibleException thrown
94
     */
95
    public ClientViewHelper(String host, String context, ClientView bean) throws MetacatInaccessibleException {
96
        clientViewBean = bean;
97
        init(host, context);
98
    }
99
    
100
    private void init(String host, String context) throws MetacatInaccessibleException {
101
        String                              metacatPath = "http://%1s%2s/metacat";
102
        String                              tmp;
103
        
104
        tmp = metacatPath.replaceFirst("%1s", host);
105
        metacatPath = tmp.replaceFirst("%2s", context);
106
        metacatClient = (MetacatClient) MetacatFactory.createMetacatConnection(metacatPath);
107
        sizeLimit = (new Integer(MetaCatUtil.getOption("datafilesizelimit"))).intValue();
108
    }
109
    
110
    /**
111
     * Main web API method for handling various actions.
112
     * @param request HttpServletRequest
113
     * @param response HttpServletResponse
114
     * @return String message
115
     */
116
    public String clientRequest(HttpServletRequest request, HttpServletResponse response)  {
117
        String                              result = null, action, contentType;
118
        MultipartParser                     multipartParser;
119
        HashMap                             responseMap;
120
        
121
        if (clientViewBean == null)
122
            clientViewBean = (ClientView) clientSession.getAttribute(ClientView.CLIENT_VIEW_BEAN);
123
        
124
        if (clientViewBean != null) {
125
            action = clientViewBean.getAction();
126
            contentType = request.getContentType();
127
            
128
            //*** BEGIN: manual bind params to bean (if we arrived here via the ClientViewHelper.jspx).
129
            if (action == null || action.equals("")) {
130
                if (contentType != null && contentType.indexOf("multipart/form-data") > -1) {
131
                    action = "Upload";
132
                } else {
133
                    action = request.getParameter("action");
134
                    clientViewBean.setDocId(request.getParameter("docid"));
135
                    clientViewBean.setMetaFileDocId(request.getParameter("metadataDocId"));
136
                    clientViewBean.setQformat(request.getParameter("qformat"));
137
                    clientViewBean.setPublicAccess(request.getParameter("publicAccess") != null);
138
                    clientViewBean.setContentStandard(request.getParameter("contentStandard"));
139
                }
140
                clientViewBean.setAction(action);
141
            }
142
            //*** END: manual bind params to bean.
143
            
144
            if (action != null) {
145
                if (action.equals("Login")) {
146
                    responseMap = handleClientRequest(null);
147
                    //*** Now that the action has been processed, clear it.
148
                    clientViewBean.setAction("");
149
                } else if (action.equals("Logout")) {
150
                    responseMap = handleClientRequest(null);
151
                    clientViewBean.setAction("");
152
                } else if (action.equals("Upload")) {
153
                    try {
154
                        //*** Init the MultipartParser.
155
                        multipartParser = new MultipartParser(request, sizeLimit * 1024 * 1024);
156
                        responseMap = handleClientRequest(multipartParser);
157
                    } catch (IOException ex) {
158
                        responseMap = new HashMap();
159
                        responseMap.put("message", ex.getMessage());
160
                    }
161
                    clientViewBean.setAction("");
162
                } else if (action.equals("Download")) {
163
                    responseMap = handleClientRequest(null);
164
                    try {
165
                        handleDownloadResponse(responseMap, response);
166
                    } catch (IOException ex) {
167
                        responseMap = new HashMap();
168
                        responseMap.put("message", ex.getMessage());
169
                    }
170
                    
171
                } else if (action.equals("Set Access")) {
172
                    responseMap = handleClientRequest(null);
173
                    clientViewBean.setAction("");
174
                } else {
175
                    responseMap = handleClientRequest(null);
176
                }
177
                result = (String) responseMap.get("message");
178
            }
179
        } else {
180
            result = "ClientViewHelper.clientRequest: ClientView bean is not instantiated.";
181
        }
182
        return(result);
183
    }
184
    
185
    /**
186
     * Main method for handling various actions.
187
     *
188
     * Note: This is mostly plain java code so it is JUnit friendly
189
     * (pass null as the MulipartParser).
190
     *
191
     * @param multipartParser Only needed if the action is "Upload".
192
     * @return HashMap containing "message", and possibly several other values.  If
193
     * the action is Download, than this will contain all needed values
194
     * to pass to handleDownloadResponse.
195
     */
196
    public HashMap handleClientRequest(MultipartParser multipartParser)  {
197
        String                              result = "", serverResponse;
198
        String                              button, posted_ldapUserName, tmp, action;
199
        HashMap                             responseMap = new HashMap();
200
        int                                 fileIdx;
201
        
202
        
203
        if (clientViewBean != null) {
204
            action = clientViewBean.getAction();
205
            if (action != null) {
206
                try {
207
                    if (action.equals("Login")) {
208
                        tmp = LDAP_TEMPLATE.replaceFirst("%1s", clientViewBean.getUsername());
209
                        posted_ldapUserName = tmp.replaceFirst("%2s", clientViewBean.getOrganization());
210
                        
211
                        serverResponse = metacatClient.login(posted_ldapUserName, clientViewBean.getPassword());
212
                        setLoggedIn(serverResponse);
213
                        result = parseXml("message", serverResponse);
214
                        contactName = parseXml("name", serverResponse);
215
                        clientViewBean.setMessage(ClientView.LOGIN_MESSAGE, result);
216
                        clientViewBean.setMessage(ClientView.UPLOAD_MESSAGE, "");
217
                        if (isLoggedIn()) {
218
                            clientViewBean.setSessionid(metacatClient.getSessionId());
219
                        }
220
                    } else if (action.equals("Logout")) {
221
                        result = metacatClient.logout();
222
                        setLoggedIn(result);
223
                        result = parseXml("message", result);
224
                        clientViewBean.setMessage(ClientView.LOGIN_MESSAGE, result);
225
                        clientViewBean.setMessage(ClientView.UPLOAD_MESSAGE, "");
226
                        if (!isLoggedIn()) {
227
                            clientViewBean.setUsername("");
228
                            clientViewBean.setPassword("");
229
                            clientViewBean.setOrganization("");
230
                            clientViewBean.setSessionid(null);
231
                        }
232
                    } else if (action.equals("Delete")) {
233
                        ClientFgdcHelper.clientDeleteRequest(clientViewBean, this);
234
                        clientViewBean.setAction("read"); //*** Set for re-query.
235
                        //*** Note: the clientViewBean will already have the updated Meta Doc Id.
236
                        
237
                    } else if (action.equals("Upload")) {
238
                        //*** Only process request if logged in.
239
                        if (isLoggedIn()) {
240
                            if (multipartParser == null)
241
                                result = "ClientViewHelper.handleClientRequest: MultipartParser is not instantiated.";
242
                            else
243
                                result = handlePackageUpload(clientViewBean, multipartParser);
244
                        } else {
245
                            result = "You must be logged in to perform an upload.";
246
                        }
247
                        clientViewBean.setMessage(ClientView.UPLOAD_MESSAGE, result);
248
                    } else if (action.equals("Update")) {
249
                        result = "This is not implemented here.  Call ClientViewHelper.jspx";
250
                    } else if (action.equals("Scope")) {
251
                        result = handleDocIdSelect();
252
                        clientViewBean.setMessage(ClientView.SELECT_MESSAGE, result);
253
                    } else if (action.equals("Download")) {
254
                        responseMap = download(clientViewBean);
255
                    } else if (action.equals("Set Access")) {
256
                        result = handleChangeAccess(clientViewBean.getMetaFileDocId(),
257
                                (clientViewBean.isPublicAccess()? PERMISSION_TYPE_ALLOW: PERMISSION_TYPE_DISALLOW));
258
                        clientViewBean.setMessage(ClientView.UPDATE_MESSAGE, result);
259
                    } else {
260
                        result = action + " action not recognized.";
261
                    }
262
                } catch (Exception ex) {
263
                    result = ex.getMessage();
264
                    clientViewBean.setMessage(ClientView.ERROR_MESSAGE, result);
265
                    ex.printStackTrace();
266
                }
267
            }
268
        } else {
269
            result = "ClientViewHelper.clientRequest: ClientView bean is not instantiated.";
270
        }
271
        responseMap.put("message", result);
272
        return(responseMap);
273
    }
274
    
275
    /**
276
     * This is a convenience method to reduce the amount of code in a Metacat Client.
277
     * It handles creating/reusing (per session) an instance of a ClientViewHelper.
278
     * @param request Since this is intended to be used by an Http client, it is passed the
279
     * available "request" variable (the HttpServletRequest).
280
     * @throws edu.ucsb.nceas.metacat.client.MetacatInaccessibleException Received by MetacatFactory.
281
     * @return ClientViewHelper instance.
282
     */
283
    public static ClientViewHelper clientViewHelperInstance(HttpServletRequest request) {
284
        ClientViewHelper                        result;
285
        
286
        result = (ClientViewHelper) request.getSession().getAttribute("ClientViewHelper");
287
        if (result == null) {
288
            try {
289
                result = new ClientViewHelper(request);
290
                request.getSession().setAttribute("ClientViewHelper", result);
291
            } catch (MetacatInaccessibleException ex) {
292
                ex.printStackTrace();
293
            }
294
        }
295
        
296
        return(result);
297
    }
298
    
299
    /**
300
     * A convenience method to be used by client code that requires
301
     * the user to be logged in.  NOTE: setUser() must have been called first,
302
     * otherwise it will always return false.
303
     * @return boolean  true if user has logged in for this session, false otherwise.
304
     */
305
    public boolean isLoggedIn() {
306
        return(loggedIn);
307
    }
308
    
309
    /**
310
     * After calling "login(ldapUserName, pwd)", call this with the username
311
     * and servers response message.  You can than use isLoggedIn() to determine if
312
     * the user is logged in, getLoginResponseElement(), etc.  The user name will also
313
     * used by calls to doMetadataUpload() for Document Id creation (scope).
314
     * @param userName User name
315
     * @param serverResponse XML login response sent from Metacat.
316
     */
317
    public void setLoggedIn(String serverResponse) {
318
        loggedIn = (serverResponse != null && serverResponse.indexOf("login") > -1);
319
    }
320
    
321
    public String parseXml(String elementName, String xml) {
322
        String                      result = null;
323
        Document                    doc;
324
        
325
        try {
326
            doc = XMLUtilities.getXMLReaderAsDOMDocument(new StringReader(xml));
327
            result = (String) xpath.evaluate(elementName, doc.getDocumentElement(), XPathConstants.STRING);
328
            if (result != null)
329
                result = result.trim();
330
        } catch (IOException ex) {
331
            ex.printStackTrace();
332
        } catch (XPathExpressionException ex) {
333
            ex.printStackTrace();
334
        }
335
        return(result);
336
    }
337
    
338
    public String handleDocIdSelect() {
339
        String                              result = "";
340
        TreeMap                             allDocIds;
341
        
342
        if (!clientViewBean.getPathValue().equals("")) {
343
            allDocIds = getSelectQueryMap();
344
            result = ClientHtmlHelper.mapToHtmlSelect(allDocIds, "docId", "width: 240", 10);
345
        }
346
        return(result);
347
    }
348
    
349
    /**
350
     * Handles metadata file and data file uploads for inserting new
351
     * Metacat data packages.  Note: if content type is not "multipart/form-data",
352
     * nothing will happen.
353
     * @param request HTTP request.
354
     * @return A 1-line status message for the user.
355
     */
356
    public String handlePackageUpload(ClientView clientViewBean, MultipartParser multipartParser) throws Exception {
357
        String                      result = "", contentType, formatType;
358
        String                      lastDocId, nextDocId, metaDocId, metaFileName;
359
        String                      fileInfo[];
360
        Reader                      reader;
361
        int                         sizeLimit, idx;
362
        InputStream                 inputStream;
363
        HashMap                     paramsMap, dataDocIDs;
364
        StringBuffer                fileName;
365
        boolean                     sendIt;
366
        Iterator                    iterIt;
367
        Stack                       docIdStack;
368
        
369
        //*** Get the First file, which should be the metadata file.
370
        paramsMap = new HashMap();
371
        fileName = new StringBuffer();
372
        inputStream = getNextInputStream(multipartParser, fileName, paramsMap);
373
        metaFileName = fileName.toString();
374
        if (metaFileName.toLowerCase().endsWith(".xml")) {
375
            //*** Keep it here for updating.
376
            setMetadataDoc(inputStream);
377
            //*** Get the Metadata File's DOC ID.
378
            lastDocId = getMetacatClient().getLastDocid(clientViewBean.getUsername());
379
            metaDocId = lastDocId = nextDocId(lastDocId, clientViewBean.getUsername());
380
            
381
            //*** Loop thru all of the data files, get fileName and inputStream.
382
            dataDocIDs = new HashMap();
383
            fileName = new StringBuffer();
384
            while ((inputStream = getNextInputStream(multipartParser, fileName, paramsMap)) != null) {
385
                //*** Get the data file's DOC ID.
386
                nextDocId = nextDocId(lastDocId, clientViewBean.getUsername());
387
                
388
                fileInfo = parseFileInfo(fileName.toString());
389
                dataDocIDs.put(nextDocId, fileInfo);
390
                
391
                //*** Upload the data file to metacat.
392
                getMetacatClient().upload(nextDocId, fileName.toString(), inputStream, Integer.MAX_VALUE);
393
                
394
                lastDocId = nextDocId;
395
                fileName = new StringBuffer();
396
            }
397
            
398
            if (ClientFgdcHelper.isFGDC(getMetadataDoc())) {
399
                sendIt = ClientFgdcHelper.handlePackageUpload(metaDocId, dataDocIDs, contactName, metaFileName, getMetadataDoc());
400
            } else {
401
                //TODO add other types of metadata grammars here...
402
                System.out.println("ClientViewHelper.handlePackageUpload: not an FGDC file = " + fileName);
403
                result = fileName + " is not an FGDC file.  Files not uploaded.";
404
                sendIt = false;
405
            }
406
            
407
            if (sendIt) {
408
                //*** Upload the metadata file to metacat.
409
                reader = XMLUtilities.getDOMTreeAsReader(metadataDoc.getDocumentElement(), false);
410
                getMetacatClient().insert(metaDocId, reader, null);
411
                
412
                result = "MetaCat Package Inserted:  the Document Identifier is " + metaDocId;
413
                reader.close();
414
                //*** Grant the public read access to the meta file.
415
                if (paramsMap.containsKey("publicAccess")) {
416
                    docIdStack = new Stack();
417
                    docIdStack.addAll(dataDocIDs.keySet());
418
                    setPublicAccess(this.PERMISSION_TYPE_ALLOW, metaDocId, docIdStack);
419
                }
420
            }
421
        } else {
422
            result = "The first file must be an XML Metadata file.  Files not uploaded.";
423
        }
424
        if (inputStream != null)
425
            inputStream.close();
426
        return(result);
427
    }
428
    
429
    private String setPublicAccess(String permissionType, String metaDocId, Stack docIdStack)
430
    throws InsufficientKarmaException, MetacatException, MetacatInaccessibleException {
431
        String                      result = " for Documents ";
432
        String                      docId, lst = metaDocId, permOrder;
433
        
434
        if (permissionType.equals("allow"))
435
            permOrder = "denyFirst";
436
        else
437
            permOrder = "allowFirst";
438
        
439
        getMetacatClient().setAccess(metaDocId, "public", "read", permissionType, permOrder);
440
        //*** Grant the public read access to the data files.
441
        while(!docIdStack.isEmpty()) {
442
            docId = (String) docIdStack.pop();
443
            getMetacatClient().setAccess(docId, "public", "read", permissionType, permOrder);
444
            lst += ", " + docId;
445
        }
446
        result = "Changed public read access to '" + permissionType + "' for " + result + lst;
447
        return(result);
448
    }
449
    
450
    private String handleChangeAccess(String metaDocId, String permissionType) throws Exception {
451
        Stack                       dataDocIDs;
452
        String                      result = "", xpathExpr = null;
453
        
454
        setMetadataDoc(metaDocId);
455
        //*** Build list of sub-documents.
456
        if (clientViewBean.getContentStandard().equals(ClientView.FEDERAL_GEOGRAPHIC_DATA_COMMITTEE)) {
457
            xpathExpr = ClientFgdcHelper.SUB_DOCS_PATH;
458
        } else if (clientViewBean.getContentStandard().equals(ClientView.ECOLOGICAL_METADATA_LANGUAGE)) {
459
            xpathExpr = null; //TODO  - EML
460
        }
461
        if (xpathExpr != null) {
462
            dataDocIDs = getNodeTextStack(xpath, xpathExpr, getMetadataDoc().getDocumentElement());
463
            result = setPublicAccess(permissionType, metaDocId, dataDocIDs);
464
        }
465
        return(result);
466
    }
467
    
468
    public String handleFileUpdate(MultipartParser multipartParser) throws Exception {
469
        String                      result = "", fNm, action, lastDocId, newDocId, xPathQuery, qFrmt;
470
        InputStream                 inputStream;
471
        HashMap                     paramsMap;
472
        StringBuffer                fileName;
473
        Iterator                    iterIt;
474
        boolean                     sendIt;
475
        String                      metadataDocId, fileInfo[];
476
        
477
        paramsMap = new HashMap();
478
        fileName = new StringBuffer();
479
        if ((inputStream = getNextInputStream(multipartParser, fileName, paramsMap)) != null) {
480
            action = (String) paramsMap.get("action");
481
            //*** Get the Doc Id.
482
            lastDocId = (String) paramsMap.get("docid");
483
            
484
            //*** Get the metadata Doc Id.
485
            metadataDocId = (String) paramsMap.get("metadataDocId");
486
            clientViewBean.setMetaFileDocId(metadataDocId);
487
            
488
            //*** Get the qformat.
489
            qFrmt = (String) paramsMap.get("qformat");
490
            clientViewBean.setQformat(qFrmt);
491
            
492
            fNm = fileName.toString();
493
            
494
            try {
495
                if (lastDocId.equals(metadataDocId)) { //*** This is the metadata file.
496
                    //*** Keep it here for updating.
497
                    setMetadataDoc(inputStream);
498
                    if (ClientFgdcHelper.isFGDC(getMetadataDoc())) {
499
                        clientViewBean.setContentStandard(ClientView.FEDERAL_GEOGRAPHIC_DATA_COMMITTEE);
500
                        if (!ClientFgdcHelper.hasMetacatInfo(lastDocId, getMetadataDoc())) {
501
                            
502
                            //*** Save the Doc Id for re-query.
503
                            clientViewBean.setMetaFileDocId(lastDocId);
504
                            clientViewBean.setAction("read"); //*** Set for re-query.
505
                            result = "Update not performed: the Metadata file has no prior Metacat info in it.";
506
                        } else {
507
                            xPathQuery = ClientFgdcHelper.XPATH_QUERY_TEMPLATE.replaceFirst("%1s", lastDocId);
508
                            newDocId = updateMetadataDoc(lastDocId, xPathQuery, fNm);
509
                            
510
                            //*** Save the Doc Id for re-query.
511
                            clientViewBean.setMetaFileDocId(newDocId);
512
                            clientViewBean.setAction("read"); //*** Set for re-query.
513
                            result = "Updated to new document (from " + lastDocId + " to " + newDocId + ")";
514
                        }
515
                    } else {
516
                        //***TODO This is EML.
517
                        clientViewBean.setContentStandard(ClientView.ECOLOGICAL_METADATA_LANGUAGE);
518
                        
519
                        //*** Save the Doc Id for re-query.
520
                        clientViewBean.setMetaFileDocId(lastDocId);
521
                        clientViewBean.setAction("read"); //*** Set for re-query.
522
                        result = "Currently this functionality only supports FGDC metadata.";
523
                    }
524
                } else {
525
                    //*** This is a data file.
526
                    //*** Query for the metadata, we need to update it with the new data file doc id.
527
                    setMetadataDoc(metadataDocId);
528
                    
529
                    if (ClientFgdcHelper.isFGDC(getMetadataDoc())) {
530
                        clientViewBean.setContentStandard(ClientView.FEDERAL_GEOGRAPHIC_DATA_COMMITTEE);
531
                        fileInfo = parseFileInfo(fNm);
532
                        
533
                        xPathQuery = ClientFgdcHelper.FGDC_DATA_FILE_QUERY_XPATH.replaceFirst("%1s", lastDocId);
534
                        newDocId = nextVersion(lastDocId, xPathQuery);
535
                        ClientFgdcHelper.updateFileNameAndType(getMetadataDoc().getDocumentElement(), newDocId, fileInfo);
536
                        //*** Upload the data file to metacat.
537
                        getMetacatClient().upload(newDocId, fNm, inputStream, Integer.MAX_VALUE);
538
                        result = "Updated to new document (from " + lastDocId + " to " + newDocId + ")";
539
                        
540
                        //*** Upload the metadata file to metacat.
541
                        xPathQuery = ClientFgdcHelper.XPATH_QUERY_TEMPLATE.replaceFirst("%1s", metadataDocId);
542
                        newDocId = updateMetadataDoc(metadataDocId, xPathQuery, null);
543
                        
544
                        //*** Save the new meta Doc Id for re-query.
545
                        clientViewBean.setMetaFileDocId(newDocId);
546
                        clientViewBean.setAction("read"); //*** Set for re-query.
547
                        
548
                    } else {
549
                        //***TODO This is EML.
550
                        clientViewBean.setContentStandard(ClientView.ECOLOGICAL_METADATA_LANGUAGE);
551
                        
552
                        //*** Save the old meta Doc Id for re-query.
553
                        clientViewBean.setMetaFileDocId(metadataDocId);
554
                        clientViewBean.setAction("read"); //*** Set for re-query.
555
                        result = "Currently this functionality only supports FGDC metadata.";
556
                    }
557
                }
558
            } catch (java.io.IOException ex) {
559
                ex.printStackTrace();
560
            }
561
        } else {
562
            result = "Please enter the updated file path/name.";
563
        }
564
        clientViewBean.setMessage(ClientView.UPDATE_MESSAGE, result);
565
        return(result);
566
    }
567
    
568
    private String updateMetadataDoc(String lastDocId, String docIdPath, String origFileName) {
569
        String                      newDocId = null;
570
        Reader                      reader;
571
        
572
        //*** Update the metadata with the new Doc Id version.
573
        try {
574
            newDocId = nextVersion(lastDocId, docIdPath);
575
            if (origFileName != null) {
576
                if (clientViewBean.getContentStandard().equals(ClientView.FEDERAL_GEOGRAPHIC_DATA_COMMITTEE))
577
                    ClientFgdcHelper.updateMetadataFileName(getMetadataDoc().getDocumentElement(), newDocId, origFileName);
578
                else
579
                    ; //TODO EML, etc.
580
            }
581
            //*** Upload the metadata file to metacat.
582
            reader = XMLUtilities.getDOMTreeAsReader(getMetadataDoc().getDocumentElement(), false);
583
            getMetacatClient().update(newDocId, reader, null);
584
            reader.close();
585
        } catch (Exception ex) {
586
            ex.printStackTrace();
587
        }
588
        return(newDocId);
589
    }
590
    
591
    private InputStream getNextInputStream(MultipartParser multipartParser, StringBuffer fileName, HashMap paramsMap)
592
    throws IOException {
593
        InputStream                     result = null;
594
        Part                            part;
595
        String                          parmName = null, value = null, fnam;
596
        
597
        while ((part = multipartParser.readNextPart()) != null) {
598
            if (part.isParam()) {
599
                parmName = part.getName();
600
                value = ((ParamPart) part).getStringValue();
601
                paramsMap.put(parmName, value);
602
                
603
            } else if (part.isFile()) {
604
                fnam = ((FilePart) part).getFileName();
605
                if (fnam != null && !fnam.equals("")) {
606
                    //*** File name is passed back via StringBuffer fileName param.
607
                    fileName.append(fnam);
608
                    result = ((FilePart) part).getInputStream();
609
                    break;
610
                }
611
            }
612
        }
613
        return(result);
614
    }
615
    
616
    private void getRemainingParameters(MultipartParser multipartParser, HashMap paramsMap)
617
    throws IOException {
618
        InputStream                     result = null;
619
        Part                            part;
620
        String                          parmName = null, value = null, fnam;
621
        
622
        while ((part = multipartParser.readNextPart()) != null) {
623
            if (part.isParam()) {
624
                parmName = part.getName();
625
                value = ((ParamPart) part).getStringValue();
626
                paramsMap.put(parmName, value);
627
            }
628
        }
629
    }
630
    
631
    /**
632
     * Queries Metacat for document listings, and returns the results in a TreeMap,
633
     * where the key is the Doc Id, and the value is the Create Date.  If the document
634
     * contains the specified 'returnfield', an addtional entry will be created with
635
     * the value being a Vector of sub-DocId's.  The key of this entry will be the
636
     * original DocId with some addtional text added.
637
     * Reads bean properties 'pathExpr' (String[]), 'pathValue' (String)
638
     * and 'returnfield' (String).
639
     * @return TreeMap
640
     */
641
    public TreeMap getSelectQueryMap() {
642
        TreeMap                         result;
643
        Document                        doc;
644
        NodeList                        nodeLst, subNodeLst;
645
        Node                            node, subNode;
646
        String                          key, val, paramExpr, paramVal;
647
        String                          value, returnFld;
648
        String                          path;
649
        Vector                          optGroup;
650
        final String                    DOCID_EXPR = "./docid";
651
        final String                    DOCNAME_EXPR = "./createdate";
652
        final String                    PARAM_EXPR = "./param[@name='%1s']";
653
        
654
        path = clientViewBean.getPathExpr();
655
        returnFld = clientViewBean.getReturnfield();
656
        value = clientViewBean.getPathValue();
657
        
658
        result = new TreeMap();
659
        //paramExpr = String.format(PARAM_EXPR, returnFld);
660
        paramExpr = PARAM_EXPR.replaceFirst("%1s", returnFld);
661
        //*** Query the database ***
662
        doc = query(path, value, returnFld);
663
        //*** Build the TreeMap to return ***
664
        try {
665
            nodeLst = (NodeList) xpath.evaluate("/resultset/document", doc, XPathConstants.NODESET);
666
            for (int i = 0; i < nodeLst.getLength(); i++) {
667
                node = nodeLst.item(i);
668
                key = xpath.evaluate(DOCID_EXPR, node);
669
                val = xpath.evaluate(DOCNAME_EXPR, node);
670
                result.put(key, key + " (" + val + ")");
671
                
672
                //*** returnfield values ***
673
                subNodeLst = (NodeList) xpath.evaluate(paramExpr, node, XPathConstants.NODESET);
674
                if (subNodeLst.getLength() > 0) {
675
                    optGroup = new Vector();
676
                    for (int k = 0; k < subNodeLst.getLength(); k++) {
677
                        subNode =  subNodeLst.item(k);
678
                        paramVal = xpath.evaluate("text()", subNode);
679
                        optGroup.add(paramVal);
680
                    }
681
                    result.put(key + " Data Files", optGroup);
682
                }
683
                
684
            }
685
        } catch (XPathExpressionException ex) {
686
            ex.printStackTrace();
687
        }
688
        return(result);
689
    }
690
    
691
    /**
692
     * Query metacat for documents that 'CONTAINS' the value at the specified XPath
693
     * expression.  Additionally, returns another non-standard field value.
694
     * Standard info contains: DocId, DocName, DocType, CreateDate, and UpdateDate.
695
     * @param pathExpr String contianing an XPath expression.
696
     * @param pathValue String containing a comparison value at the XPath expression.
697
     * @param returnFld String containing an XPath expression to a field which will be returned
698
     * in addition to the standard info.
699
     * @return DOM Document containing the results.
700
     */
701
    public Document query(String pathExpr, String pathValue, String returnFld) {
702
        Document                        result = null;
703
        InputStream                     response;
704
        BufferedReader                  buffy;
705
        Properties                      prop;
706
        
707
        try {
708
            prop = new Properties();
709
            prop.put("action", "query");
710
            prop.put("qformat", "xml");
711
            prop.put(pathExpr, pathValue);
712
            if (returnFld != null) {
713
                prop.put("returnfield", returnFld);
714
            }
715
            
716
            response = metacatClient.sendData(prop, null, null, 0);
717
            if (response != null) {
718
                buffy = new BufferedReader(new InputStreamReader(response));
719
                result = XMLUtilities.getXMLReaderAsDOMDocument(buffy);
720
            }
721
        } catch (IOException ex) {
722
            ex.printStackTrace();
723
        } catch (Exception ex) {
724
            ex.printStackTrace();
725
        }
726
        return(result);
727
    }
728
    
729
    public void setMetadataDoc(Document doc) {
730
        metadataDoc = doc;
731
    }
732
    
733
    public void setMetadataDoc(String docId) throws Exception {
734
        Document                        doc = null;
735
        BufferedReader                  buffy;
736
        Properties                      prop;
737
        InputStream                     response;
738
        
739
        //*** MetaCatServlet Properties: action, qformat and docid. ***
740
        prop = new Properties();
741
        prop.put("action", "read");
742
        prop.put("qformat", "xml");
743
        prop.put("docid", docId);
744
        response = metacatClient.sendData(prop, null, null, 0);
745
        if (response != null) {
746
            buffy = new BufferedReader(new InputStreamReader(response));
747
            doc = XMLUtilities.getXMLReaderAsDOMDocument(buffy);
748
            response.close();
749
        }
750
        setMetadataDoc(doc);
751
    }
752
    
753
    public void setMetadataDoc(InputStream ioStream) throws IOException {
754
        BufferedReader                          buffy;
755
        
756
        if (ioStream != null) {
757
            buffy = new BufferedReader(new InputStreamReader(ioStream));
758
            metadataDoc = XMLUtilities.getXMLReaderAsDOMDocument(buffy);
759
        }
760
    }
761
    
762
    public Document getMetadataDoc() {
763
        return(metadataDoc);
764
    }
765
    
766
    public String nextVersion(String lastDocId, String xPathQuery) throws XPathExpressionException {
767
        String                      result = null, tokens[], scope, ready2Split, tmp;
768
        int                         vers, docNum;
769
        final int                   LAST_TOKEN = 2;
770
        final String                TEMPLATE = "%1s.%2d.%3d";
771
        Node                        node;
772
        
773
        //*** Parse the last Doc Id, and increment the version number.
774
        if(lastDocId != null && lastDocId.indexOf(".") > -1) {
775
            ready2Split = lastDocId.replace('.','~'); //*** This is necessary for the split to work.
776
            tokens = ready2Split.split("~");
777
            if(tokens.length > LAST_TOKEN && !tokens[LAST_TOKEN].equals("")) {
778
                scope = tokens[LAST_TOKEN - 2];
779
                docNum = Integer.parseInt(tokens[LAST_TOKEN - 1]);
780
                try {
781
                    vers = Integer.parseInt(tokens[LAST_TOKEN]);
782
                    //result = String.format(TEMPLATE, scope, docNum, 1 + vers);
783
                    tmp = TEMPLATE.replaceFirst("%1s", scope);
784
                    tmp = tmp.replaceFirst("%2d", String.valueOf(docNum));
785
                    result = tmp.replaceFirst("%3d", String.valueOf(vers + 1));
786
                    
787
                } catch (NumberFormatException ex) {
788
                    //*** In case the lastDocId has something other than a number.
789
                    //result = String.format(TEMPLATE, scope, docNum, 1);
790
                    tmp = TEMPLATE.replaceFirst("%1s", scope);
791
                    tmp = tmp.replaceFirst("%2d", String.valueOf(docNum));
792
                    result = tmp.replaceFirst("%3d", "1");
793
                }
794
            } else {
795
                //*** In case the lastDocId ends with a '.'
796
                result = lastDocId + "1";
797
            }
798
        } else {
799
            //*** In case of missing doc Id.
800
            result = null;
801
        }
802
        //*** Update the Doc Id in the metadata file.
803
        if (getMetadataDoc() != null) {
804
            node = (Node) xpath.evaluate(xPathQuery, getMetadataDoc().getDocumentElement(), XPathConstants.NODE);
805
            setTextContent(xpath, node, result);
806
        }
807
        return(result);
808
    }
809
    
810
    private String nextDocId(String lastDocId, String scope) {
811
        String                      result = null, tokens[], tmp;
812
        int                         vers;
813
        String                      template = scope.toLowerCase() + ".%1d.%2d";
814
        
815
        if(lastDocId != null && lastDocId.indexOf(".") > -1) {
816
            lastDocId = lastDocId.replace('.','~'); //*** This is necessary for the split to work.
817
            tokens = lastDocId.split("~");
818
            if(tokens.length > 1 && !tokens[1].equals("")) {
819
                try {
820
                    vers = Integer.parseInt(tokens[1]);
821
                    //result = String.format(template, 1 + vers, 1);
822
                    tmp = template.replaceFirst("%1d", String.valueOf(1 + vers));
823
                    result = tmp.replaceFirst("%2d", "1");
824
                } catch (NumberFormatException ex) {
825
                    //*** In case the lastDocId has something other than a number.
826
                    //result = String.format(template, 1, 1);
827
                    tmp = template.replaceFirst("%1d", "1");
828
                    result = tmp.replaceFirst("%2d", "1");
829
                }
830
            } else {
831
                //*** In case the lastDocId ends with a '.'
832
                //result = String.format(template, 1, 1);
833
                tmp = template.replaceFirst("%1d", "1");
834
                result = tmp.replaceFirst("%2d", "1");
835
            }
836
        } else {
837
            //*** In case there isn't any doc Id's with the user name.
838
            //result = String.format(template, 1, 1);
839
            tmp = template.replaceFirst("%1d", "1");
840
            result = tmp.replaceFirst("%2d", "1");
841
        }
842
        return(result);
843
    }
844
    
845
    public MetacatClient getMetacatClient() {
846
        return(metacatClient);
847
    }
848
    
849
    //*** BEGIN: Static utility methods ***
850
    
851
    public static String[] parseFileInfo(String fileName) {
852
        String[]                        result = new String[2];
853
        int                             idx;
854
        String                          formatType;
855
        
856
        //*** Set the file format (just using file extension for now).
857
        idx = fileName.lastIndexOf(".");
858
        if (idx > 1)
859
            formatType = fileName.substring(idx+1).toUpperCase();
860
        else
861
            formatType = "";
862
        
863
        result[ClientView.FORMAT_TYPE] = formatType;
864
        result[ClientView.FILE_NAME] = fileName.toString();
865
        return(result);
866
    }
867
    
868
    public static void updateNodeText(Node root, XPath xPath, String expression, String text) {
869
        Node                    targetNode;
870
        
871
        if (text != null && !text.equals("")) {
872
            try {
873
                targetNode = (Node) xPath.evaluate(expression, root, XPathConstants.NODE);
874
                setTextContent(xPath, targetNode, text);
875
                //targetNode.setTextContent(text);
876
            } catch (XPathExpressionException ex) {
877
                ex.printStackTrace();
878
            }
879
        }
880
    }
881
    
882
    
883
    public static Node getNode(XPath xPath, String expression, Node root) {
884
        Node                        result = null;
885
        
886
        try {
887
            result = (Node) xPath.evaluate(expression, root, XPathConstants.NODE);
888
        } catch (XPathExpressionException ex) {
889
            ex.printStackTrace();
890
        }
891
        return(result);
892
        
893
    }
894
    
895
    public static String getNodeText(XPath xPath, String expression, Node root) {
896
        Node                        node;
897
        String                      result = null;
898
        
899
        node = getNode(xPath, expression, root);
900
        if (node != null && !node.equals(""))
901
            result = getTextContent(xPath, node);
902
        //result = node.getTextContent(); Not in java 1.4
903
        return(result);
904
    }
905
    
906
    public static String[] getNodeTextList(XPath xPath, String expression, Node root) {
907
        NodeList                    nodes;
908
        String                      result[] = new String[0];
909
        int                         size;
910
        
911
        try {
912
            nodes = (NodeList) xPath.evaluate(expression, root, XPathConstants.NODESET);
913
            if (nodes != null && (size = nodes.getLength()) > 0) {
914
                result = new String[size];
915
                for(int i = 0; i < size; i++)
916
                    result[i] = getTextContent(xPath, nodes.item(i));
917
                //result[i] = nodes.item(i).getTextContent(); Not in java 1.4
918
            }
919
        } catch (XPathExpressionException ex) {
920
            ex.printStackTrace();
921
        }
922
        return(result);
923
    }
924
    
925
    public static Stack getNodeTextStack(XPath xpathInstance, String xpathExpr, Node parentNode) {
926
        String                      nodeLst[];
927
        Stack                       result = new Stack();
928
        
929
        nodeLst = getNodeTextList(xpathInstance, xpathExpr, parentNode);
930
        for(int i = 0; i < nodeLst.length; i++)
931
            result.push(nodeLst[i]);
932
        return(result);
933
    }
934
    
935
    public static String getStringFromInputStream(InputStream input) {
936
        StringBuffer result = new StringBuffer();
937
        BufferedReader in = new BufferedReader(new InputStreamReader(input));
938
        String line;
939
        try {
940
            while ((line = in.readLine()) != null) {
941
                result.append(line);
942
            }
943
        } catch (IOException e) {
944
            System.out.println("ClientViewHelper.getStringFromInputStream: " + e);
945
        }
946
        return result.toString();
947
    }
948
    
949
    //*** END: Static utility methods ***
950
    
951
    public String makeRedirectUrl() {
952
        String                      result, docId, message;
953
        
954
        docId = clientViewBean.getMetaFileDocId();
955
        if (clientViewBean.getAction().equals(DOWNLOAD_ACTION)) {
956
            result = null;
957
        } else if (docId != null && !docId.equals("")) {
958
            message = clientViewBean.getMessage(ClientView.UPDATE_MESSAGE);
959
            result = "metacat?action=read&qformat=" +clientViewBean.getQformat()
960
            + "&docid=" + docId + "&sessionid=" + clientViewBean.getSessionid() + "&message=" + message;
961
        } else {
962
            result = "style/skins/" + clientViewBean.getQformat() + "/confirm.jsp";
963
        }
964
        //*** Reset bean action property.
965
        clientViewBean.setAction("");
966
        return(result);
967
    }
968
    
969
    private HashMap download(ClientView bean) {
970
        Properties                      args;
971
        InputStream                     inStream;
972
        String                          docId, metaId, fNm = null, pth, txtLst[];
973
        String                          msg = "File '~' (~) downloaded";
974
        Node                            branchRoot, metaRoot;
975
        ByteArrayOutputStream           outStream;
976
        int                             intMe;
977
        HashMap                         responseMap = new HashMap();
978
        
979
        docId = bean.getDocId();
980
        metaId = bean.getMetaFileDocId();
981
        if (docId != null && metaId != null && !docId.equals("") && !metaId.equals("")) {
982
            //*** Properties args: key=param_value, value=param_name.
983
            args = new Properties();
984
            args.put("read", "action");
985
            try {
986
                //*** First, retrieve the metadata and get the original filename.
987
                //*** Also, if this is the metadata, get a list of docId's for the package.
988
                setMetadataDoc(metaId);
989
                metaRoot = getMetadataDoc().getDocumentElement();
990
                if (ClientFgdcHelper.isFGDC(getMetadataDoc())) {
991
                    //*** FGDC
992
                    if (docId.equals(metaId)) { //*** This is the metadata file.
993
                        pth = ClientFgdcHelper.FGDC_DOCID_ROOT_XPATH.replaceFirst("%1s", docId);
994
                        branchRoot = getNode(xpath, pth, getMetadataDoc());
995
                        fNm = getNodeText(xpath, ClientFgdcHelper.FGDC_FILE_NAME_XPATH, branchRoot);
996
                        fNm = toZipFileName(fNm);
997
                        responseMap.put("contentType", "application/zip");
998
                        //*** Get the list of docId's for the entire package.
999
                        args.put(metaId, "docid");
1000
                        txtLst = getNodeTextList(xpath, ClientFgdcHelper.FGDC_DATA_FILE_NODES_XPATH, branchRoot);
1001
                        for (int i = 0; i < txtLst.length; i++)
1002
                            args.put(txtLst[i], "docid");
1003
                        args.put("zip", "qformat");
1004
                    } else { //*** This is a data file.
1005
                        pth = ClientFgdcHelper.PATH4ANCESTOR.replaceFirst("%1s", docId);
1006
                        pth = pth.replaceFirst("%2s", "digform");
1007
                        branchRoot = getNode(xpath, pth, getMetadataDoc());
1008
                        fNm = getNodeText(xpath, ClientFgdcHelper.FGDC_DATA_FILE_NAME_XPATH, branchRoot);
1009
                        responseMap.put("contentType", "application/octet-stream");
1010
                        args.put(docId, "docid");
1011
                        args.put("xml", "qformat");
1012
                    }
1013
                } else {
1014
                    //*** TODO: EML -  this is just some basic code to start with.
1015
                    if (docId.equals(metaId)) {
1016
                        fNm = "emlMetadata.xml";
1017
                        txtLst = new String[] {docId};
1018
                        args.put(txtLst[0], "docid");
1019
                        args.put("zip", "qformat");
1020
                        responseMap.put("contentType", "application/zip");
1021
                    } else {
1022
                        fNm = "emlData.dat";
1023
                        args.put("xml", "qformat");
1024
                        args.put(docId, "docid");
1025
                        responseMap.put("contentType", "application/octet-stream");
1026
                    }
1027
                }
1028
                
1029
                //*** Set the filename in the response.
1030
                responseMap.put("Content-Disposition", "attachment; filename=" + fNm);
1031
                
1032
                //*** Next, read the file from metacat.
1033
                inStream = metacatClient.sendParameters(args);
1034
                
1035
                //*** Then, convert the input stream into an output stream.
1036
                outStream = new ByteArrayOutputStream();
1037
                while ((intMe = inStream.read()) != -1) {
1038
                    outStream.write(intMe);
1039
                }
1040
                
1041
                //*** Now, write the output stream to the response.
1042
                responseMap.put("outputStream", outStream);
1043
                
1044
                //*** Finally, set the message for the user interface to display.
1045
                msg = msg.replaceFirst("~", fNm);
1046
                msg = msg.replaceFirst("~", docId);
1047
                bean.setMessage(ClientView.SELECT_MESSAGE, msg);
1048
            } catch (Exception ex) {
1049
                ex.printStackTrace();
1050
                bean.setMessage(ClientView.SELECT_MESSAGE, ex.getMessage());
1051
            }
1052
        }
1053
        responseMap.put("message", bean.getMessage(ClientView.SELECT_MESSAGE));
1054
        return(responseMap);
1055
    }
1056
    
1057
    private void handleDownloadResponse(HashMap responseMap, HttpServletResponse response) throws IOException {
1058
        ByteArrayOutputStream                       outStream;
1059
        String                                      contentDisposition, contentType;
1060
        
1061
        contentType = (String) responseMap.get("contentType");
1062
        contentDisposition = (String) responseMap.get("Content-Disposition");
1063
        outStream = (ByteArrayOutputStream) responseMap.get("outputStream");
1064
        
1065
        response.setContentType(contentType);
1066
        response.setHeader("Content-Disposition", contentDisposition);
1067
        response.setContentLength(outStream.size());
1068
        outStream.writeTo(response.getOutputStream());
1069
        response.flushBuffer();
1070
    }
1071
    
1072
    public static String toZipFileName(String fileName) {
1073
        String                      result = "metacat";
1074
        int                         idx;
1075
        
1076
        if (fileName != null && !fileName.equals("") && !fileName.equals(".")) {
1077
            idx = fileName.indexOf('.');
1078
            if (idx > -1)
1079
                result = fileName.substring(0, idx);
1080
            else
1081
                result = fileName;
1082
        }
1083
        result += ".zip";
1084
        return(result);
1085
    }
1086
    
1087
    public static void setTextContent(XPath xPath, Node elementNode, String content) throws DOMException {
1088
        Text                        textNode, newTxtNode;
1089
        Document                    document;
1090
        
1091
        textNode = (Text) getNode(xPath, "text()", elementNode);
1092
        if (textNode != null) {
1093
            if (isElementContentWhitespace(textNode)) {
1094
                //*** If there is an existing text node, and it's whitespace,
1095
                //*** create a new text node and insert it before whitespace.
1096
                document = elementNode.getOwnerDocument();
1097
                newTxtNode = document.createTextNode(content);
1098
                elementNode.insertBefore(newTxtNode, textNode);
1099
            } else {
1100
                //*** If there is an existing text node, and it has content,
1101
                //*** overwrite the existing text.
1102
                textNode.setNodeValue(content);
1103
            }
1104
        } else {
1105
            //*** If there isn't an existing text node,
1106
            //*** create a new text node and append it to the elementNode.
1107
            document = elementNode.getOwnerDocument();
1108
            newTxtNode = document.createTextNode(content);
1109
            elementNode.appendChild(newTxtNode);
1110
        }
1111
    }
1112
    
1113
    public static String getTextContent(XPath xPath, Node elementNode) throws DOMException {
1114
        String                      result = "";
1115
        Text                        textNode;
1116
        
1117
        if (elementNode.getNodeType() != Node.TEXT_NODE)
1118
            textNode = (Text) getNode(xPath, "text()", elementNode);
1119
        else
1120
            textNode = (Text) elementNode;
1121
        if (textNode != null)
1122
            result = textNode.getNodeValue();
1123
        return(result);
1124
    }
1125
    
1126
    public static boolean isElementContentWhitespace(Text textNode) {
1127
        boolean                     result = false;
1128
        String                      val;
1129
        
1130
        if ((val = textNode.getNodeValue()) != null) {
1131
            if (val != null) {
1132
                val = val.trim();
1133
                result = (val.length() == 0);
1134
            }
1135
        }
1136
        return(result);
1137
    }
1138
    
1139
}
(5-5/5)