Project

General

Profile

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

    
28
package edu.ucsb.nceas.metacat;
29

    
30
import java.io.File;
31
import java.io.FileOutputStream;
32
import java.io.IOException;
33
import java.io.OutputStreamWriter;
34
import java.io.Writer;
35
import java.sql.PreparedStatement;
36
import java.sql.ResultSet;
37
import java.sql.SQLException;
38
import java.sql.Statement;
39
import java.util.EmptyStackException;
40
import java.util.Enumeration;
41
import java.util.Hashtable;
42
import java.util.Stack;
43
import java.util.Vector;
44

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

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

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

    
67
	private boolean processingTopLevelAccess = false;
68

    
69
	private boolean processingAdditionalAccess = false;
70

    
71
	private boolean processingOtherAccess = false;
72

    
73
	private AccessSection accessObject = null;
74

    
75
	private AccessRule accessRule = null;
76

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

    
80
	private Hashtable<String, AccessSection> topLevelAccessControlMap = new Hashtable<String, AccessSection>();
81

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

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

    
97
	private Vector<AccessSection> unChangeableAccessSubTreeVector = new Vector<AccessSection>();
98

    
99
	private Stack<NodeRecord> currentUnchangeableAccessModuleNodeStack = new Stack<NodeRecord>();
100

    
101
	private AccessSection topAccessSection;
102

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

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

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

    
114
	// Indicator of inline data
115
	private boolean handleInlineData = false;
116

    
117
	private Hashtable<String, String> inlineDataNameSpace = null;
118

    
119
	private Writer inlineDataFileWriter = null;
120

    
121
	private String inlineDataFileName = null;
122

    
123
	DistributionSection currentDistributionSection = null;
124

    
125
	Vector<DistributionSection> allDistributionSections = new Vector<DistributionSection>();
126

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

    
133
	// private String distributionOnlineFileName = null;
134

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

    
138
	// Constant
139
	private static final String EML = "eml";
140

    
141
	private static final String DISTRIBUTION = "distribution";
142

    
143
	private static final String ORDER = "order";
144

    
145
	private static final String ID = "id";
146

    
147
	private static final String REFERENCES = "references";
148

    
149
	public static final String INLINE = "inline";
150

    
151
	private static final String ONLINE = "online";
152

    
153
	private static final String URL = "url";
154

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

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

    
162
	private static final String TOPLEVEL = "top";
163

    
164
	private static final String SUBTREELEVEL = "subtree";
165

    
166
	private static final String RELATION = "Provides info for";
167

    
168
	private Logger logMetacat = Logger.getLogger(Eml210SAXHandler.class);
169

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

    
203
			// If the action is update and user doesn't have "ALL" permission
204
			// we need to check if user can update access subtree			
205
			if (!control.hasPermission(user, groups, AccessControlInterface.ALLSTRING)
206
					&& action != null && action.equals("UPDATE")) {
207
				needToCheckAccessModule = true;
208
				unChangeableAccessSubTreeVector = getAccessSubTreeListFromDB();
209
			}
210

    
211
		} catch (Exception e) {
212
			throw new SAXException(e.getMessage());
213
		}
214
	}
215

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

    
227
		try {
228

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

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

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

    
286
		DBSAXNode parentNode = null;
287
		DBSAXNode currentNode = null;
288

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

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

    
322
			}
323

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

    
328
				// compare top level access module
329
				if (processingTopLevelAccess && needToCheckAccessModule) {
330
					compareAccessTextNode(currentUnchangeableAccessModuleNodeStack, textBuffer);
331
				}
332

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

    
340
				}
341

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

    
350
			}
351

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

    
384
					try {
385
						// Get dbconnection
386
						dbConn = DBConnectionPool
387
								.getDBConnection("DBSAXHandler.startElement");
388
						serialNumber = dbConn.getCheckOutSerialNumber();
389

    
390
						Statement stmt = dbConn.createStatement();
391
						ResultSet rs = stmt
392
								.executeQuery("SELECT catalog_id FROM xml_catalog "
393
										+ "WHERE entry_type = 'Schema' "
394
										+ "AND public_id = '" + doctype + "'");
395
						boolean hasRow = rs.next();
396
						if (hasRow) {
397
							catalogid = rs.getString(1);
398
						}
399
						stmt.close();
400
					}// try
