Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that handles the SAX XML events as they
4
 *             are generated from XML documents
5
 *  Copyright: 2000 Regents of the University of California and the
6
 *             National Center for Ecological Analysis and Synthesis
7
 *    Authors: Matt Jones, Jivka Bojilova
8
 *
9
 *   '$Author: leinfelder $'
10
 *     '$Date: 2011-12-07 17:04:09 -0800 (Wed, 07 Dec 2011) $'
11
 * '$Revision: 6746 $'
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 java.io.File;
31
import java.io.FileOutputStream;
32
import java.io.IOException;
33
import java.io.OutputStreamWriter;
34
import java.io.Writer;
35
import java.sql.PreparedStatement;
36
import java.sql.ResultSet;
37
import java.sql.SQLException;
38
import java.util.Date;
39
import java.util.EmptyStackException;
40
import java.util.Enumeration;
41
import java.util.Hashtable;
42
import java.util.Stack;
43
import java.util.Vector;
44

    
45
import org.apache.log4j.Logger;
46
import org.xml.sax.Attributes;
47
import org.xml.sax.SAXException;
48

    
49
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlInterface;
50
import edu.ucsb.nceas.metacat.accesscontrol.AccessRule;
51
import edu.ucsb.nceas.metacat.accesscontrol.AccessSection;
52
import edu.ucsb.nceas.metacat.database.DBConnection;
53
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
54
import edu.ucsb.nceas.metacat.properties.PropertyService;
55
import edu.ucsb.nceas.metacat.util.DocumentUtil;
56
import edu.ucsb.nceas.metacat.util.MetacatUtil;
57
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
58

    
59
/**
60
 * A database aware Class implementing callback methods for the SAX parser to
61
 * call when processing the XML stream and generating events
62
 */
