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
            //*** Get the metadata Doc Id.
484
            metadataDocId = (String) paramsMap.get("metadataDocId");
485
            //*** Get the qformat.
486
            qFrmt = (String) paramsMap.get("qformat");
487
            
488
            fNm = fileName.toString();
489
            
490
            try {
491
                if (lastDocId.equals(metadataDocId)) { //*** This is the metadata file.
492
                    //*** Keep it here for updating.
493
                    setMetadataDoc(inputStream);
494
                    if (ClientFgdcHelper.isFGDC(getMetadataDoc())) {
495
                        clientViewBean.setContentStandard(ClientView.FEDERAL_GEOGRAPHIC_DATA_COMMITTEE);
496
                        if (!ClientFgdcHelper.hasMetacatInfo(lastDocId, getMetadataDoc())) {
497
                            
498
                            //*** Save the Doc Id for re-query.
499
                            clientViewBean.setMetaFileDocId(lastDocId);
500
                            clientViewBean.setAction("read"); //*** Set for re-query.
501
                            result = "Update not performed: the Metadata file has no prior Metacat info in it.";
502
                        } else {
503
                            xPathQuery = ClientFgdcHelper.XPATH_QUERY_TEMPLATE.replaceFirst("%1s", lastDocId);
504
                            newDocId = updateMetadataDoc(lastDocId, xPathQuery, fNm);
505
                            
506
                            //*** Save the Doc Id for re-query.
507
                            clientViewBean.setMetaFileDocId(newDocId);
508
                            clientViewBean.setAction("read"); //*** Set for re-query.
509
                            result = "Updated to new document (from " + lastDocId + " to " + newDocId + ")";
510
                        }
511
                    } else {
512
                        //***TODO This is EML.
513
                        clientViewBean.setContentStandard(ClientView.ECOLOGICAL_METADATA_LANGUAGE);
514
                        
515
                        //*** Save the Doc Id for re-query.
516
                        clientViewBean.setMetaFileDocId(lastDocId);
517
                        clientViewBean.setAction("read"); //*** Set for re-query.
518
                        result = "Currently this functionality only supports FGDC metadata.";
519
                    }
520
                } else {
521
                    //*** This is a data file.
522
                    //*** Query for the metadata, we need to update it with the new data file doc id.
523
                    setMetadataDoc(metadataDocId);
524
                    
525
                    if (ClientFgdcHelper.isFGDC(getMetadataDoc())) {
526
                        clientViewBean.setContentStandard(ClientView.FEDERAL_GEOGRAPHIC_DATA_COMMITTEE);
527
                        fileInfo = parseFileInfo(fNm);
528
                        
529
                        xPathQuery = ClientFgdcHelper.FGDC_DATA_FILE_QUERY_XPATH.replaceFirst("%1s", lastDocId);
530
                        newDocId = nextVersion(lastDocId, xPathQuery);
531
                        ClientFgdcHelper.updateFileNameAndType(getMetadataDoc().getDocumentElement(), newDocId, fileInfo);
532
                        //*** Upload the data file to metacat.
533
                        result = getMetacatClient().upload(newDocId, fNm, inputStream, Integer.MAX_VALUE);
534
                        
535
                        //*** Upload the metadata file to metacat.
536
                        xPathQuery = ClientFgdcHelper.XPATH_QUERY_TEMPLATE.replaceFirst("%1s", metadataDocId);
537
                        newDocId = updateMetadataDoc(metadataDocId, xPathQuery, null);
538
                        
539
                        //*** Save the new meta Doc Id for re-query.
540
                        clientViewBean.setMetaFileDocId(newDocId);
541
                        clientViewBean.setAction("read"); //*** Set for re-query.
542
                        //result = makeRedirectUrl(newDocId, qFrmt);
543
                        result = "Updated to new document (from " + lastDocId + " to " + newDocId + ")";
544
                        
545
                    } else {
546
                        //***TODO This is EML.
547
                        clientViewBean.setContentStandard(ClientView.ECOLOGICAL_METADATA_LANGUAGE);
548
                        
549
                        //*** Save the old meta Doc Id for re-query.
550
                        clientViewBean.setMetaFileDocId(metadataDocId);
551
                        clientViewBean.setAction("read"); //*** Set for re-query.
552
                        result = "Currently this functionality only supports FGDC metadata.";
553
                    }
554
                }
555
            } catch (java.io.IOException ex) {
556
                ex.printStackTrace();
557
            }