401
					finally {
402
						// Return dbconnection
403
						DBConnectionPool.returnDBConnection(dbConn, serialNumber);
404
					}// finally
405

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

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

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

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

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

    
469
				} else if (attributeName != null && attributeName.equals(ID)) {
470

    
471
				}
472
			}// for
473

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

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

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

    
526
				accessRule = new AccessRule();
527

    
528
				// set permission type "allow"
529
				accessRule.setPermissionType(ALLOW);
530

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

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

    
546
			// compare top access level module
547
			if (processingTopLevelAccess && needToCheckAccessModule) {
548
				compareElementNameSpaceAttributes(
549
						currentUnchangeableAccessModuleNodeStack, namespaces, atts,
550
						localName, UPDATEACCESSERROR);
551

    
552
			}
553

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

    
569
			}
570

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

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

    
615
	}
616

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

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

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

    
679
		}// while
680

    
681
		// compare attributes
682
		for (int i = 0; i < attributes.getLength(); i++) {
683
			NodeRecord attriNode = null;
684
			try {
685
				attriNode = unchangeableNodeStack.pop();
686

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

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

    
716
	}
717

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

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

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

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

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

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

    
805
		if (!handleInlineData) {
806
			// Get the node from the stack
807
			DBSAXNode currentNode = (DBSAXNode) nodeStack.pop();
808
			String currentTag = currentNode.getTagName();
809

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

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

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

    
854
					}// if
855
				}// else if
856
				
857
				// write text to db if it is not inline data
858
				logMetacat.debug("Write text into DB in End Element");
859

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

    
876
			}
877

    
878
			// set hitText false
879
			hitTextNode = false;
880
			// reset textbuff
881
			textBuffer = null;
882
			textBuffer = new StringBuffer();
883

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

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

    
911
				accessObject.setEndNodeId(endNodeId);
912

    
913
				if (parentNode != null && parentNode.getTagName() != null
914
						&& parentNode.getTagName().equals(DISTRIBUTION)) {
915
					describesId.add(String.valueOf(distributionIndex));
916
					currentDistributionSection.setAccessSection(accessObject);
917
				}
918

    
919
				AccessSection newAccessObject = accessObject;
920

    
921
				if (newAccessObject != null) {
922

    
923
					// add the accessSection into a vector to store it
924
					// if it is not a reference, need to store it
925
					if (newAccessObject.getReferences() == null) {
926

    
927
						newAccessObject.setStoredTmpNodeStack(storedAccessNodeStack);
928
						accessObjectList.add(newAccessObject);
929
					}
930
					if (processingTopLevelAccess) {
931

    
932
						// top level access control will handle whole document
933
						// -docid
934
						topLevelAccessControlMap.put(docid, newAccessObject);
935
						// reset processtopleveraccess tag
936

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

    
944
							String subId = describesId.elementAt(i);
945
							if (subId != null) {
946
								additionalAccessControlMap.put(subId, newAccessObject);
947
							}// if
948
						}// for
949
						// add this hashtable in to vector
950

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

    
959
				}// if
960
				// check if access node stack is empty after parsing top access
961
				// module
962

    
963
				if (needToCheckAccessModule && processingTopLevelAccess
964
						&& !currentUnchangeableAccessModuleNodeStack.isEmpty()) {
965

    
966
					logMetacat.error("Access node stack is not empty after "
967
							+ "parsing access subtree");
968
					throw new SAXException(UPDATEACCESSERROR);
969

    
970
				}
971
				// reset access section object
972

    
973
				accessObject = null;
974

    
975
				// reset tmp stored node stack
976
				storedAccessNodeStack = null;
977
				storedAccessNodeStack = new Stack<NodeRecord>();
978

    
979
				// reset flag
980
				processingAdditionalAccess = false;
981
				processingTopLevelAccess = false;
982
				processingOtherAccess = false;
983

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

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

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

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

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

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

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

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

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

    
1148
	}
1149

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

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

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

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

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

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

    
1228
			} else {
1229

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

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

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

    
1296
		}// if
1297
		else {
1298
			// couldn't find a access section object
1299
			logMetacat.warn("couldn't find access control for document: " + docid);
1300
		}
