Project

General

Profile

1 2169 sgarg
/**
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$'
10
 *     '$Date$'
11
 * '$Revision$'
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 5752 leinfelder
import java.io.FileOutputStream;
32 2169 sgarg
import java.io.IOException;
33 5752 leinfelder
import java.io.OutputStreamWriter;
34
import java.io.Writer;
35 2169 sgarg
import java.sql.PreparedStatement;
36
import java.sql.ResultSet;
37
import java.sql.SQLException;
38 6595 leinfelder
import java.util.Date;
39 2169 sgarg
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 2663 sgarg
import org.apache.log4j.Logger;
46 2169 sgarg
import org.xml.sax.Attributes;
47
import org.xml.sax.SAXException;
48
49 5090 daigle
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlInterface;
50
import edu.ucsb.nceas.metacat.accesscontrol.AccessRule;
51
import edu.ucsb.nceas.metacat.accesscontrol.AccessSection;
52 5015 daigle
import edu.ucsb.nceas.metacat.database.DBConnection;
53
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
54 5030 daigle
import edu.ucsb.nceas.metacat.properties.PropertyService;
55 5025 daigle
import edu.ucsb.nceas.metacat.util.DocumentUtil;
56 4698 daigle
import edu.ucsb.nceas.metacat.util.MetacatUtil;
57 4080 daigle
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
58
59 2169 sgarg
/**
60 4472 daigle
 * A database aware Class implementing callback methods for the SAX parser to
61 2169 sgarg
 * call when processing the XML stream and generating events
62
 */