63
public class Eml210SAXHandler extends DBSAXHandler implements AccessControlInterface {
64

    
65
	private boolean processingTopLevelAccess = false;
66

    
67
	private boolean processingAdditionalAccess = false;
68

    
69
	private boolean processingOtherAccess = false;
70

    
71
	private AccessSection accessObject = null;
72

    
73
	private AccessRule accessRule = null;
74

    
75
	// all access rules
76
	private Vector<AccessSection> accessObjectList = new Vector<AccessSection>(); 
77

    
78
	private Hashtable<String, AccessSection> topLevelAccessControlMap = new Hashtable<String, AccessSection>();
79

    
80
	// subtree access for additionalmetadata
81
	private Hashtable<String, AccessSection> additionalAccessControlMap = new Hashtable<String, AccessSection>();
82
	
83
	
84
	private Vector<Hashtable<String, AccessSection>> additionalAccessMapList = new Vector<Hashtable<String, AccessSection>>();
85
	
86
	// ids from additionalmetadata/describes
87
	private Vector<String> describesId = new Vector<String>(); 
88
	
89
	private Stack<SubTree> subTreeInfoStack = new Stack<SubTree>();
90

    
91
	private Vector<SubTree> subTreeList = new Vector<SubTree>();
92
	
93
	private boolean needToCheckAccessModule = false;
94

    
95
	private Vector<AccessSection> unChangeableAccessSubTreeVector = new Vector<AccessSection>();
96

    
97
	private Stack<NodeRecord> currentUnchangeableAccessModuleNodeStack = new Stack<NodeRecord>();
98

    
99
	private AccessSection topAccessSection;
100

    
101
	// we need an another stack to store the access node which we pull out just
102
	// from xml. If a reference happened, we can use the stack the compare nodes
103
	private Stack<NodeRecord> storedAccessNodeStack = new Stack<NodeRecord>();
104

    
105
	// vector stored the data file id which will be write into relation table
106
	private Vector<String> onlineDataFileIdInRelationVector = new Vector<String>();
107

    
108
	// vector stored the data file id which will be write top access rules to
109
	// access table
110
	private Vector<String> onlineDataFileIdInTopAccessVector = new Vector<String>();
111

    
112
	// Indicator of inline data
113
	private boolean handleInlineData = false;
114

    
115
	private Hashtable<String, String> inlineDataNameSpace = null;
116

    
117
	private Writer inlineDataFileWriter = null;
118

    
119
	private String inlineDataFileName = null;
120

    
121
	DistributionSection currentDistributionSection = null;
122

    
123
	Vector<DistributionSection> allDistributionSections = new Vector<DistributionSection>();
124

    
125
	// This variable keeps a counter of each distribution element. This index
126
	// will be used to name the inline data file that gets written to disk, and to
127
	// strip inline data from the metadata document on file if the user does not have
128
	// read access.
129
	private int distributionIndex = 0;
130

    
131
	// private String distributionOnlineFileName = null;
132

    
133
	// This is used to delete inline files if the xml does not parse correctly.
134
	private Vector<String> inlineFileIdList = new Vector<String>();
135

    
136
	// Constant
137
	private static final String EML = "eml";
138

    
139
	private static final String DISTRIBUTION = "distribution";
140

    
141
	private static final String ORDER = "order";
142

    
143
	private static final String ID = "id";
144

    
145
	private static final String REFERENCES = "references";
146

    
147
	public static final String INLINE = "inline";
148

    
149
	private static final String ONLINE = "online";
150

    
151
	private static final String URL = "url";
152

    
153
	// private static final String PERMISSIONERROR = "User tried to update a
154
	// subtree "
155
	// + "when they don't have write permission!";
156

    
157
	private static final String UPDATEACCESSERROR = "User tried to update an "
158
			+ "access module when they don't have \"ALL\" permission!";
159

    
160
	private static final String TOPLEVEL = "top";
161

    
162
	private static final String SUBTREELEVEL = "subtree";
163

    
164
	private static final String RELATION = "Provides info for";
165

    
166
	private Logger logMetacat = Logger.getLogger(Eml210SAXHandler.class);
167

    
168
	/**
169
	 * Construct an instance of the handler class In this constructor, user can
170
	 * specify the version need to update
171
	 * 
172
	 * @param conn
173
	 *            the JDBC connection to which information is written
174
	 * @param action -
175
	 *            "INSERT" or "UPDATE"
176
	 * @param docid
177
	 *            to be inserted or updated into JDBC connection
178
	 * @param revision,
179
	 *            the user specified the revision need to be update
180
	 * @param user
181
	 *            the user connected to MetaCat servlet and owns the document
182
	 * @param groups
183
	 *            the groups to which user belongs
184
	 * @param pub
185
	 *            flag for public "read" access on document
186
	 * @param serverCode
187
	 *            the serverid from xml_replication on which this document
188
	 *            resides.
189
	 * 
190
	 */
191
	public Eml210SAXHandler(DBConnection conn, String action, String docid,
192
			String revision, String user, String[] groups, String pub, int serverCode,
193
			Date createDate, Date updateDate) throws SAXException {
194
		super(conn, action, docid, revision, user, groups, pub, serverCode, createDate,
195
				updateDate);
196
		// Get the unchangeable subtrees (user doesn't have write permission)
197
		try {
198

    
199
			if (action.equals("UPDATE")) {
200
				// If the action is update and user doesn't have "ALL" permission
201
				// we need to check if user can update access subtree			
202
				int latestRevision = DBUtil.getLatestRevisionInDocumentTable(docid);
203
				String previousDocid = 
204
					docid + PropertyService.getProperty("document.accNumSeparator") + latestRevision;
205
				
206
				PermissionController control = new PermissionController(previousDocid );
207
				if (!control.hasPermission(user, groups, AccessControlInterface.ALLSTRING)
208
						&& action != null) {
209
					needToCheckAccessModule = true;
210
					unChangeableAccessSubTreeVector = getAccessSubTreeListFromDB();
211
				}
212
			}
213

    
214
		} catch (Exception e) {
215
			throw new SAXException(e.getMessage());
216
		}
217
	}
218

    
219
	/*
220
	 * Get the subtree node info from xml_accesssubtree table
221
	 */
222
	private Vector<AccessSection> getAccessSubTreeListFromDB() throws Exception {
223
		Vector<AccessSection> result = new Vector<AccessSection>();
224
		PreparedStatement pstmt = null;
225
		ResultSet rs = null;
226
		String sql = "SELECT controllevel, subtreeid, startnodeid, endnodeid "
227
				+ "FROM xml_accesssubtree WHERE docid like ? "
228
				+ "ORDER BY startnodeid ASC";
229

    
230
		try {
231

    
232
			pstmt = connection.prepareStatement(sql);
233
			// Increase DBConnection usage count
234
			connection.increaseUsageCount(1);
235
			// Bind the values to the query
236
			pstmt.setString(1, docid);
237
			pstmt.execute();
238

    
239
			// Get result set
240
			rs = pstmt.getResultSet();
241
			while (rs.next()) {
242
				String level = rs.getString(1);
243
				String sectionId = rs.getString(2);
244
				long startNodeId = rs.getLong(3);
245
				long endNodeId = rs.getLong(4);
246
				// create a new access section
247
				AccessSection accessObj = new AccessSection();
248
				accessObj.setControlLevel(level);
249
				accessObj.setDocId(docid);
250
				accessObj.setSubTreeId(sectionId);
251
				accessObj.setStartNodeId(startNodeId);
252
				accessObj.setEndNodeId(endNodeId);
253
				Stack<NodeRecord> nodeStack = accessObj.getSubTreeNodeStack();
254
				accessObj.setSubTreeNodeStack(nodeStack);
255
				// add this access obj into vector
256
				result.add(accessObj);
257
				// Get the top level access subtree control
258
				if (level != null && level.equals(TOPLEVEL)) {
259
					topAccessSection = accessObj;
260
				}
261
			}
262
			pstmt.close();
263
		}// try
264
		catch (SQLException e) {
265
			throw new SAXException("EMLSAXHandler.getAccessSubTreeListFromDB(): "
266
					+ e.getMessage());
267
		}// catch
268
		finally {
269
			try {
270
				pstmt.close();
271
			} catch (SQLException ee) {
272
				throw new SAXException("EMLSAXHandler.getAccessSubTreeListFromDB(): "
273
						+ ee.getMessage());
274
			}
275
		}// finally
276
		return result;
277
	}
278

    
279
	/** SAX Handler that is called at the start of each XML element */
280
	public void startElement(String uri, String localName, String qName, Attributes atts)
281
			throws SAXException {
282
		// for element <eml:eml...> qname is "eml:eml", local name is "eml"
283
		// for element <acl....> both qname and local name is "eml"
284
		// uri is namesapce
285
		logMetacat.debug("Start ELEMENT(qName) " + qName);
286
		logMetacat.debug("Start ELEMENT(localName) " + localName);
287
		logMetacat.debug("Start ELEMENT(uri) " + uri);
288

    
289
		DBSAXNode parentNode = null;
290
		DBSAXNode currentNode = null;
291

    
292
		if (!handleInlineData) {
293
			// Get a reference to the parent node for the id
294
			try {
295
				parentNode = (DBSAXNode) nodeStack.peek();
296
			} catch (EmptyStackException e) {
297
				parentNode = null;
298
			}
299

    
300
			// start handle inline data
301
			if (localName.equals(INLINE)) {
302
				handleInlineData = true;
303
				// initialize namespace hash for in line data
304
				inlineDataNameSpace = new Hashtable<String, String>();
305
				// initialize file writer
306
				String docidWithoutRev = DocumentUtil.getDocIdFromString(docid);
307
				String seperator = ".";
308
				try {
309
					seperator = PropertyService.getProperty("document.accNumSeparator");
310
				} catch (PropertyNotFoundException pnfe) {
311
					logMetacat.error("Could not fing property 'accNumSeparator'. "
312
							+ "Setting separator to '.': " + pnfe.getMessage());
313
				}
314
				// the new file name will look like docid.rev.2
315
				inlineDataFileName = docidWithoutRev + seperator + revision + seperator
316
						+ distributionIndex;
317
				inlineDataFileWriter = createInlineDataFileWriter(inlineDataFileName, encoding);
318
				// put the inline file id into a vector. If upload failed,
319
				// metacat will delete the inline data file
320
				inlineFileIdList.add(inlineDataFileName);
321
				
322
				currentDistributionSection.setDistributionType(DistributionSection.INLINE_DATA_DISTRIBUTION);
323
				currentDistributionSection.setDataFileName(inlineDataFileName);
324

    
325
			}
326

    
327
			// If hit a text node, we need write this text for current's parent
328
			// node This will happen if the element is mixed
329
			if (hitTextNode && parentNode != null) {
330

    
331
				// compare top level access module
332
				if (processingTopLevelAccess && needToCheckAccessModule) {
333
					compareAccessTextNode(currentUnchangeableAccessModuleNodeStack, textBuffer);
334
				}
335

    
336
				if (needToCheckAccessModule
337
						&& (processingAdditionalAccess || processingOtherAccess || processingTopLevelAccess)) {
338
					// stored the pull out nodes into storedNode stack
339
					NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT", null,
340
							null, MetacatUtil.normalize(textBuffer.toString()));
341
					storedAccessNodeStack.push(nodeElement);
342

    
343
				}
344

    
345
				// write the textbuffer into db for parent node.
346
				endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer, parentNode);
347
				// rest hitTextNode
348
				hitTextNode = false;
349
				// reset textbuffer
350
				textBuffer = null;
351
				textBuffer = new StringBuffer();
352

    
353
			}
354

    
355
			// Document representation that points to the root document node
356
			if (atFirstElement) {
357
				atFirstElement = false;
358
				// If no DOCTYPE declaration: docname = root element
359
				// doctype = root element name or name space
360
				if (docname == null) {
361
					docname = localName;
362
					// if uri isn't null doctype = uri(namespace)
363
					// othewise root element
364
					if (uri != null && !(uri.trim()).equals("")) {
365
						doctype = uri;
366
					} else {
367
						doctype = docname;
368
					}
369
					logMetacat.debug("DOCNAME-a: " + docname);
370
					logMetacat.debug("DOCTYPE-a: " + doctype);
371
				} else if (doctype == null) {
372
					// because docname is not null and it is declared in dtd
373
					// so could not be in schema, no namespace
374
					doctype = docname;
375
					logMetacat.debug("DOCTYPE-b: " + doctype);
376
				}
377
				rootNode.writeNodename(docname);
378
				try {
379
					// for validated XML Documents store a reference to XML DB
380
					// Catalog. Because this is select statement and it needn't
381
					// roll back if insert document action failed. In order to
382
					// decrease DBConnection usage count, we get a new
383
					// dbconnection from pool String catalogid = null;
384
					DBConnection dbConn = null;
385
					int serialNumber = -1;
386

    
387
					try {
388
						// Get dbconnection
389
						dbConn = DBConnectionPool
390
								.getDBConnection("DBSAXHandler.startElement");
391
						serialNumber = dbConn.getCheckOutSerialNumber();
392
						
393
						String sql = "SELECT catalog_id FROM xml_catalog "
394
							+ "WHERE entry_type = 'Schema' "
395
							+ "AND public_id = ?";
396
						PreparedStatement pstmt = dbConn.prepareStatement(sql);
397
						pstmt.setString(1, doctype);
398
						ResultSet rs = pstmt.executeQuery();
399
						boolean hasRow = rs.next();
400
						if (hasRow) {
401
							catalogid = rs.getString(1);
402
						}
403
						pstmt.close();
404
					}// try
405
					finally {
406
						// Return dbconnection
407
						DBConnectionPool.returnDBConnection(dbConn, serialNumber);
408
					}// finally
409

    
410
					// create documentImpl object by the constructor which can
411
					// specify the revision
412
					if (!super.getIsRevisionDoc()) {
413
						currentDocument = new DocumentImpl(connection, rootNode
414
								.getNodeID(), docname, doctype, docid, revision, action,
415
								user, this.pub, catalogid, this.serverCode, createDate,
416
								updateDate);
417
					}
418

    
419
				} catch (McdbDocNotFoundException mdnfe) {
420
					Vector<Integer> revList = null;
421
					
422
					try {
423
						revList = DBUtil.getRevListFromRevisionTable(docid);
424
					} catch (SQLException sqle) {
425
						logMetacat.error("SQL error when trying to get rev list for doc " + docid + " : " + sqle.getMessage());
426
						throw (new SAXException("Doc ID " + docid + " was not found and cannot be updated.")); 
427
					}
428
					
429
					if (revList.size() > 0) {
430
						throw (new SAXException("EML210SaxHandler.startElement - Doc ID " + docid + " was deleted and cannot be updated."));
431
					} else {
432
						throw (new SAXException("EML210SaxHandler.startElement - Doc ID " + docid + " was not found and cannot be updated.")); 
433
					}
434
				} catch (Exception e) {
435
                    throw (new SAXException("EML210SaxHandler.startElement - error with action " + 
436
                    		action + " : " + e.getMessage()));
437
				}
438
			}
439

    
440
			// Create the current node representation
441
			currentNode = new DBSAXNode(connection, qName, localName, parentNode,
442
					rootNode.getNodeID(), docid, doctype);
443
			// Use a local variable to store the element node id
444
			// If this element is a start point of subtree(section), it will be
445
			// stored otherwise, it will be discarded
446
			long startNodeId = currentNode.getNodeID();
447
			// Add all of the namespaces
448
			String prefix = null;
449
			String nsuri = null;
450
			Enumeration<String> prefixes = namespaces.keys();
451
			while (prefixes.hasMoreElements()) {
452
				prefix = prefixes.nextElement();
453
				nsuri = namespaces.get(prefix);
454
				endNodeId = currentNode.setNamespace(prefix, nsuri, docid);
455
			}
456

    
457
			// Add all of the attributes
458
			for (int i = 0; i < atts.getLength(); i++) {
459
				String attributeName = atts.getQName(i);
460
				String attributeValue = atts.getValue(i);
461
				endNodeId = currentNode
462
						.setAttribute(attributeName, attributeValue, docid);
463

    
464
				// To handle name space and schema location if the attribute
465
				// name is xsi:schemaLocation. If the name space is in not
466
				// in catalog table it will be registered.
467
				if (attributeName != null
468
						&& attributeName.indexOf(MetaCatServlet.SCHEMALOCATIONKEYWORD) != -1) {
469
					SchemaLocationResolver resolver = new SchemaLocationResolver(
470
							attributeValue);
471
					resolver.resolveNameSpace();
472

    
473
				} else if (attributeName != null && attributeName.equals(ID)) {
474

    
475
				}
476
			}// for
477

    
478
			// handle access stuff
479
			if (localName.equals(ACCESS)) {
480
				if (parentNode.getTagName().equals(EML)) {
481
					processingTopLevelAccess = true;
482
				} else if (parentNode.getTagName() == DISTRIBUTION) {
483
					processingAdditionalAccess = true;
484
				} else {
485
					// process other access embedded into resource level
486
					// module
487
					processingOtherAccess = true;
488
				}
489
				// create access object
490
				accessObject = new AccessSection();
491
				// set permission order
492
				String permOrder = currentNode.getAttribute(ORDER);
493
				accessObject.setPermissionOrder(permOrder);
494
				// set access id
495
				String accessId = currentNode.getAttribute(ID);
496
				accessObject.setSubTreeId(accessId);
497
				accessObject.setStartNodeId(startNodeId);
498
				accessObject.setDocId(docid);
499
				if (processingAdditionalAccess) {
500
					accessObject.setDataFileName(inlineDataFileName);
501
				}
502

    
503
				// load top level node stack to
504
				// currentUnchangableAccessModuleNodeStack
505
				if (processingTopLevelAccess && needToCheckAccessModule) {
506
					// get the node stack for
507
					currentUnchangeableAccessModuleNodeStack = topAccessSection
508
							.getSubTreeNodeStack();
509
				}
510
			} else if (localName.equals(DISTRIBUTION)) {
511
				distributionIndex++;
512
				currentDistributionSection = new DistributionSection(distributionIndex);
513

    
514
				// handle subtree info
515
				SubTree subTree = new SubTree();
516
				// set sub tree id
517
				subTree.setSubTreeId(String.valueOf(distributionIndex));
518
				// set sub tree start element name
519
				subTree.setStartElementName(currentNode.getTagName());
520
				// set start node number
521
				subTree.setStartNodeId(startNodeId);
522
				// add to stack, but it didn't get end node id yet
523
				subTreeInfoStack.push(subTree);
524
			}
525
			// Set up a access rule for allow
526
			else if (parentNode.getTagName() != null
527
					&& (parentNode.getTagName()).equals(ACCESS)
528
					&& localName.equals(ALLOW)) {
529

    
530
				accessRule = new AccessRule();
531

    
532
				// set permission type "allow"
533
				accessRule.setPermissionType(ALLOW);
534

    
535
			}
536
			// set up an access rule for deny
537
			else if (parentNode.getTagName() != null
538
					&& (parentNode.getTagName()).equals(ACCESS) && localName.equals(DENY)) {
539
				accessRule = new AccessRule();
540
				// set permission type "allow"
541
				accessRule.setPermissionType(DENY);
542
			}
543

    
544
			// Add the node to the stack, so that any text data can be
545
			// added as it is encountered
546
			nodeStack.push(currentNode);
547
			// Add the node to the vector used by thread for writing XML Index
548
			nodeIndex.addElement(currentNode);
549

    
550
			// compare top access level module
551
			if (processingTopLevelAccess && needToCheckAccessModule) {
552
				compareElementNameSpaceAttributes(
553
						currentUnchangeableAccessModuleNodeStack, namespaces, atts,
554
						localName, UPDATEACCESSERROR);
555

    
556
			}
557

    
558
			// store access module element and attributes into stored stack
559
			if (needToCheckAccessModule
560
					&& (processingAdditionalAccess || processingOtherAccess || processingTopLevelAccess)) {
561
				// stored the pull out nodes into storedNode stack
562
				NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "ELEMENT", localName,
563
						prefix, MetacatUtil.normalize(null));
564
				storedAccessNodeStack.push(nodeElement);
565
				for (int i = 0; i < atts.getLength(); i++) {
566
					String attributeName = atts.getQName(i);
567
					String attributeValue = atts.getValue(i);
568
					NodeRecord nodeAttribute = new NodeRecord(-2, -2, -2, "ATTRIBUTE",
569
							attributeName, null, MetacatUtil.normalize(attributeValue));
570
					storedAccessNodeStack.push(nodeAttribute);
571
				}
572

    
573
			}
