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 7475 leinfelder
import edu.ucsb.nceas.utilities.access.AccessControlInterface;
50 5090 daigle
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 6802 leinfelder
import edu.ucsb.nceas.metacat.dataone.hazelcast.HazelcastService;
55 5030 daigle
import edu.ucsb.nceas.metacat.properties.PropertyService;
56 5025 daigle
import edu.ucsb.nceas.metacat.util.DocumentUtil;
57 4698 daigle
import edu.ucsb.nceas.metacat.util.MetacatUtil;
58 4080 daigle
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
59
60 2169 sgarg
/**
61 4472 daigle
 * A database aware Class implementing callback methods for the SAX parser to
62 2169 sgarg
 * call when processing the XML stream and generating events
63
 */
64 4678 daigle
public class Eml210SAXHandler extends DBSAXHandler implements AccessControlInterface {
65 2169 sgarg
66 5311 daigle
	private boolean processingTopLevelAccess = false;
67 2169 sgarg
68 5311 daigle
	private boolean processingAdditionalAccess = false;
69 2169 sgarg
70 5311 daigle
	private boolean processingOtherAccess = false;
71 2169 sgarg
72 4678 daigle
	private AccessSection accessObject = null;
73 2169 sgarg
74 4678 daigle
	private AccessRule accessRule = null;
75 2169 sgarg
76 5311 daigle
	// all access rules
77
	private Vector<AccessSection> accessObjectList = new Vector<AccessSection>();
78 2169 sgarg
79 4678 daigle
	private Hashtable<String, AccessSection> topLevelAccessControlMap = new Hashtable<String, AccessSection>();
80 2169 sgarg
81 5311 daigle
	// subtree access for additionalmetadata
82
	private Hashtable<String, AccessSection> additionalAccessControlMap = new Hashtable<String, AccessSection>();
83
84
85
	private Vector<Hashtable<String, AccessSection>> additionalAccessMapList = new Vector<Hashtable<String, AccessSection>>();
86
87
	// ids from additionalmetadata/describes
88
	private Vector<String> describesId = new Vector<String>();
89
90 4678 daigle
	private Stack<SubTree> subTreeInfoStack = new Stack<SubTree>();
91 2169 sgarg
92 5311 daigle
	private Vector<SubTree> subTreeList = new Vector<SubTree>();
93 4678 daigle
94
	private boolean needToCheckAccessModule = false;
95 2169 sgarg
96 4678 daigle
	private Vector<AccessSection> unChangeableAccessSubTreeVector = new Vector<AccessSection>();
97 2169 sgarg
98 4678 daigle
	private Stack<NodeRecord> currentUnchangeableAccessModuleNodeStack = new Stack<NodeRecord>();
99 2169 sgarg
100 4678 daigle
	private AccessSection topAccessSection;
101 2169 sgarg
102 4678 daigle
	// we need an another stack to store the access node which we pull out just
103
	// from xml. If a reference happened, we can use the stack the compare nodes
104
	private Stack<NodeRecord> storedAccessNodeStack = new Stack<NodeRecord>();
105 2169 sgarg
106 4678 daigle
	// vector stored the data file id which will be write into relation table
107
	private Vector<String> onlineDataFileIdInRelationVector = new Vector<String>();
108 2169 sgarg
109 4678 daigle
	// vector stored the data file id which will be write top access rules to
110
	// access table
111
	private Vector<String> onlineDataFileIdInTopAccessVector = new Vector<String>();
112 2169 sgarg
113 4678 daigle
	// Indicator of inline data
114
	private boolean handleInlineData = false;
115 2169 sgarg
116 4678 daigle
	private Hashtable<String, String> inlineDataNameSpace = null;
117 2169 sgarg
118 5752 leinfelder
	private Writer inlineDataFileWriter = null;
119 2169 sgarg
120 4678 daigle
	private String inlineDataFileName = null;
121 2169 sgarg
122 4678 daigle
	DistributionSection currentDistributionSection = null;
123 2169 sgarg
124 4678 daigle
	Vector<DistributionSection> allDistributionSections = new Vector<DistributionSection>();
125
126
	// This variable keeps a counter of each distribution element. This index
127
	// will be used to name the inline data file that gets written to disk, and to
128
	// strip inline data from the metadata document on file if the user does not have
129
	// read access.
130 4472 daigle
	private int distributionIndex = 0;
131 2169 sgarg
132 4678 daigle
	// private String distributionOnlineFileName = null;
133
134 4472 daigle
	// This is used to delete inline files if the xml does not parse correctly.
135 4678 daigle
	private Vector<String> inlineFileIdList = new Vector<String>();
136 2169 sgarg
137 4678 daigle
	// Constant
138
	private static final String EML = "eml";
139 2169 sgarg
140 4678 daigle
	private static final String DISTRIBUTION = "distribution";
141 2169 sgarg
142 4678 daigle
	private static final String ORDER = "order";
143 2169 sgarg
144 4678 daigle
	private static final String ID = "id";
145 2169 sgarg
146 4678 daigle
	private static final String REFERENCES = "references";
147 2169 sgarg
148 4678 daigle
	public static final String INLINE = "inline";
149 2169 sgarg
150 4678 daigle
	private static final String ONLINE = "online";
151 2169 sgarg
152 4678 daigle
	private static final String URL = "url";
153 2169 sgarg
154 4678 daigle
	// private static final String PERMISSIONERROR = "User tried to update a
155
	// subtree "
156
	// + "when they don't have write permission!";
157 2169 sgarg
158 4678 daigle
	private static final String UPDATEACCESSERROR = "User tried to update an "
159
			+ "access module when they don't have \"ALL\" permission!";
160 2169 sgarg
161 4678 daigle
	private static final String TOPLEVEL = "top";
162 2169 sgarg
163 4678 daigle
	private static final String SUBTREELEVEL = "subtree";
164 2169 sgarg
165 4678 daigle
	private static final String RELATION = "Provides info for";
166 2663 sgarg
167 4678 daigle
	private Logger logMetacat = Logger.getLogger(Eml210SAXHandler.class);
168 2169 sgarg
169 4678 daigle
	/**
170
	 * Construct an instance of the handler class In this constructor, user can
171
	 * specify the version need to update
172
	 *
173
	 * @param conn
174
	 *            the JDBC connection to which information is written
175
	 * @param action -
176
	 *            "INSERT" or "UPDATE"
177
	 * @param docid
178
	 *            to be inserted or updated into JDBC connection
179
	 * @param revision,
180
	 *            the user specified the revision need to be update
181
	 * @param user
182
	 *            the user connected to MetaCat servlet and owns the document
183
	 * @param groups
184
	 *            the groups to which user belongs
185
	 * @param pub
186
	 *            flag for public "read" access on document
187
	 * @param serverCode
188
	 *            the serverid from xml_replication on which this document
189
	 *            resides.
190
	 *
191
	 */
192
	public Eml210SAXHandler(DBConnection conn, String action, String docid,
193
			String revision, String user, String[] groups, String pub, int serverCode,
194 7128 leinfelder
			Date createDate, Date updateDate, boolean writeAccessRules) throws SAXException {
195 4678 daigle
		super(conn, action, docid, revision, user, groups, pub, serverCode, createDate,
196 7128 leinfelder
				updateDate, writeAccessRules);
197 4678 daigle
		// Get the unchangeable subtrees (user doesn't have write permission)
198
		try {
199 2169 sgarg
200 6744 leinfelder
			if (action.equals("UPDATE")) {
201
				// If the action is update and user doesn't have "ALL" permission
202
				// we need to check if user can update access subtree
203
				int latestRevision = DBUtil.getLatestRevisionInDocumentTable(docid);
204
				String previousDocid =
205
					docid + PropertyService.getProperty("document.accNumSeparator") + latestRevision;
206
207
				PermissionController control = new PermissionController(previousDocid );
208
				if (!control.hasPermission(user, groups, AccessControlInterface.ALLSTRING)
209
						&& action != null) {
210
					needToCheckAccessModule = true;
211
					unChangeableAccessSubTreeVector = getAccessSubTreeListFromDB();
212
				}
213 4678 daigle
			}
214
215
		} catch (Exception e) {
216
			throw new SAXException(e.getMessage());
217
		}
218
	}
219
220
	/*
221
	 * Get the subtree node info from xml_accesssubtree table
222
	 */
223
	private Vector<AccessSection> getAccessSubTreeListFromDB() throws Exception {
224
		Vector<AccessSection> result = new Vector<AccessSection>();
225
		PreparedStatement pstmt = null;
226
		ResultSet rs = null;
227
		String sql = "SELECT controllevel, subtreeid, startnodeid, endnodeid "
228
				+ "FROM xml_accesssubtree WHERE docid like ? "
229
				+ "ORDER BY startnodeid ASC";
230 2169 sgarg
231 4678 daigle
		try {
232 2169 sgarg
233 4678 daigle
			pstmt = connection.prepareStatement(sql);
234
			// Increase DBConnection usage count
235
			connection.increaseUsageCount(1);
236
			// Bind the values to the query
237
			pstmt.setString(1, docid);
238
			pstmt.execute();
239 2169 sgarg
240 4678 daigle
			// Get result set
241
			rs = pstmt.getResultSet();
242
			while (rs.next()) {
243
				String level = rs.getString(1);
244
				String sectionId = rs.getString(2);
245
				long startNodeId = rs.getLong(3);
246
				long endNodeId = rs.getLong(4);
247
				// create a new access section
248
				AccessSection accessObj = new AccessSection();
249
				accessObj.setControlLevel(level);
250
				accessObj.setDocId(docid);
251
				accessObj.setSubTreeId(sectionId);
252
				accessObj.setStartNodeId(startNodeId);
253
				accessObj.setEndNodeId(endNodeId);
254
				Stack<NodeRecord> nodeStack = accessObj.getSubTreeNodeStack();
255
				accessObj.setSubTreeNodeStack(nodeStack);
256
				// add this access obj into vector
257
				result.add(accessObj);
258
				// Get the top level access subtree control
259
				if (level != null && level.equals(TOPLEVEL)) {
260
					topAccessSection = accessObj;
261
				}
262
			}
263
			pstmt.close();
264
		}// try
265
		catch (SQLException e) {
266
			throw new SAXException("EMLSAXHandler.getAccessSubTreeListFromDB(): "
267
					+ e.getMessage());
268
		}// catch
269
		finally {
270
			try {
271
				pstmt.close();
272
			} catch (SQLException ee) {
273
				throw new SAXException("EMLSAXHandler.getAccessSubTreeListFromDB(): "
274
						+ ee.getMessage());
275
			}
276
		}// finally
277
		return result;
278
	}
279 2169 sgarg
280 4678 daigle
	/** SAX Handler that is called at the start of each XML element */
281
	public void startElement(String uri, String localName, String qName, Attributes atts)
282
			throws SAXException {
283
		// for element <eml:eml...> qname is "eml:eml", local name is "eml"
284
		// for element <acl....> both qname and local name is "eml"
285
		// uri is namesapce
286
		logMetacat.debug("Start ELEMENT(qName) " + qName);
287
		logMetacat.debug("Start ELEMENT(localName) " + localName);
288
		logMetacat.debug("Start ELEMENT(uri) " + uri);
289 2169 sgarg
290 4678 daigle
		DBSAXNode parentNode = null;
291
		DBSAXNode currentNode = null;
292 2169 sgarg
293 4678 daigle
		if (!handleInlineData) {
294
			// Get a reference to the parent node for the id
295
			try {
296
				parentNode = (DBSAXNode) nodeStack.peek();
297
			} catch (EmptyStackException e) {
298
				parentNode = null;
299
			}
300 2169 sgarg
301 4678 daigle
			// start handle inline data
302
			if (localName.equals(INLINE)) {
303
				handleInlineData = true;
304
				// initialize namespace hash for in line data
305
				inlineDataNameSpace = new Hashtable<String, String>();
306
				// initialize file writer
307 5025 daigle
				String docidWithoutRev = DocumentUtil.getDocIdFromString(docid);
308 4678 daigle
				String seperator = ".";
309
				try {
310
					seperator = PropertyService.getProperty("document.accNumSeparator");
311
				} catch (PropertyNotFoundException pnfe) {
312
					logMetacat.error("Could not fing property 'accNumSeparator'. "
313
							+ "Setting separator to '.': " + pnfe.getMessage());
314
				}
315
				// the new file name will look like docid.rev.2
316
				inlineDataFileName = docidWithoutRev + seperator + revision + seperator
317 4472 daigle
						+ distributionIndex;
318 5752 leinfelder
				inlineDataFileWriter = createInlineDataFileWriter(inlineDataFileName, encoding);
319 4678 daigle
				// put the inline file id into a vector. If upload failed,
320
				// metacat will delete the inline data file
321
				inlineFileIdList.add(inlineDataFileName);
322
323
				currentDistributionSection.setDistributionType(DistributionSection.INLINE_DATA_DISTRIBUTION);
324
				currentDistributionSection.setDataFileName(inlineDataFileName);
325 2169 sgarg
326 4678 daigle
			}
327 2169 sgarg
328 4678 daigle
			// If hit a text node, we need write this text for current's parent
329
			// node This will happen if the element is mixed
330
			if (hitTextNode && parentNode != null) {
331 2169 sgarg
332 4678 daigle
				// compare top level access module
333 5311 daigle
				if (processingTopLevelAccess && needToCheckAccessModule) {
334
					compareAccessTextNode(currentUnchangeableAccessModuleNodeStack, textBuffer);
335 4678 daigle
				}
336 2169 sgarg
337 4678 daigle
				if (needToCheckAccessModule
338 5311 daigle
						&& (processingAdditionalAccess || processingOtherAccess || processingTopLevelAccess)) {
339 4678 daigle
					// stored the pull out nodes into storedNode stack
340
					NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT", null,
341 4698 daigle
							null, MetacatUtil.normalize(textBuffer.toString()));
342 4678 daigle
					storedAccessNodeStack.push(nodeElement);
343 2169 sgarg
344 4678 daigle
				}
345 2169 sgarg
346 4678 daigle
				// write the textbuffer into db for parent node.
347
				endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer, parentNode);
348
				// rest hitTextNode
349
				hitTextNode = false;
350
				// reset textbuffer
351
				textBuffer = null;
352
				textBuffer = new StringBuffer();
353 2169 sgarg
354 4678 daigle
			}
355 2169 sgarg
356 4678 daigle
			// Document representation that points to the root document node
357
			if (atFirstElement) {
358
				atFirstElement = false;
359
				// If no DOCTYPE declaration: docname = root element
360
				// doctype = root element name or name space
361
				if (docname == null) {
362
					docname = localName;
363
					// if uri isn't null doctype = uri(namespace)
364
					// othewise root element
365
					if (uri != null && !(uri.trim()).equals("")) {
366
						doctype = uri;
367
					} else {
368
						doctype = docname;
369
					}
370
					logMetacat.debug("DOCNAME-a: " + docname);
371
					logMetacat.debug("DOCTYPE-a: " + doctype);
372
				} else if (doctype == null) {
373
					// because docname is not null and it is declared in dtd
374
					// so could not be in schema, no namespace
375
					doctype = docname;
376
					logMetacat.debug("DOCTYPE-b: " + doctype);
377
				}
378
				rootNode.writeNodename(docname);
379
				try {
380
					// for validated XML Documents store a reference to XML DB
381
					// Catalog. Because this is select statement and it needn't
382
					// roll back if insert document action failed. In order to
383
					// decrease DBConnection usage count, we get a new
384
					// dbconnection from pool String catalogid = null;
385
					DBConnection dbConn = null;
386
					int serialNumber = -1;
387 2169 sgarg
388 4678 daigle
					try {
389
						// Get dbconnection
390
						dbConn = DBConnectionPool
391
								.getDBConnection("DBSAXHandler.startElement");
392
						serialNumber = dbConn.getCheckOutSerialNumber();
393 6606 leinfelder
394
						String sql = "SELECT catalog_id FROM xml_catalog "
395
							+ "WHERE entry_type = 'Schema' "
396
							+ "AND public_id = ?";
397
						PreparedStatement pstmt = dbConn.prepareStatement(sql);
398
						pstmt.setString(1, doctype);
399
						ResultSet rs = pstmt.executeQuery();
400 4678 daigle
						boolean hasRow = rs.next();
401
						if (hasRow) {
402
							catalogid = rs.getString(1);
403
						}
404 6606 leinfelder
						pstmt.close();
405 4678 daigle
					}// try
406
					finally {
407
						// Return dbconnection
408
						DBConnectionPool.returnDBConnection(dbConn, serialNumber);
409
					}// finally
410 2169 sgarg
411 4678 daigle
					// create documentImpl object by the constructor which can
412
					// specify the revision
413
					if (!super.getIsRevisionDoc()) {
414
						currentDocument = new DocumentImpl(connection, rootNode
415
								.getNodeID(), docname, doctype, docid, revision, action,
416
								user, this.pub, catalogid, this.serverCode, createDate,
417
								updateDate);
418
					}
419 2169 sgarg
420 5200 daigle
				} catch (McdbDocNotFoundException mdnfe) {
421
					Vector<Integer> revList = null;
422
423
					try {
424
						revList = DBUtil.getRevListFromRevisionTable(docid);
425
					} catch (SQLException sqle) {
426
						logMetacat.error("SQL error when trying to get rev list for doc " + docid + " : " + sqle.getMessage());
427
						throw (new SAXException("Doc ID " + docid + " was not found and cannot be updated."));
428
					}
429
430
					if (revList.size() > 0) {
431 5208 daigle
						throw (new SAXException("EML210SaxHandler.startElement - Doc ID " + docid + " was deleted and cannot be updated."));
432 5200 daigle
					} else {
433 5208 daigle
						throw (new SAXException("EML210SaxHandler.startElement - Doc ID " + docid + " was not found and cannot be updated."));
434 5200 daigle
					}
435
				} catch (Exception e) {
436 5208 daigle
                    throw (new SAXException("EML210SaxHandler.startElement - error with action " +
437
                    		action + " : " + e.getMessage()));
438 4678 daigle
				}
439
			}
440 2169 sgarg
441 4678 daigle
			// Create the current node representation
442
			currentNode = new DBSAXNode(connection, qName, localName, parentNode,
443
					rootNode.getNodeID(), docid, doctype);
444
			// Use a local variable to store the element node id
445
			// If this element is a start point of subtree(section), it will be
446
			// stored otherwise, it will be discarded
447
			long startNodeId = currentNode.getNodeID();
448
			// Add all of the namespaces
449
			String prefix = null;
450
			String nsuri = null;
451
			Enumeration<String> prefixes = namespaces.keys();
452
			while (prefixes.hasMoreElements()) {
453
				prefix = prefixes.nextElement();
454
				nsuri = namespaces.get(prefix);
455
				endNodeId = currentNode.setNamespace(prefix, nsuri, docid);
456
			}
457 2169 sgarg
458 4678 daigle
			// Add all of the attributes
459
			for (int i = 0; i < atts.getLength(); i++) {
460
				String attributeName = atts.getQName(i);
461
				String attributeValue = atts.getValue(i);
462
				endNodeId = currentNode
463
						.setAttribute(attributeName, attributeValue, docid);
464 2169 sgarg
465 4678 daigle
				// To handle name space and schema location if the attribute
466
				// name is xsi:schemaLocation. If the name space is in not
467
				// in catalog table it will be registered.
468
				if (attributeName != null
469
						&& attributeName.indexOf(MetaCatServlet.SCHEMALOCATIONKEYWORD) != -1) {
470
					SchemaLocationResolver resolver = new SchemaLocationResolver(
471
							attributeValue);
472
					resolver.resolveNameSpace();
473 2169 sgarg
474 4678 daigle
				} else if (attributeName != null && attributeName.equals(ID)) {
475 5096 daigle
476 4678 daigle
				}
477
			}// for
478
479
			// handle access stuff
480
			if (localName.equals(ACCESS)) {
481
				if (parentNode.getTagName().equals(EML)) {
482 5311 daigle
					processingTopLevelAccess = true;
483 4472 daigle
				} else if (parentNode.getTagName() == DISTRIBUTION) {
484 5311 daigle
					processingAdditionalAccess = true;
485 4472 daigle
				} else {
486
					// process other access embedded into resource level
487
					// module
488 5311 daigle
					processingOtherAccess = true;
489 4472 daigle
				}
490 4678 daigle
				// create access object
491
				accessObject = new AccessSection();
492
				// set permission order
493
				String permOrder = currentNode.getAttribute(ORDER);
494
				accessObject.setPermissionOrder(permOrder);
495
				// set access id
496
				String accessId = currentNode.getAttribute(ID);
497
				accessObject.setSubTreeId(accessId);
498
				accessObject.setStartNodeId(startNodeId);
499
				accessObject.setDocId(docid);
500 5311 daigle
				if (processingAdditionalAccess) {
501 4678 daigle
					accessObject.setDataFileName(inlineDataFileName);
502
				}
503 2169 sgarg
504 4678 daigle
				// load top level node stack to
505
				// currentUnchangableAccessModuleNodeStack
506 5311 daigle
				if (processingTopLevelAccess && needToCheckAccessModule) {
507 4678 daigle
					// get the node stack for
508
					currentUnchangeableAccessModuleNodeStack = topAccessSection
509
							.getSubTreeNodeStack();
510
				}
511
			} else if (localName.equals(DISTRIBUTION)) {
512
				distributionIndex++;
513
				currentDistributionSection = new DistributionSection(distributionIndex);
514 2169 sgarg
515 4678 daigle
				// handle subtree info
516
				SubTree subTree = new SubTree();
517
				// set sub tree id
518
				subTree.setSubTreeId(String.valueOf(distributionIndex));
519
				// set sub tree start element name
520
				subTree.setStartElementName(currentNode.getTagName());
521
				// set start node number
522
				subTree.setStartNodeId(startNodeId);
523
				// add to stack, but it didn't get end node id yet
524
				subTreeInfoStack.push(subTree);
525
			}
526
			// Set up a access rule for allow
527
			else if (parentNode.getTagName() != null
528
					&& (parentNode.getTagName()).equals(ACCESS)
529
					&& localName.equals(ALLOW)) {
530 2169 sgarg
531 4678 daigle
				accessRule = new AccessRule();
532 2169 sgarg
533 4678 daigle
				// set permission type "allow"
534
				accessRule.setPermissionType(ALLOW);
535 2169 sgarg
536 4678 daigle
			}
537
			// set up an access rule for deny
538
			else if (parentNode.getTagName() != null
539
					&& (parentNode.getTagName()).equals(ACCESS) && localName.equals(DENY)) {
540
				accessRule = new AccessRule();
541
				// set permission type "allow"
542
				accessRule.setPermissionType(DENY);
543
			}
544 2169 sgarg
545 4678 daigle
			// Add the node to the stack, so that any text data can be
546
			// added as it is encountered
547
			nodeStack.push(currentNode);
548
			// Add the node to the vector used by thread for writing XML Index
549
			nodeIndex.addElement(currentNode);
550 2169 sgarg
551 4678 daigle
			// compare top access level module
552 5311 daigle
			if (processingTopLevelAccess && needToCheckAccessModule) {
553 4678 daigle
				compareElementNameSpaceAttributes(
554
						currentUnchangeableAccessModuleNodeStack, namespaces, atts,
555
						localName, UPDATEACCESSERROR);
556 2169 sgarg
557 4678 daigle
			}
558 2169 sgarg
559 4678 daigle
			// store access module element and attributes into stored stack
560
			if (needToCheckAccessModule
561 5311 daigle
					&& (processingAdditionalAccess || processingOtherAccess || processingTopLevelAccess)) {
562 4678 daigle
				// stored the pull out nodes into storedNode stack
563
				NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "ELEMENT", localName,
564 4698 daigle
						prefix, MetacatUtil.normalize(null));
565 4678 daigle
				storedAccessNodeStack.push(nodeElement);
566
				for (int i = 0; i < atts.getLength(); i++) {
567
					String attributeName = atts.getQName(i);
568
					String attributeValue = atts.getValue(i);
569
					NodeRecord nodeAttribute = new NodeRecord(-2, -2, -2, "ATTRIBUTE",
570 4698 daigle
							attributeName, null, MetacatUtil.normalize(attributeValue));
571 4678 daigle
					storedAccessNodeStack.push(nodeAttribute);
572
				}
573 2169 sgarg
574 4678 daigle
			}
