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