574

    
575
			// reset name space
576
			namespaces = null;
577
			namespaces = new Hashtable<String, String>();
578
		}// not inline data
579
		else {
580
			// we don't buffer the inline data in characters() method
581
			// so start character don't need to hand text node.
582

    
583
			// inline data may be the xml format.
584
			StringBuffer inlineElements = new StringBuffer();
585
			inlineElements.append("<").append(qName);
586
			// append attributes
587
			for (int i = 0; i < atts.getLength(); i++) {
588
				String attributeName = atts.getQName(i);
589
				String attributeValue = atts.getValue(i);
590
				inlineElements.append(" ");
591
				inlineElements.append(attributeName);
592
				inlineElements.append("=\"");
593
				inlineElements.append(attributeValue);
594
				inlineElements.append("\"");
595
			}
596
			// append namespace
597
			String prefix = null;
598
			String nsuri = null;
599
			Enumeration<String> prefixes = inlineDataNameSpace.keys();
600
			while (prefixes.hasMoreElements()) {
601
				prefix = prefixes.nextElement();
602
				nsuri = namespaces.get(prefix);
603
				inlineElements.append(" ");
604
				inlineElements.append("xmlns:");
605
				inlineElements.append(prefix);
606
				inlineElements.append("=\"");
607
				inlineElements.append(nsuri);
608
				inlineElements.append("\"");
609
			}
610
			inlineElements.append(">");
611
			// reset inline data name space
612
			inlineDataNameSpace = null;
613
			inlineDataNameSpace = new Hashtable<String, String>();
614
			// write inline data into file
615
			logMetacat.debug("the inline element data is: " + inlineElements.toString());
616
			writeInlineDataIntoFile(inlineDataFileWriter, inlineElements);
617
		}// else
618

    
619
	}
620

    
621
	private void compareElementNameSpaceAttributes(
622
			Stack<NodeRecord> unchangeableNodeStack,
623
			Hashtable<String, String> nameSpaces, Attributes attributes,
624
			String localName, String error) throws SAXException {
625
		// Get element subtree node stack (element node)
626
		NodeRecord elementNode = null;
627
		try {
628
			elementNode = unchangeableNodeStack.pop();
629
		} catch (EmptyStackException ee) {
630
			logMetacat.error("Node stack is empty for element data");
631
			throw new SAXException(error);
632
		}
633
		logMetacat.debug("current node type from xml is ELEMENT");
634
		logMetacat.debug("node type from stack: " + elementNode.getNodeType());
635
		logMetacat.debug("node name from xml document: " + localName);
636
		logMetacat.debug("node name from stack: " + elementNode.getNodeName());
637
		logMetacat.debug("node data from stack: " + elementNode.getNodeData());
638
		logMetacat.debug("node id is: " + elementNode.getNodeId());
639
		// if this node is not element or local name not equal or name space
640
		// not equals, throw an exception
641
		if (!elementNode.getNodeType().equals("ELEMENT")
642
				|| !localName.equals(elementNode.getNodeName()))
643
		// (uri != null && !uri.equals(elementNode.getNodePrefix())))
644
		{
645
			logMetacat.error("Inconsistence happened: ");
646
			logMetacat.error("current node type from xml is ELEMENT");
647
			logMetacat.error("node type from stack: " + elementNode.getNodeType());
648
			logMetacat.error("node name from xml document: " + localName);
649
			logMetacat.error("node name from stack: " + elementNode.getNodeName());
650
			logMetacat.error("node data from stack: " + elementNode.getNodeData());
651
			logMetacat.error("node id is: " + elementNode.getNodeId());
652
			throw new SAXException(error);
653
		}
654

    
655
		// compare namespace
656
		Enumeration<String> nameEn = nameSpaces.keys();
657
		while (nameEn.hasMoreElements()) {
658
			// Get namespacke node stack (element node)
659
			NodeRecord nameNode = null;
660
			try {
661
				nameNode = unchangeableNodeStack.pop();
662
			} catch (EmptyStackException ee) {
663
				logMetacat.error("Node stack is empty for namespace data");
664
				throw new SAXException(error);
665
			}
666

    
667
			String prefixName = nameEn.nextElement();
668
			String nameSpaceUri = nameSpaces.get(prefixName);
669
			if (!nameNode.getNodeType().equals("NAMESPACE")
670
					|| !prefixName.equals(nameNode.getNodeName())
671
					|| !nameSpaceUri.equals(nameNode.getNodeData())) {
672
				logMetacat.error("Inconsistence happened: ");
673
				logMetacat.error("current node type from xml is NAMESPACE");
674
				logMetacat.error("node type from stack: " + nameNode.getNodeType());
675
				logMetacat.error("current node name from xml is: " + prefixName);
676
				logMetacat.error("node name from stack: " + nameNode.getNodeName());
677
				logMetacat.error("current node data from xml is: " + nameSpaceUri);
678
				logMetacat.error("node data from stack: " + nameNode.getNodeData());
679
				logMetacat.error("node id is: " + nameNode.getNodeId());
680
				throw new SAXException(error);
681
			}
682

    
683
		}// while
684

    
685
		// compare attributes
686
		for (int i = 0; i < attributes.getLength(); i++) {
687
			NodeRecord attriNode = null;
688
			try {
689
				attriNode = unchangeableNodeStack.pop();
690

    
691
			} catch (EmptyStackException ee) {
692
				logMetacat.error("Node stack is empty for attribute data");
693
				throw new SAXException(error);
694
			}
695
			String attributeName = attributes.getQName(i);
696
			String attributeValue = attributes.getValue(i);
697
			logMetacat.debug("current node type from xml is ATTRIBUTE ");
698
			logMetacat.debug("node type from stack: " + attriNode.getNodeType());
699
			logMetacat.debug("current node name from xml is: " + attributeName);
700
			logMetacat.debug("node name from stack: " + attriNode.getNodeName());
701
			logMetacat.debug("current node data from xml is: " + attributeValue);
702
			logMetacat.debug("node data from stack: " + attriNode.getNodeData());
703
			logMetacat.debug("node id  is: " + attriNode.getNodeId());
704

    
705
			if (!attriNode.getNodeType().equals("ATTRIBUTE")
706
					|| !attributeName.equals(attriNode.getNodeName())
707
					|| !attributeValue.equals(attriNode.getNodeData())) {
708
				logMetacat.error("Inconsistence happened: ");
709
				logMetacat.error("current node type from xml is ATTRIBUTE ");
710
				logMetacat.error("node type from stack: " + attriNode.getNodeType());
711
				logMetacat.error("current node name from xml is: " + attributeName);
712
				logMetacat.error("node name from stack: " + attriNode.getNodeName());
713
				logMetacat.error("current node data from xml is: " + attributeValue);
714
				logMetacat.error("node data from stack: " + attriNode.getNodeData());
715
				logMetacat.error("node is: " + attriNode.getNodeId());
716
				throw new SAXException(error);
717
			}
718
		}// for
719

    
720
	}
