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.MetacatClient;
18
import edu.ucsb.nceas.metacat.client.MetacatFactory;
19
import edu.ucsb.nceas.metacat.client.MetacatInaccessibleException;
20
import edu.ucsb.nceas.utilities.XMLUtilities;
21
import java.io.BufferedReader;
22
import java.io.IOException;
23
import java.io.InputStream;
24
import java.io.InputStreamReader;
25
import java.io.Reader;
26
import java.io.StringReader;
27
import java.util.HashMap;
28
import java.util.Properties;
29
import java.util.TreeMap;
30
import java.util.Vector;
31
import javax.servlet.http.HttpServletRequest;
32
import javax.servlet.http.HttpServletResponse;
33
import javax.servlet.http.HttpSession;
34
import javax.xml.xpath.XPath;
35
import javax.xml.xpath.XPathConstants;
36
import javax.xml.xpath.XPathExpressionException;
37
import javax.xml.xpath.XPathFactory;
38
import org.w3c.dom.Document;
39
import org.w3c.dom.Node;
40
import org.w3c.dom.NodeList;
41

    
42
/**
43
 *
44
 * @author barteau
45
 */
46
public class ClientViewHelper {
47
    private XPath                                       xpath = XPathFactory.newInstance().newXPath();
48
    private HttpSession                                 clientSession;
49
    private ClientView                                  clientViewBean = null;
50
    private MetacatClient                               metacatClient = null;
51
    private boolean                                     loggedIn = false;
52
    private Document                                    metadataDoc = null;
53
    private int                                         sizeLimit;
54
    private String                                      contactName = "";
55
    
56
    private static final String                         LDAP_TEMPLATE = "uid=%1$s,o=%2$s,dc=ecoinformatics,dc=org";
57
    
58
    /**
59
     * Creates a new instance of ClientViewHelper
60
     */
61
    public ClientViewHelper(HttpServletRequest request) throws MetacatInaccessibleException {
62
        String                              metacatPath = "http://%1$s%2$s/metacat";
63
        String                              host, context, button;
64
        
65
        clientSession = request.getSession();
66
        
67
        host = request.getHeader("host");
68
        context = request.getContextPath();
69
        metacatPath = String.format(metacatPath, host, context);
70
        metacatClient = (MetacatClient) MetacatFactory.createMetacatConnection(metacatPath);
71
        sizeLimit = (new Integer(MetaCatUtil.getOption("datafilesizelimit"))).intValue();
72
    }
73
    
74
    public String clientRequest(HttpServletRequest request, HttpServletResponse response)  {
75
        String                              result = null, action, message, serverResponse;
76
        String                              button, contentType, posted_ldapUserName;
77
        MultipartParser                     multipartParser;
78
        
79
        if (clientViewBean == null)
80
            clientViewBean = (ClientView) clientSession.getAttribute(ClientView.CLIENT_VIEW_BEAN);
81
        
82
        if (clientViewBean != null) {
83
            action = clientViewBean.getAction();
84
            contentType = request.getContentType();
85
            if (contentType != null && contentType.contains("multipart/form-data"))
86
                action = "Upload";
87
            try {
88
                if (action.equals("Login")) {
89
                    posted_ldapUserName = String.format(LDAP_TEMPLATE, clientViewBean.getUsername(), clientViewBean.getOrganization());
90
                    serverResponse = metacatClient.login(posted_ldapUserName, clientViewBean.getPassword());
91
                    setLoggedIn(serverResponse);
92
                    message = parseXml("message", serverResponse);
93
                    contactName = parseXml("name", serverResponse);
94
                    clientViewBean.setMessage(ClientView.LOGIN_MESSAGE, message);
95
                    clientViewBean.setMessage(ClientView.UPLOAD_MESSAGE, "");
96
                    if (isLoggedIn()) {
97
                        clientViewBean.setSessionid(metacatClient.getSessionId());
98
                    }
99
                } else if (action.equals("Logout")) {
100
                    message = metacatClient.logout();
101
                    setLoggedIn(message);
102
                    message = parseXml("message", message);
103
                    clientViewBean.setMessage(ClientView.LOGIN_MESSAGE, message);
104
                    clientViewBean.setMessage(ClientView.UPLOAD_MESSAGE, "");
105
                    if (!isLoggedIn()) {
106
                        clientViewBean.setUsername("");
107
                        clientViewBean.setPassword("");
108
                        clientViewBean.setOrganization("");
109
                    }
110
                    
111
                } else if (action.equals("Delete")) {
112
                    ClientFgdcHelper.clientDeleteRequest(clientViewBean, this);
113
                    //*** Refresh the select list.
114
                    message = handleDocIdSelect();
115
                    clientViewBean.setMessage(ClientView.SELECT_MESSAGE, message);
116
                    
117
                } else if (action.equals("Replace")) {
118
                    message = "Not implemented, come back another day";
119
                    clientViewBean.setMessage(ClientView.REPLACE_MESSAGE, message);
120
                    
121
                } else if (action.equals("Upload")) {
122
                    message = "";
123
                    //*** Only process request if a file upload.
124
                    if (isLoggedIn()) {
125
                        //*** Init the MultipartParser.
126
                        multipartParser = new MultipartParser(request, sizeLimit * 1024 * 1024);
127
                        message = handlePackageUpload(clientViewBean, multipartParser);
128
                    }
129
                    clientViewBean.setMessage(ClientView.UPLOAD_MESSAGE, message);
130
                    
131
                } else if (action.equals("Update")) {
132
                    
133
                } else if (action.equals("Scope")) {
134
                    message = handleDocIdSelect();
135
                    clientViewBean.setMessage(ClientView.SELECT_MESSAGE, message);
136
                }
137
                //*** Now that the action has been processed, clear it.
138
                clientViewBean.setAction("");
139
                
140
            } catch (Exception ex) {
141
                message = ex.getMessage();
142
                clientViewBean.setMessage(ClientView.ERROR_MESSAGE, message);
143
                ex.printStackTrace();
144
            }
145
        } else {
146
            System.out.println("ClientViewHelper.clientRequest: ClientView bean is not instantiated.");
147
        }
148
        return(result);
149
    }
150
    
151
    /**
152
     * This is a convenience method to reduce the amount of code in a Metacat Client.
153
     * It handles creating/reusing (per session) an instance of a ClientViewHelper.
154
     * @param request Since this is intended to be used by an Http client, it is passed the
155
     * available "request" variable (the HttpServletRequest).
156
     * @throws edu.ucsb.nceas.metacat.client.MetacatInaccessibleException Received by MetacatFactory.
157
     * @return ClientViewHelper instance.
158
     */
159
    public static ClientViewHelper clientViewHelperInstance(HttpServletRequest request) {
160
        ClientViewHelper                        result;
161
        
162
        result = (ClientViewHelper) request.getSession().getAttribute("ClientViewHelper");
163
        if (result == null) {
164
            try {
165
                result = new ClientViewHelper(request);
166
                request.getSession().setAttribute("ClientViewHelper", result);
167
            } catch (MetacatInaccessibleException ex) {
168
                ex.printStackTrace();
169
            }
170
        }
171
        
172
        return(result);
173
    }
174
    
175
    /**
176
     * A convenience method to be used by client code that requires
177
     * the user to be logged in.  NOTE: setUser() must have been called first,
178
     * otherwise it will always return false.
179
     * @return boolean  true if user has logged in for this session, false otherwise.
180
     */
181
    public boolean isLoggedIn() {
182
        return(loggedIn);
183
    }
184
    
185
    /**
186
     * After calling "login(ldapUserName, pwd)", call this with the username
187
     * and servers response message.  You can than use isLoggedIn() to determine if
188
     * the user is logged in, getLoginResponseElement(), etc.  The user name will also
189
     * used by calls to doMetadataUpload() for Document Id creation (scope).
190
     * @param userName User name
191
     * @param serverResponse XML login response sent from Metacat.
192
     */
193
    public void setLoggedIn(String serverResponse) {
194
        loggedIn = (serverResponse != null && serverResponse.contains("login"));
195
    }
196
    
197
    private String parseXml(String elementName, String xml) {
198
        String                      result = null;
199
        Document                    doc;
200
        
201
        try {
202
            doc = XMLUtilities.getXMLReaderAsDOMDocument(new StringReader(xml));
203
            result = (String) xpath.evaluate(elementName, doc.getDocumentElement(), XPathConstants.STRING);
204
            if (result != null)
205
                result = result.trim();
206
        } catch (IOException ex) {
207
            ex.printStackTrace();
208
        } catch (XPathExpressionException ex) {
209
            ex.printStackTrace();
210
        }
211
        return(result);
212
    }
213
    
214
    private String handleDocIdSelect() {
215
        String                              result = "";
216
        TreeMap                             allDocIds;
217
        
218
        if (!clientViewBean.getPathValue().equals("")) {
219
            allDocIds = getSelectQueryMap();
220
            result = ClientHtmlHelper.mapToHtmlSelect(allDocIds, "docId", "width: 240", 10);
221
        }
222
        return(result);
223
    }
224
    
225
    /**
226
     * Handles metadata file and data file uploads for inserting new
227
     * Metacat data packages.  Note: if content type is not "multipart/form-data",
228
     * nothing will happen.
229
     * @param request HTTP request.
230
     * @return A 1-line status message for the user.
231
     */
232
    private String handlePackageUpload(ClientView clientViewBean, MultipartParser multipartParser) throws Exception {
233
        String                      result = "", contentType, formatType;
234
        String                      lastDocId, nextDocId, metaDocId;
235
        Reader                      reader;
236
        int                         sizeLimit, idx;
237
        InputStream                 inputStream;
238
        HashMap                     paramsMap, dataDocIDs;
239
        StringBuilder               fileName;
240
        boolean                     sendIt;
241
        
242
        //*** Get the First file, which should be the metadata file.
243
        paramsMap = new HashMap();
244
        fileName = new StringBuilder();
245
        inputStream = getNextInputStream(multipartParser, fileName, paramsMap);
246
        if (fileName.toString().toLowerCase().endsWith(".xml")) {
247
            //*** Keep it here for updating.
248
            setMetadataDoc(inputStream);
249
            
250
            //*** Get the Metadata File's DOC ID.
251
            lastDocId = getMetacatClient().getLastDocid(clientViewBean.getUsername());
252
            metaDocId = lastDocId = nextDocId(lastDocId, clientViewBean.getUsername());
253
            
254
            //*** Loop thru all of the data files, get fileName and inputStream.
255
            dataDocIDs = new HashMap();
256
            while ((inputStream = getNextInputStream(multipartParser, fileName, paramsMap)) != null) {
257
                //*** Get the data file's DOC ID.
258
                nextDocId = nextDocId(lastDocId, clientViewBean.getUsername());
259
                
260
                //*** Set the file format (just using file extension for now).
261
                idx = fileName.lastIndexOf(".");
262
                if (idx > 1)
263
                    formatType = fileName.substring(idx+1).toUpperCase();
264
                else
265
                    formatType = "";
266
                dataDocIDs.put(nextDocId, formatType);
267
                //*** Upload the data file to metacat.
268
                getMetacatClient().upload(nextDocId, fileName.toString(), inputStream, Integer.MAX_VALUE);
269
                
270
                lastDocId = nextDocId;
271
                fileName = new StringBuilder();
272
            }
273
            
274
            if (ClientFgdcHelper.isFGDC(getMetadataDoc())) {
275
                sendIt = ClientFgdcHelper.handlePackageUpload(metaDocId, dataDocIDs, contactName, getMetadataDoc());
276
            } else {
277
                //TODO add other types of metadata grammars here...
278
                System.out.println("ClientViewHelper.handlePackageUpload: not an FGDC file = " + fileName);
279
                result = fileName + " is not an FGDC file.  Files not uploaded.";
280
                sendIt = false;
281
            }
282
            
283
            if (sendIt) {
284
                //*** Upload the metadata file to metacat.
285
                reader = XMLUtilities.getDOMTreeAsReader(metadataDoc.getDocumentElement(), false);
286
                getMetacatClient().insert(metaDocId, reader, null);
287
                
288
                result = "MetaCat Package Inserted:  the Document Identifier is " + metaDocId;
289
                reader.close();
290
                
291
                //*** One last detail...grant the public read access.
292
                if (paramsMap.containsKey("publicAccess"))
293
                    getMetacatClient().setAccess(metaDocId, "public", "read", "allow", "allowFirst");
294
            }
295
            
296
        } else {
297
            result = "The first file must be an XML Metadata file.  Files not uploaded.";
298
        }
299
        if (inputStream != null)
300
            inputStream.close();
301
        return(result);
302
    }
303
    
304
    
305
    private InputStream getNextInputStream(MultipartParser multipartParser, StringBuilder fileName, HashMap paramsMap)
306
    throws IOException {
307
        InputStream                     result = null;
308
        Part                            part;
309
        String                          parmName = null, value = null, fnam;
310
        
311
        while ((part = multipartParser.readNextPart()) != null) {
312
            if (part.isParam()) {
313
                parmName = part.getName();
314
                value = ((ParamPart) part).getStringValue();
315
                paramsMap.put(parmName, value);
316
                System.out.println("ClientViewHelper.getNextInputStream: parmName = " + parmName + "  value = " + value);
317
                
318
            } else if (part.isFile()) {
319
                fnam = ((FilePart) part).getFileName();
320
                if (fnam != null && !fnam.equals("")) {
321
                    //*** File name is passed back via StringBuilder fileName param.
322
                    fileName.append(fnam);
323
                    result = ((FilePart) part).getInputStream();
324
                    System.out.println("ClientViewHelper.getNextInputStream: fileName = " + fileName + "  inputStream = " + result.toString());
325
                    break;
326
                }
327
            }
328
        }
329
        return(result);
330
    }
331
    
332
    /**
333
     * Queries Metacat for document listings, and returns the results in a TreeMap,
334
     * where the key is the Doc Id, and the value is the Create Date.  If the document
335
     * contains the specified 'returnfield', an addtional entry will be created with
336
     * the value being a Vector of sub-DocId's.  The key of this entry will be the
337
     * original DocId with some addtional text added.
338
     * Reads bean properties 'pathExpr' (String[]), 'pathValue' (String)
339
     * and 'returnfield' (String).
340
     * @return TreeMap
341
     */
342
    public TreeMap getSelectQueryMap() {
343
        TreeMap                         result;
344
        Document                        doc;
345
        NodeList                        nodeLst, subNodeLst;
346
        Node                            node, subNode;
347
        String                          key, val, paramExpr, paramVal;
348
        String                          value, returnFld;
349
        String                          path;
350
        Vector                          optGroup;
351
        final String                    DOCID_EXPR = "./docid";
352
        final String                    DOCNAME_EXPR = "./createdate";
353
        final String                    PARAM_EXPR = "./param[@name='%1$s']";
354
        
355
        path = clientViewBean.getPathExpr();
356
        returnFld = clientViewBean.getReturnfield();
357
        value = clientViewBean.getPathValue();
358
        
359
        result = new TreeMap();
360
        paramExpr = String.format(PARAM_EXPR, returnFld);
361
        
362
        //*** Query the database ***
363
        doc = query(path, value, returnFld);
364
        //*** Build the TreeMap to return ***
365
        try {
366
            nodeLst = (NodeList) xpath.evaluate("/resultset/document", doc, XPathConstants.NODESET);
367
            for (int i = 0; i < nodeLst.getLength(); i++) {
368
                node = nodeLst.item(i);
369
                key = xpath.evaluate(DOCID_EXPR, node);
370
                val = xpath.evaluate(DOCNAME_EXPR, node);
371
                result.put(key, key + " (" + val + ")");
372
                
373
                //*** returnfield values ***
374
                subNodeLst = (NodeList) xpath.evaluate(paramExpr, node, XPathConstants.NODESET);
375
                if (subNodeLst.getLength() > 0) {
376
                    optGroup = new Vector();
377
                    for (int k = 0; k < subNodeLst.getLength(); k++) {
378
                        subNode =  subNodeLst.item(k);
379
                        paramVal = xpath.evaluate("text()", subNode);
380
                        optGroup.add(paramVal);
381
                    }
382
                    result.put(key + " Data Files", optGroup);
383
                }
384
                
385
            }
386
        } catch (XPathExpressionException ex) {
387
            ex.printStackTrace();
388
        }
389
        return(result);
390
    }
391
    
392
    /**
393
     * Query metacat for documents that 'CONTAINS' the value at the specified XPath
394
     * expression.  Additionally, returns another non-standard field value.
395
     * Standard info contains: DocId, DocName, DocType, CreateDate, and UpdateDate.
396
     * @param pathExpr String contianing an XPath expression.
397
     * @param pathValue String containing a comparison value at the XPath expression.
398
     * @param returnFld String containing an XPath expression to a field which will be returned
399
     * in addition to the standard info.
400
     * @return DOM Document containing the results.
401
     */
402
    public Document query(String pathExpr, String pathValue, String returnFld) {
403
        Document                        result = null;
404
        InputStream                     response;
405
        BufferedReader                  buffy;
406
        Properties                      prop;
407
        
408
        try {
409
            prop = new Properties();
410
            prop.put("action", "query");
411
            prop.put("qformat", "xml");
412
            prop.put(pathExpr, pathValue);
413
            if (returnFld != null) {
414
                prop.put("returnfield", returnFld);
415
            }
416
            
417
            response = metacatClient.sendData(prop, null, null, 0);
418
            if (response != null) {
419
                buffy = new BufferedReader(new InputStreamReader(response));
420
                result = XMLUtilities.getXMLReaderAsDOMDocument(buffy);
421
            }
422
        } catch (IOException ex) {
423
            ex.printStackTrace();
424
        } catch (Exception ex) {
425
            ex.printStackTrace();
426
        }
427
        return(result);
428
    }
429
    
430
    public void setMetadataDoc(Document doc) {
431
        metadataDoc = doc;
432
    }
433
    
434
    public void setMetadataDoc(String docId) throws Exception {
435
        Document                        doc = null;
436
        BufferedReader                  buffy;
437
        Properties                      prop;
438
        InputStream                     response;
439
        
440
        //*** MetaCatServlet Properties: action, qformat and docid. ***
441
        prop = new Properties();
442
        prop.put("action", "read");
443
        prop.put("qformat", "xml");
444
        prop.put("docid", docId);
445
        response = metacatClient.sendData(prop, null, null, 0);
446
        if (response != null) {
447
            buffy = new BufferedReader(new InputStreamReader(response));
448
            doc = XMLUtilities.getXMLReaderAsDOMDocument(buffy);
449
        }
450
        setMetadataDoc(doc);
451
    }
452
    
453
    public void setMetadataDoc(InputStream ioStream) throws IOException {
454
        BufferedReader                          buffy;
455
        
456
        if (ioStream != null) {
457
            buffy = new BufferedReader(new InputStreamReader(ioStream));
458
            metadataDoc = XMLUtilities.getXMLReaderAsDOMDocument(buffy);
459
        }
460
    }
461
    
462
    public Document getMetadataDoc() {
463
        return(metadataDoc);
464
    }
465
    
466
    public String nextVersion(String lastDocId, String xPathQuery) throws XPathExpressionException {
467
        String                      result = null, tokens[], scope, ready2Split;
468
        int                         vers, docNum;
469
        final int                   LAST_TOKEN = 2;
470
        final String                TEMPLATE = "%1$s.%2$d.%3$d";
471
        Node                        node;
472
        
473
        //*** Parse the last Doc Id, and increment the version number.
474
        if(lastDocId != null && lastDocId.contains(".")) {
475
            ready2Split = lastDocId.replace('.','~'); //*** This is necessary for the split to work.
476
            tokens = ready2Split.split("~");
477
            if(tokens.length > LAST_TOKEN && !tokens[LAST_TOKEN].equals("")) {
478
                scope = tokens[LAST_TOKEN - 2];
479
                docNum = Integer.parseInt(tokens[LAST_TOKEN - 1]);
480
                try {
481
                    vers = Integer.parseInt(tokens[LAST_TOKEN]);
482
                    result = String.format(TEMPLATE, scope, docNum, 1 + vers);
483
                } catch (NumberFormatException ex) {
484
                    //*** In case the lastDocId has something other than a number.
485
                    result = String.format(TEMPLATE, scope, docNum, 1);
486
                }
487
            } else {
488
                //*** In case the lastDocId ends with a '.'
489
                result = lastDocId + "1";
490
            }
491
        } else {
492
            //*** In case of missing doc Id.
493
            result = null;
494
        }
495
        //*** Update the Doc Id in the metadata file.
496
        if (getMetadataDoc() != null) {
497
            node = (Node) xpath.evaluate(xPathQuery, getMetadataDoc().getDocumentElement(), XPathConstants.NODE);
498
            node.setTextContent(result);
499
        }
500
        return(result);
501
    }
502
    
503
    private String nextDocId(String lastDocId, String scope) {
504
        String                      result = null, tokens[];
505
        int                         vers;
506
        String                      template = scope.toLowerCase() + ".%1$d.%2$d";
507
        
508
        if(lastDocId != null && lastDocId.contains(".")) {
509
            lastDocId = lastDocId.replace('.','~'); //*** This is necessary for the split to work.
510
            tokens = lastDocId.split("~");
511
            if(tokens.length > 1 && !tokens[1].equals("")) {
512
                try {
513
                    vers = Integer.parseInt(tokens[1]);
514
                    result = String.format(template, 1 + vers, 1);
515
                } catch (NumberFormatException ex) {
516
                    //*** In case the lastDocId has something other than a number.
517
                    result = String.format(template, 1, 1);
518
                }
519
            } else {
520
                //*** In case the lastDocId ends with a '.'
521
                result = String.format(template, 1, 1);
522
            }
523
        } else {
524
            //*** In case there isn't any doc Id's with the user name.
525
            result = String.format(template, 1, 1);
526
        }
527
        return(result);
528
    }
529
    
530
    public MetacatClient getMetacatClient() {
531
        return(metacatClient);
532
    }
533
}
(5-5/5)