575 2169 sgarg
576 4678 daigle
			// reset name space
577
			namespaces = null;
578
			namespaces = new Hashtable<String, String>();
579
		}// not inline data
580
		else {
581
			// we don't buffer the inline data in characters() method
582
			// so start character don't need to hand text node.
583 2169 sgarg
584 4678 daigle
			// inline data may be the xml format.
585
			StringBuffer inlineElements = new StringBuffer();
586
			inlineElements.append("<").append(qName);
587
			// append attributes
588
			for (int i = 0; i < atts.getLength(); i++) {
589
				String attributeName = atts.getQName(i);
590
				String attributeValue = atts.getValue(i);
591
				inlineElements.append(" ");
592
				inlineElements.append(attributeName);
593
				inlineElements.append("=\"");
594
				inlineElements.append(attributeValue);
595
				inlineElements.append("\"");
596
			}
597
			// append namespace
598
			String prefix = null;
599
			String nsuri = null;
600
			Enumeration<String> prefixes = inlineDataNameSpace.keys();
601
			while (prefixes.hasMoreElements()) {
602
				prefix = prefixes.nextElement();
603
				nsuri = namespaces.get(prefix);
604
				inlineElements.append(" ");
605
				inlineElements.append("xmlns:");
606
				inlineElements.append(prefix);
607
				inlineElements.append("=\"");
608
				inlineElements.append(nsuri);
609
				inlineElements.append("\"");
610
			}
611
			inlineElements.append(">");
612
			// reset inline data name space
613
			inlineDataNameSpace = null;
614
			inlineDataNameSpace = new Hashtable<String, String>();
615
			// write inline data into file
616
			logMetacat.debug("the inline element data is: " + inlineElements.toString());
617
			writeInlineDataIntoFile(inlineDataFileWriter, inlineElements);
618
		}// else