1301

    
1302
	}// writeTopLevelAccessRuletoDB
1303

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

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

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

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

    
1378
				if (distributionType == DistributionSection.DATA_DISTRIBUTION) {
1379
					try {
1380
						PermissionController controller = new PermissionController(
1381
								distributionSection.getDataFileName(), false);
1382
						if (AccessionNumber.accNumberUsed(docid)
1383
								&& !controller.hasPermission(user, groups, "WRITE")) {
1384
							throw new SAXException(UPDATEACCESSERROR);
1385
						}
1386
					} catch (SQLException sqle) {
1387
						throw new SAXException(
1388
								"Database error checking user permissions: "
1389
										+ sqle.getMessage());
1390
					} catch (Exception e) {
1391
						throw new SAXException(
1392
								"General error checking user permissions: "
1393
										+ e.getMessage());
1394
					}
1395
				} else if (distributionType == DistributionSection.INLINE_DATA_DISTRIBUTION && action == "UPDATE") {
1396
					try {
1397
						PermissionController controller = new PermissionController(
1398
								docid, false);
1399

    
1400
						if (!controller.hasPermission(user, groups, "WRITE")) {
1401
							throw new SAXException(UPDATEACCESSERROR);
1402
						}
1403
					} catch (SQLException sqle) {
1404
						throw new SAXException(
1405
								"Database error checking user permissions: "
1406
										+ sqle.getMessage());
1407
					} catch (Exception e) {
1408
						throw new SAXException(
1409
								"General error checking user permissions: "
1410
										+ e.getMessage());
1411
					}
1412
				}
1413
				
1414
				String subSectionId = Integer.toString(distributionSection.getDistributionId());
1415
				writeGivenAccessRuleIntoDB(accessSection, false, subSectionId);
1416
			}
1417

    
1418
		}
1419
		
1420
		
1421
	}
1422

    
1423
	/* Write a given access rule into db */
1424
	private void writeGivenAccessRuleIntoDB(AccessSection accessSection,
1425
			boolean topLevel, String subSectionId) throws SAXException {
1426
		if (accessSection == null) {
1427
			throw new SAXException("The access object is null");
1428
		}
1429

    
1430
		String currentDocId = null;
1431
		String accessFileId = docid;
1432
		String permOrder = accessSection.getPermissionOrder();
1433
		if (topLevel) {
1434
			currentDocId = docid;
1435
		} else {
1436
			currentDocId = accessSection.getDataFileName();
1437
			// for subtree should specify the
1438
			if (subSectionId == null) {
1439
				throw new SAXException("The subsection is null");
1440
			}
1441
		}
1442
		try {
1443

    
1444
			AccessControlForSingleFile acfsf = new AccessControlForSingleFile(currentDocId);
1445
			Vector<AccessRule> accessRules = accessSection.getAccessRules();
1446
			// go through every rule
1447
			for (int i = 0; i < accessRules.size(); i++) {
1448
				AccessRule rule = accessRules.elementAt(i);
1449
				String permType = rule.getPermissionType();
1450
				int permission = rule.getPermission();
1451
				logMetacat.debug("permission in accesstable: " + permission);
1452
				logMetacat.debug("Permtype in accesstable: " + permType);
1453
				// go through every principle in rule
1454
				Vector<String> nameVector = rule.getPrincipal();
1455
				for (int j = 0; j < nameVector.size(); j++) {
1456
					String prName = nameVector.elementAt(j);
1457
					logMetacat.debug("Principal in accesstable: " + prName);
1458
					XMLAccessDAO dao = new XMLAccessDAO();
1459
					dao.setAccessFileId(accessFileId);
1460
					dao.setDocId(currentDocId);
1461
					dao.setPermission(new Long(permission));
1462
					dao.setPermOrder(permOrder);
1463
					dao.setPermType(permType);
1464
					dao.setPrincipalName(prName);
1465
					dao.setSubTreeId(subSectionId);
1466
					// insert if it does not exist
1467
					if (!acfsf.accessControlExists(dao)) {
1468
						acfsf.insertPermissions(dao);
1469
					}
1470
					
1471
				}// for
1472
			}// for
1473
		}// try
1474
		catch (Exception e) {
1475
			throw new SAXException("EMLSAXHandler.writeAccessRuletoDB(): "
1476
					+ e.getMessage());
1477
		}// catch
1478

    
1479
	}// writeGivenAccessRuleIntoDB