63 4678 daigle
public class Eml210SAXHandler extends DBSAXHandler implements AccessControlInterface {
64 2169 sgarg
65 5311 daigle
	private boolean processingTopLevelAccess = false;
66 2169 sgarg
67 5311 daigle
	private boolean processingAdditionalAccess = false;
68 2169 sgarg
69 5311 daigle
	private boolean processingOtherAccess = false;
70 2169 sgarg
71 4678 daigle
	private AccessSection accessObject = null;
72 2169 sgarg
73 4678 daigle
	private AccessRule accessRule = null;
74 2169 sgarg
75 5311 daigle
	// all access rules
76
	private Vector<AccessSection> accessObjectList = new Vector<AccessSection>();
77 2169 sgarg
78 4678 daigle
	private Hashtable<String, AccessSection> topLevelAccessControlMap = new Hashtable<String, AccessSection>();
79 2169 sgarg
80 5311 daigle
	// 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 4678 daigle
	private Stack<SubTree> subTreeInfoStack = new Stack<SubTree>();
90 2169 sgarg
91 5311 daigle
	private Vector<SubTree> subTreeList = new Vector<SubTree>();
92 4678 daigle
93
	private boolean needToCheckAccessModule = false;
94 2169 sgarg
95 4678 daigle
	private Vector<AccessSection> unChangeableAccessSubTreeVector = new Vector<AccessSection>();
96 2169 sgarg
97 4678 daigle
	private Stack<NodeRecord> currentUnchangeableAccessModuleNodeStack = new Stack<NodeRecord>();
98 2169 sgarg
99 4678 daigle
	private AccessSection topAccessSection;
100 2169 sgarg
101 4678 daigle
	// 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 2169 sgarg
105 4678 daigle
	// vector stored the data file id which will be write into relation table
106
	private Vector<String> onlineDataFileIdInRelationVector = new Vector<String>();
107 2169 sgarg
108 4678 daigle
	// 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 2169 sgarg
112 4678 daigle
	// Indicator of inline data
113
	private boolean handleInlineData = false;
114 2169 sgarg
115 4678 daigle
	private Hashtable<String, String> inlineDataNameSpace = null;
116 2169 sgarg
117 5752 leinfelder
	private Writer inlineDataFileWriter = null;
118 2169 sgarg
119 4678 daigle
	private String inlineDataFileName = null;
120 2169 sgarg
121 4678 daigle
	DistributionSection currentDistributionSection = null;
122 2169 sgarg
123 4678 daigle
	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 4472 daigle
	private int distributionIndex = 0;
130 2169 sgarg
131 4678 daigle
	// private String distributionOnlineFileName = null;
132
133 4472 daigle
	// This is used to delete inline files if the xml does not parse correctly.
134 4678 daigle
	private Vector<String> inlineFileIdList = new Vector<String>();
135 2169 sgarg
136 4678 daigle
	// Constant
137
	private static final String EML = "eml";
138 2169 sgarg
139 4678 daigle
	private static final String DISTRIBUTION = "distribution";
140 2169 sgarg
141 4678 daigle
	private static final String ORDER = "order";
142 2169 sgarg
143 4678 daigle
	private static final String ID = "id";
144 2169 sgarg
145 4678 daigle
	private static final String REFERENCES = "references";
146 2169 sgarg
147 4678 daigle
	public static final String INLINE = "inline";
148 2169 sgarg
149 4678 daigle
	private static final String ONLINE = "online";
150 2169 sgarg
151 4678 daigle
	private static final String URL = "url";
152 2169 sgarg
153 4678 daigle
	// private static final String PERMISSIONERROR = "User tried to update a
154
	// subtree "
155
	// + "when they don't have write permission!";
156 2169 sgarg
157 4678 daigle
	private static final String UPDATEACCESSERROR = "User tried to update an "
158
			+ "access module when they don't have \"ALL\" permission!";
159 2169 sgarg
160 4678 daigle
	private static final String TOPLEVEL = "top";
161 2169 sgarg
162 4678 daigle
	private static final String SUBTREELEVEL = "subtree";
163 2169 sgarg
164 4678 daigle
	private static final String RELATION = "Provides info for";
165 2663 sgarg
166 4678 daigle
	private Logger logMetacat = Logger.getLogger(Eml210SAXHandler.class);
167 2169 sgarg
168 4678 daigle
	/**
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 6595 leinfelder
			Date createDate, Date updateDate) throws SAXException {
194 4678 daigle
		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 2169 sgarg
199 6744 leinfelder
			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 4678 daigle
			}
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 2169 sgarg
230 4678 daigle
		try {
231 2169 sgarg
232 4678 daigle
			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 2169 sgarg
239 4678 daigle
			// 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 2169 sgarg
279 4678 daigle
	/** 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 2169 sgarg
289 4678 daigle
		DBSAXNode parentNode = null;
290
		DBSAXNode currentNode = null;
291 2169 sgarg
292 4678 daigle
		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 2169 sgarg
300 4678 daigle
			// 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 5025 daigle
				String docidWithoutRev = DocumentUtil.getDocIdFromString(docid);
307 4678 daigle
				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 4472 daigle
						+ distributionIndex;
317 5752 leinfelder
				inlineDataFileWriter = createInlineDataFileWriter(inlineDataFileName, encoding);
318 4678 daigle
				// 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 2169 sgarg
325 4678 daigle
			}
326 2169 sgarg
327 4678 daigle
			// 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 2169 sgarg
331 4678 daigle
				// compare top level access module
332 5311 daigle
				if (processingTopLevelAccess && needToCheckAccessModule) {
333
					compareAccessTextNode(currentUnchangeableAccessModuleNodeStack, textBuffer);
334 4678 daigle
				}
335 2169 sgarg
336 4678 daigle
				if (needToCheckAccessModule
337 5311 daigle
						&& (processingAdditionalAccess || processingOtherAccess || processingTopLevelAccess)) {
338 4678 daigle
					// stored the pull out nodes into storedNode stack
339
					NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT", null,
340 4698 daigle
							null, MetacatUtil.normalize(textBuffer.toString()));
341 4678 daigle
					storedAccessNodeStack.push(nodeElement);
342 2169 sgarg
343 4678 daigle
				}
344 2169 sgarg
345 4678 daigle
				// 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 2169 sgarg
353 4678 daigle
			}
354 2169 sgarg
355 4678 daigle
			// 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 2169 sgarg
387 4678 daigle
					try {
388
						// Get dbconnection
389
						dbConn = DBConnectionPool
390
								.getDBConnection("DBSAXHandler.startElement");
391
						serialNumber = dbConn.getCheckOutSerialNumber();
392 6606 leinfelder
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 4678 daigle
						boolean hasRow = rs.next();
400
						if (hasRow) {
401
							catalogid = rs.getString(1);
402
						}
403 6606 leinfelder
						pstmt.close();
404 4678 daigle
					}// try
405
					finally {
406
						// Return dbconnection
407
						DBConnectionPool.returnDBConnection(dbConn, serialNumber);
408
					}// finally
409 2169 sgarg
410 4678 daigle
					// 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 2169 sgarg
419 5200 daigle
				} 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 5208 daigle
						throw (new SAXException("EML210SaxHandler.startElement - Doc ID " + docid + " was deleted and cannot be updated."));
431 5200 daigle
					} else {
432 5208 daigle
						throw (new SAXException("EML210SaxHandler.startElement - Doc ID " + docid + " was not found and cannot be updated."));
433 5200 daigle
					}
434
				} catch (Exception e) {
435 5208 daigle
                    throw (new SAXException("EML210SaxHandler.startElement - error with action " +
436
                    		action + " : " + e.getMessage()));
437 4678 daigle
				}
438
			}
439 2169 sgarg
440 4678 daigle
			// 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 2169 sgarg
457 4678 daigle
			// 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 2169 sgarg
464 4678 daigle
				// 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 2169 sgarg
473 4678 daigle
				} else if (attributeName != null && attributeName.equals(ID)) {
474 5096 daigle
475 4678 daigle
				}
476
			}// for
477
478
			// handle access stuff
479
			if (localName.equals(ACCESS)) {
480
				if (parentNode.getTagName().equals(EML)) {
481 5311 daigle
					processingTopLevelAccess = true;
482 4472 daigle
				} else if (parentNode.getTagName() == DISTRIBUTION) {
483 5311 daigle
					processingAdditionalAccess = true;
484 4472 daigle
				} else {
485
					// process other access embedded into resource level
486
					// module
487 5311 daigle
					processingOtherAccess = true;
488 4472 daigle
				}
489 4678 daigle
				// 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 5311 daigle
				if (processingAdditionalAccess) {
500 4678 daigle
					accessObject.setDataFileName(inlineDataFileName);
501
				}
502 2169 sgarg
503 4678 daigle
				// load top level node stack to
504
				// currentUnchangableAccessModuleNodeStack
505 5311 daigle
				if (processingTopLevelAccess && needToCheckAccessModule) {
506 4678 daigle
					// 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 2169 sgarg
514 4678 daigle
				// 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 2169 sgarg
530 4678 daigle
				accessRule = new AccessRule();
531 2169 sgarg
532 4678 daigle
				// set permission type "allow"
533
				accessRule.setPermissionType(ALLOW);
534 2169 sgarg
535 4678 daigle
			}
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 2169 sgarg
544 4678 daigle
			// 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 2169 sgarg
550 4678 daigle
			// compare top access level module
551 5311 daigle
			if (processingTopLevelAccess && needToCheckAccessModule) {
552 4678 daigle
				compareElementNameSpaceAttributes(
553
						currentUnchangeableAccessModuleNodeStack, namespaces, atts,
554
						localName, UPDATEACCESSERROR);
555 2169 sgarg
556 4678 daigle
			}
557 2169 sgarg
558 4678 daigle
			// store access module element and attributes into stored stack
559
			if (needToCheckAccessModule
560 5311 daigle
					&& (processingAdditionalAccess || processingOtherAccess || processingTopLevelAccess)) {
561 4678 daigle
				// stored the pull out nodes into storedNode stack
562
				NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "ELEMENT", localName,
563 4698 daigle
						prefix, MetacatUtil.normalize(null));
564 4678 daigle
				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 4698 daigle
							attributeName, null, MetacatUtil.normalize(attributeValue));
570 4678 daigle
					storedAccessNodeStack.push(nodeAttribute);
571
				}
572 2169 sgarg
573 4678 daigle
			}
574 2169 sgarg
575 4678 daigle
			// 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 2169 sgarg
583 4678 daigle
			// 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 2169 sgarg
619 4678 daigle
	}
620 2169 sgarg
621 4678 daigle
	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 2169 sgarg
655 4678 daigle
		// 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 2169 sgarg
667 4678 daigle
			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 2169 sgarg
683 4678 daigle
		}// while
684 2169 sgarg
685 4678 daigle
		// compare attributes
686
		for (int i = 0; i < attributes.getLength(); i++) {
687
			NodeRecord attriNode = null;
688
			try {
689
				attriNode = unchangeableNodeStack.pop();
690 2169 sgarg
691 4678 daigle
			} 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 2169 sgarg
705 4678 daigle
			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 2169 sgarg
720 4678 daigle
	}
721 2169 sgarg
722 4678 daigle
	/* method to compare current text node and node in db */
723 5311 daigle
	private void compareAccessTextNode(Stack<NodeRecord> nodeStack, StringBuffer text) throws SAXException {
724 4678 daigle
		NodeRecord node = null;
725
		// get node from current stack
726
		try {
727
			node = nodeStack.pop();
728
		} catch (EmptyStackException ee) {
729 5311 daigle
			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 4678 daigle
		}
732 5311 daigle
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 4678 daigle
		if (!node.getNodeType().equals("TEXT")
742 5311 daigle
				|| !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 4678 daigle
		}// if
750
	}
751 2169 sgarg
752 4678 daigle
	/** 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 2169 sgarg
782 4678 daigle
	/** 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 2169 sgarg
787 4678 daigle
		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 2169 sgarg
799 4678 daigle
			// 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 2169 sgarg
809 4678 daigle
		if (!handleInlineData) {
810
			// Get the node from the stack
811
			DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
812
			String currentTag = currentNode.getTagName();
813 2169 sgarg
814 4678 daigle
			// 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 2169 sgarg
826 4678 daigle
				} 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 5311 daigle
						&& (processingTopLevelAccess || processingAdditionalAccess || processingOtherAccess)) {
843 4678 daigle
					// get reference
844
					data = (textBuffer.toString()).trim();
845
					// put reference id into accessSection
846
					accessObject.setReferences(data);
847 2169 sgarg
848 4678 daigle
				} 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 5311 daigle
858 4678 daigle
					}// if
859
				}// else if
860 5311 daigle
861 4678 daigle
				// write text to db if it is not inline data
862 5311 daigle
				logMetacat.debug("Write text into DB in End Element");
863 2169 sgarg
864 5311 daigle
				// compare top level access module
865
				if (processingTopLevelAccess && needToCheckAccessModule) {
866
					compareAccessTextNode(currentUnchangeableAccessModuleNodeStack,
867
							textBuffer);
868 4678 daigle
				}
869 5311 daigle
				// 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 2169 sgarg
880 5311 daigle
			}
881 2169 sgarg
882 4678 daigle
			// set hitText false
883
			hitTextNode = false;
884
			// reset textbuff
885
			textBuffer = null;
886
			textBuffer = new StringBuffer();
887 2169 sgarg
888 4678 daigle
			// 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 2169 sgarg
903 4678 daigle
			// 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 2169 sgarg
915 4678 daigle
				accessObject.setEndNodeId(endNodeId);
916 2169 sgarg
917 4678 daigle
				if (parentNode != null && parentNode.getTagName() != null
918
						&& parentNode.getTagName().equals(DISTRIBUTION)) {
919
					describesId.add(String.valueOf(distributionIndex));
920
					currentDistributionSection.setAccessSection(accessObject);
921
				}
922 2169 sgarg
923 4678 daigle
				AccessSection newAccessObject = accessObject;
924 2169 sgarg
925 4678 daigle
				if (newAccessObject != null) {
926 2169 sgarg
927 4678 daigle
					// 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 2169 sgarg
931 4678 daigle
						newAccessObject.setStoredTmpNodeStack(storedAccessNodeStack);
932
						accessObjectList.add(newAccessObject);
933
					}
934 5311 daigle
					if (processingTopLevelAccess) {
935 2169 sgarg
936 4678 daigle
						// top level access control will handle whole document
937
						// -docid
938
						topLevelAccessControlMap.put(docid, newAccessObject);
939
						// reset processtopleveraccess tag
940 2169 sgarg
941 4678 daigle
					}// if
942 5311 daigle
					else if (processingAdditionalAccess) {
943 4678 daigle
						// 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 2169 sgarg
948 4678 daigle
							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 2169 sgarg
955 4678 daigle
						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 2169 sgarg
963 4678 daigle
				}// if
964
				// check if access node stack is empty after parsing top access
965
				// module
966 2169 sgarg
967 5311 daigle
				if (needToCheckAccessModule && processingTopLevelAccess
968 4678 daigle
						&& !currentUnchangeableAccessModuleNodeStack.isEmpty()) {
969 2169 sgarg
970 4678 daigle
					logMetacat.error("Access node stack is not empty after "
971
							+ "parsing access subtree");
972
					throw new SAXException(UPDATEACCESSERROR);
973 2169 sgarg
974 4678 daigle
				}
975
				// reset access section object
976 2169 sgarg
977 4678 daigle
				accessObject = null;
978 2169 sgarg
979 4678 daigle
				// reset tmp stored node stack
980
				storedAccessNodeStack = null;
981
				storedAccessNodeStack = new Stack<NodeRecord>();
982 2169 sgarg
983 4678 daigle
				// reset flag
984 5311 daigle
				processingAdditionalAccess = false;
985
				processingTopLevelAccess = false;
986
				processingOtherAccess = false;
987 2169 sgarg
988 4678 daigle
			} 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 2169 sgarg
1025 4678 daigle
	/**
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 2169 sgarg
1035 4678 daigle
				// compare top level access module
1036 5311 daigle
				if (processingTopLevelAccess && needToCheckAccessModule) {
1037 4678 daigle
					compareCommentNode(currentUnchangeableAccessModuleNodeStack, str,
1038
							UPDATEACCESSERROR);
1039
				}
1040
				endNodeId = currentNode.writeChildNodeToDB("COMMENT", null, str, docid);
1041
				if (needToCheckAccessModule
1042 5311 daigle
						&& (processingAdditionalAccess || processingOtherAccess || processingTopLevelAccess)) {
1043 4678 daigle
					// stored the pull out nodes into storedNode stack
1044
					NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "COMMENT", null,
1045 4698 daigle
							null, MetacatUtil.normalize(str));
1046 4678 daigle
					storedAccessNodeStack.push(nodeElement);
1047 2169 sgarg
1048 4678 daigle
				}
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 2169 sgarg
1061 4678 daigle
	/* 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 2169 sgarg
1088 4678 daigle
	/**
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 2169 sgarg
1109 4678 daigle
	/** 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 2169 sgarg
1119 4678 daigle
	/**
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 5208 daigle
				String data = new String(cbuf, start, len);
1131 4678 daigle
				// compare whitespace in access top module
1132 5311 daigle
				if (processingTopLevelAccess && needToCheckAccessModule) {
1133 4678 daigle
					compareWhiteSpace(currentUnchangeableAccessModuleNodeStack, data,
1134
							UPDATEACCESSERROR);
1135
				}
1136
				// Write the content of the node to the database
1137
				if (needToCheckAccessModule
1138 5311 daigle
						&& (processingAdditionalAccess || processingOtherAccess || processingTopLevelAccess)) {
1139 4678 daigle
					// stored the pull out nodes into storedNode stack
1140
					NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT", null,
1141 4698 daigle
							null, MetacatUtil.normalize(data));
1142 4678 daigle
					storedAccessNodeStack.push(nodeElement);
1143 2169 sgarg
1144 4678 daigle
				}
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 2169 sgarg
1152 4678 daigle
	}
1153 2169 sgarg
1154 4678 daigle
	/* 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 2169 sgarg
1175 4678 daigle
	/** 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 2169 sgarg
1193 4678 daigle
	/* The method to write all access rule into db */
1194
	private void writeAccessRuleToDB() throws SAXException {
1195
		// Delete old permssion
1196 6744 leinfelder
		deletePermissionsInAccessTable();
1197 4678 daigle
		// write top leve access rule
1198
		writeTopLevelAccessRuleToDB();
1199
		// write additional access rule
1200
		// writeAdditionalAccessRuleToDB();
1201
		writeAdditionalAccessRulesToDB();
1202
	}// writeAccessRuleToDB
1203 2169 sgarg
1204 4678 daigle
	/* 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 2169 sgarg
1213 4678 daigle
			// 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 2169 sgarg
1221 4678 daigle
				// 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 2169 sgarg
1232 4678 daigle
			} else {
1233 2169 sgarg
1234 4678 daigle
				// 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 2169 sgarg
1249 4678 daigle
							Stack<NodeRecord> newStack = accessObj
1250
									.getStoredTmpNodeStack();
1251
							// revise order
1252 5025 daigle
							newStack = DocumentUtil.reviseStack(newStack);
1253 4678 daigle
							// 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 2169 sgarg
1281 4678 daigle
						// 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 2169 sgarg
1300 4678 daigle
		}// if
1301
		else {
1302
			// couldn't find a access section object
1303
			logMetacat.warn("couldn't find access control for document: " + docid);
1304
		}
1305 2169 sgarg
1306 4678 daigle
	}// writeTopLevelAccessRuletoDB
1307 2169 sgarg
1308 4678 daigle
	/* 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 2169 sgarg
1325 4678 daigle
	/* 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 2169 sgarg
1352 4678 daigle
		// 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 4472 daigle
1360 5166 daigle
	/* The method to write additional access rule into db. */
1361 4678 daigle
	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 2169 sgarg
1382 4678 daigle
				if (distributionType == DistributionSection.DATA_DISTRIBUTION) {
1383
					try {
1384 6744 leinfelder
						// check for the previous version for permissions
1385
						int latestRevision = DBUtil.getLatestRevisionInDocumentTable(distributionSection.getDataFileName());
1386
						String previousDocid =
1387
							distributionSection.getDataFileName() + PropertyService.getProperty("document.accNumSeparator") + latestRevision;
1388
						PermissionController controller = new PermissionController(previousDocid);
1389
1390 4769 daigle
						if (AccessionNumber.accNumberUsed(docid)
1391
								&& !controller.hasPermission(user, groups, "WRITE")) {
1392 4678 daigle
							throw new SAXException(UPDATEACCESSERROR);
1393
						}
1394
					} catch (SQLException sqle) {
1395
						throw new SAXException(
1396
								"Database error checking user permissions: "
1397
										+ sqle.getMessage());
1398
					} catch (Exception e) {
1399
						throw new SAXException(
1400
								"General error checking user permissions: "
1401
										+ e.getMessage());
1402
					}
1403
				} else if (distributionType == DistributionSection.INLINE_DATA_DISTRIBUTION && action == "UPDATE") {
1404
					try {
1405 6744 leinfelder
1406
						// check for the previous version for permissions
1407
						int latestRevision = DBUtil.getLatestRevisionInDocumentTable(docid);
1408
						String previousDocid =
1409
							docid + PropertyService.getProperty("document.accNumSeparator") + latestRevision;
1410
						PermissionController controller = new PermissionController(previousDocid);
1411 2169 sgarg
1412 4678 daigle
						if (!controller.hasPermission(user, groups, "WRITE")) {
1413
							throw new SAXException(UPDATEACCESSERROR);
1414
						}
1415
					} catch (SQLException sqle) {
1416
						throw new SAXException(
1417
								"Database error checking user permissions: "
1418
										+ sqle.getMessage());
1419
					} catch (Exception e) {
1420
						throw new SAXException(
1421
								"General error checking user permissions: "
1422
										+ e.getMessage());
1423
					}
1424
				}
1425
1426
				String subSectionId = Integer.toString(distributionSection.getDistributionId());
1427
				writeGivenAccessRuleIntoDB(accessSection, false, subSectionId);
1428
			}