619 2169 sgarg
620 4678 daigle
	}
621 2169 sgarg
622 4678 daigle
	private void compareElementNameSpaceAttributes(
623
			Stack<NodeRecord> unchangeableNodeStack,
624
			Hashtable<String, String> nameSpaces, Attributes attributes,
625
			String localName, String error) throws SAXException {
626
		// Get element subtree node stack (element node)
627
		NodeRecord elementNode = null;
628
		try {
629
			elementNode = unchangeableNodeStack.pop();
630
		} catch (EmptyStackException ee) {
631
			logMetacat.error("Node stack is empty for element data");
632
			throw new SAXException(error);
633
		}
634
		logMetacat.debug("current node type from xml is ELEMENT");
635
		logMetacat.debug("node type from stack: " + elementNode.getNodeType());
636
		logMetacat.debug("node name from xml document: " + localName);
637
		logMetacat.debug("node name from stack: " + elementNode.getNodeName());
638
		logMetacat.debug("node data from stack: " + elementNode.getNodeData());
639
		logMetacat.debug("node id is: " + elementNode.getNodeId());
640
		// if this node is not element or local name not equal or name space
641
		// not equals, throw an exception
642
		if (!elementNode.getNodeType().equals("ELEMENT")
643
				|| !localName.equals(elementNode.getNodeName()))
644
		// (uri != null && !uri.equals(elementNode.getNodePrefix())))
645
		{
646
			logMetacat.error("Inconsistence happened: ");
647
			logMetacat.error("current node type from xml is ELEMENT");
648
			logMetacat.error("node type from stack: " + elementNode.getNodeType());
649
			logMetacat.error("node name from xml document: " + localName);
650
			logMetacat.error("node name from stack: " + elementNode.getNodeName());
651
			logMetacat.error("node data from stack: " + elementNode.getNodeData());
652
			logMetacat.error("node id is: " + elementNode.getNodeId());
653
			throw new SAXException(error);
654
		}
655 2169 sgarg
656 4678 daigle
		// compare namespace
657
		Enumeration<String> nameEn = nameSpaces.keys();
658
		while (nameEn.hasMoreElements()) {
659
			// Get namespacke node stack (element node)
660
			NodeRecord nameNode = null;
661
			try {
662
				nameNode = unchangeableNodeStack.pop();
663
			} catch (EmptyStackException ee) {
664
				logMetacat.error("Node stack is empty for namespace data");
665
				throw new SAXException(error);
666
			}
667 2169 sgarg
668 4678 daigle
			String prefixName = nameEn.nextElement();
669
			String nameSpaceUri = nameSpaces.get(prefixName);
670
			if (!nameNode.getNodeType().equals("NAMESPACE")
671
					|| !prefixName.equals(nameNode.getNodeName())
672
					|| !nameSpaceUri.equals(nameNode.getNodeData())) {
673
				logMetacat.error("Inconsistence happened: ");
674
				logMetacat.error("current node type from xml is NAMESPACE");
675
				logMetacat.error("node type from stack: " + nameNode.getNodeType());
676
				logMetacat.error("current node name from xml is: " + prefixName);
677
				logMetacat.error("node name from stack: " + nameNode.getNodeName());
678
				logMetacat.error("current node data from xml is: " + nameSpaceUri);
679
				logMetacat.error("node data from stack: " + nameNode.getNodeData());
680
				logMetacat.error("node id is: " + nameNode.getNodeId());
681
				throw new SAXException(error);
682
			}
683 2169 sgarg
684 4678 daigle
		}// while
685 2169 sgarg
686 4678 daigle
		// compare attributes
687
		for (int i = 0; i < attributes.getLength(); i++) {
688
			NodeRecord attriNode = null;
689
			try {
690
				attriNode = unchangeableNodeStack.pop();
691 2169 sgarg
692 4678 daigle
			} catch (EmptyStackException ee) {
693
				logMetacat.error("Node stack is empty for attribute data");
694
				throw new SAXException(error);
695
			}
696
			String attributeName = attributes.getQName(i);
697
			String attributeValue = attributes.getValue(i);
698
			logMetacat.debug("current node type from xml is ATTRIBUTE ");
699
			logMetacat.debug("node type from stack: " + attriNode.getNodeType());
700
			logMetacat.debug("current node name from xml is: " + attributeName);
701
			logMetacat.debug("node name from stack: " + attriNode.getNodeName());
702
			logMetacat.debug("current node data from xml is: " + attributeValue);
703
			logMetacat.debug("node data from stack: " + attriNode.getNodeData());
704
			logMetacat.debug("node id  is: " + attriNode.getNodeId());
705 2169 sgarg
706 4678 daigle
			if (!attriNode.getNodeType().equals("ATTRIBUTE")
707
					|| !attributeName.equals(attriNode.getNodeName())
708
					|| !attributeValue.equals(attriNode.getNodeData())) {
709
				logMetacat.error("Inconsistence happened: ");
710
				logMetacat.error("current node type from xml is ATTRIBUTE ");
711
				logMetacat.error("node type from stack: " + attriNode.getNodeType());
712
				logMetacat.error("current node name from xml is: " + attributeName);
713
				logMetacat.error("node name from stack: " + attriNode.getNodeName());
714
				logMetacat.error("current node data from xml is: " + attributeValue);
715
				logMetacat.error("node data from stack: " + attriNode.getNodeData());
716
				logMetacat.error("node is: " + attriNode.getNodeId());
717
				throw new SAXException(error);
718
			}
719
		}// for
720 2169 sgarg
721 4678 daigle
	}
722 2169 sgarg
723 4678 daigle
	/* method to compare current text node and node in db */
724 5311 daigle
	private void compareAccessTextNode(Stack<NodeRecord> nodeStack, StringBuffer text) throws SAXException {
725 4678 daigle
		NodeRecord node = null;
726
		// get node from current stack
727
		try {
728
			node = nodeStack.pop();
729
		} catch (EmptyStackException ee) {
730 5311 daigle
			logMetacat.error("Node stack is empty for text data in startElement for doc id " + docid);
731
			throw new SAXException("Access rules could not be found in database.");
732 4678 daigle
		}
733 5311 daigle
734
		String dbAccessData = node.getNodeData();
735
		String docAccessData = text.toString().trim();
736
737
		logMetacat.debug("Eml210SAXHandler.compareAccessTextNode - \n" +
738
					"\t access node type from db:       " + node.getNodeType() + "\n" +
739
					"\t access node data from db:       " + node.getNodeData() + "\n" +
740
					"\t access node data from document: " + text.toString());
741
742 4678 daigle
		if (!node.getNodeType().equals("TEXT")
743 5311 daigle
				|| !docAccessData.equals(dbAccessData)) {
744
			logMetacat.warn("Eml210SAXHandler.compareAccessTextNode - Access record mismatch: \n" +
745
					"\t access node type from db:       " + node.getNodeType() + "\n" +
746
					"\t access node data from db:       " + dbAccessData + "\n" +
747
					"\t access node data from document: " + docAccessData);
748
749
			throw new SAXException(UPDATEACCESSERROR + " [Eml210SAXHandler.compareAccessTextNode]");
750 4678 daigle
		}// if
751
	}
752 2169 sgarg
753 4678 daigle
	/** SAX Handler that is called for each XML text node */