1480

    
1481
	/* Delete from db all permission for resources related to @aclid if any. */
1482
	private void deletePermissionsInAccessTable(String aclid) throws SAXException {
1483
		Statement stmt = null;
1484
		try {
1485
			// delete all acl records for resources related to @aclid if any
1486
			stmt = connection.createStatement();
1487
			// Increase DBConnection usage count
1488
			connection.increaseUsageCount(1);
1489
			logMetacat.debug("running sql: DELETE FROM xml_access WHERE accessfileid = '"
1490
					+ aclid + "'");
1491
			stmt.execute("DELETE FROM xml_access WHERE accessfileid = '" + aclid + "'");
1492

    
1493
		} catch (SQLException e) {
1494
			throw new SAXException(e.getMessage());
1495
		} finally {
1496
			try {
1497
				stmt.close();
1498
			} catch (SQLException ee) {
1499
				throw new SAXException(ee.getMessage());
1500
			}
1501
		}
1502
	}// deletePermissionsInAccessTable
1503

    
1504
	/*
1505
	 * In order to make sure only usr has "all" permission can update access
1506
	 * subtree in eml document we need to keep access subtree info in
1507
	 * xml_accesssubtree table, such as docid, version, startnodeid, endnodeid
1508
	 */
1509
	private void writeAccessSubTreeIntoDB(AccessSection accessSection, String level)
1510
			throws SAXException {
1511
		if (accessSection == null) {
1512
			throw new SAXException("The access object is null");
1513
		}
1514

    
1515
		String sql = null;
1516
		PreparedStatement pstmt = null;
1517
		sql = "INSERT INTO xml_accesssubtree (docid, rev, controllevel, "
1518
				+ "subtreeid, startnodeid, endnodeid) VALUES " + " (?, ?, ?, ?, ?, ?)";
1519
		try {
1520

    
1521
			pstmt = connection.prepareStatement(sql);
1522
			// Increase DBConnection usage count
1523
			connection.increaseUsageCount(1);
1524
			long startNodeId = accessSection.getStartNodeId();
1525
			long endNodeId = accessSection.getEndNodeId();
1526
			String sectionId = accessSection.getSubTreeId();
1527
			// Bind the values to the query
1528
			pstmt.setString(1, docid);
1529
			logMetacat.debug("Docid in access-subtreetable: " + docid);
1530
			pstmt.setLong(2, (new Long(revision)).longValue());
1531
			logMetacat.debug("rev in accesssubtreetable: " + revision);
1532
			pstmt.setString(3, level);
1533
			logMetacat.debug("contorl level in access-subtree table: " + level);
1534
			pstmt.setString(4, sectionId);
1535
			logMetacat.debug("Subtree id in access-subtree table: " + sectionId);
1536
			pstmt.setLong(5, startNodeId);
1537
			logMetacat.debug("Start node id is: " + startNodeId);
1538
			pstmt.setLong(6, endNodeId);
1539
			logMetacat.debug("End node id is: " + endNodeId);
1540
			logMetacat.debug("running sql: " + pstmt.toString());
1541
			pstmt.execute();
1542
			pstmt.close();
1543
		}// try
1544
		catch (SQLException e) {
1545
			throw new SAXException("EMLSAXHandler.writeAccessSubTreeIntoDB(): "
1546
					+ e.getMessage());
1547
		}// catch
1548
		finally {
1549
			try {
1550
				pstmt.close();
1551
			} catch (SQLException ee) {
1552
				throw new SAXException("EMLSAXHandler.writeAccessSubTreeIntoDB(): "
1553
						+ ee.getMessage());
1554
			}
1555
		}// finally
1556

    
1557
	}// writeAccessSubtreeIntoDB
1558

    
1559
	/* Delete every access subtree record from xml_accesssubtree. */