721

    
722
	/* method to compare current text node and node in db */
723
	private void compareAccessTextNode(Stack<NodeRecord> nodeStack, StringBuffer text) throws SAXException {
724
		NodeRecord node = null;
725
		// get node from current stack
726
		try {
727
			node = nodeStack.pop();
728
		} catch (EmptyStackException ee) {
729
			logMetacat.error("Node stack is empty for text data in startElement for doc id " + docid);
730
			throw new SAXException("Access rules could not be found in database.");
731
		}
732

    
733
		String dbAccessData = node.getNodeData();
734
		String docAccessData = text.toString().trim();
735
		
736
		logMetacat.debug("Eml210SAXHandler.compareAccessTextNode - \n" +
737
					"\t access node type from db:       " + node.getNodeType() + "\n" +
738
					"\t access node data from db:       " + node.getNodeData() + "\n" +
739
					"\t access node data from document: " + text.toString());
740
		
741
		if (!node.getNodeType().equals("TEXT")
742
				|| !docAccessData.equals(dbAccessData)) {
743
			logMetacat.warn("Eml210SAXHandler.compareAccessTextNode - Access record mismatch: \n" +
744
					"\t access node type from db:       " + node.getNodeType() + "\n" +
745
					"\t access node data from db:       " + dbAccessData + "\n" +
746
					"\t access node data from document: " + docAccessData);
747
			
748
			throw new SAXException(UPDATEACCESSERROR + " [Eml210SAXHandler.compareAccessTextNode]");
749
		}// if
750
	}
751

    
752
	/** SAX Handler that is called for each XML text node */
753
	public void characters(char[] cbuf, int start, int len) throws SAXException {
754
		logMetacat.debug("CHARACTERS");
755
		if (!handleInlineData) {
756
			// buffer all text nodes for same element. This is for if text was
757
			// split into different nodes
758
			textBuffer.append(new String(cbuf, start, len));
759
			// set hittextnode true
760
			hitTextNode = true;
761
			// if text buffer .size is greater than max, write it to db.
762
			// so we can save memory
763
			if (textBuffer.length() > MAXDATACHARS) {
764
				logMetacat.debug("Write text into DB in charaters"
765
						+ " when text buffer size is greater than maxmum number");
766
				DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
767
				endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer, currentNode);
768
				textBuffer = null;
769
				textBuffer = new StringBuffer();
770
			}
771
		} else {
772
			// this is inline data and write file system directly
773
			// we don't need to buffer it.
774
			StringBuffer inlineText = new StringBuffer();
775
			inlineText.append(new String(cbuf, start, len));
776
			logMetacat.debug("The inline text data write into file system: "
777
					+ inlineText.toString());
778
			writeInlineDataIntoFile(inlineDataFileWriter, inlineText);
779
		}
780
	}
781

    
782
	/** SAX Handler that is called at the end of each XML element */
783
	public void endElement(String uri, String localName, String qName)
784
			throws SAXException {
785
		logMetacat.debug("End ELEMENT " + qName);
786

    
787
		if (localName.equals(INLINE) && handleInlineData) {
788
			// Get the node from the stack
789
			DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
790
			logMetacat.debug("End of inline data");
791
			// close file writer
792
			try {
793
				inlineDataFileWriter.close();
794
				handleInlineData = false;
795
			} catch (IOException ioe) {
796
				throw new SAXException(ioe.getMessage());
797
			}
798

    
799
			// write put inline data file name into text buffer (without path)
800
			textBuffer = new StringBuffer(inlineDataFileName);
801
			// write file name into db
802
			endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer, currentNode);
803
			// reset textbuff
804
			textBuffer = null;
805
			textBuffer = new StringBuffer();
806
			return;
807
		}
808

    
809
		if (!handleInlineData) {
810
			// Get the node from the stack
811
			DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
812
			String currentTag = currentNode.getTagName();
813

    
814
			// If before the end element, the parser hit text nodes and store
815
			// them into the buffer, write the buffer to data base. The reason
816
			// we put write database here is for xerces some time split text
817
			// node
818
			if (hitTextNode) {
819
				// get access value
820
				String data = null;
821
				// add principal
822
				if (currentTag.equals(PRINCIPAL) && accessRule != null) {
823
					data = (textBuffer.toString()).trim();
824
					accessRule.addPrincipal(data);
825

    
826
				} else if (currentTag.equals(PERMISSION) && accessRule != null) {
827
					data = (textBuffer.toString()).trim();
828
					// we combine different a permission into one value
829
					int permission = accessRule.getPermission();
830
					// add permission
831
					if (data.toUpperCase().equals(READSTRING)) {
832
						permission = permission | READ;
833
					} else if (data.toUpperCase().equals(WRITESTRING)) {
834
						permission = permission | WRITE;
835
					} else if (data.toUpperCase().equals(CHMODSTRING)) {
836
						permission = permission | CHMOD;
837
					} else if (data.toUpperCase().equals(ALLSTRING)) {
838
						permission = permission | ALL;
839
					}
840
					accessRule.setPermission(permission);
841
				} else if (currentTag.equals(REFERENCES)
842
						&& (processingTopLevelAccess || processingAdditionalAccess || processingOtherAccess)) {
843
					// get reference
844
					data = (textBuffer.toString()).trim();
845
					// put reference id into accessSection
846
					accessObject.setReferences(data);
847

    
848
				} else if (currentTag.equals(URL)) {
849
					// handle online data, make sure its'parent is online
850
					DBSAXNode parentNode = (DBSAXNode) nodeStack.peek();
851
					if (parentNode != null && parentNode.getTagName() != null
852
							&& parentNode.getTagName().equals(ONLINE)) {
853
						// if online data is in local metacat, add it to the
854
						// vector
855
						data = (textBuffer.toString()).trim();
856
						handleOnlineUrlDataFile(data);
857

    
858
					}// if
859
				}// else if
860
				
861
				// write text to db if it is not inline data
862
				logMetacat.debug("Write text into DB in End Element");
863

    
864
				// compare top level access module
865
				if (processingTopLevelAccess && needToCheckAccessModule) {
866
					compareAccessTextNode(currentUnchangeableAccessModuleNodeStack,
867
							textBuffer);
868
				}
869
				// write text node into db
870
				endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer, currentNode);
871
			}
872
			
873
			if (needToCheckAccessModule
874
					&& (processingAdditionalAccess || processingOtherAccess || processingTopLevelAccess)) {
875
				// stored the pull out nodes into storedNode stack
876
				NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT", null,
877
						null, MetacatUtil.normalize(textBuffer.toString()));
878
				storedAccessNodeStack.push(nodeElement);
879

    
880
			}
881

    
882
			// set hitText false
883
			hitTextNode = false;
884
			// reset textbuff
885
			textBuffer = null;
886
			textBuffer = new StringBuffer();
887

    
888
			// hand sub stree stuff
889
			if (!subTreeInfoStack.empty()) {
890
				SubTree tree = subTreeInfoStack.peek();// get last
891
				// subtree
892
				if (tree != null && tree.getStartElementName() != null
893
						&& (tree.getStartElementName()).equals(currentTag)) {
894
					// find the end of sub tree and set the end node id
895
					tree.setEndNodeId(endNodeId);
896
					// add the subtree into the final store palace
897
					subTreeList.add(tree);
898
					// get rid of it from stack
899
					subTreeInfoStack.pop();
900
				}// if
901
			}// if
902

    
903
			// access stuff