754
	public void characters(char[] cbuf, int start, int len) throws SAXException {
755
		logMetacat.debug("CHARACTERS");
756
		if (!handleInlineData) {
757
			// buffer all text nodes for same element. This is for if text was
758
			// split into different nodes
759
			textBuffer.append(new String(cbuf, start, len));
760
			// set hittextnode true
761
			hitTextNode = true;
762
			// if text buffer .size is greater than max, write it to db.
763
			// so we can save memory
764
			if (textBuffer.length() > MAXDATACHARS) {
765
				logMetacat.debug("Write text into DB in charaters"
766
						+ " when text buffer size is greater than maxmum number");
767
				DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
768
				endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer, currentNode);
769
				textBuffer = null;
770
				textBuffer = new StringBuffer();
771
			}
772
		} else {
773
			// this is inline data and write file system directly
774
			// we don't need to buffer it.
775
			StringBuffer inlineText = new StringBuffer();
776
			inlineText.append(new String(cbuf, start, len));
777
			logMetacat.debug("The inline text data write into file system: "
778
					+ inlineText.toString());
779
			writeInlineDataIntoFile(inlineDataFileWriter, inlineText);
780
		}
781
	}
782 2169 sgarg
783 4678 daigle
	/** SAX Handler that is called at the end of each XML element */
784
	public void endElement(String uri, String localName, String qName)
785
			throws SAXException {
786
		logMetacat.debug("End ELEMENT " + qName);
787 2169 sgarg
788 4678 daigle
		if (localName.equals(INLINE) && handleInlineData) {
789
			// Get the node from the stack
790
			DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
791
			logMetacat.debug("End of inline data");
792
			// close file writer
793
			try {
794
				inlineDataFileWriter.close();
795
				handleInlineData = false;
796
			} catch (IOException ioe) {
797
				throw new SAXException(ioe.getMessage());
798
			}
799 2169 sgarg
800 4678 daigle
			// write put inline data file name into text buffer (without path)
801
			textBuffer = new StringBuffer(inlineDataFileName);
802
			// write file name into db
803
			endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer, currentNode);
804
			// reset textbuff
805
			textBuffer = null;
806
			textBuffer = new StringBuffer();
807
			return;
808
		}
809 2169 sgarg
810 4678 daigle
		if (!handleInlineData) {
811
			// Get the node from the stack
812
			DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
813
			String currentTag = currentNode.getTagName();
814 2169 sgarg
815 4678 daigle
			// If before the end element, the parser hit text nodes and store
816
			// them into the buffer, write the buffer to data base. The reason
817
			// we put write database here is for xerces some time split text
818
			// node
819
			if (hitTextNode) {
820
				// get access value
821
				String data = null;
822
				// add principal
823
				if (currentTag.equals(PRINCIPAL) && accessRule != null) {
824
					data = (textBuffer.toString()).trim();
825
					accessRule.addPrincipal(data);
826 2169 sgarg
827 4678 daigle
				} else if (currentTag.equals(PERMISSION) && accessRule != null) {
828
					data = (textBuffer.toString()).trim();
829
					// we combine different a permission into one value
830
					int permission = accessRule.getPermission();
831
					// add permission
832
					if (data.toUpperCase().equals(READSTRING)) {
833
						permission = permission | READ;
834
					} else if (data.toUpperCase().equals(WRITESTRING)) {
835
						permission = permission | WRITE;
836
					} else if (data.toUpperCase().equals(CHMODSTRING)) {
837
						permission = permission | CHMOD;
838
					} else if (data.toUpperCase().equals(ALLSTRING)) {
839
						permission = permission | ALL;
840
					}
841
					accessRule.setPermission(permission);
842
				} else if (currentTag.equals(REFERENCES)
843 5311 daigle
						&& (processingTopLevelAccess || processingAdditionalAccess || processingOtherAccess)) {
844 4678 daigle
					// get reference
845
					data = (textBuffer.toString()).trim();
846
					// put reference id into accessSection
847
					accessObject.setReferences(data);
848 2169 sgarg
849 4678 daigle
				} else if (currentTag.equals(URL)) {
850
					// handle online data, make sure its'parent is online
851
					DBSAXNode parentNode = (DBSAXNode) nodeStack.peek();
852
					if (parentNode != null && parentNode.getTagName() != null
853
							&& parentNode.getTagName().equals(ONLINE)) {
854
						// if online data is in local metacat, add it to the
855
						// vector
856
						data = (textBuffer.toString()).trim();
857
						handleOnlineUrlDataFile(data);
858 5311 daigle
859 4678 daigle
					}// if
860
				}// else if
861 5311 daigle
862 4678 daigle
				// write text to db if it is not inline data
863 5311 daigle
				logMetacat.debug("Write text into DB in End Element");
864 2169 sgarg
865 5311 daigle
				// compare top level access module
866
				if (processingTopLevelAccess && needToCheckAccessModule) {
867
					compareAccessTextNode(currentUnchangeableAccessModuleNodeStack,
868
							textBuffer);
869 4678 daigle
				}
870 5311 daigle
				// write text node into db
871
				endNodeId = writeTextForDBSAXNode(endNodeId, textBuffer, currentNode);
872
			}
873
874
			if (needToCheckAccessModule
875
					&& (processingAdditionalAccess || processingOtherAccess || processingTopLevelAccess)) {
876
				// stored the pull out nodes into storedNode stack
877
				NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT", null,
878
						null, MetacatUtil.normalize(textBuffer.toString()));
879
				storedAccessNodeStack.push(nodeElement);
880 2169 sgarg
881 5311 daigle
			}
882 2169 sgarg
883 4678 daigle
			// set hitText false
884
			hitTextNode = false;
885
			// reset textbuff
886
			textBuffer = null;
887
			textBuffer = new StringBuffer();
888 2169 sgarg
889 4678 daigle
			// hand sub stree stuff
890
			if (!subTreeInfoStack.empty()) {
891
				SubTree tree = subTreeInfoStack.peek();// get last
892
				// subtree
893
				if (tree != null && tree.getStartElementName() != null
894
						&& (tree.getStartElementName()).equals(currentTag)) {
895
					// find the end of sub tree and set the end node id
896
					tree.setEndNodeId(endNodeId);
897
					// add the subtree into the final store palace
898
					subTreeList.add(tree);
899
					// get rid of it from stack
900
					subTreeInfoStack.pop();
901
				}// if
902
			}// if
903 2169 sgarg
904 4678 daigle
			// access stuff
905
			if (currentTag.equals(ALLOW) || currentTag.equals(DENY)) {
906
				// finish parser access rule and assign it to new one
907
				AccessRule newRule = accessRule;
908
				// add the new rule to access section object
909
				accessObject.addAccessRule(newRule);
910
				// reset access rule
911
				accessRule = null;
912
			} else if (currentTag.equals(ACCESS)) {
913
				// finish parsing an access section and assign it to new one
914
				DBSAXNode parentNode = (DBSAXNode) nodeStack.peek();
915 2169 sgarg
916 4678 daigle
				accessObject.setEndNodeId(endNodeId);
917 2169 sgarg
918 4678 daigle
				if (parentNode != null && parentNode.getTagName() != null
919
						&& parentNode.getTagName().equals(DISTRIBUTION)) {
920
					describesId.add(String.valueOf(distributionIndex));
921
					currentDistributionSection.setAccessSection(accessObject);
922
				}
923 2169 sgarg
924 4678 daigle
				AccessSection newAccessObject = accessObject;
925 2169 sgarg
926 4678 daigle
				if (newAccessObject != null) {
927 2169 sgarg
928 4678 daigle
					// add the accessSection into a vector to store it
929
					// if it is not a reference, need to store it
930
					if (newAccessObject.getReferences() == null) {
931 2169 sgarg
932 4678 daigle
						newAccessObject.setStoredTmpNodeStack(storedAccessNodeStack);
933
						accessObjectList.add(newAccessObject);
934
					}
935 5311 daigle
					if (processingTopLevelAccess) {
936 2169 sgarg
937 4678 daigle
						// top level access control will handle whole document
938
						// -docid
939
						topLevelAccessControlMap.put(docid, newAccessObject);
940
						// reset processtopleveraccess tag
941 2169 sgarg
942 4678 daigle
					}// if
943 5311 daigle
					else if (processingAdditionalAccess) {
944 4678 daigle
						// for additional control put everything in describes
945
						// value
946
						// and access object into hash
947
						for (int i = 0; i < describesId.size(); i++) {
948 2169 sgarg
949 4678 daigle
							String subId = describesId.elementAt(i);
950
							if (subId != null) {
951
								additionalAccessControlMap.put(subId, newAccessObject);
952
							}// if
953
						}// for
954
						// add this hashtable in to vector
955 2169 sgarg
956 4678 daigle
						additionalAccessMapList.add(additionalAccessControlMap);
957
						// reset this hashtable in order to store another
958
						// additional
959
						// accesscontrol
960
						additionalAccessControlMap = null;
961
						additionalAccessControlMap = new Hashtable<String, AccessSection>();
962
					}// if
963 2169 sgarg
964 4678 daigle
				}// if
965
				// check if access node stack is empty after parsing top access
966
				// module
967 2169 sgarg
968 5311 daigle
				if (needToCheckAccessModule && processingTopLevelAccess
969 4678 daigle
						&& !currentUnchangeableAccessModuleNodeStack.isEmpty()) {
970 2169 sgarg
971 4678 daigle
					logMetacat.error("Access node stack is not empty after "
972
							+ "parsing access subtree");
973
					throw new SAXException(UPDATEACCESSERROR);
974 2169 sgarg
975 4678 daigle
				}
976
				// reset access section object
977 2169 sgarg
978 4678 daigle
				accessObject = null;
979 2169 sgarg
980 4678 daigle
				// reset tmp stored node stack
981
				storedAccessNodeStack = null;
982
				storedAccessNodeStack = new Stack<NodeRecord>();
983 2169 sgarg
984 4678 daigle
				// reset flag
985 5311 daigle
				processingAdditionalAccess = false;
986
				processingTopLevelAccess = false;
987
				processingOtherAccess = false;
988 2169 sgarg
989 4678 daigle
			} else if (currentTag.equals(DISTRIBUTION)) {
990
				// If the current Distribution is inline or data and it doesn't have an access section
991
				// we use the top level access section (if it exists)
992
				if ((currentDistributionSection.getDistributionType() == DistributionSection.DATA_DISTRIBUTION
993
						|| currentDistributionSection.getDistributionType() == DistributionSection.INLINE_DATA_DISTRIBUTION)
994
						&& currentDistributionSection.getAccessSection() == null
995
						&& topLevelAccessControlMap.size() > 0) {
996
997
					AccessSection accessSection = new AccessSection();
998
					accessSection.setDocId(docid);
999
					AccessSection topLevelAccess = topLevelAccessControlMap.get(docid);
1000
					accessSection.setPermissionOrder(topLevelAccess.getPermissionOrder());
1001
					Vector<AccessRule> accessRuleList = topLevelAccess.getAccessRules();
1002
					for (AccessRule accessRule : accessRuleList) {
1003
						accessSection.addAccessRule(accessRule);
1004
					}
1005
					currentDistributionSection.setAccessSection(accessSection);
1006
				}
1007
				if (currentDistributionSection.getAccessSection() != null) {
1008
					currentDistributionSection.getAccessSection().setDataFileName(currentDistributionSection.getDataFileName());
1009
				}
1010
				allDistributionSections.add(currentDistributionSection);
1011
				currentDistributionSection = null;
1012
				describesId = null;
1013
				describesId = new Vector<String>();
1014
			}