558
        } else {
559
            result = "Please enter the updated file path/name.";
560
        }
561
        clientViewBean.setMessage(ClientView.UPDATE_MESSAGE, result);
562
        return(result);
563
    }
564
    
565
    private String updateMetadataDoc(String lastDocId, String docIdPath, String origFileName) {
566
        String                      newDocId = null;
567
        Reader                      reader;
568
        
569
        //*** Update the metadata with the new Doc Id version.
570
        try {
571
            newDocId = nextVersion(lastDocId, docIdPath);
572
            if (origFileName != null) {
573
                if (clientViewBean.getContentStandard().equals(ClientView.FEDERAL_GEOGRAPHIC_DATA_COMMITTEE))
574
                    ClientFgdcHelper.updateMetadataFileName(getMetadataDoc().getDocumentElement(), newDocId, origFileName);
575
                else
576
                    ; //TODO EML, etc.
577
            }
578
            //*** Upload the metadata file to metacat.
579
            reader = XMLUtilities.getDOMTreeAsReader(getMetadataDoc().getDocumentElement(), false);
580
            getMetacatClient().update(newDocId, reader, null);
581
            reader.close();
582
        } catch (Exception ex) {
583
            ex.printStackTrace();
584
        }
585
        return(newDocId);
586
    }
587
    
588
    private InputStream getNextInputStream(MultipartParser multipartParser, StringBuffer fileName, HashMap paramsMap)
589
    throws IOException {
590
        InputStream                     result = null;
591
        Part                            part;
592
        String                          parmName = null, value = null, fnam;
593
        
594
        while ((part = multipartParser.readNextPart()) != null) {
595
            if (part.isParam()) {
596
                parmName = part.getName();
597
                value = ((ParamPart) part).getStringValue();
598
                paramsMap.put(parmName, value);
599
                
600
            } else if (part.isFile()) {
601
                fnam = ((FilePart) part).getFileName();
602
                if (fnam != null && !fnam.equals("")) {
603
                    //*** File name is passed back via StringBuffer fileName param.
604
                    fileName.append(fnam);
605
                    result = ((FilePart) part).getInputStream();
606
                    break;
607
                }
608
            }
609
        }
610
        return(result);
611
    }
612
    
613
    private void getRemainingParameters(MultipartParser multipartParser, HashMap paramsMap)
614
    throws IOException {
615
        InputStream                     result = null;
616
        Part                            part;
617
        String                          parmName = null, value = null, fnam;
618
        
619
        while ((part = multipartParser.readNextPart()) != null) {
620
            if (part.isParam()) {
621
                parmName = part.getName();
622
                value = ((ParamPart) part).getStringValue();
623
                paramsMap.put(parmName, value);
624
            }
625
        }
626
    }
627
    
628
    /**
629
     * Queries Metacat for document listings, and returns the results in a TreeMap,
630
     * where the key is the Doc Id, and the value is the Create Date.  If the document
631
     * contains the specified 'returnfield', an addtional entry will be created with
632
     * the value being a Vector of sub-DocId's.  The key of this entry will be the
633
     * original DocId with some addtional text added.
634
     * Reads bean properties 'pathExpr' (String[]), 'pathValue' (String)
635
     * and 'returnfield' (String).
636
     * @return TreeMap
637
     */
