Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that implements a metadata catalog as a java Servlet
4
 *  Copyright: 2000 Regents of the University of California and the
5
 *             National Center for Ecological Analysis and Synthesis
6
 *    Authors: Matt Jones, Dan Higgins, Jivka Bojilova, Chad Berkley
7
 *    Release: @release@
8
 *
9
 *   '$Author: jones $'
10
 *     '$Date: 2004-03-29 13:59:21 -0800 (Mon, 29 Mar 2004) $'
11
 * '$Revision: 2072 $'
12
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 2 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program; if not, write to the Free Software
25
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
 */
27

    
28
package edu.ucsb.nceas.metacat;
29

    
30
import com.oreilly.servlet.multipart.FilePart;
31
import com.oreilly.servlet.multipart.MultipartParser;
32
import com.oreilly.servlet.multipart.ParamPart;
33
import com.oreilly.servlet.multipart.Part;
34

    
35
import java.io.File;
36
import java.io.PrintWriter;
37
import java.io.IOException;
38
import java.io.StringReader;
39
import java.io.FileInputStream;
40
import java.io.BufferedInputStream;
41
import java.util.Enumeration;
42
import java.util.Hashtable;
43
import java.util.ResourceBundle;
44
import java.util.Random;
45
import java.util.PropertyResourceBundle;
46
import java.util.Vector;
47
import java.net.URL;
48
import java.net.MalformedURLException;
49
import java.sql.PreparedStatement;
50
import java.sql.ResultSet;
51
import java.sql.Connection;
52
import java.sql.SQLException;
53
import java.lang.reflect.*;
54
import java.net.*;
55
import java.util.zip.*;
56

    
57
import javax.servlet.ServletConfig;
58
import javax.servlet.ServletContext;
59
import javax.servlet.ServletException;
60
import javax.servlet.ServletInputStream;
61
import javax.servlet.http.HttpServlet;
62
import javax.servlet.http.HttpServletRequest;
63
import javax.servlet.http.HttpServletResponse;
64
import javax.servlet.http.HttpSession;
65
import javax.servlet.http.HttpUtils;
66
import javax.servlet.ServletOutputStream;
67

    
68
import org.ecoinformatics.eml.EMLParser;
69
import edu.ucsb.nceas.utilities.Options;
70

    
71
import org.xml.sax.SAXException;
72

    
73
/**
74
 * A metadata catalog server implemented as a Java Servlet
75
 *
76
 * <p>Valid parameters are:<br>
77
 * action=query -- query the values of all elements and attributes
78
 *                     and return a result set of nodes<br>
79
 * action=squery -- structured query (see pathquery.dtd)<br>
80
 * action= -- export a zip format for data packadge<br>
81
 * action=read -- read any metadata/data file from Metacat and from Internet<br>
82
 * action=insert -- insert an XML document into the database store<br>
83
 * action=update -- update an XML document that is in the database store<br>
84
 * action=delete --  delete an XML document from the database store<br>
85
 * action=validate -- vallidate the xml contained in valtext<br>
86
 * doctype -- document type list returned by the query (publicID)<br>
87
 * qformat=xml -- display resultset from query in XML<br>
88
 * qformat=html -- display resultset from query in HTML<br>
89
 * qformat=zip -- zip resultset from query<br>
90
 * docid=34 -- display the document with the document ID number 34<br>
91
 * doctext -- XML text of the document to load into the database<br>
92
 * acltext -- XML access text for a document to load into the database<br>
93
 * dtdtext -- XML DTD text for a new DTD to load into Metacat XML Catalog<br>
94
 * query -- actual query text (to go with 'action=query' or 'action=squery')<br>
95
 * valtext -- XML text to be validated<br>
96
 * action=getaccesscontrol -- retrieve acl info for Metacat document<br>
97
 * action=getdoctypes -- retrieve all doctypes (publicID)<br>
98
 * action=getdtdschema -- retrieve a DTD or Schema file<br>
99
 * action=getdataguide -- retrieve a Data Guide<br>
100
 * action=getprincipals -- retrieve a list of principals in XML<br>
101
 * datadoc -- data document name (id)<br>
102
 * <p>
103
 * The particular combination of parameters that are valid for each
104
 * particular action value is quite specific.  This documentation
105
 * will be reorganized to reflect this information.
106
 */