1560
	private void deleteAccessSubTreeRecord(String docId) throws SAXException {
1561
		Statement stmt = null;
1562
		try {
1563
			// delete all acl records for resources related to @aclid if any
1564
			stmt = connection.createStatement();
1565
			// Increase DBConnection usage count
1566
			connection.increaseUsageCount(1);
1567
			logMetacat.debug("running sql: DELETE FROM xml_accesssubtree WHERE docid = '"
1568
					+ docId + "'");
1569
			stmt.execute("DELETE FROM xml_accesssubtree WHERE docid = '" + docId + "'");
1570

    
1571
		} catch (SQLException e) {
1572
			throw new SAXException(e.getMessage());
1573
		} finally {
1574
			try {
1575
				stmt.close();
1576
			} catch (SQLException ee) {
1577
				throw new SAXException(ee.getMessage());
1578
			}
1579
		}
1580
	}// deleteAccessSubTreeRecord
1581

    
1582
	// open a file writer for writing inline data to file
1583
	private Writer createInlineDataFileWriter(String fileName, String encoding) throws SAXException {
1584
		Writer writer = null;
1585
		String path;
1586
		try {
1587
			path = PropertyService.getProperty("application.inlinedatafilepath");
1588
		} catch (PropertyNotFoundException pnfe) {
1589
			throw new SAXException(pnfe.getMessage());
1590
		}
1591
		/*
1592
		 * File inlineDataDirectory = new File(path);
1593
		 */
1594
		String newFile = path + "/" + fileName;
1595
		logMetacat.debug("inline file name: " + newFile);
1596
		try {
1597
			// true means append
1598
			writer = new OutputStreamWriter(new FileOutputStream(newFile, true), encoding);
1599
		} catch (IOException ioe) {
1600
			throw new SAXException(ioe.getMessage());
1601
		}
1602
		return writer;
1603
	}
1604

    
1605
	// write inline data into file system and return file name(without path)
1606
	private void writeInlineDataIntoFile(Writer writer, StringBuffer data)
1607
			throws SAXException {
1608
		try {
1609
			writer.write(data.toString());
1610
			writer.flush();
1611
		} catch (Exception e) {
1612
			throw new SAXException(e.getMessage());
1613
		}
1614
	}
1615

    
1616

    
1617

    
1618
	// if xml file failed to upload, we need to call this method to delete
1619
	// the inline data already in file system
1620
	public void deleteInlineFiles() throws SAXException {
1621
		if (!inlineFileIdList.isEmpty()) {
1622
			for (int i = 0; i < inlineFileIdList.size(); i++) {
1623
				String fileName = inlineFileIdList.elementAt(i);
1624
				deleteInlineDataFile(fileName);
1625
			}
1626
		}
1627
	}
1628

    
1629
	/* delete the inline data file */
1630
	private void deleteInlineDataFile(String fileName) throws SAXException {
1631
		String path;
1632
		try {
1633
			path = PropertyService.getProperty("application.inlinedatafilepath");
1634
		} catch (PropertyNotFoundException pnfe) {
1635
			throw new SAXException("Could not find inline data file path: "
1636
					+ pnfe.getMessage());
1637
		}
1638
		File inlineDataDirectory = new File(path);
1639
		File newFile = new File(inlineDataDirectory, fileName);
1640
		newFile.delete();
1641

    
1642
	}
1643

    
1644
	/* Delete relations */
1645
	private void deleteRelations() throws SAXException {
1646
		PreparedStatement pStmt = null;
1647
		String sql = "DELETE FROM xml_relation where docid =?";
1648
		try {
1649
			pStmt = connection.prepareStatement(sql);
1650
			// bind variable
1651
			pStmt.setString(1, docid);
1652
			// execute query
1653
			pStmt.execute();
1654
			pStmt.close();
1655
		}// try
1656
		catch (SQLException e) {
1657
			throw new SAXException("EMLSAXHandler.deleteRelations(): " + e.getMessage());
1658
		}// catch
1659
		finally {
1660
			try {
1661
				pStmt.close();
1662
			}// try
1663
			catch (SQLException ee) {
1664
				throw new SAXException("EMLSAXHandler.deleteRelations: "
1665
						+ ee.getMessage());
1666
			}// catch
1667
		}// finally
1668
	}
1669

    
1670
	/*
1671
	 * Write an online data file id into xml_relation table. The dataId
1672
	 * shouldnot have the revision
1673
	 */
1674
	private void writeOnlineDataFileIdIntoRelationTable(String dataId)