638
    public TreeMap getSelectQueryMap() {
639
        TreeMap                         result;
640
        Document                        doc;
641
        NodeList                        nodeLst, subNodeLst;
642
        Node                            node, subNode;
643
        String                          key, val, paramExpr, paramVal;
644
        String                          value, returnFld;
645
        String                          path;
646
        Vector                          optGroup;
647
        final String                    DOCID_EXPR = "./docid";
648
        final String                    DOCNAME_EXPR = "./createdate";
649
        final String                    PARAM_EXPR = "./param[@name='%1s']";
650
        
651
        path = clientViewBean.getPathExpr();
652
        returnFld = clientViewBean.getReturnfield();
653
        value = clientViewBean.getPathValue();
654
        
655
        result = new TreeMap();
656
        //paramExpr = String.format(PARAM_EXPR, returnFld);
657
        paramExpr = PARAM_EXPR.replaceFirst("%1s", returnFld);
658
        //*** Query the database ***
659
        doc = query(path, value, returnFld);
660
        //*** Build the TreeMap to return ***
661
        try {
662
            nodeLst = (NodeList) xpath.evaluate("/resultset/document", doc, XPathConstants.NODESET);
663
            for (int i = 0; i < nodeLst.getLength(); i++) {
664
                node = nodeLst.item(i);
665
                key = xpath.evaluate(DOCID_EXPR, node);
666
                val = xpath.evaluate(DOCNAME_EXPR, node);
667
                result.put(key, key + " (" + val + ")");
668
                
669
                //*** returnfield values ***
670
                subNodeLst = (NodeList) xpath.evaluate(paramExpr, node, XPathConstants.NODESET);
671
                if (subNodeLst.getLength() > 0) {
672
                    optGroup = new Vector();
673
                    for (int k = 0; k < subNodeLst.getLength(); k++) {
674
                        subNode =  subNodeLst.item(k);
675
                        paramVal = xpath.evaluate("text()", subNode);
676
                        optGroup.add(paramVal);
677
                    }
678
                    result.put(key + " Data Files", optGroup);
679
                }
680
                
681
            }
682
        } catch (XPathExpressionException ex) {
683
            ex.printStackTrace();
684
        }
685
        return(result);
686
    }
687
    
688
    /**
689
     * Query metacat for documents that 'CONTAINS' the value at the specified XPath
690
     * expression.  Additionally, returns another non-standard field value.
691
     * Standard info contains: DocId, DocName, DocType, CreateDate, and UpdateDate.
692
     * @param pathExpr String contianing an XPath expression.
693
     * @param pathValue String containing a comparison value at the XPath expression.
694
     * @param returnFld String containing an XPath expression to a field which will be returned
695
     * in addition to the standard info.
696
     * @return DOM Document containing the results.
697
     */
698
    public Document query(String pathExpr, String pathValue, String returnFld) {
699
        Document                        result = null;
700
        InputStream                     response;
701
        BufferedReader                  buffy;
702
        Properties                      prop;
703
        
704
        try {
705
            prop = new Properties();
706
            prop.put("action", "query");
707
            prop.put("qformat", "xml");
708
            prop.put(pathExpr, pathValue);
709
            if (returnFld != null) {
710
                prop.put("returnfield", returnFld);
711
            }
712
            
713
            response = metacatClient.sendData(prop, null, null, 0);
714
            if (response != null) {
715
                buffy = new BufferedReader(new InputStreamReader(response));
716
                result = XMLUtilities.getXMLReaderAsDOMDocument(buffy);
717
            }
718
        } catch (IOException ex) {
719
            ex.printStackTrace();
720
        } catch (Exception ex) {
721
            ex.printStackTrace();
722
        }
723
        return(result);
724
    }
725
    
726
    public void setMetadataDoc(Document doc) {
727
        metadataDoc = doc;
728
    }
729
    
730
    public void setMetadataDoc(String docId) throws Exception {
731
        Document                        doc = null;
732
        BufferedReader                  buffy;
733
        Properties                      prop;
734
        InputStream                     response;
735
        
736
        //*** MetaCatServlet Properties: action, qformat and docid. ***
737
        prop = new Properties();
738
        prop.put("action", "read");
739
        prop.put("qformat", "xml");
740
        prop.put("docid", docId);
741
        response = metacatClient.sendData(prop, null, null, 0);
742
        if (response != null) {
743
            buffy = new BufferedReader(new InputStreamReader(response));
744
            doc = XMLUtilities.getXMLReaderAsDOMDocument(buffy);
745
            response.close();
746
        }
747
        setMetadataDoc(doc);
748
    }
749
    