1429 2169 sgarg
1430 4678 daigle
		}
1431
1432
1433
	}
1434 2169 sgarg
1435 4678 daigle
	/* Write a given access rule into db */
1436
	private void writeGivenAccessRuleIntoDB(AccessSection accessSection,
1437
			boolean topLevel, String subSectionId) throws SAXException {
1438
		if (accessSection == null) {
1439
			throw new SAXException("The access object is null");
1440
		}
1441 2169 sgarg
1442 6744 leinfelder
		String guid = null;
1443
		try {
1444
			guid = IdentifierManager.getInstance().getGUID(docid, Integer.valueOf(revision));
1445
		} catch (NumberFormatException e) {
1446
			throw new SAXException(e.getMessage(), e);
1447
		} catch (McdbDocNotFoundException e) {
1448
			// register the default mapping now
1449
			guid = docid + "." + revision;
1450
			IdentifierManager.getInstance().createMapping(guid, guid);
1451
		}
1452
1453 4678 daigle
		String permOrder = accessSection.getPermissionOrder();
1454 6019 leinfelder
		String sql = null;
1455
		PreparedStatement pstmt = null;
1456 4678 daigle
		if (topLevel) {
1457 6744 leinfelder
			sql = "INSERT INTO xml_access (guid, principal_name, permission, "
1458 6019 leinfelder
					+ "perm_type, perm_order, accessfileid) VALUES "
1459
					+ " (?, ?, ?, ?, ?, ?)";
1460 4678 daigle
		} else {
1461 6744 leinfelder
			sql = "INSERT INTO xml_access (guid,principal_name, "
1462 6019 leinfelder
					+ "permission, perm_type, perm_order, accessfileid, subtreeid"
1463
					+ ") VALUES" + " (?, ?, ?, ?, ?, ?, ?)";
1464 4678 daigle
		}
1465
		try {
1466 2169 sgarg
1467 6019 leinfelder
			pstmt = connection.prepareStatement(sql);
1468
			// Increase DBConnection usage count
1469
			connection.increaseUsageCount(1);
1470
			// Bind the values to the query
1471 6744 leinfelder
			pstmt.setString(6, guid);
1472
			logMetacat.debug("Accessfileid in accesstable: " + guid);
1473 6019 leinfelder
			pstmt.setString(5, permOrder);
1474
			logMetacat.debug("PermOder in accesstable: " + permOrder);
1475
			// if it is not top level, set subsection id
1476
			if (topLevel) {
1477 6744 leinfelder
				pstmt.setString(1, guid);
1478
				logMetacat.debug("Guid in accesstable: " + guid);
1479 6019 leinfelder
			}
1480
			if (!topLevel) {
1481 6744 leinfelder
				// TODO: look up guid?
1482 6019 leinfelder
				pstmt.setString(1, accessSection.getDataFileName());
1483
				logMetacat.debug("Docid in accesstable: " + inlineDataFileName);
1484
1485
				// for subtree should specify the
1486
				if (subSectionId == null) {
1487
					throw new SAXException("The subsection is null");
1488
				}
1489
1490
				pstmt.setString(7, subSectionId);
1491
				logMetacat.debug("SubSectionId in accesstable: " + subSectionId);
1492
			}
1493
1494 4678 daigle
			Vector<AccessRule> accessRules = accessSection.getAccessRules();
1495
			// go through every rule
1496
			for (int i = 0; i < accessRules.size(); i++) {
1497
				AccessRule rule = accessRules.elementAt(i);
1498
				String permType = rule.getPermissionType();
1499
				int permission = rule.getPermission();
1500 6019 leinfelder
				pstmt.setInt(3, permission);
1501 4678 daigle
				logMetacat.debug("permission in accesstable: " + permission);
1502 6019 leinfelder
				pstmt.setString(4, permType);
1503 4678 daigle
				logMetacat.debug("Permtype in accesstable: " + permType);
1504
				// go through every principle in rule
1505
				Vector<String> nameVector = rule.getPrincipal();
1506
				for (int j = 0; j < nameVector.size(); j++) {
1507
					String prName = nameVector.elementAt(j);
1508 6019 leinfelder
					pstmt.setString(2, prName);
1509 4678 daigle
					logMetacat.debug("Principal in accesstable: " + prName);
1510 6019 leinfelder
					logMetacat.debug("running sql: " + pstmt.toString());
1511
					pstmt.execute();
1512 4678 daigle
				}// for
1513
			}// for
1514 6019 leinfelder
			pstmt.close();
1515 4678 daigle
		}// try
1516 6019 leinfelder
		catch (SQLException e) {
1517 4678 daigle
			throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
1518
					+ e.getMessage());
1519
		}// catch