904
			if (currentTag.equals(ALLOW) || currentTag.equals(DENY)) {
905
				// finish parser access rule and assign it to new one
906
				AccessRule newRule = accessRule;
907
				// add the new rule to access section object
908
				accessObject.addAccessRule(newRule);
909
				// reset access rule
910
				accessRule = null;
911
			} else if (currentTag.equals(ACCESS)) {
912
				// finish parsing an access section and assign it to new one
913
				DBSAXNode parentNode = (DBSAXNode) nodeStack.peek();
914

    
915
				accessObject.setEndNodeId(endNodeId);
916

    
917
				if (parentNode != null && parentNode.getTagName() != null
918
						&& parentNode.getTagName().equals(DISTRIBUTION)) {
919
					describesId.add(String.valueOf(distributionIndex));
920
					currentDistributionSection.setAccessSection(accessObject);
921
				}
922

    
923
				AccessSection newAccessObject = accessObject;
924

    
925
				if (newAccessObject != null) {
926

    
927
					// add the accessSection into a vector to store it
928
					// if it is not a reference, need to store it
929
					if (newAccessObject.getReferences() == null) {
930

    
931
						newAccessObject.setStoredTmpNodeStack(storedAccessNodeStack);
932
						accessObjectList.add(newAccessObject);
933
					}
934
					if (processingTopLevelAccess) {
935

    
936
						// top level access control will handle whole document
937
						// -docid
938
						topLevelAccessControlMap.put(docid, newAccessObject);
939
						// reset processtopleveraccess tag
940

    
941
					}// if
942
					else if (processingAdditionalAccess) {
943
						// for additional control put everything in describes
944
						// value
945
						// and access object into hash
946
						for (int i = 0; i < describesId.size(); i++) {
947

    
948
							String subId = describesId.elementAt(i);
949
							if (subId != null) {
950
								additionalAccessControlMap.put(subId, newAccessObject);
951
							}// if
952
						}// for
953
						// add this hashtable in to vector
954

    
955
						additionalAccessMapList.add(additionalAccessControlMap);
956
						// reset this hashtable in order to store another
957
						// additional
958
						// accesscontrol
959
						additionalAccessControlMap = null;
960
						additionalAccessControlMap = new Hashtable<String, AccessSection>();
961
					}// if
962

    
963
				}// if
964
				// check if access node stack is empty after parsing top access
965
				// module
966

    
967
				if (needToCheckAccessModule && processingTopLevelAccess
968
						&& !currentUnchangeableAccessModuleNodeStack.isEmpty()) {
969

    
970
					logMetacat.error("Access node stack is not empty after "
971
							+ "parsing access subtree");
972
					throw new SAXException(UPDATEACCESSERROR);
973

    
974
				}
975
				// reset access section object
976

    
977
				accessObject = null;
978

    
979
				// reset tmp stored node stack
980
				storedAccessNodeStack = null;
981
				storedAccessNodeStack = new Stack<NodeRecord>();
982

    
983
				// reset flag
984
				processingAdditionalAccess = false;
985
				processingTopLevelAccess = false;
986
				processingOtherAccess = false;
987

    
988
			} else if (currentTag.equals(DISTRIBUTION)) {
989
				// If the current Distribution is inline or data and it doesn't have an access section
990
				// we use the top level access section (if it exists)
991
				if ((currentDistributionSection.getDistributionType() == DistributionSection.DATA_DISTRIBUTION 
992
						|| currentDistributionSection.getDistributionType() == DistributionSection.INLINE_DATA_DISTRIBUTION)
993
						&& currentDistributionSection.getAccessSection() == null
994
						&& topLevelAccessControlMap.size() > 0) {
995
					
996
					AccessSection accessSection = new AccessSection();
997
					accessSection.setDocId(docid);	
998
					AccessSection topLevelAccess = topLevelAccessControlMap.get(docid);
999
					accessSection.setPermissionOrder(topLevelAccess.getPermissionOrder());
1000
					Vector<AccessRule> accessRuleList = topLevelAccess.getAccessRules();
1001
					for (AccessRule accessRule : accessRuleList) {
1002
						accessSection.addAccessRule(accessRule);
1003
					}
1004
					currentDistributionSection.setAccessSection(accessSection);
1005
				} 
1006
				if (currentDistributionSection.getAccessSection() != null) {
1007
					currentDistributionSection.getAccessSection().setDataFileName(currentDistributionSection.getDataFileName());
1008
				}
1009
				allDistributionSections.add(currentDistributionSection);
1010
				currentDistributionSection = null;
1011
				describesId = null;
1012
				describesId = new Vector<String>();
1013
			}
1014
		} else {
1015
			// this is in inline part
1016
			StringBuffer endElement = new StringBuffer();
1017
			endElement.append("</");
1018
			endElement.append(qName);
1019
			endElement.append(">");
1020
			logMetacat.debug("inline endElement: " + endElement.toString());
1021
			writeInlineDataIntoFile(inlineDataFileWriter, endElement);
1022
		}
1023
	}
1024

    
1025
	/**
1026
	 * SAX Handler that receives notification of comments in the DTD
1027
	 */
1028
	public void comment(char[] ch, int start, int length) throws SAXException {
1029
		logMetacat.debug("COMMENT");
1030
		if (!handleInlineData) {
1031
			if (!processingDTD) {
1032
				DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1033
				String str = new String(ch, start, length);
1034

    
1035
				// compare top level access module
1036
				if (processingTopLevelAccess && needToCheckAccessModule) {
1037
					compareCommentNode(currentUnchangeableAccessModuleNodeStack, str,
1038
							UPDATEACCESSERROR);
1039
				}
1040
				endNodeId = currentNode.writeChildNodeToDB("COMMENT", null, str, docid);
1041
				if (needToCheckAccessModule
1042
						&& (processingAdditionalAccess || processingOtherAccess || processingTopLevelAccess)) {
1043
					// stored the pull out nodes into storedNode stack
1044
					NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "COMMENT", null,
1045
							null, MetacatUtil.normalize(str));
1046
					storedAccessNodeStack.push(nodeElement);
1047

    
1048
				}
1049
			}
1050
		} else {
1051
			// inline data comment
1052
			StringBuffer inlineComment = new StringBuffer();
1053
			inlineComment.append("<!--");
1054
			inlineComment.append(new String(ch, start, length));
1055
			inlineComment.append("-->");
1056
			logMetacat.debug("inline data comment: " + inlineComment.toString());
1057
			writeInlineDataIntoFile(inlineDataFileWriter, inlineComment);
1058
		}
1059
	}
1060

    
1061
	/* Compare comment from xml and db */
1062
	private void compareCommentNode(Stack<NodeRecord> nodeStack, String string,
1063
			String error) throws SAXException {
1064
		NodeRecord node = null;
1065
		try {
1066
			node = nodeStack.pop();
1067
		} catch (EmptyStackException ee) {
1068
			logMetacat.error("the stack is empty for comment data");
1069
			throw new SAXException(error);
1070
		}
1071
		logMetacat.debug("current node type from xml is COMMENT");
1072
		logMetacat.debug("node type from stack: " + node.getNodeType());
1073
		logMetacat.debug("current node data from xml is: " + string);
1074
		logMetacat.debug("node data from stack: " + node.getNodeData());
1075
		logMetacat.debug("node is from stack: " + node.getNodeId());
1076
		// if not consistent terminate program and throw a exception
1077
		if (!node.getNodeType().equals("COMMENT") || !string.equals(node.getNodeData())) {
1078
			logMetacat.error("Inconsistence happened: ");
1079
			logMetacat.error("current node type from xml is COMMENT");
1080
			logMetacat.error("node type from stack: " + node.getNodeType());
1081
			logMetacat.error("current node data from xml is: " + string);
1082
			logMetacat.error("node data from stack: " + node.getNodeData());
1083
			logMetacat.error("node is from stack: " + node.getNodeId());
1084
			throw new SAXException(error);
1085
		}// if
1086
	}
1087

    
1088
	/**
1089
	 * SAX Handler called once for each processing instruction found: node that
1090
	 * PI may occur before or after the root element.
1091
	 */
1092
	public void processingInstruction(String target, String data) throws SAXException {
1093
		logMetacat.debug("PI");
1094
		if (!handleInlineData) {
1095
			DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1096
			endNodeId = currentNode.writeChildNodeToDB("PI", target, data, docid);
1097
		} else {
1098
			StringBuffer inlinePI = new StringBuffer();
1099
			inlinePI.append("<?");
1100
			inlinePI.append(target);
1101
			inlinePI.append(" ");
1102
			inlinePI.append(data);
1103
			inlinePI.append("?>");
1104
			logMetacat.debug("inline data pi is: " + inlinePI.toString());
1105
			writeInlineDataIntoFile(inlineDataFileWriter, inlinePI);
1106
		}
1107
	}
1108

    
1109
	/** SAX Handler that is called at the start of Namespace */
1110
	public void startPrefixMapping(String prefix, String uri) throws SAXException {
1111
		logMetacat.debug("NAMESPACE");
1112
		if (!handleInlineData) {
1113
			namespaces.put(prefix, uri);
1114
		} else {
1115
			inlineDataNameSpace.put(prefix, uri);
1116
		}
1117
	}
1118

    
1119
	/**
1120
	 * SAX Handler that is called for each XML text node that is Ignorable white
1121
	 * space
1122
	 */
1123
	public void ignorableWhitespace(char[] cbuf, int start, int len) throws SAXException {
1124
		// When validation is turned "on", white spaces are reported here
1125
		// When validation is turned "off" white spaces are not reported here,
1126
		// but through characters() callback
1127
		logMetacat.debug("IGNORABLEWHITESPACE");
1128
		if (!handleInlineData) {
1129
			DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1130
				String data = new String(cbuf, start, len);
1131
				// compare whitespace in access top module
1132
				if (processingTopLevelAccess && needToCheckAccessModule) {
1133
					compareWhiteSpace(currentUnchangeableAccessModuleNodeStack, data,
1134
							UPDATEACCESSERROR);
1135
				}
1136
				// Write the content of the node to the database
1137
				if (needToCheckAccessModule
1138
						&& (processingAdditionalAccess || processingOtherAccess || processingTopLevelAccess)) {
1139
					// stored the pull out nodes into storedNode stack
1140
					NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT", null,
1141
							null, MetacatUtil.normalize(data));
1142
					storedAccessNodeStack.push(nodeElement);
1143

    
1144
				}
1145
				endNodeId = currentNode.writeChildNodeToDB("TEXT", null, data, docid);
1146
		} else {
1147
			// This is inline data write to file directly
1148
			StringBuffer inlineWhiteSpace = new StringBuffer(new String(cbuf, start, len));
1149
			writeInlineDataIntoFile(inlineDataFileWriter, inlineWhiteSpace);
1150
		}
1151

    
1152
	}
1153

    
1154
	/* Compare whitespace from xml and db */
1155
	private void compareWhiteSpace(Stack<NodeRecord> nodeStack, String string,
1156
			String error) throws SAXException {
1157
		NodeRecord node = null;
1158
		try {
1159
			node = nodeStack.pop();
1160
		} catch (EmptyStackException ee) {
1161
			logMetacat.error("the stack is empty for whitespace data");
1162
			throw new SAXException(error);
1163
		}
1164
		if (!node.getNodeType().equals("TEXT") || !string.equals(node.getNodeData())) {
1165
			logMetacat.error("Inconsistence happened: ");
1166
			logMetacat.error("current node type from xml is WHITESPACE TEXT");
1167
			logMetacat.error("node type from stack: " + node.getNodeType());
1168
			logMetacat.error("current node data from xml is: " + string);
1169
			logMetacat.error("node data from stack: " + node.getNodeData());
1170
			logMetacat.error("node is from stack: " + node.getNodeId());
1171
			throw new SAXException(error);
1172
		}// if
1173
	}
1174

    
1175
	/** SAX Handler that receives notification of end of the document */