750
    public void setMetadataDoc(InputStream ioStream) throws IOException {
751
        BufferedReader                          buffy;
752
        
753
        if (ioStream != null) {
754
            buffy = new BufferedReader(new InputStreamReader(ioStream));
755
            metadataDoc = XMLUtilities.getXMLReaderAsDOMDocument(buffy);
756
        }
757
    }
758
    
759
    public Document getMetadataDoc() {
760
        return(metadataDoc);
761
    }
762
    
763
    public String nextVersion(String lastDocId, String xPathQuery) throws XPathExpressionException {
764
        String                      result = null, tokens[], scope, ready2Split, tmp;
765
        int                         vers, docNum;
766
        final int                   LAST_TOKEN = 2;
767
        final String                TEMPLATE = "%1s.%2d.%3d";
768
        Node                        node;
769
        
770
        //*** Parse the last Doc Id, and increment the version number.
771
        if(lastDocId != null && lastDocId.indexOf(".") > -1) {
772
            ready2Split = lastDocId.replace('.','~'); //*** This is necessary for the split to work.
773
            tokens = ready2Split.split("~");
774
            if(tokens.length > LAST_TOKEN && !tokens[LAST_TOKEN].equals("")) {
775
                scope = tokens[LAST_TOKEN - 2];
776
                docNum = Integer.parseInt(tokens[LAST_TOKEN - 1]);
777
                try {
778
                    vers = Integer.parseInt(tokens[LAST_TOKEN]);
779
                    //result = String.format(TEMPLATE, scope, docNum, 1 + vers);
780
                    tmp = TEMPLATE.replaceFirst("%1s", scope);
781
                    tmp = tmp.replaceFirst("%2d", String.valueOf(docNum));
782
                    result = tmp.replaceFirst("%3d", String.valueOf(vers + 1));
783
                    
784
                } catch (NumberFormatException ex) {
785
                    //*** In case the lastDocId has something other than a number.
786
                    //result = String.format(TEMPLATE, scope, docNum, 1);
787
                    tmp = TEMPLATE.replaceFirst("%1s", scope);
788
                    tmp = tmp.replaceFirst("%2d", String.valueOf(docNum));
789
                    result = tmp.replaceFirst("%3d", "1");
790
                }
791
            } else {
792
                //*** In case the lastDocId ends with a '.'
793
                result = lastDocId + "1";
794
            }
795
        } else {
796
            //*** In case of missing doc Id.
797
            result = null;
798
        }
799
        //*** Update the Doc Id in the metadata file.
800
        if (getMetadataDoc() != null) {
801
            node = (Node) xpath.evaluate(xPathQuery, getMetadataDoc().getDocumentElement(), XPathConstants.NODE);
802
            setTextContent(xpath, node, result);
803
            //node.setTextContent(result);
804
        }
805
        return(result);
806
    }
807
    
808
    private String nextDocId(String lastDocId, String scope) {
809
        String                      result = null, tokens[], tmp;
810
        int                         vers;
811
        String                      template = scope.toLowerCase() + ".%1d.%2d";
812
        
813
        if(lastDocId != null && lastDocId.indexOf(".") > -1) {
814
            lastDocId = lastDocId.replace('.','~'); //*** This is necessary for the split to work.
815
            tokens = lastDocId.split("~");
816
            if(tokens.length > 1 && !tokens[1].equals("")) {
817
                try {
818
                    vers = Integer.parseInt(tokens[1]);
819
                    //result = String.format(template, 1 + vers, 1);
820
                    tmp = template.replaceFirst("%1d", String.valueOf(1 + vers));
821
                    result = tmp.replaceFirst("%2d", "1");
822
                } catch (NumberFormatException ex) {
823
                    //*** In case the lastDocId has something other than a number.
824
                    //result = String.format(template, 1, 1);
825
                    tmp = template.replaceFirst("%1d", "1");
826
                    result = tmp.replaceFirst("%2d", "1");
827
                }
828
            } else {
829
                //*** In case the lastDocId ends with a '.'
830
                //result = String.format(template, 1, 1);
831
                tmp = template.replaceFirst("%1d", "1");
832
                result = tmp.replaceFirst("%2d", "1");
833
            }
834
        } else {
835
            //*** In case there isn't any doc Id's with the user name.
836
            //result = String.format(template, 1, 1);
837
            tmp = template.replaceFirst("%1d", "1");
838
            result = tmp.replaceFirst("%2d", "1");
839
        }
840
        return(result);
841
    }