1520 6019 leinfelder
		finally {
1521
			try {
1522
				pstmt.close();
1523
			} catch (SQLException ee) {
1524
				throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
1525
						+ ee.getMessage());
1526
			}
1527
		}// finally
1528 2169 sgarg
1529 4678 daigle
	}// writeGivenAccessRuleIntoDB
1530 2169 sgarg
1531 6744 leinfelder
1532 6019 leinfelder
1533 6744 leinfelder
	/* Delete from db all permission for resources related to the document, if any */
1534
	private void deletePermissionsInAccessTable() throws SAXException {
1535 6606 leinfelder
		PreparedStatement pstmt = null;
1536 4678 daigle
		try {
1537 6744 leinfelder
			String sql = "DELETE FROM xml_access " +
1538
					"WHERE accessfileid IN (SELECT guid from identifier where docid = ? and rev = ?)";
1539 4678 daigle
			// delete all acl records for resources related to @aclid if any
1540 6606 leinfelder
			pstmt = connection.prepareStatement(sql);
1541 6744 leinfelder
			pstmt.setString(1, docid);
1542
			pstmt.setInt(2, Integer.valueOf(revision));
1543 4678 daigle
			// Increase DBConnection usage count
1544
			connection.increaseUsageCount(1);
1545 6606 leinfelder
			logMetacat.debug("running sql: " + sql);
1546
			pstmt.execute();
1547 4678 daigle
1548
		} catch (SQLException e) {
1549
			throw new SAXException(e.getMessage());
1550
		} finally {
1551
			try {
1552 6606 leinfelder
				pstmt.close();
1553 4678 daigle
			} catch (SQLException ee) {
1554
				throw new SAXException(ee.getMessage());
1555
			}
1556
		}
1557
	}// deletePermissionsInAccessTable