1015
		} else {
1016
			// this is in inline part
1017
			StringBuffer endElement = new StringBuffer();
1018
			endElement.append("</");
1019
			endElement.append(qName);
1020
			endElement.append(">");
1021
			logMetacat.debug("inline endElement: " + endElement.toString());
1022
			writeInlineDataIntoFile(inlineDataFileWriter, endElement);
1023
		}
1024
	}
1025 2169 sgarg
1026 4678 daigle
	/**
1027
	 * SAX Handler that receives notification of comments in the DTD
1028
	 */
1029
	public void comment(char[] ch, int start, int length) throws SAXException {
1030
		logMetacat.debug("COMMENT");
1031
		if (!handleInlineData) {
1032
			if (!processingDTD) {
1033
				DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1034
				String str = new String(ch, start, length);
1035 2169 sgarg
1036 4678 daigle
				// compare top level access module
1037 5311 daigle
				if (processingTopLevelAccess && needToCheckAccessModule) {
1038 4678 daigle
					compareCommentNode(currentUnchangeableAccessModuleNodeStack, str,
1039
							UPDATEACCESSERROR);
1040
				}
1041
				endNodeId = currentNode.writeChildNodeToDB("COMMENT", null, str, docid);
1042
				if (needToCheckAccessModule
1043 5311 daigle
						&& (processingAdditionalAccess || processingOtherAccess || processingTopLevelAccess)) {
1044 4678 daigle
					// stored the pull out nodes into storedNode stack
1045
					NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "COMMENT", null,
1046 4698 daigle
							null, MetacatUtil.normalize(str));
1047 4678 daigle
					storedAccessNodeStack.push(nodeElement);
1048 2169 sgarg
1049 4678 daigle
				}
1050
			}
1051
		} else {
1052
			// inline data comment
1053
			StringBuffer inlineComment = new StringBuffer();
1054
			inlineComment.append("<!--");
1055
			inlineComment.append(new String(ch, start, length));
1056
			inlineComment.append("-->");
1057
			logMetacat.debug("inline data comment: " + inlineComment.toString());
1058
			writeInlineDataIntoFile(inlineDataFileWriter, inlineComment);
1059
		}
1060
	}
1061 2169 sgarg
1062 4678 daigle
	/* Compare comment from xml and db */
1063
	private void compareCommentNode(Stack<NodeRecord> nodeStack, String string,
1064
			String error) throws SAXException {
1065
		NodeRecord node = null;
1066
		try {
1067
			node = nodeStack.pop();
1068
		} catch (EmptyStackException ee) {
1069
			logMetacat.error("the stack is empty for comment data");
1070
			throw new SAXException(error);
1071
		}
1072
		logMetacat.debug("current node type from xml is COMMENT");
1073
		logMetacat.debug("node type from stack: " + node.getNodeType());
1074
		logMetacat.debug("current node data from xml is: " + string);
1075
		logMetacat.debug("node data from stack: " + node.getNodeData());
1076
		logMetacat.debug("node is from stack: " + node.getNodeId());
1077
		// if not consistent terminate program and throw a exception
1078
		if (!node.getNodeType().equals("COMMENT") || !string.equals(node.getNodeData())) {
1079
			logMetacat.error("Inconsistence happened: ");
1080
			logMetacat.error("current node type from xml is COMMENT");
1081
			logMetacat.error("node type from stack: " + node.getNodeType());
1082
			logMetacat.error("current node data from xml is: " + string);
1083
			logMetacat.error("node data from stack: " + node.getNodeData());
1084
			logMetacat.error("node is from stack: " + node.getNodeId());
1085
			throw new SAXException(error);
1086
		}// if
1087
	}
1088 2169 sgarg
1089 4678 daigle
	/**
1090
	 * SAX Handler called once for each processing instruction found: node that
1091
	 * PI may occur before or after the root element.
1092
	 */
1093
	public void processingInstruction(String target, String data) throws SAXException {
1094
		logMetacat.debug("PI");
1095
		if (!handleInlineData) {
1096
			DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1097
			endNodeId = currentNode.writeChildNodeToDB("PI", target, data, docid);
1098
		} else {
1099
			StringBuffer inlinePI = new StringBuffer();
1100
			inlinePI.append("<?");
1101
			inlinePI.append(target);
1102
			inlinePI.append(" ");
1103
			inlinePI.append(data);
1104
			inlinePI.append("?>");
1105
			logMetacat.debug("inline data pi is: " + inlinePI.toString());
1106
			writeInlineDataIntoFile(inlineDataFileWriter, inlinePI);
1107
		}
1108
	}
1109 2169 sgarg
1110 4678 daigle
	/** SAX Handler that is called at the start of Namespace */
1111
	public void startPrefixMapping(String prefix, String uri) throws SAXException {
1112
		logMetacat.debug("NAMESPACE");
1113
		if (!handleInlineData) {
1114
			namespaces.put(prefix, uri);
1115
		} else {
1116
			inlineDataNameSpace.put(prefix, uri);
1117
		}
1118
	}
1119 2169 sgarg
1120 4678 daigle
	/**
1121
	 * SAX Handler that is called for each XML text node that is Ignorable white
1122
	 * space
1123
	 */
1124
	public void ignorableWhitespace(char[] cbuf, int start, int len) throws SAXException {
1125
		// When validation is turned "on", white spaces are reported here
1126
		// When validation is turned "off" white spaces are not reported here,
1127
		// but through characters() callback
1128
		logMetacat.debug("IGNORABLEWHITESPACE");
1129
		if (!handleInlineData) {
1130
			DBSAXNode currentNode = (DBSAXNode) nodeStack.peek();
1131 5208 daigle
				String data = new String(cbuf, start, len);
1132 4678 daigle
				// compare whitespace in access top module
1133 5311 daigle
				if (processingTopLevelAccess && needToCheckAccessModule) {
1134 4678 daigle
					compareWhiteSpace(currentUnchangeableAccessModuleNodeStack, data,
1135
							UPDATEACCESSERROR);
1136
				}
1137
				// Write the content of the node to the database
1138
				if (needToCheckAccessModule
1139 5311 daigle
						&& (processingAdditionalAccess || processingOtherAccess || processingTopLevelAccess)) {
1140 4678 daigle
					// stored the pull out nodes into storedNode stack
1141
					NodeRecord nodeElement = new NodeRecord(-2, -2, -2, "TEXT", null,
1142 4698 daigle
							null, MetacatUtil.normalize(data));
1143 4678 daigle
					storedAccessNodeStack.push(nodeElement);
1144 2169 sgarg
1145 4678 daigle
				}
1146
				endNodeId = currentNode.writeChildNodeToDB("TEXT", null, data, docid);
1147
		} else {
1148
			// This is inline data write to file directly
1149
			StringBuffer inlineWhiteSpace = new StringBuffer(new String(cbuf, start, len));
1150
			writeInlineDataIntoFile(inlineDataFileWriter, inlineWhiteSpace);
1151
		}
1152 2169 sgarg
1153 4678 daigle
	}
1154 2169 sgarg
1155 4678 daigle
	/* Compare whitespace from xml and db */
1156
	private void compareWhiteSpace(Stack<NodeRecord> nodeStack, String string,
1157
			String error) throws SAXException {
1158
		NodeRecord node = null;
1159
		try {
1160
			node = nodeStack.pop();
1161
		} catch (EmptyStackException ee) {
1162
			logMetacat.error("the stack is empty for whitespace data");
1163
			throw new SAXException(error);
1164
		}
1165
		if (!node.getNodeType().equals("TEXT") || !string.equals(node.getNodeData())) {
1166
			logMetacat.error("Inconsistence happened: ");
1167
			logMetacat.error("current node type from xml is WHITESPACE TEXT");
1168
			logMetacat.error("node type from stack: " + node.getNodeType());
1169
			logMetacat.error("current node data from xml is: " + string);
1170
			logMetacat.error("node data from stack: " + node.getNodeData());
1171
			logMetacat.error("node is from stack: " + node.getNodeId());
1172
			throw new SAXException(error);
1173
		}// if
1174
	}
1175 2169 sgarg
1176 4678 daigle
	/** SAX Handler that receives notification of end of the document */
1177
	public void endDocument() throws SAXException {
1178
		logMetacat.debug("end Document");
1179
		// There are some unchangable subtree didn't be compare
1180
		// This maybe cause user change the subtree id
1181
		if (!super.getIsRevisionDoc()) {
1182
			// write access rule to db
1183 7128 leinfelder
			if (writeAccessRules) {
1184
				writeAccessRuleToDB();
1185
			}
1186 4678 daigle
			// delete relation table
1187
			deleteRelations();
1188
			// write relations
1189
			for (int i = 0; i < onlineDataFileIdInRelationVector.size(); i++) {
1190
				String id = onlineDataFileIdInRelationVector.elementAt(i);
1191
				writeOnlineDataFileIdIntoRelationTable(id);
1192
			}
1193
		}
1194
	}
1195 2169 sgarg
1196 4678 daigle
	/* The method to write all access rule into db */
1197
	private void writeAccessRuleToDB() throws SAXException {
1198
		// Delete old permssion
1199 6744 leinfelder
		deletePermissionsInAccessTable();
1200 4678 daigle
		// write top leve access rule
1201
		writeTopLevelAccessRuleToDB();
1202
		// write additional access rule
1203
		// writeAdditionalAccessRuleToDB();
1204
		writeAdditionalAccessRulesToDB();
1205
	}// writeAccessRuleToDB
1206 2169 sgarg
1207 4678 daigle
	/* The method to write top level access rule into db. */