107
public class MetaCatServlet extends HttpServlet {
108

    
109
  private ServletConfig config = null;
110
  private ServletContext context = null;
111
  private String resultStyleURL = null;
112
  private String xmlcatalogfile = null;
113
  private String saxparser = null;
114
  private String datafilepath = null;
115
  private File dataDirectory = null;
116
  private String servletpath = null;
117
  private String htmlpath = null;
118
  private PropertyResourceBundle options = null;
119
  private MetaCatUtil util = null;
120
  private DBConnectionPool connPool = null;
121
  private Hashtable sessionHash = new Hashtable();
122
  private static final String PROLOG = "<?xml version=\"1.0\"?>";
123
  private static final String SUCCESS = "<success>";
124
  private static final String SUCCESSCLOSE = "</success>";
125
  private static final String ERROR = "<error>";
126
  private static final String ERRORCLOSE = "</error>";
127
  public static final String SCHEMALOCATIONKEYWORD = ":schemaLocation";
128
  public static final String NONAMESPACELOCATION = ":noNamespaceSchemaLocation";
129
  public static final String EML2KEYWORD =":eml";
130
  private static final String CONFIG_DIR  = "WEB-INF";
131
  private static final String CONFIG_NAME = "metacat.properties";
132

    
133
  /**
134
   * Initialize the servlet by creating appropriate database connections
135
   */
136
  public void init( ServletConfig config ) throws ServletException {
137
    try {
138
      super.init( config );
139
      this.config = config;
140
      this.context = config.getServletContext();
141
      System.out.println("MetaCatServlet Initialize");
142

    
143
      // Initialize the properties file for our options
144
      String dirPath = context.getRealPath(CONFIG_DIR);
145
      File propertyFile = new File(dirPath,CONFIG_NAME);
146
      Options options = null;
147
      try {
148
          options = Options.initialize(propertyFile);
149
          MetaCatUtil.debugMessage("Options configured: " + 
150
            options.getOption("configured"), 20);
151
      } catch (IOException ioe) {
152
        MetaCatUtil.debugMessage("Error in loading options: "
153
           +ioe.getMessage(), 20);
154
      }
155

    
156
      util = new MetaCatUtil();
157

    
158
      //initial DBConnection pool
159
      connPool = DBConnectionPool.getInstance();
160

    
161
      // Get the configuration file information
162
      resultStyleURL = util.getOption("resultStyleURL");
163
      xmlcatalogfile = util.getOption("xmlcatalogfile");
164
      saxparser = util.getOption("saxparser");
165
      datafilepath = util.getOption("datafilepath");
166
      dataDirectory = new File(datafilepath);
167
      servletpath = util.getOption("servletpath");
168
      htmlpath = util.getOption("htmlpath");
169

    
170

    
171
    } catch ( ServletException ex ) {
172
      throw ex;
173
    } catch (SQLException e) {
174
      MetaCatUtil.debugMessage("Error in MetacatServlet.init: "
175
                                          +e.getMessage(), 20);
176
    }
177
  }
178

    
179
  /**
180
   * Close all db connections from the pool
181
   */
182
  public void destroy() {
183
      // Close all db connection
184
      System.out.println("Destroying MetacatServlet");
185
      connPool.release();
186
  }
187

    
188
  /** Handle "GET" method requests from HTTP clients */
189
  public void doGet (HttpServletRequest request, HttpServletResponse response)
190
    throws ServletException, IOException {
191

    
192
    // Process the data and send back the response
193
    handleGetOrPost(request, response);
194
  }
195

    
196
  /** Handle "POST" method requests from HTTP clients */
197
  public void doPost( HttpServletRequest request, HttpServletResponse response)
198
    throws ServletException, IOException {
199

    
200
    // Process the data and send back the response
201
    handleGetOrPost(request, response);
202
  }
203

    
204
  /**
205
   * Control servlet response depending on the action parameter specified
206
   */
207
  private void handleGetOrPost(HttpServletRequest request,
208
                               HttpServletResponse response)
209
                               throws ServletException, IOException
210
  {
211

    
212
    if ( util == null ) {
213
        util = new MetaCatUtil();
214
    }
215
    /*MetaCatUtil.debugMessage("Connection pool size: "
216
                                     +connPool.getSizeOfDBConnectionPool(),10);
217
    MetaCatUtil.debugMessage("Free DBConnection number: "
218
                                  +connPool.getFreeDBConnectionNumber(), 10);*/
219
    //If all DBConnection in the pool are free and DBConnection pool
220
    //size is greater than initial value, shrink the connection pool
221
    //size to initial value
222
    DBConnectionPool.shrinkDBConnectionPoolSize();
223

    
224
    //Debug message to print out the method which have a busy DBConnection
225
    connPool.printMethodNameHavingBusyDBConnection();
226

    
227
    String ctype = request.getContentType();
228
    if (ctype != null && ctype.startsWith("multipart/form-data")) {
229
      handleMultipartForm(request, response);
230
    } else {
231

    
232

    
233
      String name = null;
234
      String[] value = null;
235
      String[] docid = new String[3];
236
      Hashtable params = new Hashtable();
237
      Enumeration paramlist = request.getParameterNames();
238

    
239

    
240
      while (paramlist.hasMoreElements()) {
241

    
242
        name = (String)paramlist.nextElement();
243
        value = request.getParameterValues(name);
244

    
245
        // Decode the docid and mouse click information
246
        if (name.endsWith(".y")) {
247
          docid[0] = name.substring(0,name.length()-2);
248
          params.put("docid", docid);
249
          name = "ypos";
250
        }
251
        if (name.endsWith(".x")) {
252
          name = "xpos";
253
        }
254

    
255
        params.put(name,value);
256
      }
257

    
258

    
259
      //handle param is emptpy
260
      if (params.isEmpty() || params == null)
261
      {
262
        return;
263
      }
264

    
265
      //if the user clicked on the input images, decode which image
266
      //was clicked then set the action.
267
      String action = ((String[])params.get("action"))[0];
268
      util.debugMessage("Line 230: Action is: " + action, 1);
269

    
270
      // This block handles session management for the servlet
271
      // by looking up the current session information for all actions
272
      // other than "login" and "logout"
273
      String username = null;
274
      String password = null;
275
      String[] groupnames = null;
276
      String sess_id = null;
277

    
278
      // handle login action
279
      if (action.equals("login")) {
280
        PrintWriter out = response.getWriter();
281
        handleLoginAction(out, params, request, response);
282
        out.close();
283

    
284
      // handle logout action
285
      } else if (action.equals("logout")) {
286
        PrintWriter out = response.getWriter();
287
        handleLogoutAction(out, params, request, response);
288
        out.close();
289

    
290
      // handle shrink DBConnection request
291
      } else if (action.equals("shrink")) {
292
        PrintWriter out = response.getWriter();
293
        boolean success = false;
294
        //If all DBConnection in the pool are free and DBConnection pool
295
        //size is greater than initial value, shrink the connection pool
296
        //size to initial value
297
        success = DBConnectionPool.shrinkConnectionPoolSize();
298
        if (success)
299
        {
300
          //if successfully shrink the pool size to initial value
301
          out.println("DBConnection Pool shrink successfully");
302
        }//if
303
        else
304
        {
305
          out.println("DBConnection pool couldn't shrink successfully");
306
        }
307
       //close out put
308
        out.close();
309

    
310
      // aware of session expiration on every request
311
      }
312
      else
313
      {
314
        HttpSession sess = request.getSession(true);
315
        if (sess.isNew() && !params.containsKey("sessionid")) {
316
          // session expired or has not been stored b/w user requests
317
          MetaCatUtil.debugMessage("in session is new or no sessionid", 40);
318
          username = "public";
319
          sess.setAttribute("username", username);
320
        }
321
        else
322
        {
323
          MetaCatUtil.debugMessage("in session is not new or " + 
324
                                    " has sessionid parameter", 40);
325
          try
326
          {
327
            if(params.containsKey("sessionid"))
328
            {
329
              sess_id = ((String[])params.get("sessionid"))[0];
330
              MetaCatUtil.debugMessage("in has sessionid " + sess_id, 40);
331
              if(sessionHash.containsKey(sess_id))
332
              {
333
                MetaCatUtil.debugMessage("find the id " + sess_id + 
334
                                         " in hash table", 40);
335
                sess = (HttpSession)sessionHash.get(sess_id);
336
              }
337
            }
338
            else
339
            {
340
              // we already store the session in login, so we don't need here
341
              /*MetaCatUtil.debugMessage("in no sessionid parameter ", 40);
342
              sess_id = (String)sess.getId();
343
              MetaCatUtil.debugMessage("storing the session id "+ sess_id +
344
                  " which has username " + sess.getAttribute("username") + 
345
                 " into session hash in handleGetOrPost method", 35);
346
              sessionHash.put(sess_id, sess);*/
347
            }
348
          }
349
          catch(IllegalStateException ise)
350
          {
351
            System.out.println("error in handleGetOrPost: this shouldn't " +
352
                               "happen: the session should be valid: " +
353
                               ise.getMessage());
354
          }
355

    
356
          username = (String)sess.getAttribute("username");
357
          MetaCatUtil.debugMessage("The user name from session is: "+
358
                                   username, 20);
359
          password = (String)sess.getAttribute("password");
360
          groupnames = (String[])sess.getAttribute("groupnames");
361
        }
362
      
363
        //make user user username should be public
364
        if (username == null || (username.trim().equals("")))
365
        {
366
          username = "public";
367
        }
368
        MetaCatUtil.debugMessage("The user is : "+ username, 5);
369
      }
370
       // Now that we know the session is valid, we can delegate the request
371
      // to a particular action handler
372
      if(action.equals("query")) {
373
        PrintWriter out = response.getWriter();
374
        handleQuery(out,params,response,username,groupnames,sess_id);
375
        out.close();
376
      } else if(action.equals("squery")) {
377
        PrintWriter out = response.getWriter();
378
        if(params.containsKey("query")) {
379
         handleSQuery(out, params,response,username,groupnames,sess_id);
380
         out.close();
381
        } else {
382
          out.println("Illegal action squery without \"query\" parameter");
383
          out.close();
384
        }
385
      } else if (action.equals("export")) {
386

    
387
        handleExportAction(params, response, username, groupnames, password);
388
      } else if (action.equals("read")) {
389
        handleReadAction(params, response, username,password, groupnames);
390
      } else if (action.equals("readinlinedata")) {
391
        handleReadInlineDataAction(params, response, username,
392
                                   password, groupnames);
393
      } else if (action.equals("insert") || action.equals("update")) {
394
        PrintWriter out = response.getWriter();
395
        if ( (username != null) &&  !username.equals("public") ) {
396
          handleInsertOrUpdateAction(out,params,username,groupnames);
397
        } else {
398
          out.println("Permission denied for user "+username +" " + action);
399
       }
400
        out.close();
401
      } else if (action.equals("delete")) {
402
        PrintWriter out = response.getWriter();
403
        if ( (username != null) &&  !username.equals("public") ) {
404
          handleDeleteAction(out, params, response, username, groupnames);
405
        } else {
406
          out.println("Permission denied for " + action);
407
        }
408
        out.close();
409
      } else if (action.equals("validate")) {
410
        PrintWriter out = response.getWriter();
411
        handleValidateAction(out, params);
412
        out.close();
413
      } else if (action.equals("setaccess")) {
414
         PrintWriter out = response.getWriter();
415
         handleSetAccessAction(out, params, username);
416
        out.close();
417
      } else if (action.equals("getaccesscontrol")) {
418
        PrintWriter out = response.getWriter();
419
        handleGetAccessControlAction(out,params,response,username,groupnames);
420
        out.close();
421
      } else if (action.equals("getprincipals")) {
422
        PrintWriter out = response.getWriter();
423
        handleGetPrincipalsAction(out, username, password);
424
        out.close();
425
      } else if (action.equals("getdoctypes")) {
426
        PrintWriter out = response.getWriter();
427
        handleGetDoctypesAction(out, params, response);
428
        out.close();
429
      } else if (action.equals("getdtdschema")) {
430
        PrintWriter out = response.getWriter();
431
        handleGetDTDSchemaAction(out, params, response);
432
        out.close();
433
      } else if (action.equals("getlastdocid")) {
434
        PrintWriter out = response.getWriter();
435
        handleGetMaxDocidAction(out, params, response);
436
        out.close();
437
      } else if (action.equals("getrevisionanddoctype")) {
438
        PrintWriter out = response.getWriter();
439
        handleGetRevisionAndDocTypeAction(out, params);
440
        out.close();
441
      } else if (action.equals("login") || action.equals("logout")) {
442
      } else if (action.equals("protocoltest")) {
443
        String testURL = "metacat://dev.nceas.ucsb.edu/NCEAS.897766.9";
444
        try {
445
          testURL = ((String[])params.get("url"))[0];
446
        } catch (Throwable t) {
447
        }
448
        String phandler = System.getProperty("java.protocol.handler.pkgs");
449
        response.setContentType("text/html");
450
        PrintWriter out = response.getWriter();
451
        out.println("<body bgcolor=\"white\">");
452
        out.println("<p>Handler property: <code>" + phandler + "</code></p>");
453
        out.println("<p>Starting test for:<br>");
454
        out.println("    " + testURL + "</p>");
455
        try {
456
          URL u = new URL(testURL);
457
          out.println("<pre>");
458
          out.println("Protocol: " + u.getProtocol());
459
          out.println("    Host: " + u.getHost());
460
          out.println("    Port: " + u.getPort());
461
          out.println("    Path: " + u.getPath());
462
          out.println("     Ref: " + u.getRef());
463
          String pquery = u.getQuery();
464
          out.println("   Query: " + pquery);
465
          out.println("  Params: ");
466
          if (pquery != null) {
467
            Hashtable qparams = util.parseQuery(u.getQuery());
468
            for (Enumeration en = qparams.keys(); en.hasMoreElements(); ) {
469
              String pname = (String)en.nextElement();
470
              String pvalue = (String)qparams.get(pname);
471
              out.println("    " + pname + ": " + pvalue);
472
            }
473
          }
474
          out.println("</pre>");
475
          out.println("</body>");
476
          out.close();
477
        } catch (MalformedURLException mue) {
478
          System.out.println("bad url from MetacatServlet.handleGetOrPost");
479
          out.println(mue.getMessage());
480
          mue.printStackTrace(out);
481
          out.close();
482
        }
483
      } else {
484
        PrintWriter out = response.getWriter();
485
        out.println("<?xml version=\"1.0\"?>");
486
        out.println("<error>");
487
        out.println("Error: action not registered.  Please report this error.");
488
        out.println("</error>");
489
        out.close();
490
      }
491

    
492
      //util.closeConnections();
493
      // Close the stream to the client
494
      //out.close();
495
    }
496
  }
497

    
498
  // LOGIN & LOGOUT SECTION
499
  /**
500
   * Handle the login request. Create a new session object.
501
   * Do user authentication through the session.
502
   */
503
  private void handleLoginAction(PrintWriter out, Hashtable params,
504
               HttpServletRequest request, HttpServletResponse response) {
505

    
506
    AuthSession sess = null;
507
    String un = ((String[])params.get("username"))[0];
508
    MetaCatUtil.debugMessage("user " + un + " try to login", 20);
509
    String pw = ((String[])params.get("password"))[0];
510
    String action = ((String[])params.get("action"))[0];
511
    String qformat = ((String[])params.get("qformat"))[0];
512

    
513
    try {
514
      sess = new AuthSession();
515
    } catch (Exception e) {
516
      System.out.println("error in MetacatServlet.handleLoginAction: " +
517
                          e.getMessage());
518
      out.println(e.getMessage());
519
      return;
520
    }
521
    boolean isValid = sess.authenticate(request, un, pw);
522
    
523
    //if it is authernticate is true, store the session
524
    if (isValid)
525
    {
526
      HttpSession session = sess.getSessions();
527
      String id = session.getId();
528
      MetaCatUtil.debugMessage("Store session id " + id + 
529
               "which has username" + session.getAttribute("username")+
530
               " into hash in login method", 35);
531
      sessionHash.put(id, session);
532
    }
533
    
534
    // format and transform the output
535
    if (qformat.equals("xml")) {
536
      response.setContentType("text/xml");
537
      out.println(sess.getMessage());
538
    } else {
539

    
540
      try {
541

    
542
        DBTransform trans = new DBTransform();
543
        response.setContentType("text/html");
544
        trans.transformXMLDocument(sess.getMessage(), "-//NCEAS//login//EN",
545
                                   "-//W3C//HTML//EN", qformat, out, null);
546

    
547
      } catch(Exception e) {
548

    
549
        MetaCatUtil.debugMessage("Error in MetaCatServlet.handleLoginAction: "
550
                                +e.getMessage(), 30);
551
      }
552

    
553
    // any output is returned
554
    }
555
  }
556

    
557
  /**
558
   * Handle the logout request. Close the connection.
559
   */
560
  private void handleLogoutAction(PrintWriter out, Hashtable params,
561
               HttpServletRequest request, HttpServletResponse response) {
562

    
563
    String qformat = ((String[])params.get("qformat"))[0];
564

    
565
    // close the connection
566
    HttpSession sess = request.getSession(false);
567
    MetaCatUtil.debugMessage("After get session in logout request", 40);
568
    if (sess != null) 
569
    {
570
     MetaCatUtil.debugMessage("The session id " + sess.getId() + 
571
                              " will be invalidate in logout action", 30);
572
     MetaCatUtil.debugMessage("The session contains user " + 
573
                               sess.getAttribute("username") +
574
                               " will be invalidate in logout action", 30);
575
      sess.invalidate();  
576
    }
577

    
578
    // produce output
579
    StringBuffer output = new StringBuffer();
580
    output.append("<?xml version=\"1.0\"?>");
581
    output.append("<logout>");
582
    output.append("User logged out");
583
    output.append("</logout>");
584

    
585
    //format and transform the output
586
    if (qformat.equals("xml")) {
587
      response.setContentType("text/xml");
588
      out.println(output.toString());
589
    } else {
590

    
591
      try {
592

    
593
        DBTransform trans = new DBTransform();
594
        response.setContentType("text/html");
595
        trans.transformXMLDocument(output.toString(), "-//NCEAS//login//EN",
596
                                   "-//W3C//HTML//EN", qformat, out, null);
597

    
598
      } catch(Exception e) {
599

    
600
        MetaCatUtil.debugMessage("Error in MetaCatServlet.handleLogoutAction"
601
                                  +e.getMessage(), 30);
602
      }
603
    }
604
  }
605
  // END OF LOGIN & LOGOUT SECTION
606

    
607
  // SQUERY & QUERY SECTION
608
  /**
609
   * Retreive the squery xml, execute it and display it
610
   *
611
   * @param out the output stream to the client
612
   * @param params the Hashtable of parameters that should be included
613
   * in the squery.
614
   * @param response the response object linked to the client
615
   * @param conn the database connection
616
   */
617
  protected void handleSQuery(PrintWriter out, Hashtable params,
618
                 HttpServletResponse response, String user, String[] groups,
619
                 String sessionid)
620
  {
621
    String xmlquery = ((String[])params.get("query"))[0];
622
    String qformat = ((String[])params.get("qformat"))[0];
623
    String resultdoc = null;
624
    MetaCatUtil.debugMessage("xmlquery: "+xmlquery, 30);
625
    double startTime = System.currentTimeMillis()/1000;
626
    Hashtable doclist = runQuery(xmlquery, user, groups);
627
    double docListTime = System.currentTimeMillis()/1000;
628
    MetaCatUtil.debugMessage("Time for getting doc list: "
629
                                            +(docListTime-startTime), 30);
630

    
631
    resultdoc = createResultDocument(doclist, transformQuery(xmlquery));
632
    double toStringTime = System.currentTimeMillis()/1000;
633
    MetaCatUtil.debugMessage("Time to create xml string: "
634
                              +(toStringTime-docListTime), 30);
635
    //format and transform the results
636
    double outPutTime = 0;
637
    if(qformat.equals("xml")) {
638
      response.setContentType("text/xml");
639
      out.println(resultdoc);
640
      outPutTime = System.currentTimeMillis()/1000;
641
      MetaCatUtil.debugMessage("Output time: "+(outPutTime-toStringTime), 30);
642
    } else {
643
      transformResultset(resultdoc, response, out, qformat, sessionid, params);
644
      outPutTime = System.currentTimeMillis()/1000;
645
      MetaCatUtil.debugMessage("Output time: "+(outPutTime-toStringTime), 30);
646
    }
647
  }
648

    
649
   /**
650
    * Create the xml query, execute it and display the results.
651
    *
652
    * @param out the output stream to the client
653
    * @param params the Hashtable of parameters that should be included
654
    * in the squery.
655
    * @param response the response object linked to the client
656
    */
657
  protected void handleQuery(PrintWriter out, Hashtable params,
658
                 HttpServletResponse response, String user, String[] groups,
659
                 String sessionid)
660
  {
661
    //create the query and run it
662
    String xmlquery = DBQuery.createSQuery(params);
663
    Hashtable doclist = runQuery(xmlquery, user, groups);
664
    String qformat = ((String[])params.get("qformat"))[0];
665
    String resultdoc = null;
666

    
667
    resultdoc = createResultDocument(doclist, transformQuery(params));
668

    
669
    //format and transform the results
670
    if(qformat.equals("xml")) {
671
      response.setContentType("text/xml");
672
      out.println(resultdoc);
673
    } else {
674
      transformResultset(resultdoc, response, out, qformat, sessionid, params);
675
    }
676
  }
677

    
678
  /**
679
   * Removes the <?xml version="x"?> tag from the beginning of xmlquery
680
   * so it can properly be placed in the <query> tag of the resultset.
681
   * This method is overwritable so that other applications can customize
682
   * the structure of what is in the <query> tag.
683
   *
684
   * @param xmlquery is the query to remove the <?xml version="x"?> tag from.
685
   */
686
  protected String transformQuery(Hashtable params)
687
  {
688
    //DBQuery.createSQuery is a re-calling of a previously called
689
    //function but it is necessary
690
    //so that overriding methods have access to the params hashtable
691
    String xmlquery = DBQuery.createSQuery(params);
692
    //the <?xml version="1.0"?> tag is the first 22 characters of the
693
    xmlquery = xmlquery.trim();
694
    int index = xmlquery.indexOf("?>");
695
    if ( index != -1 )
696
    {
697
      //have <?xml version="1.0"?>
698
      return xmlquery.substring(index + 2, xmlquery.length());
699
    }
700
    else
701
    {
702
      // don't have <?xml version="1.0"?>
703
      return xmlquery;
704
    }
705
  }
706

    
707
  /**
708
   * removes the <?xml version="1.0"?> tag from the beginning.  This takes a
709
   * string as a param instead of a hashtable.
710
   *
711
   * @param xmlquery a string representing a query.
712
   */
713
  protected String transformQuery(String xmlquery)
714
  {
715
    xmlquery = xmlquery.trim();
716
    int index = xmlquery.indexOf("?>");
717
    if (index != -1)
718
    {
719
      return xmlquery.substring(index + 2, xmlquery.length());
720
    }
721
    else
722
    {
723
      return xmlquery;
724
    }
725
  }
726

    
727
  /**
728
   * Run the query and return a hashtable of results.
729
   *
730
   * @param xmlquery the query to run
731
   */
732
  private Hashtable runQuery(String xmlquery, String user, String[] groups)
733
  {
734
    Hashtable doclist=null;
735

    
736
    try
737
    {
738

    
739
      DBQuery queryobj = new DBQuery(saxparser);
740
      doclist = queryobj.findDocuments(new StringReader(xmlquery),user,groups);
741

    
742
      return doclist;
743
    }
744
    catch (Exception e)
745
    {
746

    
747
      MetaCatUtil.debugMessage("Error in MetacatServlet.runQuery: "
748
                                                      + e.getMessage(), 30);
749
      doclist = null;
750
      return doclist;
751
    }
752
  }
753

    
754
  /**
755
   * Transorms an xml resultset document to html and sends it to the browser
756
   *
757
   * @param resultdoc the string representation of the document that needs
758
   * to be transformed.
759
   * @param response the HttpServletResponse object bound to the client.
760
   * @param out the output stream to the client
761
   * @param qformat the name of the style-set to use for transformations
762
   */
763
  protected void transformResultset(String resultdoc,
764
                                    HttpServletResponse response,
765
                                    PrintWriter out, String qformat,
766
                                    String sessionid, Hashtable params)
767
  {
768

    
769
    try {
770

    
771
      DBTransform trans = new DBTransform();
772
      response.setContentType("text/html");
773
      trans.transformXMLDocument(resultdoc, "-//NCEAS//resultset//EN",
774
                                 "-//W3C//HTML//EN", qformat, out, params,
775
                                 sessionid);
776

    
777
    }
778
    catch(Exception e)
779
    {
780

    
781
      MetaCatUtil.debugMessage("Error in MetaCatServlet.transformResultset:"
782
                                +e.getMessage(), 30);
783
    }
784
  }
785

    
786
  /**
787
   * Transforms a hashtable of documents to an xml or html result.
788
   *
789
   * @param doclist- the hashtable to transform
790
   * @param xmlquery- the query that returned the doclist result
791
   */
792
  protected String createResultDocument(Hashtable doclist, String xmlquery)
793
  {
794
    // Create a buffer to hold the xml result
795
    StringBuffer resultset = new StringBuffer();
796

    
797
    // Print the resulting root nodes
798
    String docid = null;
799
    String document = null;
800
    resultset.append("<?xml version=\"1.0\"?>\n");
801
    resultset.append("<resultset>\n");
802

    
803
    resultset.append("  <query>" + xmlquery + "</query>");
804

    
805
    if(doclist != null)
806
    {
807
      Enumeration doclistkeys = doclist.keys();
808
      while (doclistkeys.hasMoreElements())
809
      {
810
        docid = (String)doclistkeys.nextElement();
811
        document = (String)doclist.get(docid);
812
        resultset.append("  <document>" + document + "</document>");
813
      }
814
    }
815

    
816
    resultset.append("</resultset>");
817
    return resultset.toString();
818
  }
819
  // END OF SQUERY & QUERY SECTION
820

    
821
 //Exoport section
822
 /**
823
   * Handle the "export" request of data package from Metacat in zip format
824
   * @param params the Hashtable of HTTP request parameters
825
   * @param response the HTTP response object linked to the client
826
   * @param user the username sent the request
827
   * @param groups the user's groupnames
828
   */
829
  private void handleExportAction(Hashtable params,
830
    HttpServletResponse response, String user, String[] groups, String passWord)
831
  {
832
    // Output stream
833
    ServletOutputStream out = null;
834
    // Zip output stream
835
    ZipOutputStream zOut = null;
836
    DocumentImpl docImpls=null;
837
    DBQuery queryObj=null;
838

    
839
    String[] docs = new String[10];
840
    String docId = "";
841

    
842
    try
843
    {
844
      // read the params
845
      if (params.containsKey("docid"))
846
      {
847
        docs = (String[])params.get("docid");
848
      }//if
849
      // Create a DBuery to handle export
850
      queryObj = new DBQuery(saxparser);
851
      // Get the docid
852
      docId=docs[0];
853
      // Make sure the client specify docid
854
      if (docId == null || docId.equals(""))
855
      {
856
        response.setContentType("text/xml"); //MIME type
857
        // Get a printwriter
858
        PrintWriter pw = response.getWriter();
859
        // Send back message
860
        pw.println("<?xml version=\"1.0\"?>");
861
        pw.println("<error>");
862
        pw.println("You didn't specify requested docid");
863
        pw.println("</error>");
864
        // Close printwriter
865
        pw.close();
866
        return;
867
      }//if
868
      // Get output stream
869
      out = response.getOutputStream();
870
      response.setContentType("application/zip"); //MIME type
871
      zOut = new ZipOutputStream(out);
872
      zOut =queryObj.getZippedPackage(docId, out, user, groups, passWord);
873
      zOut.finish(); //terminate the zip file
874
      zOut.close();  //close the zip stream
875

    
876
    }//try
877
    catch (Exception e)
878
    {
879
      try
880
      {
881
        response.setContentType("text/xml"); //MIME type
882
        // Send error message back
883
        if (out != null)
884
        {
885
            PrintWriter pw = new PrintWriter(out);
886
            pw.println("<?xml version=\"1.0\"?>");
887
            pw.println("<error>");
888
            pw.println(e.getMessage());
889
            pw.println("</error>");
890
            // Close printwriter
891
            pw.close();
892
            // Close output stream
893
            out.close();
894
        }//if
895
        // Close zip output stream
896
        if ( zOut != null )
897
        {
898
          zOut.close();
899
        }//if
900
      }//try
901
      catch (IOException ioe)
902
      {
903
        MetaCatUtil.debugMessage("Problem with the servlet output " +
904
                           "in MetacatServlet.handleExportAction: " +
905
                           ioe.getMessage(), 30);
906
      }//catch
907

    
908
      MetaCatUtil.debugMessage("Error in MetacatServlet.handleExportAction: " +
909
                         e.getMessage(), 30);
910
      e.printStackTrace(System.out);
911

    
912
    }//catch
913

    
914
  }//handleExportAction
915

    
916

    
917
   //read inline data section
918
 /**
919
   * In eml2 document, the xml can have inline data and data was stripped off
920
   * and store in file system. This action can be used to read inline data only
921
   * @param params the Hashtable of HTTP request parameters
922
   * @param response the HTTP response object linked to the client
923
   * @param user the username sent the request
924
   * @param groups the user's groupnames
925
   */
926
  private void handleReadInlineDataAction(Hashtable params,
927
                                          HttpServletResponse response,
928
                                          String user, String passWord,
929
                                          String[] groups)
930
  {
931
    String[] docs = new String[10];
932
    String inlineDataId = null;
933
    String docId = "";
934
    ServletOutputStream out = null;
935

    
936
    try
937
    {
938
      // read the params
939
      if (params.containsKey("inlinedataid"))
940
      {
941
        docs = (String[])params.get("inlinedataid");
942
      }//if
943
      // Get the docid
944
      inlineDataId=docs[0];
945
      // Make sure the client specify docid
946
      if (inlineDataId == null || inlineDataId.equals(""))
947
      {
948
        throw new Exception("You didn't specify requested inlinedataid");
949
      }//if
950

    
951
      // check for permission
952
      docId = MetaCatUtil.getDocIdWithoutRevFromInlineDataID(inlineDataId);
953
      PermissionController controller = new PermissionController(docId);
954
      // check top level read permission
955
      if (!controller.hasPermission(user, groups,
956
                                    AccessControlInterface.READSTRING))
957
      {
958
          throw new Exception("User "+ user + " doesn't have permission "+
959
                              " to read document " + docId);
960
      }//if
961
      // if the document has subtree control, we need to check subtree control
962
      else if(controller.hasSubTreeAccessControl())
963
      {
964
        // get node id for inlinedata
965
        long nodeId=getInlineDataNodeId(inlineDataId, docId);
966
        if (!controller.hasPermissionForSubTreeNode(user, groups,
967
                                     AccessControlInterface.READSTRING, nodeId))
968
        {
969
           throw new Exception("User "+ user + " doesn't have permission "+
970
                              " to read inlinedata " + inlineDataId);
971
        }//if
972

    
973
      }//else
974

    
975
      // Get output stream
976
      out = response.getOutputStream();
977
      // read the inline data from the file
978
      String inlinePath = MetaCatUtil.getOption("inlinedatafilepath");
979
      File lineData = new File(inlinePath, inlineDataId);
980
      FileInputStream input = new FileInputStream(lineData);
981
      byte [] buffer = new byte[4*1024];
982
      int bytes = input.read(buffer);
983
      while (bytes != -1)
984
      {
985
        out.write(buffer, 0, bytes);
986
        bytes = input.read(buffer);
987
      }
988
      out.close();
989

    
990
    }//try
991
    catch (Exception e)
992
    {
993
      try
994
      {
995
        PrintWriter pw = null;
996
        // Send error message back
997
        if (out != null)
998
        {
999
            pw = new PrintWriter(out);
1000
        }//if
1001
        else
1002
        {
1003
          pw = response.getWriter();
1004
        }
1005
         pw.println("<?xml version=\"1.0\"?>");
1006
         pw.println("<error>");
1007
         pw.println(e.getMessage());
1008
         pw.println("</error>");
1009
         // Close printwriter
1010
         pw.close();
1011
         // Close output stream if out is not null
1012
         if (out != null)
1013
         {
1014
           out.close();
1015
         }
1016
     }//try
1017
     catch (IOException ioe)
1018
     {
1019
        MetaCatUtil.debugMessage("Problem with the servlet output " +
1020
                           "in MetacatServlet.handleExportAction: " +
1021
                           ioe.getMessage(), 30);
1022
     }//catch
1023

    
1024
      MetaCatUtil.debugMessage("Error in MetacatServlet.handleReadInlineDataAction: "
1025
                                + e.getMessage(), 30);
1026

    
1027
    }//catch
1028

    
1029
  }//handleReadInlineDataAction
1030

    
1031
  /*
1032
   * Get the nodeid from xml_nodes for the inlinedataid
1033
   */
1034
  private long getInlineDataNodeId(String inLineDataId, String docId)
1035
                                   throws SQLException
1036
  {
1037
    long nodeId = 0;
1038
    String INLINE = "inline";
1039
    boolean hasRow;
1040
    PreparedStatement pStmt = null;
1041
    DBConnection conn = null;
1042
    int serialNumber = -1;
1043
    String sql ="SELECT nodeid FROM xml_nodes WHERE docid=? AND nodedata=? " +
1044
                "AND nodetype='TEXT' AND parentnodeid IN " +
1045
                "(SELECT nodeid FROM xml_nodes WHERE docid=? AND " +
1046
                "nodetype='ELEMENT' AND nodename='" + INLINE + "')";
1047

    
1048
    try
1049
    {
1050
      //check out DBConnection
1051
      conn=DBConnectionPool.getDBConnection("AccessControlList.isAllowFirst");
1052
      serialNumber=conn.getCheckOutSerialNumber();
1053

    
1054
      pStmt = conn.prepareStatement(sql);
1055
      //bind value
1056
      pStmt.setString(1, docId);//docid
1057
      pStmt.setString(2, inLineDataId);//inlinedataid
1058
      pStmt.setString(3, docId);
1059
      // excute query
1060
      pStmt.execute();
1061
      ResultSet rs = pStmt.getResultSet();
1062
      hasRow=rs.next();
1063
      // get result
1064
      if (hasRow)
1065
      {
1066
        nodeId = rs.getLong(1);
1067
      }//if
1068

    
1069
    }//try
1070
    catch (SQLException e)
1071
    {
1072
      throw e;
1073
    }
1074
    finally
1075
    {
1076
      try
1077
      {
1078
        pStmt.close();
1079
      }
1080
      finally
1081
      {
1082
        DBConnectionPool.returnDBConnection(conn, serialNumber);
1083
      }
1084
    }
1085
    MetaCatUtil.debugMessage("The nodeid for inlinedataid " + inLineDataId +
1086
                             " is: "+nodeId, 35);
1087
    return nodeId;
1088
  }
1089

    
1090

    
1091

    
1092
  // READ SECTION
1093
  /**
1094
   * Handle the "read" request of metadata/data files from Metacat
1095
   * or any files from Internet;
1096
   * transformed metadata XML document into HTML presentation if requested;
1097
   * zip files when more than one were requested.
1098
   *
1099
   * @param params the Hashtable of HTTP request parameters
1100
   * @param response the HTTP response object linked to the client
1101
   * @param user the username sent the request
1102
   * @param groups the user's groupnames
1103
   */
1104
  private void handleReadAction(Hashtable params, HttpServletResponse response,
1105
                                String user, String passWord, String[] groups)
1106
  {
1107
    ServletOutputStream out = null;
1108
    ZipOutputStream zout = null;
1109
    PrintWriter pw = null;
1110
    boolean zip = false;
1111
    boolean withInlineData = true;
1112

    
1113
    try {
1114
      String[] docs = new String[0];
1115
      String docid = "";
1116
      String qformat = "";
1117
      String abstrpath = null;
1118

    
1119
      // read the params
1120
      if (params.containsKey("docid")) {
1121
        docs = (String[])params.get("docid");
1122
      }
1123
      if (params.containsKey("qformat")) {
1124
        qformat = ((String[])params.get("qformat"))[0];
1125
      }
1126
      // the param for only metadata (eml)
1127
      if (params.containsKey("inlinedata"))
1128
      {
1129

    
1130
        String inlineData = ((String[])params.get("inlinedata"))[0];
1131
        if (inlineData.equalsIgnoreCase("false"))
1132
        {
1133
          withInlineData = false;
1134
        }
1135
      }
1136
      if ( (docs.length > 1) || qformat.equals("zip") ) {
1137
        zip = true;
1138
        out = response.getOutputStream();
1139
        response.setContentType("application/zip"); //MIME type
1140
        zout = new ZipOutputStream(out);
1141
      }
1142
      // go through the list of docs to read
1143
      for (int i=0; i < docs.length; i++ ) {
1144
        try {
1145

    
1146
          URL murl = new URL(docs[i]);
1147
          Hashtable murlQueryStr = util.parseQuery(murl.getQuery());
1148
          // case docid="http://.../?docid=aaa"
1149
          // or docid="metacat://.../?docid=bbb"
1150
          if (murlQueryStr.containsKey("docid")) {
1151
            // get only docid, eliminate the rest
1152
            docid = (String)murlQueryStr.get("docid");
1153
            if ( zip ) {
1154
              addDocToZip(docid, zout, user, groups);
1155
            } else {
1156
              readFromMetacat(response, docid, qformat, abstrpath,
1157
                              user, groups, zip, zout, withInlineData, params);
1158
            }
1159

    
1160
          // case docid="http://.../filename"
1161
          } else {
1162
            docid = docs[i];
1163
            if ( zip ) {
1164
              addDocToZip(docid, zout, user, groups);
1165
            } else {
1166
              readFromURLConnection(response, docid);
1167
            }
1168
          }
1169

    
1170
        // case docid="ccc"
1171
        } catch (MalformedURLException mue) {
1172
          docid = docs[i];
1173
          if ( zip ) {
1174
            addDocToZip(docid, zout, user, groups);
1175
          } else {
1176
            readFromMetacat(response, docid, qformat, abstrpath,
1177
                            user, groups, zip, zout, withInlineData, params);
1178
          }
1179
        }
1180

    
1181
      } /* end for */
1182

    
1183
      if ( zip ) {
1184
        zout.finish(); //terminate the zip file
1185
        zout.close();  //close the zip stream
1186
      }
1187

    
1188

    
1189
    }
1190
    // To handle doc not found exception
1191
    catch (McdbDocNotFoundException notFoundE)
1192
    {
1193
      // the docid which didn't be found
1194
      String notFoundDocId = notFoundE.getUnfoundDocId();
1195
      String notFoundRevision = notFoundE.getUnfoundRevision();
1196
      MetaCatUtil.debugMessage("Missed id: "+ notFoundDocId, 30);
1197
      MetaCatUtil.debugMessage("Missed rev: "+ notFoundRevision, 30);
1198
      try
1199
      {
1200
        // read docid from remote server
1201
        readFromRemoteMetaCat(response, notFoundDocId, notFoundRevision,
1202
                                              user, passWord, out, zip, zout);
1203
        // Close zout outputstream
1204
        if ( zout != null)
1205
        {
1206
          zout.close();
1207
        }
1208
        // close output stream
1209
        if (out != null)
1210
        {
1211
          out.close();
1212
        }
1213

    
1214
      }//try
1215
      catch ( Exception exc)
1216
      {
1217
        MetaCatUtil.debugMessage("Erorr in MetacatServlet.hanldReadAction: "+
1218
                                      exc.getMessage(), 30);
1219
        try
1220
        {
1221
          if (out != null)
1222
          {
1223
            response.setContentType("text/xml");
1224
            // Send back error message by printWriter
1225
            pw = new PrintWriter(out);
1226
            pw.println("<?xml version=\"1.0\"?>");
1227
            pw.println("<error>");
1228
            pw.println(notFoundE.getMessage());
1229
            pw.println("</error>");
1230
            pw.close();
1231
            out.close();
1232

    
1233
          }
1234
          else
1235
          {
1236
           response.setContentType("text/xml"); //MIME type
1237
           // Send back error message if out = null
1238
           if (pw == null)
1239
           {
1240
             // If pw is null, open the respnose
1241
            pw = response.getWriter();
1242
           }
1243
           pw.println("<?xml version=\"1.0\"?>");
1244
           pw.println("<error>");
1245
           pw.println(notFoundE.getMessage());
1246
           pw.println("</error>");
1247
           pw.close();
1248
        }
1249
        // close zout
1250
        if ( zout != null )
1251
        {
1252
          zout.close();
1253
        }
1254
        }//try
1255
        catch (IOException ie)
1256
        {
1257
          MetaCatUtil.debugMessage("Problem with the servlet output " +
1258
                           "in MetacatServlet.handleReadAction: " +
1259
                           ie.getMessage(), 30);
1260
        }//cathch
1261
      }//catch
1262
    }// catch McdbDocNotFoundException
1263
    catch (Exception e)
1264
    {
1265
      try {
1266

    
1267
        if (out != null) {
1268
            response.setContentType("text/xml"); //MIME type
1269
            pw = new PrintWriter(out);
1270
            pw.println("<?xml version=\"1.0\"?>");
1271
            pw.println("<error>");
1272
            pw.println(e.getMessage());
1273
            pw.println("</error>");
1274
            pw.close();
1275
            out.close();
1276
        }
1277
        else
1278
        {
1279
           response.setContentType("text/xml"); //MIME type
1280
           // Send back error message if out = null
1281
           if ( pw == null)
1282
           {
1283
            pw = response.getWriter();
1284
           }
1285
           pw.println("<?xml version=\"1.0\"?>");
1286
           pw.println("<error>");
1287
           pw.println(e.getMessage());
1288
           pw.println("</error>");
1289
           pw.close();
1290

    
1291
        }
1292
        // Close zip output stream
1293
        if ( zout != null ) { zout.close(); }
1294

    
1295
      } catch (IOException ioe) {
1296
        MetaCatUtil.debugMessage("Problem with the servlet output " +
1297
                           "in MetacatServlet.handleReadAction: " +
1298
                           ioe.getMessage(), 30);
1299
        ioe.printStackTrace(System.out);
1300

    
1301
      }
1302

    
1303
      MetaCatUtil.debugMessage("Error in MetacatServlet.handleReadAction: " +
1304
                               e.getMessage(), 30);
1305
      //e.printStackTrace(System.out);
1306
    }
1307

    
1308
  }
1309

    
1310
  // read metadata or data from Metacat
1311
  private void readFromMetacat(HttpServletResponse response, String docid,
1312
                               String qformat, String abstrpath, String user,
1313
                               String[] groups, boolean zip,
1314
                               ZipOutputStream zout, boolean withInlineData,
1315
                               Hashtable params)
1316
               throws ClassNotFoundException, IOException, SQLException,
1317
                      McdbException, Exception
1318
  {
1319

    
1320
    try {
1321

    
1322

    
1323
      DocumentImpl doc = new DocumentImpl(docid);
1324

    
1325
      //check the permission for read
1326
      if (!doc.hasReadPermission(user, groups, docid))
1327
      {
1328
        Exception e = new Exception("User " + user + " does not have permission"
1329
                       +" to read the document with the docid " + docid);
1330

    
1331
        throw e;
1332
      }
1333

    
1334
      if ( doc.getRootNodeID() == 0 ) {
1335
        // this is data file
1336
        String filepath = util.getOption("datafilepath");
1337
        if(!filepath.endsWith("/")) {
1338
          filepath += "/";
1339
        }
1340
        String filename = filepath + docid;
1341
        FileInputStream fin = null;
1342
        fin = new FileInputStream(filename);
1343

    
1344
        //MIME type
1345
        String contentType = getServletContext().getMimeType(filename);
1346
        if (contentType == null)
1347
        {
1348
          ContentTypeProvider provider = new ContentTypeProvider(docid);
1349
          contentType = provider.getContentType();
1350
          MetaCatUtil.debugMessage("Final contenttype is: "+ contentType, 30);
1351
        }
1352

    
1353
        response.setContentType(contentType);
1354
        // if we decide to use "application/octet-stream" for all data returns
1355
        // response.setContentType("application/octet-stream");
1356

    
1357
        try {
1358

    
1359
          ServletOutputStream out = response.getOutputStream();
1360
          byte[] buf = new byte[4 * 1024]; // 4K buffer
1361
          int b = fin.read(buf);
1362
          while (b != -1) {
1363
            out.write(buf, 0, b);
1364
            b = fin.read(buf);
1365
          }
1366
        } finally {
1367
          if (fin != null) fin.close();
1368
        }
1369

    
1370
      } else {
1371
        // this is metadata doc
1372
        if ( qformat.equals("xml") ) {
1373

    
1374
          // set content type first
1375
          response.setContentType("text/xml");   //MIME type
1376
          PrintWriter out = response.getWriter();
1377
          doc.toXml(out, user, groups, withInlineData);
1378
        } else {
1379
          response.setContentType("text/html");  //MIME type
1380
          PrintWriter out = response.getWriter();
1381

    
1382
          // Look up the document type
1383
          String doctype = doc.getDoctype();
1384
          // Transform the document to the new doctype
1385
          DBTransform dbt = new DBTransform();
1386
          dbt.transformXMLDocument(doc.toString(user, groups, withInlineData),
1387
                                   doctype,"-//W3C//HTML//EN",
1388
                                   qformat, out, params);
1389
        }
1390

    
1391
      }
1392
    }
1393
    catch (Exception except)
1394
    {
1395
      throw except;
1396

    
1397
    }
1398

    
1399
  }
1400

    
1401
  // read data from URLConnection
1402
  private void readFromURLConnection(HttpServletResponse response, String docid)
1403
               throws IOException, MalformedURLException
1404
  {
1405
    ServletOutputStream out = response.getOutputStream();
1406
    String contentType = getServletContext().getMimeType(docid); //MIME type
1407
    if (contentType == null) {
1408
      if (docid.endsWith(".xml")) {
1409
        contentType="text/xml";
1410
      } else if (docid.endsWith(".css")) {
1411
        contentType="text/css";
1412
      } else if (docid.endsWith(".dtd")) {
1413
        contentType="text/plain";
1414
      } else if (docid.endsWith(".xsd")) {
1415
        contentType="text/xml";
1416
      } else if (docid.endsWith("/")) {
1417
        contentType="text/html";
1418
      } else {
1419
        File f = new File(docid);
1420
        if ( f.isDirectory() ) {
1421
          contentType="text/html";
1422
        } else {
1423
          contentType="application/octet-stream";
1424
        }
1425
      }
1426
    }
1427
    response.setContentType(contentType);
1428
    // if we decide to use "application/octet-stream" for all data returns
1429
    // response.setContentType("application/octet-stream");
1430

    
1431
    // this is http url
1432
    URL url = new URL(docid);
1433
    BufferedInputStream bis = null;
1434
    try {
1435
      bis = new BufferedInputStream(url.openStream());
1436
      byte[] buf = new byte[4 * 1024]; // 4K buffer
1437
      int b = bis.read(buf);
1438
      while (b != -1) {
1439
        out.write(buf, 0, b);
1440
        b = bis.read(buf);
1441
      }
1442
    } finally {
1443
      if (bis != null) bis.close();
1444
    }
1445

    
1446
  }
1447

    
1448
  // read file/doc and write to ZipOutputStream
1449
  private void addDocToZip(String docid, ZipOutputStream zout,
1450
                              String user, String[] groups)
1451
               throws ClassNotFoundException, IOException, SQLException,
1452
                      McdbException, Exception
1453
  {
1454
    byte[] bytestring = null;
1455
    ZipEntry zentry = null;
1456

    
1457
    try {
1458
      URL url = new URL(docid);
1459

    
1460
      // this http url; read from URLConnection; add to zip
1461
      zentry = new ZipEntry(docid);
1462
      zout.putNextEntry(zentry);
1463
      BufferedInputStream bis = null;
1464
      try {
1465
        bis = new BufferedInputStream(url.openStream());
1466
        byte[] buf = new byte[4 * 1024]; // 4K buffer
1467
        int b = bis.read(buf);
1468
        while(b != -1) {
1469
          zout.write(buf, 0, b);
1470
          b = bis.read(buf);
1471
        }
1472
      } finally {
1473
        if (bis != null) bis.close();
1474
      }
1475
      zout.closeEntry();
1476

    
1477
    } catch (MalformedURLException mue) {
1478

    
1479
      // this is metacat doc (data file or metadata doc)
1480

    
1481
      try {
1482

    
1483
        DocumentImpl doc = new DocumentImpl(docid);
1484

    
1485
        //check the permission for read
1486
        if (!doc.hasReadPermission(user, groups, docid))
1487
        {
1488
          Exception e = new Exception("User " + user + " does not have "
1489
                    +"permission to read the document with the docid " + docid);
1490

    
1491
          throw e;
1492
        }
1493

    
1494
        if ( doc.getRootNodeID() == 0 ) {
1495
          // this is data file; add file to zip
1496
          String filepath = util.getOption("datafilepath");
1497
          if(!filepath.endsWith("/")) {
1498
            filepath += "/";
1499
          }
1500
          String filename = filepath + docid;
1501
          FileInputStream fin = null;
1502
          fin = new FileInputStream(filename);
1503
          try {
1504

    
1505
            zentry = new ZipEntry(docid);
1506
            zout.putNextEntry(zentry);
1507
            byte[] buf = new byte[4 * 1024]; // 4K buffer
1508
            int b = fin.read(buf);
1509
            while (b != -1) {
1510
              zout.write(buf, 0, b);
1511
              b = fin.read(buf);
1512
            }
1513
          } finally {
1514
            if (fin != null) fin.close();
1515
          }
1516
          zout.closeEntry();
1517

    
1518
        } else {
1519
          // this is metadata doc; add doc to zip
1520
          bytestring = doc.toString().getBytes();
1521
          zentry = new ZipEntry(docid + ".xml");
1522
          zentry.setSize(bytestring.length);
1523
          zout.putNextEntry(zentry);
1524
          zout.write(bytestring, 0, bytestring.length);
1525
          zout.closeEntry();
1526
        }
1527
      } catch (Exception except) {
1528
        throw except;
1529

    
1530
      }
1531

    
1532
    }
1533

    
1534
  }
1535
  
1536
  /**
1537
   * If metacat couldn't find a data file or document locally, it will read this
1538
   * docid from its home server. This is for the replication feature
1539
   */
1540
  private void readFromRemoteMetaCat(HttpServletResponse response, String docid,
1541
                     String rev, String user, String password,
1542
                     ServletOutputStream out, boolean zip, ZipOutputStream zout)
1543
                        throws Exception
1544
 {
1545
   // Create a object of RemoteDocument, "" is for zipEntryPath
1546
   RemoteDocument remoteDoc =
1547
                        new RemoteDocument (docid, rev,user, password, "");
1548
   String docType = remoteDoc.getDocType();
1549
   // Only read data file
1550
   if (docType.equals("BIN"))
1551
   {
1552
    // If it is zip format
1553
    if (zip)
1554
    {
1555
      remoteDoc.readDocumentFromRemoteServerByZip(zout);
1556
    }//if
1557
    else
1558
    {
1559
      if (out == null)
1560
      {
1561
        out = response.getOutputStream();
1562
      }//if
1563
      response.setContentType("application/octet-stream");
1564
      remoteDoc.readDocumentFromRemoteServer(out);
1565
    }//else (not zip)
1566
   }//if doctype=bin
1567
   else
1568
   {
1569
     throw new Exception("Docid: "+docid+"."+rev+" couldn't find");
1570
   }//else
1571
 }//readFromRemoteMetaCat
1572

    
1573
  // END OF READ SECTION
1574

    
1575

    
1576

    
1577
  // INSERT/UPDATE SECTION
1578
  /**
1579
   * Handle the database putdocument request and write an XML document
1580
   * to the database connection
1581
   */
1582
  private void handleInsertOrUpdateAction(PrintWriter out, Hashtable params,
1583
               String user, String[] groups) {
1584

    
1585
    DBConnection dbConn = null;
1586
    int serialNumber = -1;
1587

    
1588
    try {
1589
      // Get the document indicated
1590
      String[] doctext = (String[])params.get("doctext");
1591

    
1592
      String pub = null;
1593
      if (params.containsKey("public")) {
1594
        pub = ((String[])params.get("public"))[0];
1595
      }
1596

    
1597
      StringReader dtd = null;
1598
      if (params.containsKey("dtdtext")) {
1599
        String[] dtdtext = (String[])params.get("dtdtext");
1600
        try {
1601
          if ( !dtdtext[0].equals("") ) {
1602
            dtd = new StringReader(dtdtext[0]);
1603
          }
1604
        } catch (NullPointerException npe) {}
1605
      }
1606

    
1607
      StringReader xml = new StringReader(doctext[0]);
1608
      boolean validate = false;
1609
      DocumentImplWrapper documentWrapper = null;
1610
      try {
1611
        // look inside XML Document for <!DOCTYPE ... PUBLIC/SYSTEM ... >
1612
        // in order to decide whether to use validation parser
1613
        validate = needDTDValidation(xml);
1614
        if (validate)
1615
        {
1616
          // set a dtd base validation parser
1617
          String rule = DocumentImpl.DTD;
1618
          documentWrapper = new DocumentImplWrapper(rule, validate);
1619
        }
1620
        else if (needSchemaValidation(xml))
1621
        {
1622
          // for eml2
1623
          if (needEml2Validation(xml))
1624
          {
1625
             // set eml2 base validation parser
1626
            String rule = DocumentImpl.EML2;
1627
            // using emlparser to check id validation
1628
            EMLParser parser = new EMLParser(doctext[0]);
1629
            documentWrapper = new DocumentImplWrapper(rule, true);
1630
          }
1631
          else
1632
          {
1633
            // set schema base validation parser
1634
            String rule = DocumentImpl.SCHEMA;
1635
            documentWrapper = new DocumentImplWrapper(rule, true);
1636
          }
1637
        }
1638
        else
1639
        {
1640
          documentWrapper = new DocumentImplWrapper("", false);
1641
        }
1642

    
1643
        String[] action = (String[])params.get("action");
1644
        String[] docid = (String[])params.get("docid");
1645
        String newdocid = null;
1646

    
1647
        String doAction = null;
1648
        if (action[0].equals("insert")) {
1649
          doAction = "INSERT";
1650
        } else if (action[0].equals("update")) {
1651
          doAction = "UPDATE";
1652
        }
1653

    
1654
        try
1655
        {
1656
          // get a connection from the pool
1657
          dbConn=DBConnectionPool.
1658
                  getDBConnection("MetaCatServlet.handleInsertOrUpdateAction");
1659
          serialNumber=dbConn.getCheckOutSerialNumber();
1660

    
1661
           // write the document to the database
1662
          try
1663
          {
1664
            String accNumber = docid[0];
1665
            MetaCatUtil.debugMessage(""+ doAction + " " + accNumber +"...", 10);
1666
            if (accNumber.equals(""))
1667
            {
1668
              accNumber = null;
1669
            }//if
1670
            newdocid = documentWrapper.write(dbConn, xml, pub, dtd, doAction,
1671
                                          accNumber, user, groups);
1672

    
1673
          }//try
1674
          catch (NullPointerException npe)
1675
          {
1676
            newdocid = documentWrapper.write(dbConn, xml, pub, dtd, doAction,
1677
                                          null, user, groups);
1678
          }//catch
1679

    
1680
        }//try
1681
        finally
1682
        {
1683
          // Return db connection
1684
          DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1685
        }
1686

    
1687
        // set content type and other response header fields first
1688
        //response.setContentType("text/xml");
1689
        out.println("<?xml version=\"1.0\"?>");
1690
        out.println("<success>");
1691
        out.println("<docid>" + newdocid + "</docid>");
1692
        out.println("</success>");
1693

    
1694
      }
1695
      catch (NullPointerException npe)
1696
      {
1697
        //response.setContentType("text/xml");
1698
        out.println("<?xml version=\"1.0\"?>");
1699
        out.println("<error>");
1700
        out.println(npe.getMessage());
1701
        out.println("</error>");
1702
      }
1703
    }
1704
    catch (Exception e)
1705
    {
1706
      //response.setContentType("text/xml");
1707
      out.println("<?xml version=\"1.0\"?>");
1708
      out.println("<error>");
1709
      out.println(e.getMessage());
1710
      out.println("</error>");
1711
    }
1712
  }
1713

    
1714
  /**
1715
   * Parse XML Document to look for <!DOCTYPE ... PUBLIC/SYSTEM ... >
1716
   * in order to decide whether to use validation parser
1717
   */
1718
  private static boolean needDTDValidation(StringReader xmlreader) throws 
1719
                                                             IOException 
1720
  {
1721

    
1722
    
1723
    StringBuffer cbuff = new StringBuffer();
1724
    java.util.Stack st = new java.util.Stack();
1725
    boolean validate = false;
1726
    int c;
1727
    int inx;
1728

    
1729
    // read from the stream until find the keywords
1730
    while ( (st.empty() || st.size()<4) && ((c = xmlreader.read()) != -1) ) {
1731
      cbuff.append((char)c);
1732

    
1733
      // "<!DOCTYPE" keyword is found; put it in the stack
1734
      if ( (inx = cbuff.toString().indexOf("<!DOCTYPE")) != -1 ) {
1735
        cbuff = new StringBuffer();
1736
        st.push("<!DOCTYPE");
1737
      }
1738
      // "PUBLIC" keyword is found; put it in the stack
1739
      if ( (inx = cbuff.toString().indexOf("PUBLIC")) != -1 ) {
1740
        cbuff = new StringBuffer();
1741
        st.push("PUBLIC");
1742
      }
1743
      // "SYSTEM" keyword is found; put it in the stack
1744
      if ( (inx = cbuff.toString().indexOf("SYSTEM")) != -1 ) {
1745
        cbuff = new StringBuffer();
1746
        st.push("SYSTEM");
1747
      }
1748
      // ">" character is found; put it in the stack
1749
      // ">" is found twice: fisrt from <?xml ...?>
1750
      // and second from <!DOCTYPE ... >
1751
      if ( (inx = cbuff.toString().indexOf(">")) != -1 ) {
1752
        cbuff = new StringBuffer();
1753
        st.push(">");
1754
      }
1755
    }
1756

    
1757
    // close the stream
1758
    xmlreader.reset();
1759

    
1760
    // check the stack whether it contains the keywords:
1761
    // "<!DOCTYPE", "PUBLIC" or "SYSTEM", and ">" in this order
1762
    if ( st.size() == 4 ) {
1763
      if ( ((String)st.pop()).equals(">") &&
1764
           ( ((String)st.peek()).equals("PUBLIC") |
1765
             ((String)st.pop()).equals("SYSTEM") ) &&
1766
           ((String)st.pop()).equals("<!DOCTYPE") )  {
1767
        validate = true;
1768
      }
1769
    }
1770

    
1771
    MetaCatUtil.debugMessage("Validation for dtd is " + validate, 10);
1772
    return validate;
1773
  }
1774
  // END OF INSERT/UPDATE SECTION
1775

    
1776
  /* check if the xml string contains key words to specify schema loocation*/
1777
  private boolean needSchemaValidation(StringReader xml) throws IOException
1778
  {
1779
    boolean needSchemaValidate =false;
1780
    if (xml == null)
1781
    {
1782
      MetaCatUtil.debugMessage("Validation for schema is " +
1783
                               needSchemaValidate, 10);
1784
      return needSchemaValidate;
1785
    }
1786
    System.out.println("before get target line");
1787
    String targetLine = getSchemaLine(xml);
1788
    System.out.println("before get target line");
1789
    // to see if the second line contain some keywords
1790
    if (targetLine != null && (targetLine.indexOf(SCHEMALOCATIONKEYWORD) != -1||
1791
             targetLine.indexOf(NONAMESPACELOCATION) != -1 ))
1792
    {
1793
      // if contains schema location key word, should be validate
1794
      needSchemaValidate = true;
1795
    }
1796

    
1797
    MetaCatUtil.debugMessage("Validation for schema is " +
1798
                             needSchemaValidate, 10);
1799
    return needSchemaValidate;
1800

    
1801
  }
1802

    
1803
   /* check if the xml string contains key words to specify schema loocation*/
1804
  private boolean needEml2Validation(StringReader xml) throws IOException
1805
  {
1806
    boolean needEml2Validate =false;
1807
    String emlNameSpace =DocumentImpl.EMLNAMESPACE;
1808
    String schemaLocationContent = null;
1809
    if (xml == null)
1810
    {
1811
      MetaCatUtil.debugMessage("Validation for schema is " +
1812
                               needEml2Validate, 10);
1813
      return needEml2Validate;
1814
    }
1815
    String targetLine = getSchemaLine(xml);
1816

    
1817
    if (targetLine != null)
1818
    {
1819
      
1820
      int startIndex = targetLine.indexOf(SCHEMALOCATIONKEYWORD);
1821
      int start = 1;
1822
      int end   = 1;
1823
      String schemaLocation = null;
1824
      int count = 0;
1825
      if (startIndex != -1)
1826
      {
1827
        for ( int i=startIndex; i<targetLine.length(); i++)
1828
        {
1829
          if (targetLine.charAt(i) =='"')
1830
          {
1831
            count ++;
1832
          }
1833
          if (targetLine.charAt(i) =='"' && count == 1)
1834
          {
1835
            start = i;
1836
          }
1837
          if (targetLine.charAt(i) =='"' && count == 2)
1838
          {
1839
            end = i;
1840
            break;
1841
          }
1842
        }
1843
      }
1844
      schemaLocation = targetLine.substring(start+1, end);
1845
      MetaCatUtil.debugMessage("schemaLocation in xml is: "+schemaLocation, 30);
1846
      if ( schemaLocation.indexOf(emlNameSpace) != -1)
1847
      {
1848
        needEml2Validate = true;
1849
      }
1850
    }
1851

    
1852
    MetaCatUtil.debugMessage("Validation for eml is " +
1853
                             needEml2Validate, 10);
1854
    return needEml2Validate;
1855

    
1856
  }
1857

    
1858
  private String getSchemaLine(StringReader xml) throws IOException
1859
  {
1860
    // find the line
1861
    String secondLine = null;
1862
    int count =0;
1863
    int endIndex = 0;
1864
    int startIndex = 0;
1865
    final int TARGETNUM = 2;
1866
    StringBuffer buffer = new StringBuffer();
1867
    boolean comment =false;
1868
    char thirdPreviousCharacter = '?';
1869
    char secondPreviousCharacter ='?';
1870
    char previousCharacter = '?';
1871
    char currentCharacter = '?';
1872
    
1873
    while ( (currentCharacter = (char) xml.read()) != -1)
1874
    {
1875
      //in a comment
1876
      if (currentCharacter =='-' && previousCharacter == '-'  && 
1877
          secondPreviousCharacter =='!' && thirdPreviousCharacter == '<')
1878
      {
1879
        comment = true;
1880
      }
1881
      //out of comment
1882
      if (comment && currentCharacter == '>' && previousCharacter == '-' && 
1883
          secondPreviousCharacter =='-')
1884
      {
1885
         comment = false;
1886
      }
1887
      
1888
      //this is not comment
1889
      if (currentCharacter !='!' && previousCharacter == '<' && !comment)
1890
      {
1891
        count ++;
1892
      }
1893
      // get target line
1894
      if (count == TARGETNUM && currentCharacter !='>')
1895
      {
1896
        buffer.append(currentCharacter);
1897
      }
1898
      if (count == TARGETNUM && currentCharacter == '>')
1899
      {
1900
          break;
1901
      }
1902
      thirdPreviousCharacter = secondPreviousCharacter;
1903
      secondPreviousCharacter = previousCharacter;
1904
      previousCharacter = currentCharacter;
1905
      
1906
    }
1907
    secondLine = buffer.toString();
1908
    MetaCatUtil.debugMessage("the second line string is: "+secondLine, 25);
1909
    xml.reset();
1910
    return secondLine;
1911
  }
1912

    
1913
  // DELETE SECTION
1914
  /**
1915
   * Handle the database delete request and delete an XML document
1916
   * from the database connection
1917
   */
1918
  private void handleDeleteAction(PrintWriter out, Hashtable params,
1919
               HttpServletResponse response, String user, String[] groups) {
1920

    
1921
    String[] docid = (String[])params.get("docid");
1922

    
1923
    // delete the document from the database
1924
    try {
1925

    
1926
                                      // NOTE -- NEED TO TEST HERE
1927
                                      // FOR EXISTENCE OF DOCID PARAM
1928
                                      // BEFORE ACCESSING ARRAY
1929
      try {
1930
        DocumentImpl.delete(docid[0], user, groups);
1931
        response.setContentType("text/xml");
1932
        out.println("<?xml version=\"1.0\"?>");
1933
        out.println("<success>");
1934
        out.println("Document deleted.");
1935
        out.println("</success>");
1936
      } catch (AccessionNumberException ane) {
1937
        response.setContentType("text/xml");
1938
        out.println("<?xml version=\"1.0\"?>");
1939
        out.println("<error>");
1940
        out.println("Error deleting document!!!");
1941
        out.println(ane.getMessage());
1942
        out.println("</error>");
1943
      }
1944
    } catch (Exception e) {
1945
      response.setContentType("text/xml");
1946
      out.println("<?xml version=\"1.0\"?>");
1947
      out.println("<error>");
1948
      out.println(e.getMessage());
1949
      out.println("</error>");
1950
    }
1951
  }
1952
  // END OF DELETE SECTION
1953

    
1954
  // VALIDATE SECTION
1955
  /**
1956
   * Handle the validation request and return the results to the requestor
1957
   */
1958
  private void handleValidateAction(PrintWriter out, Hashtable params) {
1959

    
1960
    // Get the document indicated
1961
    String valtext = null;
1962
    DBConnection dbConn = null;
1963
    int serialNumber = -1;
1964

    
1965
    try {
1966
      valtext = ((String[])params.get("valtext"))[0];
1967
    } catch (Exception nullpe) {
1968

    
1969

    
1970
      String docid = null;
1971
      try {
1972
        // Find the document id number
1973
        docid = ((String[])params.get("docid"))[0];
1974

    
1975

    
1976
        // Get the document indicated from the db
1977
        DocumentImpl xmldoc = new DocumentImpl(docid);
1978
        valtext = xmldoc.toString();
1979

    
1980
      } catch (NullPointerException npe) {
1981

    
1982
        out.println("<error>Error getting document ID: " + docid + "</error>");
1983
        //if ( conn != null ) { util.returnConnection(conn); }
1984
        return;
1985
      } catch (Exception e) {
1986

    
1987
        out.println(e.getMessage());
1988
      }
1989
    }
1990

    
1991

    
1992
    try {
1993
      // get a connection from the pool
1994
      dbConn=DBConnectionPool.
1995
                  getDBConnection("MetaCatServlet.handleValidateAction");
1996
      serialNumber=dbConn.getCheckOutSerialNumber();
1997
      DBValidate valobj = new DBValidate(saxparser,dbConn);
1998
      boolean valid = valobj.validateString(valtext);
1999

    
2000
      // set content type and other response header fields first
2001

    
2002
      out.println(valobj.returnErrors());
2003

    
2004
    } catch (NullPointerException npe2) {
2005
      // set content type and other response header fields first
2006

    
2007
      out.println("<error>Error validating document.</error>");
2008
    } catch (Exception e) {
2009

    
2010
      out.println(e.getMessage());
2011
    } finally {
2012
      // Return db connection
2013
      DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2014
    }
2015
  }
2016
  // END OF VALIDATE SECTION
2017

    
2018
  // OTHER ACTION HANDLERS
2019

    
2020
  /**
2021
   * Handle "getrevsionanddoctype" action
2022
   * Given a docid, return it's current revision and doctype from data base
2023
   * The output is String look like "rev;doctype"
2024
   */
2025
  private void handleGetRevisionAndDocTypeAction(PrintWriter out,
2026
                                                              Hashtable params)
2027
  {
2028
    // To store doc parameter
2029
    String [] docs = new String[10];
2030
    // Store a single doc id
2031
    String givenDocId = null;
2032
    // Get docid from parameters
2033
    if (params.containsKey("docid"))
2034
    {
2035
      docs = (String[])params.get("docid");
2036
    }
2037
    // Get first docid form string array
2038
    givenDocId = docs[0];
2039

    
2040
    try
2041
    {
2042
      // Make sure there is a docid
2043
      if (givenDocId == null || givenDocId.equals(""))
2044
      {
2045
        throw new Exception("User didn't specify docid!");
2046
      }//if
2047

    
2048
      // Create a DBUtil object
2049
      DBUtil dbutil = new DBUtil();
2050
      // Get a rev and doctype
2051
      String revAndDocType =
2052
                dbutil.getCurrentRevisionAndDocTypeForGivenDocument(givenDocId);
2053
      out.println(revAndDocType);
2054

    
2055
    }//try
2056
    catch (Exception e)
2057
    {
2058
      // Handle exception
2059
      out.println("<?xml version=\"1.0\"?>");
2060
      out.println("<error>");
2061
      out.println(e.getMessage());
2062
      out.println("</error>");
2063
    }//catch
2064

    
2065
  }//handleGetRevisionAndDocTypeAction
2066

    
2067
  /**
2068
   * Handle "getaccesscontrol" action.
2069
   * Read Access Control List from db connection in XML format
2070
   */
2071
  private void handleGetAccessControlAction(PrintWriter out, Hashtable params,
2072
                                       HttpServletResponse response,
2073
                                       String username, String[] groupnames) {
2074

    
2075
    DBConnection dbConn = null;
2076
    int serialNumber = -1;
2077
    String docid = ((String[])params.get("docid"))[0];
2078

    
2079
    try {
2080

    
2081
        // get connection from the pool
2082
        dbConn=DBConnectionPool.
2083
                 getDBConnection("MetaCatServlet.handleGetAccessControlAction");
2084
        serialNumber=dbConn.getCheckOutSerialNumber();
2085
        AccessControlList aclobj = new AccessControlList(dbConn);
2086
        String acltext = aclobj.getACL(docid, username, groupnames);
2087
        out.println(acltext);
2088

    
2089
    } catch (Exception e) {
2090
      out.println("<?xml version=\"1.0\"?>");
2091
      out.println("<error>");
2092
      out.println(e.getMessage());
2093
      out.println("</error>");
2094
    } finally {
2095
      // Retrun db connection to pool
2096
      DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2097
    }
2098

    
2099
  }
2100

    
2101
  /**
2102
   * Handle the "getprincipals" action.
2103
   * Read all principals from authentication scheme in XML format
2104
   */
2105
  private void handleGetPrincipalsAction(PrintWriter out, String user,
2106
                                         String password) {
2107

    
2108

    
2109
    try {
2110

    
2111

    
2112
        AuthSession auth = new AuthSession();
2113
        String principals = auth.getPrincipals(user, password);
2114
        out.println(principals);
2115

    
2116
    } catch (Exception e) {
2117
      out.println("<?xml version=\"1.0\"?>");
2118
      out.println("<error>");
2119
      out.println(e.getMessage());
2120
      out.println("</error>");
2121
    }
2122

    
2123
  }
2124

    
2125
  /**
2126
   * Handle "getdoctypes" action.
2127
   * Read all doctypes from db connection in XML format
2128
   */
2129
  private void handleGetDoctypesAction(PrintWriter out, Hashtable params,
2130
                                       HttpServletResponse response) {
2131

    
2132

    
2133
    try {
2134

    
2135

    
2136
        DBUtil dbutil = new DBUtil();
2137
        String doctypes = dbutil.readDoctypes();
2138
        out.println(doctypes);
2139

    
2140
    } catch (Exception e) {
2141
      out.println("<?xml version=\"1.0\"?>");
2142
      out.println("<error>");
2143
      out.println(e.getMessage());
2144
      out.println("</error>");
2145
    }
2146

    
2147
  }
2148

    
2149
  /**
2150
   * Handle the "getdtdschema" action.
2151
   * Read DTD or Schema file for a given doctype from Metacat catalog system
2152
   */
2153
  private void handleGetDTDSchemaAction(PrintWriter out, Hashtable params,
2154
                                        HttpServletResponse response) {
2155

    
2156

    
2157
    String doctype = null;
2158
    String[] doctypeArr = (String[])params.get("doctype");
2159

    
2160
    // get only the first doctype specified in the list of doctypes
2161
    // it could be done for all doctypes in that list
2162
    if (doctypeArr != null) {
2163
        doctype = ((String[])params.get("doctype"))[0];
2164
    }
2165

    
2166
    try {
2167

    
2168

    
2169
        DBUtil dbutil = new DBUtil();
2170
        String dtdschema = dbutil.readDTDSchema(doctype);
2171
        out.println(dtdschema);
2172

    
2173
    } catch (Exception e) {
2174
      out.println("<?xml version=\"1.0\"?>");
2175
      out.println("<error>");
2176
      out.println(e.getMessage());
2177
      out.println("</error>");
2178
    }
2179

    
2180
  }
2181

    
2182
  /**
2183
   * Handle the "getlastdocid" action.
2184
   * Get the latest docid with rev number from db connection in XML format
2185
   */
2186
  private void handleGetMaxDocidAction(PrintWriter out, Hashtable params,
2187
                                        HttpServletResponse response) {
2188

    
2189

    
2190
    String scope = ((String[])params.get("scope"))[0];
2191
    if (scope == null) {
2192
        scope = ((String[])params.get("username"))[0];
2193
    }
2194

    
2195
    try {
2196

    
2197

    
2198
        DBUtil dbutil = new DBUtil();
2199
        String lastDocid = dbutil.getMaxDocid(scope);
2200
        out.println("<?xml version=\"1.0\"?>");
2201
        out.println("<lastDocid>");
2202
        out.println("  <scope>" + scope + "</scope>");
2203
        out.println("  <docid>" + lastDocid + "</docid>");
2204
        out.println("</lastDocid>");
2205

    
2206
    } catch (Exception e) {
2207
      out.println("<?xml version=\"1.0\"?>");
2208
      out.println("<error>");
2209
      out.println(e.getMessage());
2210
      out.println("</error>");
2211
    }
2212

    
2213
  }
2214

    
2215
  /**
2216
   * Handle documents passed to metacat that are encoded using the
2217
   * "multipart/form-data" mime type.  This is typically used for uploading
2218
   * data files which may be binary and large.
2219
   */
2220
  private void handleMultipartForm(HttpServletRequest request,
2221
                                   HttpServletResponse response)
2222
  {
2223
    PrintWriter out = null;
2224
    String action = null;
2225

    
2226
    // Parse the multipart form, and save the parameters in a Hashtable and
2227
    // save the FileParts in a hashtable
2228

    
2229
    Hashtable params = new Hashtable();
2230
    Hashtable fileList = new Hashtable();
2231
    int sizeLimit = (new Integer(MetaCatUtil.getOption("datafilesizelimit")))
2232
                                                                   .intValue();
2233
    MetaCatUtil.debugMessage("The limit size of data file is: "+sizeLimit, 50);
2234

    
2235
    try {
2236
      // MBJ: need to put filesize limit in Metacat config (metacat.properties)
2237
      MultipartParser mp = new MultipartParser(request, sizeLimit*1024*1024);
2238
      Part part;
2239
      while ((part = mp.readNextPart()) != null) {
2240
        String name = part.getName();
2241

    
2242
        if (part.isParam()) {
2243
          // it's a parameter part
2244
          ParamPart paramPart = (ParamPart) part;
2245
          String value = paramPart.getStringValue();
2246
          params.put(name, value);
2247
          if (name.equals("action")) {
2248
            action = value;
2249
          }
2250
        } else if (part.isFile()) {
2251
          // it's a file part
2252
          FilePart filePart = (FilePart) part;
2253
          fileList.put(name, filePart);
2254

    
2255
          // Stop once the first file part is found, otherwise going onto the
2256
          // next part prevents access to the file contents.  So...for upload
2257
          // to work, the datafile must be the last part
2258
          break;
2259
        }
2260
      }
2261
    } catch (IOException ioe) {
2262
      try {
2263
        out = response.getWriter();
2264
      } catch (IOException ioe2) {
2265
        System.err.println("Fatal Error: couldn't get response output stream.");
2266
      }
2267
      out.println("<?xml version=\"1.0\"?>");
2268
      out.println("<error>");
2269
      out.println("Error: problem reading multipart data.");
2270
      out.println("</error>");
2271
    }
2272

    
2273
    // Get the session information
2274
    String username = null;
2275
    String password = null;
2276
    String[] groupnames = null;
2277
    String sess_id = null;
2278

    
2279
    // be aware of session expiration on every request
2280
    HttpSession sess = request.getSession(true);
2281
    if (sess.isNew()) {
2282
      // session expired or has not been stored b/w user requests
2283
      username = "public";
2284
      sess.setAttribute("username", username);
2285
    } else {
2286
      username = (String)sess.getAttribute("username");
2287
      password = (String)sess.getAttribute("password");
2288
      groupnames = (String[])sess.getAttribute("groupnames");
2289
      try {
2290
        sess_id = (String)sess.getId();
2291
      } catch(IllegalStateException ise) {
2292
        System.out.println("error in  handleMultipartForm: this shouldn't " +
2293
                           "happen: the session should be valid: " +
2294
                           ise.getMessage());
2295
      }
2296
    }
2297

    
2298
    // Get the out stream
2299
    try {
2300
          out = response.getWriter();
2301
        } catch (IOException ioe2) {
2302
          util.debugMessage("Fatal Error: couldn't get response "+
2303
                             "output stream.", 30);
2304
        }
2305

    
2306
    if ( action.equals("upload")) {
2307
      if (username != null &&  !username.equals("public")) {
2308
        handleUploadAction(request, out, params, fileList,
2309
                           username, groupnames);
2310
      } else {
2311

    
2312
        out.println("<?xml version=\"1.0\"?>");
2313
        out.println("<error>");
2314
        out.println("Permission denied for " + action);
2315
        out.println("</error>");
2316
      }
2317
    } else {
2318
      /*try {
2319
        out = response.getWriter();
2320
      } catch (IOException ioe2) {
2321
        System.err.println("Fatal Error: couldn't get response output stream.");
2322
      }*/
2323
      out.println("<?xml version=\"1.0\"?>");
2324
      out.println("<error>");
2325
      out.println("Error: action not registered.  Please report this error.");
2326
      out.println("</error>");
2327
    }
2328
    out.close();
2329
  }
2330

    
2331
  /**
2332
   * Handle the upload action by saving the attached file to disk and
2333
   * registering it in the Metacat db
2334
   */
2335
  private void handleUploadAction(HttpServletRequest request,
2336
                                  PrintWriter out,
2337
                                  Hashtable params, Hashtable fileList,
2338
                                  String username, String[] groupnames)
2339
  {
2340
    //PrintWriter out = null;
2341
    //Connection conn = null;
2342
    String action = null;
2343
    String docid = null;
2344

    
2345
    /*response.setContentType("text/xml");
2346
    try
2347
    {
2348
      out = response.getWriter();
2349
    }
2350
    catch (IOException ioe2)
2351
    {
2352
      System.err.println("Fatal Error: couldn't get response output stream.");
2353
    }*/
2354

    
2355
    if (params.containsKey("docid"))
2356
    {
2357
      docid = (String)params.get("docid");
2358
    }
2359

    
2360
    // Make sure we have a docid and datafile
2361
    if (docid != null && fileList.containsKey("datafile")) {
2362

    
2363
      // Get a reference to the file part of the form
2364
      FilePart filePart = (FilePart)fileList.get("datafile");
2365
      String fileName = filePart.getFileName();
2366
      MetaCatUtil.debugMessage("Uploading filename: " + fileName, 10);
2367

    
2368
      // Check if the right file existed in the uploaded data
2369
      if (fileName != null) {
2370

    
2371
        try
2372
        {
2373
           //MetaCatUtil.debugMessage("Upload datafile " + docid +"...", 10);
2374
           //If document get lock data file grant
2375
           if (DocumentImpl.getDataFileLockGrant(docid))
2376
           {
2377
              // register the file in the database (which generates an exception
2378
              //if the docid is not acceptable or other untoward things happen
2379
              DocumentImpl.registerDocument(fileName, "BIN", docid, username);
2380

    
2381
              // Save the data file to disk using "docid" as the name
2382
              dataDirectory.mkdirs();
2383
              File newFile = new File(dataDirectory, docid);
2384
              long size = filePart.writeTo(newFile);
2385

    
2386
              // Force replication this data file
2387
              // To data file, "insert" and update is same
2388
              // The fourth parameter is null. Because it is notification server
2389
              // and this method is in MetaCatServerlet. It is original command,
2390
              // not get force replication info from another metacat
2391
              ForceReplicationHandler frh = new ForceReplicationHandler
2392
                                                (docid, "insert", false, null);
2393

    
2394
              // set content type and other response header fields first
2395
              out.println("<?xml version=\"1.0\"?>");
2396
              out.println("<success>");
2397
              out.println("<docid>" + docid + "</docid>");
2398
              out.println("<size>" + size + "</size>");
2399
              out.println("</success>");
2400
          }//if
2401

    
2402
        } //try
2403
        catch (Exception e)
2404
        {
2405
          out.println("<?xml version=\"1.0\"?>");
2406
          out.println("<error>");
2407
          out.println(e.getMessage());
2408
          out.println("</error>");
2409
        }
2410

    
2411
      }
2412
      else
2413
      {
2414
        // the field did not contain a file
2415
        out.println("<?xml version=\"1.0\"?>");
2416
        out.println("<error>");
2417
        out.println("The uploaded data did not contain a valid file.");
2418
        out.println("</error>");
2419
      }
2420
    }
2421
    else
2422
    {
2423
      // Error bcse docid missing or file missing
2424
      out.println("<?xml version=\"1.0\"?>");
2425
      out.println("<error>");
2426
      out.println("The uploaded data did not contain a valid docid " +
2427
                  "or valid file.");
2428
      out.println("</error>");
2429
    }
2430
  }
2431

    
2432
  /*
2433
   * A method to handle set access action
2434
   */
2435
  private void handleSetAccessAction(PrintWriter out,
2436
                                   Hashtable params,
2437
                                   String username)
2438
  {
2439
    String [] docList        = null;
2440
    String [] principalList  = null;
2441
    String [] permissionList = null;
2442
    String [] permTypeList   = null;
2443
    String [] permOrderList  = null;
2444
    String permission = null;
2445
    String permType   = null;
2446
    String permOrder  = null;
2447
    Vector errorList  = new Vector();
2448
    String error      = null;
2449
    Vector successList = new Vector();
2450
    String success    = null;
2451

    
2452

    
2453
    // Get parameters
2454
    if (params.containsKey("docid"))
2455
    {
2456
      docList = (String[])params.get("docid");
2457
    }
2458
    if (params.containsKey("principal"))
2459
    {
2460
      principalList = (String[])params.get("principal");
2461
    }
2462
    if (params.containsKey("permission"))
2463
    {
2464
      permissionList = (String[])params.get("permission");
2465

    
2466
    }
2467
    if (params.containsKey("permType"))
2468
    {
2469
      permTypeList = (String[])params.get("permType");
2470

    
2471
    }
2472
    if (params.containsKey("permOrder"))
2473
    {
2474
      permOrderList = (String[])params.get("permOrder");
2475

    
2476
    }
2477

    
2478
    // Make sure the parameter is not null
2479
    if (docList == null || principalList == null || permTypeList == null ||
2480
        permissionList == null)
2481
    {
2482
      error = "Please check your parameter list, it should look like: "+
2483
              "?action=setaccess&docid=pipeline.1.1&principal=public" +
2484
              "&permission=read&permType=allow&permOrder=allowFirst";
2485
      errorList.addElement(error);
2486
      outputResponse(successList, errorList, out);
2487
      return;
2488
    }
2489

    
2490
    // Only select first element for permission, type and order
2491
    permission = permissionList[0];
2492
    permType = permTypeList[0];
2493
    if (permOrderList != null)
2494
    {
2495
       permOrder = permOrderList[0];
2496
    }
2497

    
2498
    // Get package doctype set
2499
    Vector packageSet =MetaCatUtil.getOptionList(
2500
                                    MetaCatUtil.getOption("packagedoctypeset"));
2501
    //debug
2502
    if (packageSet != null)
2503
    {
2504
      for (int i = 0; i<packageSet.size(); i++)
2505
      {
2506
        MetaCatUtil.debugMessage("doctype in package set: " +
2507
                              (String)packageSet.elementAt(i), 34);
2508
      }
2509
    }//if
2510

    
2511
    // handle every accessionNumber
2512
    for (int i=0; i <docList.length; i++)
2513
    {
2514
      String accessionNumber = docList[i];
2515
      String owner = null;
2516
      String publicId = null;
2517
      // Get document owner and public id
2518
      try
2519
      {
2520
        owner = getFieldValueForDoc(accessionNumber, "user_owner");
2521
        publicId = getFieldValueForDoc(accessionNumber, "doctype");
2522
      }//try
2523
      catch (Exception e)
2524
      {
2525
        MetaCatUtil.debugMessage("Error in handleSetAccessAction: " +
2526
                                  e.getMessage(), 30);
2527
        error = "Error in set access control for document - " + accessionNumber+
2528
                 e.getMessage();
2529
        errorList.addElement(error);
2530
        continue;
2531
      }
2532
      //check if user is the owner. Only owner can do owner
2533
      if (username == null || owner == null || !username.equals(owner))
2534
      {
2535
        error = "User - " + username + " does not have permission to set " +
2536
                "access control for docid - " + accessionNumber;
2537
        errorList.addElement(error);
2538
        continue;
2539
      }
2540

    
2541
      // If docid publicid is BIN data file or other beta4, 6 package document
2542
      // we could not do set access control. Because we don't want inconsistent
2543
      // to its access docuemnt
2544
      if (publicId!=null && packageSet!=null && packageSet.contains(publicId))
2545
      {
2546
        error = "Could not set access control to document "+ accessionNumber +
2547
                "because it is in a pakcage and it has a access file for it";
2548
        errorList.addElement(error);
2549
        continue;
2550
      }
2551

    
2552
      // for every principle
2553
      for (int j = 0; j<principalList.length; j++)
2554
      {
2555
        String principal = principalList[j];
2556
        try
2557
        {
2558
          //insert permission
2559
          AccessControlForSingleFile accessControl = new
2560
                           AccessControlForSingleFile(accessionNumber,
2561
                                    principal, permission, permType, permOrder);
2562
          accessControl.insertPermissions();
2563
          success = "Set access control to document "+ accessionNumber +
2564
                    " successfully";
2565
          successList.addElement(success);
2566
        }
2567
        catch (Exception ee)
2568
        {
2569
          MetaCatUtil.debugMessage("Erorr in handleSetAccessAction2: " +
2570
                                   ee.getMessage(), 30);
2571
          error = "Faild to set access control for document " +
2572
                  accessionNumber + " because " + ee.getMessage();
2573
          errorList.addElement(error);
2574
          continue;
2575
        }
2576
      }//for every principle
2577
    }//for every document
2578
    outputResponse(successList, errorList, out);
2579
  }//handleSetAccessAction
2580

    
2581

    
2582
  /*
2583
   * A method try to determin a docid's public id, if couldn't find null
2584
   * will be returned.
2585
   */
2586
  private String getFieldValueForDoc(String accessionNumber, String fieldName)
2587
                                      throws Exception
2588
  {
2589
    if (accessionNumber==null || accessionNumber.equals("") ||fieldName == null
2590
        || fieldName.equals(""))
2591
    {
2592
      throw new Exception("Docid or field name was not specified");
2593
    }
2594

    
2595
    PreparedStatement pstmt = null;
2596
    ResultSet rs = null;
2597
    String fieldValue = null;
2598
    String docId = null;
2599
    DBConnection conn = null;
2600
    int serialNumber = -1;
2601

    
2602
    // get rid of revision if access number has
2603
    docId = MetaCatUtil.getDocIdFromString(accessionNumber);
2604
    try
2605
    {
2606
      //check out DBConnection
2607
      conn=DBConnectionPool.getDBConnection("MetaCatServlet.getPublicIdForDoc");
2608
      serialNumber=conn.getCheckOutSerialNumber();
2609
      pstmt = conn.prepareStatement(
2610
            "SELECT " + fieldName + " FROM xml_documents " +
2611
            "WHERE docid = ? ");
2612

    
2613
      pstmt.setString(1, docId);
2614
      pstmt.execute();
2615
      rs = pstmt.getResultSet();
2616
      boolean hasRow = rs.next();
2617
      int perm = 0;
2618
      if ( hasRow )
2619
      {
2620
        fieldValue = rs.getString(1);
2621
      }
2622
      else
2623
      {
2624
        throw new Exception("Could not find document: "+accessionNumber);
2625
      }
2626
    }//try
2627
    catch (Exception e)
2628
    {
2629
      MetaCatUtil.debugMessage("Exception in MetacatServlet.getPublicIdForDoc: "
2630
                               + e.getMessage(), 30);
2631
      throw e;
2632
    }
2633
    finally
2634
    {
2635
      try
2636
      {
2637
        rs.close();
2638
        pstmt.close();
2639

    
2640
      }
2641
      finally
2642
      {
2643
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2644
      }
2645
    }
2646
    return fieldValue;
2647
  }//getFieldValueForDoc
2648

    
2649
  /*
2650
   * A method to output setAccess action result
2651
   */
2652
  private void outputResponse(Vector successList,
2653
                              Vector errorList,
2654
                              PrintWriter out)
2655
  {
2656
    boolean error = false;
2657
    boolean success = false;
2658
    // Output prolog
2659
    out.println(PROLOG);
2660
    // output success message
2661
    if ( successList != null)
2662
    {
2663
      for (int i = 0; i<successList.size(); i++)
2664
      {
2665
        out.println(SUCCESS);
2666
        out.println((String)successList.elementAt(i));
2667
        out.println(SUCCESSCLOSE);
2668
        success = true;
2669
      }//for
2670
    }//if
2671
    // output error message
2672
    if (errorList != null)
2673
    {
2674
      for (int i = 0; i<errorList.size(); i++)
2675
      {
2676
        out.println(ERROR);
2677
        out.println((String)errorList.elementAt(i));
2678
        out.println(ERRORCLOSE);
2679
        error = true;
2680
      }//for
2681
    }//if
2682

    
2683
    // if no error and no success info, send a error that nothing happened
2684
    if( !error && !success)
2685
    {
2686
      out.println(ERROR);
2687
      out.println("Nothing happend for setaccess action");
2688
      out.println(ERRORCLOSE);
2689
    }
2690

    
2691
  }//outputResponse
2692
}
(39-39/58)