842
    
843
    public MetacatClient getMetacatClient() {
844
        return(metacatClient);
845
    }
846
    
847
    //*** BEGIN: Static utility methods ***
848
    
849
    public static String[] parseFileInfo(String fileName) {
850
        String[]                        result = new String[2];
851
        int                             idx;
852
        String                          formatType;
853
        
854
        //*** Set the file format (just using file extension for now).
855
        idx = fileName.lastIndexOf(".");
856
        if (idx > 1)
857
            formatType = fileName.substring(idx+1).toUpperCase();
858
        else
859
            formatType = "";
860
        
861
        result[ClientView.FORMAT_TYPE] = formatType;
862
        result[ClientView.FILE_NAME] = fileName.toString();
863
        return(result);
864
    }
865
    
866
    public static void updateNodeText(Node root, XPath xPath, String expression, String text) {
867
        Node                    targetNode;
868
        
869
        if (text != null && !text.equals("")) {
870
            try {
871
                targetNode = (Node) xPath.evaluate(expression, root, XPathConstants.NODE);
872
                setTextContent(xPath, targetNode, text);
873
                //targetNode.setTextContent(text);
874
            } catch (XPathExpressionException ex) {
875
                ex.printStackTrace();
876
            }
877
        }
878
    }
879
    
880
    
881
    public static Node getNode(XPath xPath, String expression, Node root) {
882
        Node                        result = null;
883
        
884
        try {
885
            result = (Node) xPath.evaluate(expression, root, XPathConstants.NODE);
886
        } catch (XPathExpressionException ex) {
887
            ex.printStackTrace();
888
        }
889
        return(result);
890
        
891
    }
892
    
893
    public static String getNodeText(XPath xPath, String expression, Node root) {
894
        Node                        node;
895
        String                      result = null;
896
        
897
        node = getNode(xPath, expression, root);
898
        if (node != null && !node.equals(""))
899
            result = getTextContent(xPath, node);
900
        //result = node.getTextContent(); Not in java 1.4
901
        return(result);
902
    }
903
    
904
    public static String[] getNodeTextList(XPath xPath, String expression, Node root) {
905
        NodeList                    nodes;
906
        String                      result[] = null;
907
        int                         size;
908
        
909
        try {
910
            nodes = (NodeList) xPath.evaluate(expression, root, XPathConstants.NODESET);
911
            if (nodes != null && (size = nodes.getLength()) > 0) {
912
                result = new String[size];
913
                for(int i = 0; i < size; i++)
914
                    result[i] = getTextContent(xPath, nodes.item(i));
915
                //result[i] = nodes.item(i).getTextContent(); Not in java 1.4
916
            }
917
        } catch (XPathExpressionException ex) {
918
            ex.printStackTrace();
919
        }
920
        return(result);
921
    }
922
    
923
    public static Stack getNodeTextStack(XPath xpathInstance, String xpathExpr, Node parentNode) {
924
        String                      nodeLst[];
925
        Stack                       result = new Stack();
926
        
927
        nodeLst = getNodeTextList(xpathInstance, xpathExpr, parentNode);
928
        for(int i = 0; i < nodeLst.length; i++)
929
            result.push(nodeLst[i]);
930
        return(result);
931
    }
932
    
933
    public static String getStringFromInputStream(InputStream input) {
934
        StringBuffer result = new StringBuffer();
935
        BufferedReader in = new BufferedReader(new InputStreamReader(input));
936
        String line;
937
        try {
938
            while ((line = in.readLine()) != null) {
939
                result.append(line);
940
            }
941
        } catch (IOException e) {
942
            System.out.println("ClientViewHelper.getStringFromInputStream: " + e);
943
        }
944
        return result.toString();
945
    }
946
    
947
    //*** END: Static utility methods ***
948
    