1176
	public void endDocument() throws SAXException {
1177
		logMetacat.debug("end Document");
1178
		// There are some unchangable subtree didn't be compare
1179
		// This maybe cause user change the subtree id
1180
		if (!super.getIsRevisionDoc()) {
1181
			// write access rule to db
1182
			writeAccessRuleToDB();
1183
			// delete relation table
1184
			deleteRelations();
1185
			// write relations
1186
			for (int i = 0; i < onlineDataFileIdInRelationVector.size(); i++) {
1187
				String id = onlineDataFileIdInRelationVector.elementAt(i);
1188
				writeOnlineDataFileIdIntoRelationTable(id);
1189
			}
1190
		}
1191
	}
1192

    
1193
	/* The method to write all access rule into db */
1194
	private void writeAccessRuleToDB() throws SAXException {
1195
		// Delete old permssion
1196
		deletePermissionsInAccessTable();
1197
		// write top leve access rule
1198
		writeTopLevelAccessRuleToDB();
1199
		// write additional access rule
1200
		// writeAdditionalAccessRuleToDB();
1201
		writeAdditionalAccessRulesToDB();
1202
	}// writeAccessRuleToDB
1203

    
1204
	/* The method to write top level access rule into db. */
1205
	private void writeTopLevelAccessRuleToDB() throws SAXException {
1206
		// for top document level
1207
		AccessSection accessSection = topLevelAccessControlMap.get(docid);
1208
		boolean top = true;
1209
		String subSectionId = null;
1210
		if (accessSection != null) {
1211
			AccessSection accessSectionObj = accessSection;
1212

    
1213
			// if accessSection is not null and is not reference
1214
			if (accessSectionObj.getReferences() == null) {
1215
				// write the top level access module into xml_accesssubtree to
1216
				// store info and then when update to check if the user can
1217
				// update it or not
1218
				deleteAccessSubTreeRecord(docid);
1219
				writeAccessSubTreeIntoDB(accessSectionObj, TOPLEVEL);
1220

    
1221
				// write access section into xml_access table
1222
				writeGivenAccessRuleIntoDB(accessSectionObj, top, subSectionId);
1223
				// write online data file into xml_access too.
1224
				// for (int i= 0; i <onlineDataFileIdInTopAccessVector.size();
1225
				// i++)
1226
				// {
1227
				// String id = onlineDataFileIdInTopAccessVector.elementAt(i);
1228
				// writeAccessRuleForRelatedDataFileIntoDB(accessSectionObj,
1229
				// id);
1230
				// }
1231

    
1232
			} else {
1233

    
1234
				// this is a reference and go trough the vector which contains
1235
				// all access object
1236
				String referenceId = accessSectionObj.getReferences();
1237
				boolean findAccessObject = false;
1238
				logMetacat.debug("referered id for top access: " + referenceId);
1239
				for (int i = 0; i < accessObjectList.size(); i++) {
1240
					AccessSection accessObj = accessObjectList.elementAt(i);
1241
					String accessObjId = accessObj.getSubTreeId();
1242
					if (referenceId != null && accessObj != null
1243
							&& referenceId.equals(accessObjId)) {
1244
						// make sure the user didn't change any thing in this
1245
						// access moduel
1246
						// too if user doesn't have all permission
1247
						if (needToCheckAccessModule) {
1248

    
1249
							Stack<NodeRecord> newStack = accessObj
1250
									.getStoredTmpNodeStack();
1251
							// revise order
1252
							newStack = DocumentUtil.reviseStack(newStack);
1253
							// go throught the vector of
1254
							// unChangeableAccessSubtreevector
1255
							// and find the one whose id is as same as
1256
							// referenceid
1257
							AccessSection oldAccessObj = getAccessSectionFromUnchangableAccessVector(referenceId);
1258
							// if oldAccessObj is null something is wrong
1259
							if (oldAccessObj == null) {
1260
								throw new SAXException(UPDATEACCESSERROR);
1261
							}// if
1262
							else {
1263
								// Get the node stack from old access obj
1264
								Stack<NodeRecord> oldStack = oldAccessObj
1265
										.getSubTreeNodeStack();
1266
								compareNodeStacks(newStack, oldStack);
1267
							}// else
1268
						}// if
1269
						// write accessobject into db
1270
						writeGivenAccessRuleIntoDB(accessObj, top, subSectionId);
1271
						// write online data file into xml_access too.
1272
						// for (int j= 0; j
1273
						// <onlineDataFileIdInTopAccessVector.size(); j++)
1274
						// {
1275
						// String id =
1276
						// onlineDataFileIdInTopAccessVector.elementAt(j);
1277
						// writeAccessRuleForRelatedDataFileIntoDB(accessSectionObj,
1278
						// id);
1279
						// }
1280

    
1281
						// write the reference access into xml_accesssubtree
1282
						// too write the top level access module into
1283
						// xml_accesssubtree to store info and then when update
1284
						// to check if the user can update it or not
1285
						deleteAccessSubTreeRecord(docid);
1286
						writeAccessSubTreeIntoDB(accessSectionObj, TOPLEVEL);
1287
						writeAccessSubTreeIntoDB(accessObj, SUBTREELEVEL);
1288
						findAccessObject = true;
1289
						break;
1290
					}
1291
				}// for
1292
				// if we couldn't find an access subtree id for this reference
1293
				// id
1294
				if (!findAccessObject) {
1295
					throw new SAXException("The referenceid: " + referenceId
1296
							+ " is not access subtree");
1297
				}// if
1298
			}// else
1299

    
1300
		}// if
1301
		else {
1302
			// couldn't find a access section object
1303
			logMetacat.warn("couldn't find access control for document: " + docid);
1304
		}
1305

    
1306
	}// writeTopLevelAccessRuletoDB
1307

    
1308
	/* Given a subtree id and find the responding access section */
1309
	private AccessSection getAccessSectionFromUnchangableAccessVector(String id) {
1310
		AccessSection result = null;
1311
		// Makse sure the id
1312
		if (id == null || id.equals("")) {
1313
			return result;
1314
		}
1315
		// go throught vector and find the list
1316
		for (int i = 0; i < unChangeableAccessSubTreeVector.size(); i++) {
1317
			AccessSection accessObj = unChangeableAccessSubTreeVector.elementAt(i);
1318
			if (accessObj.getSubTreeId() != null && (accessObj.getSubTreeId()).equals(id)) {
1319
				result = accessObj;
1320
			}// if
1321
		}// for
1322
		return result;
1323
	}// getAccessSectionFromUnchangableAccessVector
1324

    
1325
	/* Compare two node stacks to see if they are same */
1326
	private void compareNodeStacks(Stack<NodeRecord> stack1, Stack<NodeRecord> stack2)
1327
			throws SAXException {
1328
		// make sure stack1 and stack2 are not empty
1329
		if (stack1.isEmpty() || stack2.isEmpty()) {
1330
			logMetacat.error("Because stack is empty!");
1331
			throw new SAXException(UPDATEACCESSERROR);
1332
		}
1333
		// go throw two stacks and compare every element
1334
		while (!stack1.isEmpty()) {
1335
			// Pop an element from stack1
1336
			NodeRecord record1 = stack1.pop();
1337
			// Pop an element from stack2(stack 2 maybe empty)
1338
			NodeRecord record2 = null;
1339
			try {
1340
				record2 = stack2.pop();
1341
			} catch (EmptyStackException ee) {
1342
				logMetacat.error("Node stack2 is empty but stack1 isn't!");
1343
				throw new SAXException(UPDATEACCESSERROR);
1344
			}
1345
			// if two records are not same throw a exception
1346
			if (!record1.contentEquals(record2)) {
1347
				logMetacat.error("Two records from new and old stack are not " + "same!");
1348
				throw new SAXException(UPDATEACCESSERROR);
1349
			}// if
1350
		}// while
1351

    
1352
		// now stack1 is empty and we should make sure stack2 is empty too
1353
		if (!stack2.isEmpty()) {
1354
			logMetacat
1355
					.error("stack2 still has some elements while stack " + "is empty! ");
1356
			throw new SAXException(UPDATEACCESSERROR);
1357
		}// if
1358
	}// comparingNodeStacks
1359

    
1360
	/* The method to write additional access rule into db. */