1675
			throws SAXException {
1676
		PreparedStatement pStmt = null;
1677
		String sql = "INSERT into xml_relation (docid, packagetype, subject, "
1678
				+ "relationship, object) values (?, ?, ?, ?, ?)";
1679
		try {
1680
			pStmt = connection.prepareStatement(sql);
1681
			// bind variable
1682
			pStmt.setString(1, docid);
1683
			pStmt.setString(2, doctype); //DocumentImpl.EML2_1_0NAMESPACE);
1684
			pStmt.setString(3, docid);
1685
			pStmt.setString(4, RELATION);
1686
			pStmt.setString(5, dataId);
1687
			// execute query
1688
			pStmt.execute();
1689
			pStmt.close();
1690
		}// try
1691
		catch (SQLException e) {
1692
			throw new SAXException(
1693
					"EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): "
1694
							+ e.getMessage());
1695
		}// catch
1696
		finally {
1697
			try {
1698
				pStmt.close();
1699
			}// try
1700
			catch (SQLException ee) {
1701
				throw new SAXException(
1702
						"EMLSAXHandler.writeOnlineDataFileIdIntoRelationTable(): "
1703
								+ ee.getMessage());
1704
			}// catch
1705
		}// finally
1706

    
1707
	}// writeOnlineDataFileIdIntoRelationTable
1708

    
1709
	/*
1710
	 * This method will handle data file in online url. If the data file is in
1711
	 * ecogrid protocol, then the datafile identifier(without rev)should be put
1712
	 * into onlineDataFileRelationVector. The docid in this vector will be
1713
	 * insert into xml_relation table in endDocument(). If the data file doesn't
1714
	 * exsit in xml_documents or xml_revision table, or the user has all
1715
	 * permission to the data file if the docid already existed, the data file
1716
	 * id (without rev)will be put into onlineDataFileTopAccessVector. The top
1717
	 * access rules specified in this eml document will apply to the data file.
1718
	 * NEED to do: We should also need to implement http and ftp. Those external
1719
	 * files should be download and assign a data file id to it.
1720
	 */
1721
	private void handleOnlineUrlDataFile(String url) throws SAXException {
1722
		logMetacat.warn("The url is " + url);
1723

    
1724
		if (currentDistributionSection == null) {
1725
			throw new SAXException("Trying to set the online file name for a null"
1726
					+ " distribution section");
1727
		}
1728

    
1729
		// if the url is not in ecogrid protocol, null will be returned
1730
		String accessionNumber = DocumentUtil.getAccessionNumberFromEcogridIdentifier(url);
1731
		if (accessionNumber == null) {
1732
			// the accession number is null if the url does not references a
1733
			// local data file (url would start with "ecogrid://"
1734
			currentDistributionSection
1735
					.setDistributionType(DistributionSection.ONLINE_DATA_DISTRIBUTION);
1736
		} else {
1737
			// handle ecogrid protocol
1738
			// get rid of revision number to get the docid.
1739
			String docid = DocumentUtil.getDocIdFromAccessionNumber(accessionNumber);
1740

    
1741
			currentDistributionSection
1742
					.setDistributionType(DistributionSection.DATA_DISTRIBUTION);
1743
			currentDistributionSection.setDataFileName(docid);
1744

    
1745
			// distributionOnlineFileName = docid;
1746
			onlineDataFileIdInRelationVector.add(docid);
1747
			try {				
1748
				if (!AccessionNumber.accNumberUsed(docid)) {
1749
					onlineDataFileIdInTopAccessVector.add(docid);
1750
				} else {
1751
					PermissionController controller = new PermissionController(accessionNumber);				
1752
					if (controller.hasPermission(user, groups,AccessControlInterface.ALLSTRING)) {
1753
						onlineDataFileIdInTopAccessVector.add(docid);
1754
					} else {
1755
						throw new SAXException(UPDATEACCESSERROR);
1756
					}
1757
				} 
1758
			}// try
1759
			catch (Exception e) {
1760
				logMetacat.error("Eorr in "
1761
								+ "Eml210SAXHanlder.handleOnlineUrlDataFile is "
1762
								+ e.getMessage());
1763
				throw new SAXException(e.getMessage());
1764
			}
1765
		}
1766
	}
1767
}
(33-33/65)