949
    public String makeRedirectUrl() {
950
        String                      result, docId, message;
951
        
952
        docId = clientViewBean.getMetaFileDocId();
953
        if (clientViewBean.getAction().equals(DOWNLOAD_ACTION)) {
954
            result = null;
955
        } else if (docId != null && !docId.equals("")) {
956
            message = clientViewBean.getMessage(ClientView.UPDATE_MESSAGE);
957
            result = "metacat?action=read&qformat=" +clientViewBean.getQformat()
958
            + "&docid=" + docId + "&sessionid=" + clientViewBean.getSessionid() + "&message=" + message;
959
        } else {
960
            result = "style/common/confirm.jspx";
961
        }
962
        //*** Reset bean action property.
963
        clientViewBean.setAction("");
964
        return(result);
965
    }
966
    
967
    private HashMap download(ClientView bean) {
968
        Properties                      args;
969
        InputStream                     inStream;
970
        String                          docId, metaId, fNm = null, pth, txtLst[];
971
        String                          msg = "File '~' (~) downloaded";
972
        Node                            branchRoot, metaRoot;
973
        ByteArrayOutputStream           outStream;
974
        int                             intMe;
975
        HashMap                         responseMap = new HashMap();
976
        
977
        docId = bean.getDocId();
978
        metaId = bean.getMetaFileDocId();
979
        if (docId != null && metaId != null && !docId.equals("") && !metaId.equals("")) {
980
            //*** Properties args: key=param_value, value=param_name.
981
            args = new Properties();
982
            args.put("read", "action");
983
            try {
984
                //*** First, retrieve the metadata and get the original filename.
985
                //*** Also, if this is the metadata, get a list of docId's for the package.
986
                setMetadataDoc(metaId);
987
                metaRoot = getMetadataDoc().getDocumentElement();
988
                if (ClientFgdcHelper.isFGDC(getMetadataDoc())) {
989
                    //*** FGDC
990
                    if (docId.equals(metaId)) { //*** This is the metadata file.
991
                        pth = ClientFgdcHelper.FGDC_DOCID_ROOT_XPATH.replaceFirst("%1s", docId);
992
                        branchRoot = getNode(xpath, pth, getMetadataDoc());
993
                        fNm = getNodeText(xpath, ClientFgdcHelper.FGDC_FILE_NAME_XPATH, branchRoot);
994
                        fNm = toZipFileName(fNm);
995
                        responseMap.put("contentType", "application/zip");
996
                        //*** Get the list of docId's for the entire package.
997
                        args.put(metaId, "docid");
998
                        txtLst = getNodeTextList(xpath, ClientFgdcHelper.FGDC_DATA_FILE_NODES_XPATH, branchRoot);
999
                        for (int i = 0; i < txtLst.length; i++)
1000
                            args.put(txtLst[i], "docid");
1001
                        args.put("zip", "qformat");
1002
                    } else { //*** This is a data file.
1003
                        pth = ClientFgdcHelper.PATH4ANCESTOR.replaceFirst("%1s", docId);
1004
                        pth = pth.replaceFirst("%2s", "digform");
1005
                        branchRoot = getNode(xpath, pth, getMetadataDoc());
1006
                        fNm = getNodeText(xpath, ClientFgdcHelper.FGDC_DATA_FILE_NAME_XPATH, branchRoot);
1007
                        responseMap.put("contentType", "application/octet-stream");
1008
                        args.put(docId, "docid");
1009
                        args.put("xml", "qformat");
1010
                    }
1011
                } else {
1012
                    //*** TODO: EML -  this is just some basic code to start with.
1013
                    if (docId.equals(metaId)) {
1014
                        fNm = "emlMetadata.xml";
1015
                        txtLst = new String[] {docId};
1016
                        args.put(txtLst[0], "docid");
1017
                        args.put("zip", "qformat");
1018
                        responseMap.put("contentType", "application/zip");
1019
                    } else {
1020
                        fNm = "emlData.dat";
1021
                        args.put("xml", "qformat");
1022
                        args.put(docId, "docid");
1023
                        responseMap.put("contentType", "application/octet-stream");
1024
                    }
1025
                }
1026
                
1027
                //*** Set the filename in the response.
1028
                responseMap.put("Content-Disposition", "attachment; filename=" + fNm);
1029
                
1030
                //*** Next, read the file from metacat.
1031
                inStream = metacatClient.sendParameters(args);
1032
                
1033
                //*** Then, convert the input stream into an output stream.
1034
                outStream = new ByteArrayOutputStream();
1035
                while ((intMe = inStream.read()) != -1) {
1036
                    outStream.write(intMe);
1037
                }
1038
                
1039
                //*** Now, write the output stream to the response.
1040
                responseMap.put("outputStream", outStream);
1041
                
1042
                //*** Finally, set the message for the user interface to display.
1043
                msg = msg.replaceFirst("~", fNm);
1044
                msg = msg.replaceFirst("~", docId);
1045
                bean.setMessage(ClientView.SELECT_MESSAGE, msg);
1046
            } catch (Exception ex) {
1047
                ex.printStackTrace();
1048
                bean.setMessage(ClientView.SELECT_MESSAGE, ex.getMessage());
1049
            }
1050
        }
1051
        responseMap.put("message", bean.getMessage(ClientView.SELECT_MESSAGE));
1052
        return(responseMap);
1053
    }