1361
	private void writeAdditionalAccessRulesToDB() throws SAXException {
1362
		
1363
		// Iterate through every distribution and write access sections for data and inline
1364
		// types to the database
1365
		for (DistributionSection distributionSection : allDistributionSections) {			
1366
			// we're only interested in data and inline distributions
1367
			int distributionType = distributionSection.getDistributionType();
1368
			if (distributionType == DistributionSection.DATA_DISTRIBUTION
1369
					|| distributionType == DistributionSection.INLINE_DATA_DISTRIBUTION) {
1370
				AccessSection accessSection = distributionSection.getAccessSection();
1371
				
1372
				// If the distribution doesn't have an access section, we continue.
1373
				if (accessSection == null) {
1374
					continue;		
1375
				} 
1376
				
1377
				// We want to check file permissions for all online data updates and inserts, or for 
1378
				// inline updates.
1379
//				if (distributionType == DistributionSection.DATA_DISTRIBUTION
1380
//						|| (distributionType == DistributionSection.INLINE_DATA_DISTRIBUTION && action == "UPDATE")) {
1381

    
1382
				if (distributionType == DistributionSection.DATA_DISTRIBUTION) {
1383
					try {
1384
						// check for the previous version for permissions on update
1385
						String dataDocid = distributionSection.getDataFileName();
1386
						String previousDocid = dataDocid;
1387
						if (action == "UPDATE") {
1388
							String docidWithoutRev = DocumentUtil.getDocIdFromString(dataDocid);
1389
							int latestRevision = DBUtil.getLatestRevisionInDocumentTable(docidWithoutRev);
1390
							if (latestRevision > 0) {
1391
								previousDocid = distributionSection.getDataFileName() + PropertyService.getProperty("document.accNumSeparator") + latestRevision;
1392
							}
1393
						}
1394
						
1395
						PermissionController controller = new PermissionController(previousDocid);
1396
						
1397
						if (AccessionNumber.accNumberUsed(docid)
1398
								&& !controller.hasPermission(user, groups, "WRITE")) {
1399
							throw new SAXException(UPDATEACCESSERROR);
1400
						}
1401
					} catch (SQLException sqle) {
1402
						throw new SAXException(
1403
								"Database error checking user permissions: "
1404
										+ sqle.getMessage());
1405
					} catch (Exception e) {
1406
						throw new SAXException(
1407
								"General error checking user permissions: "
1408
										+ e.getMessage());
1409
					}
1410
				} else if (distributionType == DistributionSection.INLINE_DATA_DISTRIBUTION && action == "UPDATE") {
1411
					try {
1412
						
1413
						// check for the previous version for permissions
1414
						int latestRevision = DBUtil.getLatestRevisionInDocumentTable(docid);
1415
						String previousDocid = 
1416
							docid + PropertyService.getProperty("document.accNumSeparator") + latestRevision;
1417
						PermissionController controller = new PermissionController(previousDocid);
1418

    
1419
						if (!controller.hasPermission(user, groups, "WRITE")) {
1420
							throw new SAXException(UPDATEACCESSERROR);
1421
						}
1422
					} catch (SQLException sqle) {
1423
						throw new SAXException(
1424
								"Database error checking user permissions: "
1425
										+ sqle.getMessage());
1426
					} catch (Exception e) {
1427
						throw new SAXException(
1428
								"General error checking user permissions: "
1429
										+ e.getMessage());
1430
					}
1431
				}
1432
				
1433
				String subSectionId = Integer.toString(distributionSection.getDistributionId());
1434
				writeGivenAccessRuleIntoDB(accessSection, false, subSectionId);
1435
			}
1436

    
1437
		}
1438
		
1439
		
1440
	}
1441

    
1442
	/* Write a given access rule into db */
1443
	private void writeGivenAccessRuleIntoDB(AccessSection accessSection,
1444
			boolean topLevel, String subSectionId) throws SAXException {
1445
		if (accessSection == null) {
1446
			throw new SAXException("The access object is null");
1447
		}
1448

    
1449
		String guid = null;
1450
		try {
1451
			guid = IdentifierManager.getInstance().getGUID(docid, Integer.valueOf(revision));
1452
		} catch (NumberFormatException e) {
1453
			throw new SAXException(e.getMessage(), e);
1454
		} catch (McdbDocNotFoundException e) {
1455
			// register the default mapping now
1456
			guid = docid + "." + revision;
1457
			IdentifierManager.getInstance().createMapping(guid, guid);
1458
		}
1459
		
1460
		String permOrder = accessSection.getPermissionOrder();
1461
		String sql = null;
1462
		PreparedStatement pstmt = null;
1463
		if (topLevel) {
1464
			sql = "INSERT INTO xml_access (guid, principal_name, permission, "
1465
					+ "perm_type, perm_order, accessfileid) VALUES "
1466
					+ " (?, ?, ?, ?, ?, ?)";
1467
		} else {
1468
			sql = "INSERT INTO xml_access (guid,principal_name, "
1469
					+ "permission, perm_type, perm_order, accessfileid, subtreeid"
1470
					+ ") VALUES" + " (?, ?, ?, ?, ?, ?, ?)";
1471
		}
1472
		try {
1473

    
1474
			pstmt = connection.prepareStatement(sql);
1475
			// Increase DBConnection usage count
1476
			connection.increaseUsageCount(1);
1477
			// Bind the values to the query
1478
			pstmt.setString(6, guid);
1479
			logMetacat.debug("Accessfileid in accesstable: " + guid);
1480
			pstmt.setString(5, permOrder);
1481
			logMetacat.debug("PermOder in accesstable: " + permOrder);
1482
			// if it is not top level, set subsection id
1483
			if (topLevel) {
1484
				pstmt.setString(1, guid);
1485
				logMetacat.debug("Guid in accesstable: " + guid);
1486
			}
1487
			if (!topLevel) {
1488
				// TODO: look up guid?
1489
				pstmt.setString(1, accessSection.getDataFileName());
1490
				logMetacat.debug("Docid in accesstable: " + inlineDataFileName);
1491

    
1492
				// for subtree should specify the
1493
				if (subSectionId == null) {
1494
					throw new SAXException("The subsection is null");
1495
				}
1496

    
1497
				pstmt.setString(7, subSectionId);
1498
				logMetacat.debug("SubSectionId in accesstable: " + subSectionId);
1499
			}
1500

    
1501
			Vector<AccessRule> accessRules = accessSection.getAccessRules();
1502
			// go through every rule
1503
			for (int i = 0; i < accessRules.size(); i++) {
1504
				AccessRule rule = accessRules.elementAt(i);
1505
				String permType = rule.getPermissionType();
1506
				int permission = rule.getPermission();
1507
				pstmt.setInt(3, permission);
1508
				logMetacat.debug("permission in accesstable: " + permission);
1509
				pstmt.setString(4, permType);
1510
				logMetacat.debug("Permtype in accesstable: " + permType);
1511
				// go through every principle in rule
1512
				Vector<String> nameVector = rule.getPrincipal();
1513
				for (int j = 0; j < nameVector.size(); j++) {
1514
					String prName = nameVector.elementAt(j);
1515
					pstmt.setString(2, prName);
1516
					logMetacat.debug("Principal in accesstable: " + prName);
1517
					logMetacat.debug("running sql: " + pstmt.toString());
1518
					pstmt.execute();
1519
				}// for
1520
			}// for
1521
			pstmt.close();
1522
		}// try
1523
		catch (SQLException e) {
1524
			throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
1525
					+ e.getMessage());
1526
		}// catch
1527
		finally {
1528
			try {
1529
				pstmt.close();
1530
			} catch (SQLException ee) {
1531
				throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
1532
						+ ee.getMessage());
1533
			}
1534
		}// finally
1535

    
1536
	}// writeGivenAccessRuleIntoDB
1537

    
1538
	
1539

    
1540
	/* Delete from db all permission for resources related to the document, if any */
1541
	private void deletePermissionsInAccessTable() throws SAXException {
1542
		PreparedStatement pstmt = null;
1543
		try {
1544
			String sql = "DELETE FROM xml_access " +
1545
					"WHERE accessfileid IN (SELECT guid from identifier where docid = ? and rev = ?)";
1546
			// delete all acl records for resources related to @aclid if any
1547
			pstmt = connection.prepareStatement(sql);
1548
			pstmt.setString(1, docid);
1549
			pstmt.setInt(2, Integer.valueOf(revision));
1550
			// Increase DBConnection usage count
1551
			connection.increaseUsageCount(1);
1552
			logMetacat.debug("running sql: " + sql);
1553
			pstmt.execute();
1554

    
1555
		} catch (SQLException e) {
1556
			throw new SAXException(e.getMessage());
1557
		} finally {
1558
			try {
1559
				pstmt.close();
1560
			} catch (SQLException ee) {
1561
				throw new SAXException(ee.getMessage());
1562
			}
1563
		}
1564
	}// deletePermissionsInAccessTable
1565

    
1566
	/*
1567
	 * In order to make sure only usr has "all" permission can update access
1568
	 * subtree in eml document we need to keep access subtree info in
1569
	 * xml_accesssubtree table, such as docid, version, startnodeid, endnodeid
1570
	 */
1571
	private void writeAccessSubTreeIntoDB(AccessSection accessSection, String level)
1572
			throws SAXException {
1573
		if (accessSection == null) {
1574
			throw new SAXException("The access object is null");
1575
		}
1576

    
1577
		String sql = null;
1578
		PreparedStatement pstmt = null;
1579
		sql = "INSERT INTO xml_accesssubtree (docid, rev, controllevel, "
1580
				+ "subtreeid, startnodeid, endnodeid) VALUES " + " (?, ?, ?, ?, ?, ?)";
1581
		try {
1582

    
1583
			pstmt = connection.prepareStatement(sql);
1584
			// Increase DBConnection usage count
1585
			connection.increaseUsageCount(1);
1586
			long startNodeId = accessSection.getStartNodeId();
1587
			long endNodeId = accessSection.getEndNodeId();
1588
			String sectionId = accessSection.getSubTreeId();
1589
			// Bind the values to the query
1590
			pstmt.setString(1, docid);
1591
			logMetacat.debug("Docid in access-subtreetable: " + docid);
1592
			pstmt.setLong(2, (new Long(revision)).longValue());
1593
			logMetacat.debug("rev in accesssubtreetable: " + revision);
1594
			pstmt.setString(3, level);
1595
			logMetacat.debug("contorl level in access-subtree table: " + level);
1596
			pstmt.setString(4, sectionId);
1597
			logMetacat.debug("Subtree id in access-subtree table: " + sectionId);
1598
			pstmt.setLong(5, startNodeId);
1599
			logMetacat.debug("Start node id is: " + startNodeId);
1600
			pstmt.setLong(6, endNodeId);
1601
			logMetacat.debug("End node id is: " + endNodeId);
1602
			logMetacat.debug("running sql: " + pstmt.toString());
1603
			pstmt.execute();
1604
			pstmt.close();
1605
		}// try
1606
		catch (SQLException e) {
1607
			throw new SAXException("EMLSAXHandler.writeAccessSubTreeIntoDB(): "
1608
					+ e.getMessage());
1609
		}// catch
1610
		finally {
1611
			try {
1612
				pstmt.close();
1613
			} catch (SQLException ee) {
1614
				throw new SAXException("EMLSAXHandler.writeAccessSubTreeIntoDB(): "
1615
						+ ee.getMessage());
1616
			}
1617
		}// finally
1618

    
1619
	}// writeAccessSubtreeIntoDB