1558
1559
	/*
1560
	 * In order to make sure only usr has "all" permission can update access
1561
	 * subtree in eml document we need to keep access subtree info in
1562
	 * xml_accesssubtree table, such as docid, version, startnodeid, endnodeid
1563
	 */
1564
	private void writeAccessSubTreeIntoDB(AccessSection accessSection, String level)
1565
			throws SAXException {
1566
		if (accessSection == null) {
1567
			throw new SAXException("The access object is null");
1568
		}
1569
1570
		String sql = null;
1571
		PreparedStatement pstmt = null;
1572
		sql = "INSERT INTO xml_accesssubtree (docid, rev, controllevel, "
1573
				+ "subtreeid, startnodeid, endnodeid) VALUES " + " (?, ?, ?, ?, ?, ?)";
1574
		try {
1575
1576
			pstmt = connection.prepareStatement(sql);
1577
			// Increase DBConnection usage count
1578
			connection.increaseUsageCount(1);
1579
			long startNodeId = accessSection.getStartNodeId();
1580
			long endNodeId = accessSection.getEndNodeId();
1581
			String sectionId = accessSection.getSubTreeId();
1582
			// Bind the values to the query
1583
			pstmt.setString(1, docid);
1584
			logMetacat.debug("Docid in access-subtreetable: " + docid);
1585
			pstmt.setLong(2, (new Long(revision)).longValue());
1586
			logMetacat.debug("rev in accesssubtreetable: " + revision);
1587
			pstmt.setString(3, level);
1588
			logMetacat.debug("contorl level in access-subtree table: " + level);
1589
			pstmt.setString(4, sectionId);
1590
			logMetacat.debug("Subtree id in access-subtree table: " + sectionId);
1591
			pstmt.setLong(5, startNodeId);
1592
			logMetacat.debug("Start node id is: " + startNodeId);
1593
			pstmt.setLong(6, endNodeId);
1594
			logMetacat.debug("End node id is: " + endNodeId);
1595
			logMetacat.debug("running sql: " + pstmt.toString());
1596
			pstmt.execute();
1597
			pstmt.close();
1598
		}// try
1599
		catch (SQLException e) {
1600
			throw new SAXException("EMLSAXHandler.writeAccessSubTreeIntoDB(): "
1601
					+ e.getMessage());
1602
		}// catch
1603
		finally {
1604
			try {
1605
				pstmt.close();
1606
			} catch (SQLException ee) {
1607
				throw new SAXException("EMLSAXHandler.writeAccessSubTreeIntoDB(): "
1608
						+ ee.getMessage());
1609
			}
1610
		}// finally
1611
1612
	}// writeAccessSubtreeIntoDB