1208
	private void writeTopLevelAccessRuleToDB() throws SAXException {
1209
		// for top document level
1210
		AccessSection accessSection = topLevelAccessControlMap.get(docid);
1211
		boolean top = true;
1212
		String subSectionId = null;
1213
		if (accessSection != null) {
1214
			AccessSection accessSectionObj = accessSection;
1215 2169 sgarg
1216 4678 daigle
			// if accessSection is not null and is not reference
1217
			if (accessSectionObj.getReferences() == null) {
1218 7137 leinfelder
				// check for denyFirst permOrder
1219
				String permOrder = accessSectionObj.getPermissionOrder();
1220
				if (permOrder.equals(AccessControlInterface.DENYFIRST) && ignoreDenyFirst) {
1221
					logMetacat.warn("Metacat no longer supports EML 'denyFirst' access rules - ignoring this access block");
1222
			    	return;
1223
			    }
1224 4678 daigle
				// write the top level access module into xml_accesssubtree to
1225
				// store info and then when update to check if the user can
1226
				// update it or not
1227
				deleteAccessSubTreeRecord(docid);
1228
				writeAccessSubTreeIntoDB(accessSectionObj, TOPLEVEL);
1229 2169 sgarg
1230 4678 daigle
				// write access section into xml_access table
1231
				writeGivenAccessRuleIntoDB(accessSectionObj, top, subSectionId);
1232
				// write online data file into xml_access too.
1233
				// for (int i= 0; i <onlineDataFileIdInTopAccessVector.size();
1234
				// i++)
1235
				// {
1236
				// String id = onlineDataFileIdInTopAccessVector.elementAt(i);
1237
				// writeAccessRuleForRelatedDataFileIntoDB(accessSectionObj,
1238
				// id);
1239
				// }
1240 2169 sgarg
1241 4678 daigle
			} else {
1242 2169 sgarg
1243 4678 daigle
				// this is a reference and go trough the vector which contains
1244
				// all access object
1245
				String referenceId = accessSectionObj.getReferences();
1246
				boolean findAccessObject = false;
1247
				logMetacat.debug("referered id for top access: " + referenceId);
1248
				for (int i = 0; i < accessObjectList.size(); i++) {
1249
					AccessSection accessObj = accessObjectList.elementAt(i);
1250
					String accessObjId = accessObj.getSubTreeId();
1251 7137 leinfelder
					// check for denyFirst permOrder
1252
					String permOrder = accessObj.getPermissionOrder();
1253
					if (permOrder.equals(AccessControlInterface.DENYFIRST) && ignoreDenyFirst) {
1254
						logMetacat.warn("Metacat no longer supports EML 'denyFirst' access rules - ignoring this access block, subtree id: " + accessObjId);
1255
				    	continue;
1256
				    }
1257 4678 daigle
					if (referenceId != null && accessObj != null
1258
							&& referenceId.equals(accessObjId)) {
1259
						// make sure the user didn't change any thing in this
1260
						// access moduel
1261
						// too if user doesn't have all permission
1262
						if (needToCheckAccessModule) {
1263 2169 sgarg
1264 4678 daigle
							Stack<NodeRecord> newStack = accessObj
1265
									.getStoredTmpNodeStack();
1266
							// revise order
1267 5025 daigle
							newStack = DocumentUtil.reviseStack(newStack);
1268 4678 daigle
							// go throught the vector of
1269
							// unChangeableAccessSubtreevector
1270
							// and find the one whose id is as same as
1271
							// referenceid
1272
							AccessSection oldAccessObj = getAccessSectionFromUnchangableAccessVector(referenceId);
1273
							// if oldAccessObj is null something is wrong
1274
							if (oldAccessObj == null) {
1275
								throw new SAXException(UPDATEACCESSERROR);
1276
							}// if
1277
							else {
1278
								// Get the node stack from old access obj
1279
								Stack<NodeRecord> oldStack = oldAccessObj
1280
										.getSubTreeNodeStack();
1281
								compareNodeStacks(newStack, oldStack);
1282
							}// else
1283
						}// if
1284
						// write accessobject into db
1285
						writeGivenAccessRuleIntoDB(accessObj, top, subSectionId);
1286
						// write online data file into xml_access too.
1287
						// for (int j= 0; j
1288
						// <onlineDataFileIdInTopAccessVector.size(); j++)
1289
						// {
1290
						// String id =
1291
						// onlineDataFileIdInTopAccessVector.elementAt(j);
1292
						// writeAccessRuleForRelatedDataFileIntoDB(accessSectionObj,
1293
						// id);
1294
						// }
1295 2169 sgarg
1296 4678 daigle
						// write the reference access into xml_accesssubtree
1297
						// too write the top level access module into
1298
						// xml_accesssubtree to store info and then when update
1299
						// to check if the user can update it or not
1300
						deleteAccessSubTreeRecord(docid);
1301
						writeAccessSubTreeIntoDB(accessSectionObj, TOPLEVEL);
1302
						writeAccessSubTreeIntoDB(accessObj, SUBTREELEVEL);
1303
						findAccessObject = true;
1304
						break;
1305
					}
1306
				}// for
1307
				// if we couldn't find an access subtree id for this reference
1308
				// id
1309
				if (!findAccessObject) {
1310
					throw new SAXException("The referenceid: " + referenceId
1311
							+ " is not access subtree");
1312
				}// if
1313
			}// else
1314 2169 sgarg
1315 4678 daigle
		}// if
1316
		else {
1317
			// couldn't find a access section object
1318
			logMetacat.warn("couldn't find access control for document: " + docid);
1319
		}
1320 2169 sgarg
1321 4678 daigle
	}// writeTopLevelAccessRuletoDB
1322 2169 sgarg
1323 4678 daigle
	/* Given a subtree id and find the responding access section */
1324
	private AccessSection getAccessSectionFromUnchangableAccessVector(String id) {
1325
		AccessSection result = null;
1326
		// Makse sure the id
1327
		if (id == null || id.equals("")) {
1328
			return result;
1329
		}
1330
		// go throught vector and find the list
1331
		for (int i = 0; i < unChangeableAccessSubTreeVector.size(); i++) {
1332
			AccessSection accessObj = unChangeableAccessSubTreeVector.elementAt(i);
1333
			if (accessObj.getSubTreeId() != null && (accessObj.getSubTreeId()).equals(id)) {
1334
				result = accessObj;
1335
			}// if
1336
		}// for
1337
		return result;
1338
	}// getAccessSectionFromUnchangableAccessVector
1339 2169 sgarg
1340 4678 daigle
	/* Compare two node stacks to see if they are same */
1341
	private void compareNodeStacks(Stack<NodeRecord> stack1, Stack<NodeRecord> stack2)
1342
			throws SAXException {
1343
		// make sure stack1 and stack2 are not empty
1344
		if (stack1.isEmpty() || stack2.isEmpty()) {
1345
			logMetacat.error("Because stack is empty!");
1346
			throw new SAXException(UPDATEACCESSERROR);
1347
		}
1348
		// go throw two stacks and compare every element
1349
		while (!stack1.isEmpty()) {
1350
			// Pop an element from stack1
1351
			NodeRecord record1 = stack1.pop();
1352
			// Pop an element from stack2(stack 2 maybe empty)
1353
			NodeRecord record2 = null;
1354
			try {
1355
				record2 = stack2.pop();
1356
			} catch (EmptyStackException ee) {
1357
				logMetacat.error("Node stack2 is empty but stack1 isn't!");
1358
				throw new SAXException(UPDATEACCESSERROR);
1359
			}
1360
			// if two records are not same throw a exception
1361
			if (!record1.contentEquals(record2)) {
1362
				logMetacat.error("Two records from new and old stack are not " + "same!");
1363
				throw new SAXException(UPDATEACCESSERROR);
1364
			}// if
1365
		}// while
1366 2169 sgarg
1367 4678 daigle
		// now stack1 is empty and we should make sure stack2 is empty too
1368
		if (!stack2.isEmpty()) {
1369
			logMetacat
1370
					.error("stack2 still has some elements while stack " + "is empty! ");
1371
			throw new SAXException(UPDATEACCESSERROR);
1372
		}// if
1373
	}// comparingNodeStacks
1374 4472 daigle
1375 5166 daigle
	/* The method to write additional access rule into db. */
1376 4678 daigle
	private void writeAdditionalAccessRulesToDB() throws SAXException {
1377
1378
		// Iterate through every distribution and write access sections for data and inline
1379
		// types to the database
1380
		for (DistributionSection distributionSection : allDistributionSections) {
1381
			// we're only interested in data and inline distributions
1382
			int distributionType = distributionSection.getDistributionType();
1383
			if (distributionType == DistributionSection.DATA_DISTRIBUTION
1384
					|| distributionType == DistributionSection.INLINE_DATA_DISTRIBUTION) {
1385
				AccessSection accessSection = distributionSection.getAccessSection();
1386
1387
				// If the distribution doesn't have an access section, we continue.
1388
				if (accessSection == null) {
1389
					continue;
1390 7137 leinfelder
				}
1391 4678 daigle
1392 7137 leinfelder
				// check for denyFirst permOrder
1393
				String permOrder = accessSection.getPermissionOrder();
1394
				if (permOrder.equals(AccessControlInterface.DENYFIRST) && ignoreDenyFirst) {
1395
					logMetacat.warn("Metacat no longer supports EML 'denyFirst' access rules - ignoring this access block: " + distributionSection.getDataFileName());
1396
			    	continue;
1397
			    }
1398
1399 4678 daigle
				// We want to check file permissions for all online data updates and inserts, or for
1400
				// inline updates.
1401
//				if (distributionType == DistributionSection.DATA_DISTRIBUTION
1402
//						|| (distributionType == DistributionSection.INLINE_DATA_DISTRIBUTION && action == "UPDATE")) {
1403 2169 sgarg
1404 4678 daigle
				if (distributionType == DistributionSection.DATA_DISTRIBUTION) {
1405
					try {
1406 6746 leinfelder
						// check for the previous version for permissions on update
1407 7293 leinfelder
						// we need to look up the docid from the guid, if we have it
1408 6746 leinfelder
						String dataDocid = distributionSection.getDataFileName();
1409 7293 leinfelder
						try {
1410
							dataDocid = IdentifierManager.getInstance().getLocalId(dataDocid);
1411
						} catch (McdbDocNotFoundException mcdbnfe) {
1412
							// ignore
1413
							logMetacat.warn("Could not find guid/docid mapping for " + dataDocid);
1414
						}
1415 6746 leinfelder
						String previousDocid = dataDocid;
1416
						if (action == "UPDATE") {
1417
							String docidWithoutRev = DocumentUtil.getDocIdFromString(dataDocid);
1418
							int latestRevision = DBUtil.getLatestRevisionInDocumentTable(docidWithoutRev);
1419
							if (latestRevision > 0) {
1420 6748 leinfelder
								previousDocid = docidWithoutRev + PropertyService.getProperty("document.accNumSeparator") + latestRevision;
1421 6746 leinfelder
							}
1422
						}
1423
1424 6744 leinfelder
						PermissionController controller = new PermissionController(previousDocid);
1425
1426 4769 daigle
						if (AccessionNumber.accNumberUsed(docid)
1427
								&& !controller.hasPermission(user, groups, "WRITE")) {
1428 4678 daigle
							throw new SAXException(UPDATEACCESSERROR);
1429
						}
1430
					} catch (SQLException sqle) {
1431
						throw new SAXException(
1432
								"Database error checking user permissions: "
1433
										+ sqle.getMessage());
1434
					} catch (Exception e) {
1435
						throw new SAXException(
1436
								"General error checking user permissions: "
1437
										+ e.getMessage());
1438
					}
1439
				} else if (distributionType == DistributionSection.INLINE_DATA_DISTRIBUTION && action == "UPDATE") {
1440
					try {
1441 6744 leinfelder
1442
						// check for the previous version for permissions
1443
						int latestRevision = DBUtil.getLatestRevisionInDocumentTable(docid);
1444
						String previousDocid =
1445
							docid + PropertyService.getProperty("document.accNumSeparator") + latestRevision;
1446
						PermissionController controller = new PermissionController(previousDocid);
1447 2169 sgarg
1448 4678 daigle
						if (!controller.hasPermission(user, groups, "WRITE")) {
1449
							throw new SAXException(UPDATEACCESSERROR);
1450
						}
1451
					} catch (SQLException sqle) {
1452
						throw new SAXException(
1453
								"Database error checking user permissions: "
1454
										+ sqle.getMessage());
1455
					} catch (Exception e) {
1456
						throw new SAXException(
1457
								"General error checking user permissions: "
1458
										+ e.getMessage());
1459
					}
1460
				}
1461
1462 6749 leinfelder
				// clear previous versions first
1463
				deleteAccessRule(accessSection, false);
1464
1465
				// now write the new ones
1466 4678 daigle
				String subSectionId = Integer.toString(distributionSection.getDistributionId());
1467
				writeGivenAccessRuleIntoDB(accessSection, false, subSectionId);
1468
			}
1469 2169 sgarg
1470 4678 daigle
		}
1471
1472
1473
	}
1474 6749 leinfelder
1475
	/**
1476
	 *  delete existing access for given access rule
1477
	 *
1478
	 */
