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