1613
1614
	/* Delete every access subtree record from xml_accesssubtree. */
1615
	private void deleteAccessSubTreeRecord(String docId) throws SAXException {
1616 6606 leinfelder
		PreparedStatement pstmt = null;
1617 4678 daigle
		try {
1618 6606 leinfelder
			String sql = "DELETE FROM xml_accesssubtree WHERE docid = ?";
1619 4678 daigle
			// delete all acl records for resources related to @aclid if any
1620 6606 leinfelder
			pstmt = connection.prepareStatement(sql);
1621
			pstmt.setString(1, docId);
1622 4678 daigle
			// Increase DBConnection usage count
1623
			connection.increaseUsageCount(1);
1624 6606 leinfelder
			logMetacat.debug("running sql: " + sql);
1625
			pstmt.execute();
1626 4678 daigle
1627
		} catch (SQLException e) {
1628
			throw new SAXException(e.getMessage());
1629
		} finally {
1630
			try {
1631 6606 leinfelder
				pstmt.close();
1632 4678 daigle
			} catch (SQLException ee) {
1633
				throw new SAXException(ee.getMessage());
1634
			}
1635
		}
1636
	}// deleteAccessSubTreeRecord
1637
1638
	// open a file writer for writing inline data to file
1639 5752 leinfelder
	private Writer createInlineDataFileWriter(String fileName, String encoding) throws SAXException {
1640
		Writer writer = null;
1641 4678 daigle
		String path;
1642
		try {
1643
			path = PropertyService.getProperty("application.inlinedatafilepath");
1644
		} catch (PropertyNotFoundException pnfe) {
1645
			throw new SAXException(pnfe.getMessage());
1646
		}
1647
		/*
1648
		 * File inlineDataDirectory = new File(path);
1649
		 */
1650
		String newFile = path + "/" + fileName;
1651
		logMetacat.debug("inline file name: " + newFile);
1652
		try {
1653
			// true means append
1654 5752 leinfelder
			writer = new OutputStreamWriter(new FileOutputStream(newFile, true), encoding);
1655 4678 daigle
		} catch (IOException ioe) {
1656
			throw new SAXException(ioe.getMessage());
1657
		}
1658
		return writer;
1659
	}