1479
	private void deleteAccessRule(AccessSection accessSection, boolean topLevel) throws SAXException {
1480
1481
		if (accessSection == null) {
1482
			throw new SAXException("The access object is null");
1483
		}
1484
1485
		PreparedStatement pstmt = null;
1486 2169 sgarg
1487 6749 leinfelder
		String sql = null;
1488
		sql = "DELETE FROM xml_access WHERE guid = ?";
1489
1490
		try {
1491
1492
			pstmt = connection.prepareStatement(sql);
1493
			// Increase DBConnection usage count
1494
			connection.increaseUsageCount(1);
1495
			// Bind the values to the query
1496
			String guid = null;
1497
			if (topLevel) {
1498
				try {
1499
					guid = IdentifierManager.getInstance().getGUID(docid, Integer.valueOf(revision));
1500
				} catch (NumberFormatException e) {
1501
					throw new SAXException(e.getMessage(), e);
1502
				} catch (McdbDocNotFoundException e) {
1503
					// register the default mapping now
1504
					guid = docid + "." + revision;
1505
					IdentifierManager.getInstance().createMapping(guid, guid);
1506
				}
1507
			} else {
1508
				guid = accessSection.getDataFileName();
1509
1510
			}
1511
			pstmt.setString(1, guid);
1512
			logMetacat.debug("guid in accesstable: " + guid);
1513
1514
			logMetacat.debug("running sql: " + pstmt.toString());
1515
			pstmt.execute();
1516
1517
			pstmt.close();
1518
		}// try
1519
		catch (SQLException e) {
1520
			throw new SAXException("EMLSAXHandler.deleteAccessRule(): "
1521
					+ e.getMessage());
1522
		}// catch
1523
		finally {
1524
			try {
1525
				pstmt.close();
1526
			} catch (SQLException ee) {
1527
				throw new SAXException("EMLSAXHandler.deleteAccessRule(): "
1528
						+ ee.getMessage());
1529
			}
1530
		}// finally
1531
1532
	}
1533
1534 4678 daigle
	/* Write a given access rule into db */
1535
	private void writeGivenAccessRuleIntoDB(AccessSection accessSection,
1536
			boolean topLevel, String subSectionId) throws SAXException {
1537
		if (accessSection == null) {
1538
			throw new SAXException("The access object is null");
1539
		}
1540 2169 sgarg
1541 6744 leinfelder
		String guid = null;
1542 6802 leinfelder
		String referencedGuid = accessSection.getDataFileName();
1543
1544 6744 leinfelder
		try {
1545
			guid = IdentifierManager.getInstance().getGUID(docid, Integer.valueOf(revision));
1546
		} catch (NumberFormatException e) {
1547
			throw new SAXException(e.getMessage(), e);
1548
		} catch (McdbDocNotFoundException e) {
1549
			// register the default mapping now
1550
			guid = docid + "." + revision;
1551
			IdentifierManager.getInstance().createMapping(guid, guid);
1552
		}
1553
1554 4678 daigle
		String permOrder = accessSection.getPermissionOrder();
1555 6019 leinfelder
		String sql = null;
1556
		PreparedStatement pstmt = null;
1557 4678 daigle
		if (topLevel) {
1558 6744 leinfelder
			sql = "INSERT INTO xml_access (guid, principal_name, permission, "
1559 6019 leinfelder
					+ "perm_type, perm_order, accessfileid) VALUES "
1560
					+ " (?, ?, ?, ?, ?, ?)";
1561 4678 daigle
		} else {
1562 6744 leinfelder
			sql = "INSERT INTO xml_access (guid,principal_name, "
1563 6019 leinfelder
					+ "permission, perm_type, perm_order, accessfileid, subtreeid"
1564
					+ ") VALUES" + " (?, ?, ?, ?, ?, ?, ?)";
1565 4678 daigle
		}
1566
		try {
1567 2169 sgarg
1568 6019 leinfelder
			pstmt = connection.prepareStatement(sql);
1569
			// Increase DBConnection usage count
1570
			connection.increaseUsageCount(1);
1571
			// Bind the values to the query
1572 6744 leinfelder
			pstmt.setString(6, guid);
1573
			logMetacat.debug("Accessfileid in accesstable: " + guid);
1574 6019 leinfelder
			pstmt.setString(5, permOrder);
1575
			logMetacat.debug("PermOder in accesstable: " + permOrder);
1576
			// if it is not top level, set subsection id
1577
			if (topLevel) {
1578 6744 leinfelder
				pstmt.setString(1, guid);
1579
				logMetacat.debug("Guid in accesstable: " + guid);
1580 6019 leinfelder
			}
1581
			if (!topLevel) {
1582 6802 leinfelder
				// use the referenced guid
1583
				pstmt.setString(1, referencedGuid );
1584 6019 leinfelder
				logMetacat.debug("Docid in accesstable: " + inlineDataFileName);
1585
1586
				// for subtree should specify the
1587
				if (subSectionId == null) {
1588
					throw new SAXException("The subsection is null");
1589
				}
1590
1591
				pstmt.setString(7, subSectionId);
1592
				logMetacat.debug("SubSectionId in accesstable: " + subSectionId);
1593
			}
1594
1595 4678 daigle
			Vector<AccessRule> accessRules = accessSection.getAccessRules();
1596
			// go through every rule
1597
			for (int i = 0; i < accessRules.size(); i++) {
1598
				AccessRule rule = accessRules.elementAt(i);
1599
				String permType = rule.getPermissionType();
1600
				int permission = rule.getPermission();
1601 6019 leinfelder
				pstmt.setInt(3, permission);
1602 4678 daigle
				logMetacat.debug("permission in accesstable: " + permission);
1603 6019 leinfelder
				pstmt.setString(4, permType);
1604 4678 daigle
				logMetacat.debug("Permtype in accesstable: " + permType);
1605
				// go through every principle in rule
1606
				Vector<String> nameVector = rule.getPrincipal();
1607
				for (int j = 0; j < nameVector.size(); j++) {
1608
					String prName = nameVector.elementAt(j);
1609 6019 leinfelder
					pstmt.setString(2, prName);
1610 4678 daigle
					logMetacat.debug("Principal in accesstable: " + prName);
1611 6019 leinfelder
					logMetacat.debug("running sql: " + pstmt.toString());
1612
					pstmt.execute();
1613 4678 daigle
				}// for
1614
			}// for
1615 6019 leinfelder
			pstmt.close();
1616 4678 daigle
		}// try
1617 6019 leinfelder
		catch (SQLException e) {
1618 4678 daigle
			throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
1619
					+ e.getMessage());
1620
		}// catch
1621 6019 leinfelder
		finally {
1622
			try {
1623
				pstmt.close();
1624
			} catch (SQLException ee) {
1625
				throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
1626
						+ ee.getMessage());
1627
			}
1628
		}// finally
1629 6802 leinfelder
1630
		// for D1, refresh the entries
1631
		HazelcastService.getInstance().refreshSystemMetadataEntry(guid);
1632
		HazelcastService.getInstance().refreshSystemMetadataEntry(referencedGuid);
1633
1634 2169 sgarg
1635 4678 daigle
	}// writeGivenAccessRuleIntoDB
1636 2169 sgarg
1637 6744 leinfelder
	/* Delete from db all permission for resources related to the document, if any */
1638
	private void deletePermissionsInAccessTable() throws SAXException {
1639 6606 leinfelder
		PreparedStatement pstmt = null;
1640 4678 daigle
		try {
1641 6749 leinfelder
1642 6744 leinfelder
			String sql = "DELETE FROM xml_access " +
1643 6749 leinfelder
					// the file defines access for another file
1644
					"WHERE accessfileid IN " +
1645
						"(SELECT guid from identifier where docid = ? and rev = ?) " +
1646
					// the described file has other versions describing it
1647
					"OR guid IN " +
1648
						"(SELECT xa.guid from xml_access xa, identifier id" +
1649
						" WHERE xa.accessfileid = id.guid " +
1650
						" AND id.docid = ?" +
1651
						" AND id.rev = ?)";
1652 4678 daigle
			// delete all acl records for resources related to @aclid if any
1653 6606 leinfelder
			pstmt = connection.prepareStatement(sql);
1654 6744 leinfelder
			pstmt.setString(1, docid);
1655
			pstmt.setInt(2, Integer.valueOf(revision));
1656 6749 leinfelder
			// second part of query
1657
			pstmt.setString(3, docid);
1658
			pstmt.setInt(4, Integer.valueOf(revision));
1659 4678 daigle
			// Increase DBConnection usage count
1660
			connection.increaseUsageCount(1);
1661 6606 leinfelder
			logMetacat.debug("running sql: " + sql);
1662
			pstmt.execute();
1663 4678 daigle
1664
		} catch (SQLException e) {
1665
			throw new SAXException(e.getMessage());
1666
		} finally {
1667
			try {
1668 6606 leinfelder
				pstmt.close();
1669 4678 daigle
			} catch (SQLException ee) {
1670
				throw new SAXException(ee.getMessage());
1671
			}
1672
		}
1673
	}// deletePermissionsInAccessTable
1674
1675
	/*
1676
	 * In order to make sure only usr has "all" permission can update access
1677
	 * subtree in eml document we need to keep access subtree info in
1678
	 * xml_accesssubtree table, such as docid, version, startnodeid, endnodeid
1679
	 */
1680
	private void writeAccessSubTreeIntoDB(AccessSection accessSection, String level)
1681
			throws SAXException {
1682
		if (accessSection == null) {
1683
			throw new SAXException("The access object is null");
1684
		}
1685
1686
		String sql = null;
1687
		PreparedStatement pstmt = null;
1688
		sql = "INSERT INTO xml_accesssubtree (docid, rev, controllevel, "
1689
				+ "subtreeid, startnodeid, endnodeid) VALUES " + " (?, ?, ?, ?, ?, ?)";
1690
		try {
1691
1692
			pstmt = connection.prepareStatement(sql);
1693
			// Increase DBConnection usage count
1694
			connection.increaseUsageCount(1);
1695
			long startNodeId = accessSection.getStartNodeId();
1696
			long endNodeId = accessSection.getEndNodeId();
1697
			String sectionId = accessSection.getSubTreeId();
1698
			// Bind the values to the query
1699
			pstmt.setString(1, docid);
1700
			logMetacat.debug("Docid in access-subtreetable: " + docid);
1701
			pstmt.setLong(2, (new Long(revision)).longValue());
1702
			logMetacat.debug("rev in accesssubtreetable: " + revision);
1703
			pstmt.setString(3, level);
1704
			logMetacat.debug("contorl level in access-subtree table: " + level);
1705
			pstmt.setString(4, sectionId);
1706
			logMetacat.debug("Subtree id in access-subtree table: " + sectionId);
1707
			pstmt.setLong(5, startNodeId);
1708
			logMetacat.debug("Start node id is: " + startNodeId);
1709
			pstmt.setLong(6, endNodeId);
1710
			logMetacat.debug("End node id is: " + endNodeId);
1711
			logMetacat.debug("running sql: " + pstmt.toString());
1712
			pstmt.execute();
1713
			pstmt.close();
1714
		}// try
1715
		catch (SQLException e) {
1716
			throw new SAXException("EMLSAXHandler.writeAccessSubTreeIntoDB(): "
1717
					+ e.getMessage());
1718
		}// catch
1719
		finally {
1720
			try {
1721
				pstmt.close();
1722
			} catch (SQLException ee) {
1723
				throw new SAXException("EMLSAXHandler.writeAccessSubTreeIntoDB(): "
1724
						+ ee.getMessage());
1725
			}
1726
		}// finally
1727
1728
	}// writeAccessSubtreeIntoDB