1620

    
1621
	/* Delete every access subtree record from xml_accesssubtree. */
1622
	private void deleteAccessSubTreeRecord(String docId) throws SAXException {
1623
		PreparedStatement pstmt = null;
1624
		try {
1625
			String sql = "DELETE FROM xml_accesssubtree WHERE docid = ?";
1626
			// delete all acl records for resources related to @aclid if any
1627
			pstmt = connection.prepareStatement(sql);
1628
			pstmt.setString(1, docId);
1629
			// Increase DBConnection usage count
1630
			connection.increaseUsageCount(1);
1631
			logMetacat.debug("running sql: " + sql);
1632
			pstmt.execute();
1633

    
1634
		} catch (SQLException e) {
1635
			throw new SAXException(e.getMessage());
1636
		} finally {
1637
			try {
1638
				pstmt.close();
1639
			} catch (SQLException ee) {
1640
				throw new SAXException(ee.getMessage());
1641
			}
1642
		}
1643
	}// deleteAccessSubTreeRecord
1644

    
1645
	// open a file writer for writing inline data to file
1646
	private Writer createInlineDataFileWriter(String fileName, String encoding) throws SAXException {
1647
		Writer writer = null;
1648
		String path;
1649
		try {
1650
			path = PropertyService.getProperty("application.inlinedatafilepath");
1651
		} catch (PropertyNotFoundException pnfe) {
1652
			throw new SAXException(pnfe.getMessage());
1653
		}
1654
		/*
1655
		 * File inlineDataDirectory = new File(path);
1656
		 */
1657
		String newFile = path + "/" + fileName;
1658
		logMetacat.debug("inline file name: " + newFile);
1659
		try {
1660
			// true means append
1661
			writer = new OutputStreamWriter(new FileOutputStream(newFile, true), encoding);
1662
		} catch (IOException ioe) {
1663
			throw new SAXException(ioe.getMessage());
1664
		}
1665
		return writer;
1666
	}
1667

    
1668
	// write inline data into file system and return file name(without path)
1669
	private void writeInlineDataIntoFile(Writer writer, StringBuffer data)
1670
			throws SAXException {
1671
		try {
1672
			writer.write(data.toString());
1673
			writer.flush();
1674
		} catch (Exception e) {
1675
			throw new SAXException(e.getMessage());
1676
		}
1677
	}
1678

    
1679

    
1680

    
1681
	// if xml file failed to upload, we need to call this method to delete
1682
	// the inline data already in file system
1683
	public void deleteInlineFiles() throws SAXException {
1684
		if (!inlineFileIdList.isEmpty()) {
1685
			for (int i = 0; i < inlineFileIdList.size(); i++) {
1686
				String fileName = inlineFileIdList.elementAt(i);
1687
				deleteInlineDataFile(fileName);
1688
			}
1689
		}
1690
	}
1691

    
1692
	/* delete the inline data file */
1693
	private void deleteInlineDataFile(String fileName) throws SAXException {
1694
		String path;
1695
		try {
1696
			path = PropertyService.getProperty("application.inlinedatafilepath");
1697
		} catch (PropertyNotFoundException pnfe) {
1698
			throw new SAXException("Could not find inline data file path: "
1699
					+ pnfe.getMessage());
1700
		}
1701
		File inlineDataDirectory = new File(path);
1702
		File newFile = new File(inlineDataDirectory, fileName);
1703
		newFile.delete();
1704

    
1705
	}
1706

    
1707
	/* Delete relations */
1708
	private void deleteRelations() throws SAXException {
1709
		PreparedStatement pStmt = null;
1710
		String sql = "DELETE FROM xml_relation where docid =?";
1711
		try {
1712
			pStmt = connection.prepareStatement(sql);
1713
			// bind variable
1714
			pStmt.setString(1, docid);
1715
			// execute query
1716
			pStmt.execute();
1717
			pStmt.close();
1718
		}// try
1719
		catch (SQLException e) {
1720
			throw new SAXException("EMLSAXHandler.deleteRelations(): " + e.getMessage());
1721
		}// catch
1722
		finally {
1723
			try {
1724
				pStmt.close();
1725
			}// try
1726
			catch (SQLException ee) {
1727
				throw new SAXException("EMLSAXHandler.deleteRelations: "
1728
						+ ee.getMessage());
1729
			}// catch
1730
		}// finally
1731
	}
1732

    
1733
	/*
1734
	 * Write an online data file id into xml_relation table. The dataId
1735
	 * shouldnot have the revision
1736
	 */
1737
	private void writeOnlineDataFileIdIntoRelationTable(String dataId)
1738
			throws SAXException {
1739
		PreparedStatement pStmt = null;
1740
		String sql = "INSERT into xml_relation (docid, packagetype, subject, "
1741
				+ "relationship, object) values (?, ?, ?, ?, ?)";
1742
		try {
1743
			pStmt = connection.prepareStatement(sql);
1744
			// bind variable
1745
			pStmt.setString(1, docid);
1746
			pStmt.setString(2, doctype); //DocumentImpl.EML2_1_0NAMESPACE);
1747
			pStmt.setString(3, docid);
1748
			pStmt.setString(4, RELATION);
1749
			pStmt.setString(5, dataId);
1750
			// execute query
1751
			pStmt.execute();
1752
			pStmt.close();
1753
		}// try
1754
		catch (SQLException e) {
1755
			throw new SAXException(
1756
					"EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): "
1757
							+ e.getMessage());
1758
		}// catch
1759
		finally {
1760
			try {
1761
				pStmt.close();
1762
			}// try
1763
			catch (SQLException ee) {
1764
				throw new SAXException(
1765
						"EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): "
1766
								+ ee.getMessage());
1767
			}// catch
1768
		}// finally
1769

    
1770
	}// writeOnlineDataFileIdIntoRelationTable
1771

    
1772
	/*
1773
	 * This method will handle data file in online url. If the data file is in
1774
	 * ecogrid protocol, then the datafile identifier(without rev)should be put
1775
	 * into onlineDataFileRelationVector. The docid in this vector will be
1776
	 * insert into xml_relation table in endDocument(). If the data file doesn't
1777
	 * exsit in xml_documents or xml_revision table, or the user has all
1778
	 * permission to the data file if the docid already existed, the data file
1779
	 * id (without rev)will be put into onlineDataFileTopAccessVector. The top
1780
	 * access rules specified in this eml document will apply to the data file.
1781
	 * NEED to do: We should also need to implement http and ftp. Those external
1782
	 * files should be download and assign a data file id to it.
1783
	 */
1784
	private void handleOnlineUrlDataFile(String url) throws SAXException {
1785
		logMetacat.warn("The url is " + url);
1786

    
1787
		if (currentDistributionSection == null) {
1788
			throw new SAXException("Trying to set the online file name for a null"
1789
					+ " distribution section");
1790
		}
1791

    
1792
		// if the url is not in ecogrid protocol, null will be returned
1793
		String accessionNumber = DocumentUtil.getAccessionNumberFromEcogridIdentifier(url);
1794
		if (accessionNumber == null) {
1795
			// the accession number is null if the url does not references a
1796
			// local data file (url would start with "ecogrid://"
1797
			currentDistributionSection
1798
					.setDistributionType(DistributionSection.ONLINE_DATA_DISTRIBUTION);
1799
		} else {
1800
			// handle ecogrid protocol
1801
			// get rid of revision number to get the docid.
1802
			String docid = DocumentUtil.getDocIdFromAccessionNumber(accessionNumber);
1803
			int rev = DocumentUtil.getRevisionFromAccessionNumber(accessionNumber);
1804
			String guid = null;
1805
			try {
1806
				guid = IdentifierManager.getInstance().getGUID(docid, rev);
1807
			} catch (McdbDocNotFoundException e1) {
1808
				guid = docid + "." + rev;
1809
				IdentifierManager.getInstance().createMapping(guid, guid);
1810
			}
1811

    
1812
			currentDistributionSection
1813
					.setDistributionType(DistributionSection.DATA_DISTRIBUTION);
1814
			currentDistributionSection.setDataFileName(guid);
1815

    
1816
			// distributionOnlineFileName = docid;
1817
			onlineDataFileIdInRelationVector.add(guid);
1818
			try {				
1819
				if (!AccessionNumber.accNumberUsed(docid)) {
1820
					onlineDataFileIdInTopAccessVector.add(guid);
1821
				} else {
1822
					// check the previous revision if we have it
1823
					int previousRevision = rev;
1824
					Vector<Integer> revisions = DBUtil.getRevListFromRevisionTable(docid);
1825
					if (revisions != null && revisions.size() > 0) {
1826
						previousRevision = revisions.get(revisions.size() - 1);
1827
					}
1828
					String previousDocid = 
1829
						docid + PropertyService.getProperty("document.accNumSeparator") + previousRevision;
1830
					
1831
					PermissionController controller = new PermissionController(previousDocid);				
1832
					if (controller.hasPermission(user, groups,AccessControlInterface.ALLSTRING)) {
1833
						onlineDataFileIdInTopAccessVector.add(guid);
1834
					} else {
1835
						throw new SAXException(UPDATEACCESSERROR);
1836
					}
1837
				} 
1838
			}// try
1839
			catch (Exception e) {
1840
				logMetacat.error("Eorr in "
1841
								+ "Eml210SAXHanlder.handleOnlineUrlDataFile is "
1842
								+ e.getMessage());
1843
				throw new SAXException(e.getMessage());
1844
			}
1845
		}
1846
	}
1847
}
(33-33/64)