1660
1661
	// write inline data into file system and return file name(without path)
1662 5752 leinfelder
	private void writeInlineDataIntoFile(Writer writer, StringBuffer data)
1663 4678 daigle
			throws SAXException {
1664
		try {
1665
			writer.write(data.toString());
1666
			writer.flush();
1667
		} catch (Exception e) {
1668
			throw new SAXException(e.getMessage());
1669
		}
1670
	}
1671
1672 4080 daigle
1673 2169 sgarg
1674 4678 daigle
	// if xml file failed to upload, we need to call this method to delete
1675
	// the inline data already in file system
1676
	public void deleteInlineFiles() throws SAXException {
1677
		if (!inlineFileIdList.isEmpty()) {
1678
			for (int i = 0; i < inlineFileIdList.size(); i++) {
1679
				String fileName = inlineFileIdList.elementAt(i);
1680
				deleteInlineDataFile(fileName);
1681
			}
1682
		}
1683
	}
1684 2169 sgarg
1685 4678 daigle
	/* delete the inline data file */
1686
	private void deleteInlineDataFile(String fileName) throws SAXException {
1687
		String path;
1688
		try {
1689
			path = PropertyService.getProperty("application.inlinedatafilepath");
1690
		} catch (PropertyNotFoundException pnfe) {
1691
			throw new SAXException("Could not find inline data file path: "
1692
					+ pnfe.getMessage());
1693
		}
1694
		File inlineDataDirectory = new File(path);
1695
		File newFile = new File(inlineDataDirectory, fileName);
1696
		newFile.delete();
1697 2169 sgarg
1698 4678 daigle
	}
1699 2169 sgarg
1700 4678 daigle
	/* Delete relations */
1701
	private void deleteRelations() throws SAXException {
1702
		PreparedStatement pStmt = null;
1703
		String sql = "DELETE FROM xml_relation where docid =?";
1704
		try {
1705
			pStmt = connection.prepareStatement(sql);
1706
			// bind variable
1707
			pStmt.setString(1, docid);
1708
			// execute query
1709
			pStmt.execute();
1710
			pStmt.close();
1711
		}// try
1712
		catch (SQLException e) {
1713
			throw new SAXException("EMLSAXHandler.deleteRelations(): " + e.getMessage());
1714
		}// catch
1715
		finally {
1716
			try {
1717
				pStmt.close();
1718
			}// try
1719
			catch (SQLException ee) {
1720
				throw new SAXException("EMLSAXHandler.deleteRelations: "
1721
						+ ee.getMessage());
1722
			}// catch
1723
		}// finally
1724
	}