1054
    
1055
    private void handleDownloadResponse(HashMap responseMap, HttpServletResponse response) throws IOException {
1056
        ByteArrayOutputStream                       outStream;
1057
        String                                      contentDisposition, contentType;
1058
        
1059
        contentType = (String) responseMap.get("contentType");
1060
        contentDisposition = (String) responseMap.get("Content-Disposition");
1061
        outStream = (ByteArrayOutputStream) responseMap.get("outputStream");
1062
        
1063
        response.setContentType(contentType);
1064
        response.setHeader("Content-Disposition", contentDisposition);
1065
        response.setContentLength(outStream.size());
1066
        outStream.writeTo(response.getOutputStream());
1067
        response.flushBuffer();
1068
    }
1069
    
1070
    public static String toZipFileName(String fileName) {
1071
        String                      result = "metacat";
1072
        int                         idx;
1073
        
1074
        if (fileName != null && !fileName.equals("") && !fileName.equals(".")) {
1075
            idx = fileName.indexOf('.');
1076
            if (idx > -1)
1077
                result = fileName.substring(0, idx);
1078
            else
1079
                result = fileName;
1080
        }
1081
        result += ".zip";
1082
        return(result);
1083
    }
1084
    
1085
    public static void setTextContent(XPath xPath, Node elementNode, String content) throws DOMException {
1086
        Text                        textNode, newTxtNode;
1087
        Document                    document;
1088
        
1089
        textNode = (Text) getNode(xPath, "text()", elementNode);
1090
        if (textNode != null) {
1091
            if (isElementContentWhitespace(textNode)) {
1092
                //*** If there is an existing text node, and it's whitespace,
1093
                //*** create a new text node and insert it before whitespace.
1094
                document = elementNode.getOwnerDocument();
1095
                newTxtNode = document.createTextNode(content);
1096
                elementNode.insertBefore(newTxtNode, textNode);
1097
            } else {
1098
                //*** If there is an existing text node, and it has content,
1099
                //*** overwrite the existing text.
1100
                textNode.setNodeValue(content);
1101
            }
1102
        } else {
1103
            //*** If there isn't an existing text node,
1104
            //*** create a new text node and append it to the elementNode.
1105
            document = elementNode.getOwnerDocument();
1106
            newTxtNode = document.createTextNode(content);
1107
            elementNode.appendChild(newTxtNode);
1108
        }
1109
    }
1110
    
1111
    public static String getTextContent(XPath xPath, Node elementNode) throws DOMException {
1112
        String                      result = "";
1113
        Text                        textNode;
1114
        
1115
        textNode = (Text) getNode(xPath, "text()", elementNode);
1116
        if (textNode != null)
1117
            result = textNode.getNodeValue();
1118
        return(result);
1119
    }
1120
    
1121
    public static boolean isElementContentWhitespace(Text textNode) {
1122
        boolean                     result = false;
1123
        String                      val;
1124
        
1125
        if ((val = textNode.getNodeValue()) != null) {
1126
            if (val != null) {
1127
                val = val.trim();
1128
                result = (val.length() == 0);
1129
            }
1130
        }
1131
        return(result);
1132
    }
1133
    
1134
}
(5-5/5)