1729
1730
	/* Delete every access subtree record from xml_accesssubtree. */
1731
	private void deleteAccessSubTreeRecord(String docId) throws SAXException {
1732 6606 leinfelder
		PreparedStatement pstmt = null;
1733 4678 daigle
		try {
1734 6606 leinfelder
			String sql = "DELETE FROM xml_accesssubtree WHERE docid = ?";
1735 4678 daigle
			// delete all acl records for resources related to @aclid if any
1736 6606 leinfelder
			pstmt = connection.prepareStatement(sql);
1737
			pstmt.setString(1, docId);
1738 4678 daigle
			// Increase DBConnection usage count
1739
			connection.increaseUsageCount(1);
1740 6606 leinfelder
			logMetacat.debug("running sql: " + sql);
1741
			pstmt.execute();
1742 4678 daigle
1743
		} catch (SQLException e) {
1744
			throw new SAXException(e.getMessage());
1745
		} finally {
1746
			try {
1747 6606 leinfelder
				pstmt.close();
1748 4678 daigle
			} catch (SQLException ee) {
1749
				throw new SAXException(ee.getMessage());
1750
			}
1751
		}
1752
	}// deleteAccessSubTreeRecord
1753
1754
	// open a file writer for writing inline data to file
1755 5752 leinfelder
	private Writer createInlineDataFileWriter(String fileName, String encoding) throws SAXException {
1756
		Writer writer = null;
1757 4678 daigle
		String path;
1758
		try {
1759
			path = PropertyService.getProperty("application.inlinedatafilepath");
1760
		} catch (PropertyNotFoundException pnfe) {
1761
			throw new SAXException(pnfe.getMessage());
1762
		}
1763
		/*
1764
		 * File inlineDataDirectory = new File(path);
1765
		 */
1766
		String newFile = path + "/" + fileName;
1767
		logMetacat.debug("inline file name: " + newFile);
1768
		try {
1769
			// true means append
1770 5752 leinfelder
			writer = new OutputStreamWriter(new FileOutputStream(newFile, true), encoding);
1771 4678 daigle
		} catch (IOException ioe) {
1772
			throw new SAXException(ioe.getMessage());
1773
		}
1774
		return writer;
1775
	}
1776
1777
	// write inline data into file system and return file name(without path)
1778 5752 leinfelder
	private void writeInlineDataIntoFile(Writer writer, StringBuffer data)
1779 4678 daigle
			throws SAXException {
1780
		try {
1781
			writer.write(data.toString());
1782
			writer.flush();
1783
		} catch (Exception e) {
1784
			throw new SAXException(e.getMessage());
1785
		}
1786
	}
1787
1788 4080 daigle
1789 2169 sgarg
1790 4678 daigle
	// if xml file failed to upload, we need to call this method to delete
1791
	// the inline data already in file system
1792
	public void deleteInlineFiles() throws SAXException {
1793
		if (!inlineFileIdList.isEmpty()) {
1794
			for (int i = 0; i < inlineFileIdList.size(); i++) {
1795
				String fileName = inlineFileIdList.elementAt(i);
1796
				deleteInlineDataFile(fileName);
1797
			}
1798
		}
1799
	}
1800 2169 sgarg
1801 4678 daigle
	/* delete the inline data file */
1802
	private void deleteInlineDataFile(String fileName) throws SAXException {
1803
		String path;
1804
		try {
1805
			path = PropertyService.getProperty("application.inlinedatafilepath");
1806
		} catch (PropertyNotFoundException pnfe) {
1807
			throw new SAXException("Could not find inline data file path: "
1808
					+ pnfe.getMessage());
1809
		}
1810
		File inlineDataDirectory = new File(path);
1811
		File newFile = new File(inlineDataDirectory, fileName);
1812
		newFile.delete();
1813 2169 sgarg
1814 4678 daigle
	}
1815 2169 sgarg
1816 4678 daigle
	/* Delete relations */
1817
	private void deleteRelations() throws SAXException {
1818
		PreparedStatement pStmt = null;
1819
		String sql = "DELETE FROM xml_relation where docid =?";
1820
		try {
1821
			pStmt = connection.prepareStatement(sql);
1822
			// bind variable
1823
			pStmt.setString(1, docid);
1824
			// execute query
1825
			pStmt.execute();
1826
			pStmt.close();
1827
		}// try
1828
		catch (SQLException e) {
1829
			throw new SAXException("EMLSAXHandler.deleteRelations(): " + e.getMessage());
1830
		}// catch
1831
		finally {
1832
			try {
1833
				pStmt.close();
1834
			}// try
1835
			catch (SQLException ee) {
1836
				throw new SAXException("EMLSAXHandler.deleteRelations: "
1837
						+ ee.getMessage());
1838
			}// catch
1839
		}// finally
1840
	}
1841 2169 sgarg
1842 4678 daigle
	/*
1843
	 * Write an online data file id into xml_relation table. The dataId
1844
	 * shouldnot have the revision
1845
	 */
1846
	private void writeOnlineDataFileIdIntoRelationTable(String dataId)
1847
			throws SAXException {
1848
		PreparedStatement pStmt = null;
1849
		String sql = "INSERT into xml_relation (docid, packagetype, subject, "
1850
				+ "relationship, object) values (?, ?, ?, ?, ?)";
1851
		try {
1852
			pStmt = connection.prepareStatement(sql);
1853
			// bind variable
1854
			pStmt.setString(1, docid);
1855 5709 leinfelder
			pStmt.setString(2, doctype); //DocumentImpl.EML2_1_0NAMESPACE);
1856 4678 daigle
			pStmt.setString(3, docid);
1857
			pStmt.setString(4, RELATION);
1858
			pStmt.setString(5, dataId);
1859
			// execute query
1860
			pStmt.execute();
1861
			pStmt.close();
1862
		}// try
1863
		catch (SQLException e) {
1864
			throw new SAXException(
1865
					"EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): "
1866
							+ e.getMessage());
1867
		}// catch
1868
		finally {
1869
			try {
1870
				pStmt.close();
1871
			}// try
1872
			catch (SQLException ee) {
1873
				throw new SAXException(
1874
						"EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): "
1875
								+ ee.getMessage());
1876
			}// catch
1877
		}// finally
1878 2169 sgarg
1879 4678 daigle
	}// writeOnlineDataFileIdIntoRelationTable
1880 2169 sgarg
1881 4678 daigle
	/*
1882
	 * This method will handle data file in online url. If the data file is in
1883
	 * ecogrid protocol, then the datafile identifier(without rev)should be put
1884
	 * into onlineDataFileRelationVector. The docid in this vector will be
1885
	 * insert into xml_relation table in endDocument(). If the data file doesn't
1886
	 * exsit in xml_documents or xml_revision table, or the user has all
1887
	 * permission to the data file if the docid already existed, the data file
1888
	 * id (without rev)will be put into onlineDataFileTopAccessVector. The top
1889
	 * access rules specified in this eml document will apply to the data file.
1890
	 * NEED to do: We should also need to implement http and ftp. Those external
1891
	 * files should be download and assign a data file id to it.
1892
	 */
1893
	private void handleOnlineUrlDataFile(String url) throws SAXException {
1894
		logMetacat.warn("The url is " + url);
1895 2169 sgarg
1896 4678 daigle
		if (currentDistributionSection == null) {
1897
			throw new SAXException("Trying to set the online file name for a null"
1898
					+ " distribution section");
1899
		}
1900
1901
		// if the url is not in ecogrid protocol, null will be returned
1902 5025 daigle
		String accessionNumber = DocumentUtil.getAccessionNumberFromEcogridIdentifier(url);
1903 7112 leinfelder
1904
		// check he accession number and get docid.rev if we can
1905
		String docid = null;
1906
		int rev = 0;
1907
		if (accessionNumber != null) {
1908
			// get rid of revision number to get the docid.
1909
			try {
1910
				docid = DocumentUtil.getDocIdFromAccessionNumber(accessionNumber);
1911
				rev = DocumentUtil.getRevisionFromAccessionNumber(accessionNumber);
1912
			} catch (Exception e) {
1913
				logMetacat.warn(e.getClass().getName() + " - Problem parsing accession number for: " + accessionNumber + ". Message: " + e.getMessage());
1914
				accessionNumber = null;
1915
			}
1916
		}
1917
1918 4678 daigle
		if (accessionNumber == null) {
1919
			// the accession number is null if the url does not references a
1920
			// local data file (url would start with "ecogrid://"
1921
			currentDistributionSection
1922
					.setDistributionType(DistributionSection.ONLINE_DATA_DISTRIBUTION);
1923
		} else {
1924 7112 leinfelder
			// look up the guid using docid/rev
1925 6744 leinfelder
			String guid = null;
1926
			try {
1927
				guid = IdentifierManager.getInstance().getGUID(docid, rev);
1928
			} catch (McdbDocNotFoundException e1) {
1929 7135 leinfelder
				// no need to do this if we are not writing access rules for the data
1930
				if (!writeAccessRules) {
1931
					logMetacat.warn("Not configured to write access rules for data referenced by: " + url);
1932
					return;
1933
				}
1934 6744 leinfelder
				guid = docid + "." + rev;
1935
				IdentifierManager.getInstance().createMapping(guid, guid);
1936
			}
1937 4678 daigle
1938
			currentDistributionSection
1939
					.setDistributionType(DistributionSection.DATA_DISTRIBUTION);
1940 6744 leinfelder
			currentDistributionSection.setDataFileName(guid);
1941 4678 daigle
1942
			// distributionOnlineFileName = docid;
1943 6746 leinfelder
			onlineDataFileIdInRelationVector.add(guid);
1944 4733 daigle
			try {
1945 4678 daigle
				if (!AccessionNumber.accNumberUsed(docid)) {
1946 6746 leinfelder
					onlineDataFileIdInTopAccessVector.add(guid);
1947 4678 daigle
				} else {
1948 6746 leinfelder
					// check the previous revision if we have it
1949
					int previousRevision = rev;
1950
					Vector<Integer> revisions = DBUtil.getRevListFromRevisionTable(docid);
1951
					if (revisions != null && revisions.size() > 0) {
1952
						previousRevision = revisions.get(revisions.size() - 1);
1953
					}
1954
					String previousDocid =
1955
						docid + PropertyService.getProperty("document.accNumSeparator") + previousRevision;
1956
1957
					PermissionController controller = new PermissionController(previousDocid);
1958 4733 daigle
					if (controller.hasPermission(user, groups,AccessControlInterface.ALLSTRING)) {
1959 6746 leinfelder
						onlineDataFileIdInTopAccessVector.add(guid);
1960 4733 daigle
					} else {
1961
						throw new SAXException(UPDATEACCESSERROR);
1962
					}
1963
				}
1964 4678 daigle
			}// try
1965
			catch (Exception e) {
1966
				logMetacat.error("Eorr in "
1967
								+ "Eml210SAXHanlder.handleOnlineUrlDataFile is "
1968
								+ e.getMessage());
1969
				throw new SAXException(e.getMessage());
1970
			}
1971
		}
1972
	}
1973 2169 sgarg
}