1725 2169 sgarg
1726 4678 daigle
	/*
1727
	 * Write an online data file id into xml_relation table. The dataId
1728
	 * shouldnot have the revision
1729
	 */
1730
	private void writeOnlineDataFileIdIntoRelationTable(String dataId)
1731
			throws SAXException {
1732
		PreparedStatement pStmt = null;
1733
		String sql = "INSERT into xml_relation (docid, packagetype, subject, "
1734
				+ "relationship, object) values (?, ?, ?, ?, ?)";
1735
		try {
1736
			pStmt = connection.prepareStatement(sql);
1737
			// bind variable
1738
			pStmt.setString(1, docid);
1739 5709 leinfelder
			pStmt.setString(2, doctype); //DocumentImpl.EML2_1_0NAMESPACE);
1740 4678 daigle
			pStmt.setString(3, docid);
1741
			pStmt.setString(4, RELATION);
1742
			pStmt.setString(5, dataId);
1743
			// execute query
1744
			pStmt.execute();
1745
			pStmt.close();
1746
		}// try
1747
		catch (SQLException e) {
1748
			throw new SAXException(
1749
					"EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): "
1750
							+ e.getMessage());
1751
		}// catch
1752
		finally {
1753
			try {
1754
				pStmt.close();
1755
			}// try
1756
			catch (SQLException ee) {
1757
				throw new SAXException(
1758
						"EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): "
1759
								+ ee.getMessage());
1760
			}// catch
1761
		}// finally
1762 2169 sgarg
1763 4678 daigle
	}// writeOnlineDataFileIdIntoRelationTable
1764 2169 sgarg
1765 4678 daigle
	/*
1766
	 * This method will handle data file in online url. If the data file is in
1767
	 * ecogrid protocol, then the datafile identifier(without rev)should be put
1768
	 * into onlineDataFileRelationVector. The docid in this vector will be
1769
	 * insert into xml_relation table in endDocument(). If the data file doesn't
1770
	 * exsit in xml_documents or xml_revision table, or the user has all
1771
	 * permission to the data file if the docid already existed, the data file
1772
	 * id (without rev)will be put into onlineDataFileTopAccessVector. The top
1773
	 * access rules specified in this eml document will apply to the data file.
1774
	 * NEED to do: We should also need to implement http and ftp. Those external
1775
	 * files should be download and assign a data file id to it.
1776
	 */
1777
	private void handleOnlineUrlDataFile(String url) throws SAXException {
1778
		logMetacat.warn("The url is " + url);
1779 2169 sgarg
1780 4678 daigle
		if (currentDistributionSection == null) {
1781
			throw new SAXException("Trying to set the online file name for a null"
1782
					+ " distribution section");
1783
		}
1784
1785
		// if the url is not in ecogrid protocol, null will be returned
1786 5025 daigle
		String accessionNumber = DocumentUtil.getAccessionNumberFromEcogridIdentifier(url);
1787 4678 daigle
		if (accessionNumber == null) {
1788
			// the accession number is null if the url does not references a
1789
			// local data file (url would start with "ecogrid://"
1790
			currentDistributionSection
1791
					.setDistributionType(DistributionSection.ONLINE_DATA_DISTRIBUTION);
1792
		} else {
1793
			// handle ecogrid protocol
1794
			// get rid of revision number to get the docid.
1795 5025 daigle
			String docid = DocumentUtil.getDocIdFromAccessionNumber(accessionNumber);
1796 6744 leinfelder
			int rev = DocumentUtil.getRevisionFromAccessionNumber(accessionNumber);
1797
			String guid = null;
1798
			try {
1799
				guid = IdentifierManager.getInstance().getGUID(docid, rev);
1800
			} catch (McdbDocNotFoundException e1) {
1801
				guid = docid + "." + rev;
1802
				IdentifierManager.getInstance().createMapping(guid, guid);
1803
			}
1804 4678 daigle
1805
			currentDistributionSection
1806
					.setDistributionType(DistributionSection.DATA_DISTRIBUTION);
1807 6744 leinfelder
			currentDistributionSection.setDataFileName(guid);
1808 4678 daigle
1809
			// distributionOnlineFileName = docid;
1810
			onlineDataFileIdInRelationVector.add(docid);
1811 4733 daigle
			try {
1812 4678 daigle
				if (!AccessionNumber.accNumberUsed(docid)) {
1813
					onlineDataFileIdInTopAccessVector.add(docid);
1814
				} else {
1815 4733 daigle
					PermissionController controller = new PermissionController(accessionNumber);
1816
					if (controller.hasPermission(user, groups,AccessControlInterface.ALLSTRING)) {
1817
						onlineDataFileIdInTopAccessVector.add(docid);
1818
					} else {
1819
						throw new SAXException(UPDATEACCESSERROR);
1820
					}
1821
				}
1822 4678 daigle
			}// try
1823
			catch (Exception e) {
1824
				logMetacat.error("Eorr in "
1825
								+ "Eml210SAXHanlder.handleOnlineUrlDataFile is "
1826
								+ e.getMessage());
1827
				throw new SAXException(e.getMessage());
1828
			}
1829
		}
1830
	}
1831 2169 sgarg
}