Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that implements session utility methods 
4
 *  Copyright: 2008 Regents of the University of California and the
5
 *             National Center for Ecological Analysis and Synthesis
6
 *    Authors: Michael Daigle
7
 * 
8
 *   '$Author: daigle $'
9
 *     '$Date: 2008-08-22 16:23:38 -0700 (Fri, 22 Aug 2008) $'
10
 * '$Revision: 4297 $'
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 2 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program; if not, write to the Free Software
24
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
 */
26

    
27
package edu.ucsb.nceas.metacat.service;
28

    
29
import java.io.File;
30
import java.io.FileWriter;
31
import java.io.IOException;
32
import java.io.OutputStream;
33
import java.io.StringReader;
34
import java.net.HttpURLConnection;
35
import java.net.MalformedURLException;
36
import java.net.URL;
37
import java.sql.PreparedStatement;
38
import java.sql.ResultSet;
39
import java.sql.SQLException;
40
import java.util.Hashtable;
41
import java.util.Vector;
42
import java.util.regex.Matcher;
43
import java.util.regex.Pattern;
44

    
45
import org.apache.commons.io.IOUtils;
46
import org.apache.log4j.Logger;
47

    
48
import edu.ucsb.nceas.metacat.DocumentImpl;
49
import edu.ucsb.nceas.metacat.MetaCatServlet;
50
import edu.ucsb.nceas.metacat.database.DBConnection;
51
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
52
import edu.ucsb.nceas.metacat.properties.PropertyService;
53
import edu.ucsb.nceas.metacat.shared.BaseService;
54
import edu.ucsb.nceas.metacat.shared.ServiceException;
55
import edu.ucsb.nceas.utilities.FileUtil;
56
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
57
import edu.ucsb.nceas.utilities.StringUtil;
58

    
59
public class XMLSchemaService extends BaseService {
60
	
61
	public static final String NAMESPACEKEYWORD = "xmlns";
62
	
63
	public static final String SCHEMA_DIR = "/schema/";
64
	
65
	private static XMLSchemaService xmlSchemaService = null;
66
	
67
	private static Logger logMetacat = Logger.getLogger(XMLSchemaService.class);
68
	
69
	private static boolean useFullSchemaValidation = false;
70
	
71
//	private static String documentNamespace = null;
72
	
73
	// all schema objects that represent schemas registered in the db that 
74
	// actually have files on disk.
75
	private static Vector<XMLSchema> registeredSchemaList = new Vector<XMLSchema>();
76
	
77
	// a convenience list that holds the names of registered namespaces.
78
    private static Vector<String> nameSpaceList = new Vector<String>();
79
    
80
    // a convenience string that holds all name spaces and locations in a space
81
    // delimited format. Those items don't have a format id. This is the old way we handle the schema location
82
    private static String nameSpaceAndLocationStringWithoutFormatId = ""; 
83
	
84
    //this hash table is design for schema variants. Two schemas have the same name space,
85
    //but they have different content (location). So we different format id to
86
    //distinguish them. The key of the hash table is the format id, the values is all the namespace schema location
87
    //delimited string for this format id.
88
    private static Hashtable<String, String> formatId_NamespaceLocationHash = new Hashtable<String, String>();
89
	/**
90
	 * private constructor since this is a singleton
91
	 */
92
	private XMLSchemaService() {
93
        _serviceName = "XMLSchemaService";
94
        try {
95
            doRefresh();
96
        } catch (ServiceException e) {
97
            logMetacat.debug(e.getMessage());
98
        }
99
	}
100
	
101
	/**
102
	 * Get the single instance of XMLService.
103
	 * 
104
	 * @return the single instance of XMLService
105
	 */
106
	public static XMLSchemaService getInstance() {
107
		if (xmlSchemaService == null) {
108
			xmlSchemaService = new XMLSchemaService();
109
		}
110
		return xmlSchemaService;
111
	}
112
	
113
	public boolean refreshable() {
114
		return true;
115
	}
116
	
117
	/**
118
	 * refresh the persistant values in this service.
119
	 */
120
	public void doRefresh() throws ServiceException {
121
	    logMetacat.debug("XMLService.doRefresh - refreshing the schema service.");
122
		try {
123
			populateRegisteredSchemaList();
124
			setUseFullSchemaValidation();
125
			createRegisteredNameSpaceList();
126
			createRegisteredNameSpaceAndLocationString();
127
		} catch (PropertyNotFoundException pnfe) {
128
			logMetacat.error("XMLService.doRefresh - Could not find property: xml.useFullSchemaValidation. " + 
129
					"Setting to false.");
130
		}
131
	}
132
	
133
	public void stop() throws ServiceException {
134
		return;
135
	}
136
	
137
	/**
138
	 * Gets the registered schema list. This list holds schemas that exist in
139
	 * the xml_catalog table that also have associated files in the schema
140
	 * directory.
141
	 * 
142
	 * @return a list of XMLSchema objects holding registered schema information
143
	 */
144
	public Vector<XMLSchema> getRegisteredSchemaList() {
145
		return registeredSchemaList;
146
	}
147
	
148
	/**
149
	 * Gets the name space and location string. This is a convenience method.
150
	 * The string will have space delimited namespaces and locations that are
151
	 * held in the registered schema list. This is the old way Metacat worked.
152
	 * Usually, we will call the method getNameSapceAndLocation(String formatId) first.
153
	 * If the method return null, we will call this method.
154
	 * 
155
	 * @return a string that holds space delimited registered namespaces and
156
	 *         locations.
157
	 */
158
	public String getNameSpaceAndLocationStringWithoutFormatId() {
159
		return nameSpaceAndLocationStringWithoutFormatId;
160
	}
161
	
162
	
163
	/**
164
	 * Get the all schema-location pairs registered for the formatId.
165
	 * The null will be returned, if we can find it.
166
	 * @param formatId
167
	 * @return
168
	 */
169
	public String getNameSpaceAndLocation(String formatId) {
170
	    if(formatId == null) {
171
	        return null;
172
	    } else {
173
	        return formatId_NamespaceLocationHash.get(formatId);
174
	    }
175
	}
176
	
177
	/**
178
	 * Gets a list of name spaces. This is a convenience method. The list will 
179
	 * have all namespaces that are held in the registered schema list.
180
	 * 
181
	 * @return a list that holds registered namespaces.
182
	 */
183
	public Vector<String> getNameSpaceList() {
184
		return nameSpaceList;
185
	}
186
	
187
	/**
188
	 * Report whether xml parsing is set to use full schema parsing. If full
189
	 * schema parsing is true, new schemas will be validated before being
190
	 * entered into the database and file system.
191
	 * 
192
	 * @return true if the xml.useFullSchemaValidation property is set to true,
193
	 *         false otherwise.
194
	 */
195
	public boolean useFullSchemaValidation() {
196
		return useFullSchemaValidation;
197
	}
198
	
199
	/**
200
	 * sets the UseFullSchemaValidation variable.  The only way this should be
201
	 * set is in the constructor or the refresh methods.
202
	 */
203
	private void setUseFullSchemaValidation() throws PropertyNotFoundException {
204
		String strUseFullSchemaValidation = 
205
			PropertyService.getProperty("xml.useFullSchemaValidation");
206
		useFullSchemaValidation = Boolean.valueOf(strUseFullSchemaValidation);
207
	}
208

    
209
	/**
210
	 * Populate the list of registered schemas. This reads all schemas in the
211
	 * xml_catalog table and then makes sure the schema actually exists and is
212
	 * readable on disk.
213
	 */
214
	public void populateRegisteredSchemaList() {
215
		DBConnection conn = null;
216
		int serialNumber = -1;
217
		PreparedStatement pstmt = null;
218
		ResultSet resultSet = null;
219
		registeredSchemaList = new Vector<XMLSchema>();
220

    
221
		// get the system id from the xml_catalog table for all schemas.
222
		String sql = "SELECT public_id, system_id, format_id FROM xml_catalog where "
223
				+ "entry_type ='" + DocumentImpl.SCHEMA + "'";
224
		try {
225
			// check out DBConnection
226
			conn = DBConnectionPool
227
					.getDBConnection("XMLService.populateRegisteredSchemaList");
228
			serialNumber = conn.getCheckOutSerialNumber();
229
			pstmt = conn.prepareStatement(sql);
230
			logMetacat.debug("XMLService.populateRegisteredSchemaList - Selecting schemas: " + pstmt.toString());
231
			pstmt.execute();
232
			resultSet = pstmt.getResultSet();
233

    
234
			// make sure the schema actually exists on the file system. If so,
235
			// add it to the registered schema list.
236
			while (resultSet.next()) {
237
				String fileNamespace = resultSet.getString(1);
238
				String fileLocation = resultSet.getString(2);
239
				String formatId = resultSet.getString(3);
240
				logMetacat.debug("XMLService.populateRegisteredSchemaList - Registering schema: " + fileNamespace + " " + fileLocation+ " and format id "+formatId);
241
				XMLSchema xmlSchema = new XMLSchema(fileNamespace, fileLocation, formatId);
242
				if(fileLocation.startsWith("http://") || fileLocation.startsWith("https://"))
243
				{
244
				    continue;//skip the external schemas.
245
				    /*//System.out.println("processing an http schemal location");
246
				    logMetacat.debug("XMLService.populateRegisteredSchemaList - Processing http schema location: " + fileLocation);
247
				    xmlSchema.setExternalFileUri(fileLocation);
248
				    //cache the file
249
				    try
250
				    {
251
				        URL u = new URL(fileLocation);
252
				        //System.out.println("downloading " + fileLocation);
253
				        logMetacat.debug("XMLService.populateRegisteredSchemaList - Downloading http based schema...");
254
				        HttpURLConnection connection = (HttpURLConnection) u.openConnection();
255
				        connection.setDoOutput(true);
256
			            connection.setRequestMethod("GET");
257
                                    connection.setReadTimeout(5000);
258
                                    //System.out.println("the ============== the read timeout is ================"+connection.getReadTimeout());
259
			            //System.out.println("the ============== the connection timeout is ================"+connection.getConnectTimeout());
260
			            connection.connect();
261
			            String schema = IOUtils.toString(connection.getInputStream());
262
			            
263
			            String deployDir = PropertyService.getProperty("application.deployDir");
264
			            String contextName = PropertyService.getProperty("application.context");
265
			            String filename = fileLocation.substring(fileLocation.lastIndexOf("/"), 
266
                                fileLocation.length());
267
			            File schemaFile = new File(deployDir + "/" + contextName + "/" +
268
			                    "schema/" + filename);
269
			            //System.out.println("writing schema to " + schemaFile.getAbsolutePath());
270
			            FileWriter fw = new FileWriter(schemaFile);
271
			            fw.write(schema);
272
			            fw.flush();
273
			            fw.close();
274
			            logMetacat.debug("XMLService.populateRegisteredSchemaList - Schema downloaded to " + schemaFile.getAbsolutePath());
275
			            fileLocation = "/schema/" + filename;
276
			            //System.out.println("fileLocation set to " + fileLocation);
277
			            logMetacat.debug("XMLService.populateRegisteredSchemaList - fileLocation set to " + fileLocation);
278
			            xmlSchema.setFileName(fileLocation);
279
				    }
280
				    catch(MalformedURLException me)
281
				    {
282
				        logMetacat.warn("Could not cache a registered schema at " + fileLocation +
283
				                " because a connection could not be made to the given url: " + 
284
				                me.getMessage());
285
				    }
286
                    catch (IOException ioe)
287
                    {
288
                        logMetacat.warn("Could not cache a registered schema at " + fileLocation +
289
                        " because an IOException occured: " + ioe.getMessage());
290
                    }
291
                    catch(PropertyNotFoundException pnfe)
292
                    {
293
                        logMetacat.warn("Could not cache a registered schema at " + fileLocation +
294
                                " because the property 'application.tempDir' could not be found.");
295
                    }
296
				    
297
				    xmlSchema.setFileName(fileLocation);*/
298
				}
299
				else
300
				{
301
				    xmlSchema.setFileName(fileLocation);
302
				}
303
								
304
				if (FileUtil.getFileStatus(xmlSchema.getLocalFileDir()) >= FileUtil.EXISTS_READABLE) 
305
				{
306
					registeredSchemaList.add(xmlSchema);
307
				}
308
				else if(fileLocation.startsWith("http://") || fileLocation.startsWith("https://"))
309
                {  //the schema resides on a different server, to validate, we need to go get it 
310
                    //registeredSchemaList.add(xmlSchema);
311
                }
312
				else 
313
				{
314
					logMetacat.warn("XMLService.populateRegisteredSchemaList - Schema file: " + xmlSchema.getLocalFileDir() + " is registered "
315
							+ " in the database but does not exist on the file system.");
316
				}
317
			}
318
		} catch (SQLException e) {
319
			logMetacat.error("XMLService.populateRegisteredSchemaList - SQL Error: "
320
					+ e.getMessage());
321
		} finally {
322
			try {
323
				pstmt.close();
324
			}// try
325
			catch (SQLException sqlE) {
326
				logMetacat.error("XMLSchemaService.populateRegisteredSchemaList - Error in XMLService.populateRegisteredSchemaList(): "
327
						+ sqlE.getMessage());
328
			}
329
			DBConnectionPool.returnDBConnection(conn, serialNumber);
330
		}
331
	}	
332
	
333
	/**
334
	 * create a space delimited string of all namespaces and locations
335
	 * in the registered schema list.
336
	 */
337
	private static void createRegisteredNameSpaceAndLocationString() {
338
		boolean firstRowWithoutFormatid = true;
339
		boolean firstRowWithFormatid = true;
340
		nameSpaceAndLocationStringWithoutFormatId = "";
341
		
342
		for (XMLSchema xmlSchema : registeredSchemaList) {
343
		    String formatId = xmlSchema.getFormatId();
344
		    if( formatId == null ||formatId.trim().equals("")) {
345
		        //this is to handle the old way - no schema variants 
346
		        if (!firstRowWithoutFormatid) {
347
	                nameSpaceAndLocationStringWithoutFormatId += " ";
348
	            }
349
	            nameSpaceAndLocationStringWithoutFormatId += xmlSchema.getFileNamespace() + " "
350
	                    + xmlSchema.getLocalFileUri();
351
	            firstRowWithoutFormatid = false;
352
		    } else {
353
		        //it has a format id on the xml_catalog table. It is a variant.
354
		        if(!formatId_NamespaceLocationHash.containsKey(xmlSchema.getFormatId())) {
355
		            //the hash table hasn't stored the value. So put it on the hash.
356
		            formatId_NamespaceLocationHash.put(formatId, xmlSchema.getFileNamespace() + " "
357
	                        + xmlSchema.getLocalFileUri());
358
		        } else {
359
		          //the hash table already has it. We will attache the new pair to the exist value
360
		            String value = formatId_NamespaceLocationHash.get(formatId);
361
		            value += " "+ xmlSchema.getFileNamespace() + " "
362
	                        + xmlSchema.getLocalFileUri();
363
		            formatId_NamespaceLocationHash.put(formatId, value);
364
		        }
365
		    }
366
			
367
		}
368
	}
369

    
370
	/**
371
	 * create a lsit of all namespaces in the registered schema list.
372
	 */
373
	private static void createRegisteredNameSpaceList() {
374
		nameSpaceList = new Vector<String>();
375
		for (XMLSchema xmlSchema : registeredSchemaList) {
376
			nameSpaceList.add(xmlSchema.getFileNamespace());
377
		}
378
	}
379
	
380
	/**
381
	 * Checks to see that all schemas are registered. If a single one in the
382
	 * list is not, this will return false.
383
	 * 
384
	 * @param schemaList
385
	 *            a list of schemas as they appear in xml.
386
	 * @return true if all schemas are registered.
387
	 */
388
	public static boolean areAllSchemasRegistered(Vector<XMLSchema> schemaList) {			
389
		for (XMLSchema xmlSchema : schemaList) {
390
			if ( ! isSchemaRegistered(xmlSchema)) {
391
				return false;
392
			}
393
		}		
394
		return true;
395
	}
396
	
397
	/**
398
	 * Returns true if the schema is registered.
399
	 * 
400
	 * @param schema
401
	 *            a single schema as it appears in xml
402
	 * @return true if the schema is registered, false otherwise.
403
	 */
404
	public static boolean isSchemaRegistered(XMLSchema xmlSchema) {
405
		for (XMLSchema registeredXmlSchema : registeredSchemaList) {
406
			if (registeredXmlSchema.getLocalFileUri().equals(
407
						xmlSchema.getLocalFileUri())
408
					&& registeredXmlSchema.getFileNamespace().equals(
409
							xmlSchema.getFileNamespace())) {
410
				return true;
411
			}
412
		}
413

    
414
		return false;
415
	}
416
	
417
    /**
418
	 * See if schemas have been specified in the xml:schemalocation attribute.
419
	 * If so, return a vector of the system ids.
420
	 * 
421
	 * @param xml
422
	 *            the document we want to look in for schema location
423
	 * @return a vector of XMLSchema objects, or an empty vector if none are
424
	 *         found
425
	 */
426
	public static Vector<XMLSchema> findSchemasInXML(StringReader xml) throws IOException {
427
		Logger logMetacat = Logger.getLogger(MetaCatServlet.class);
428
		Vector<XMLSchema> schemaList = new Vector<XMLSchema>();
429

    
430
		// no xml. return empty vector
431
		if (xml == null) {
432
			logMetacat.debug("XMLSchemaService.findSchemasInXML - Returning empty schemaList.");
433
			return schemaList;
434
		}
435

    
436
		// Get the "second line" from the xml
437
		String targetLine = getSchemaLine(xml);
438

    
439
		// see if there is a match for xsi.schemaLocation. If so, extract the
440
		// schemas.
441
		if (targetLine != null) {
442
			String regex = "(\\p{Graph}*):schemaLocation=\"([^\"]*)\"";
443
			Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE
444
					| Pattern.DOTALL);
445
			Matcher matcher = pattern.matcher(targetLine);
446
			int i = 0;
447
			while (i < targetLine.length()) {
448
				if (!matcher.find(i)) {
449
					break;
450
				}
451

    
452
				String uri = matcher.group(2);
453
				uri = StringUtil.replaceTabsNewLines(uri);
454
				uri = StringUtil.replaceDuplicateSpaces(uri);
455

    
456
				// each namespace could have several schema locations. parsedUri
457
				// will hold a list of uri and files.
458
				Vector<String> parsedUri = StringUtil.toVector(uri, ' ');
459
				for (int j = 0; j < parsedUri.size(); j = j + 2) {
460
					if (j + 1 >= parsedUri.size()) {
461
						throw new IOException(
462
								"Odd number of elements found when parsing schema location: "
463
										+ targetLine
464
										+ ". There should be an even number of uri/files in location.");
465
					}
466
					String formatId = null;
467
					XMLSchema xmlSchema = new XMLSchema(parsedUri.get(j), parsedUri
468
							.get(j + 1), formatId);
469
					schemaList.add(xmlSchema);
470
				}
471
				i = matcher.end();
472
			}
473
		}
474

    
475
		logMetacat.debug("XMLSchemaService.findSchemasInXML - Schemas for eml are " + schemaList.toString());
476

    
477
		return schemaList;
478
	}    
479
    
480
    /**
481
	 * Returns all the namespace for an xml document.  This is done by getting
482
	 * the internal namespace declaration (prefix) and looking for xmlns:<prefix>
483
	 * 
484
	 * @param xml
485
	 *            the document to search
486
	 * @return a string holding the namespace
487
	 */
488
	public static String findDocumentNamespace(StringReader xml) throws IOException {
489
		String namespace = null;
490

    
491
		String eml2_0_0NameSpace = DocumentImpl.EML2_0_0NAMESPACE;
492
		String eml2_0_1NameSpace = DocumentImpl.EML2_0_1NAMESPACE;
493
		String eml2_1_0NameSpace = DocumentImpl.EML2_1_0NAMESPACE;
494
		String eml2_1_1NameSpace = DocumentImpl.EML2_1_1NAMESPACE;
495

    
496

    
497
		if (xml == null) {
498
			logMetacat.debug("XMLSchemaService.findDocumentNamespace - XML doc is null.  There is no namespace.");
499
			return namespace;
500
		}
501

    
502
		String targetLine = getSchemaLine(xml);
503

    
504
		// the prefix is at the beginning of the doc
505
		String prefix = null;
506
		String regex1 = "^\\s*(\\p{Graph}+):\\p{Graph}* ";
507
		Pattern pattern = Pattern.compile(regex1, Pattern.CASE_INSENSITIVE);
508
		Matcher matcher = pattern.matcher(targetLine);
509
		if (matcher.find()) {
510
			prefix = matcher.group(1).trim();
511
		}
512

    
513
		// if a prefix was found, we are looking for xmlns:<prefix>="namespace"
514
		// if no prefix was found, we grab the first namespace.
515
		String regex2;
516
		if (prefix != null) {
517
			regex2 = "xmlns:" + prefix + "=['\"](.*)['\"]";
518
		} else {
519
			regex2 = "xmlns:.*=['\"](.*)['\"]";
520
		}
521
		Pattern pattern2 = Pattern.compile(regex2, Pattern.CASE_INSENSITIVE);
522
		Matcher matcher2 = pattern2.matcher(targetLine);
523
		if (matcher2.find()) {
524
			namespace = matcher2.group(1);
525

    
526
			if (namespace.indexOf(eml2_0_0NameSpace) != -1) {
527
				namespace = eml2_0_0NameSpace;
528
			} else if (namespace.indexOf(eml2_0_1NameSpace) != -1) {
529
				namespace = eml2_0_1NameSpace;
530
			} else if (namespace.indexOf(eml2_1_0NameSpace) != -1) {
531
				namespace = eml2_1_0NameSpace;
532
			} else if (namespace.indexOf(eml2_1_1NameSpace) != -1) {
533
				namespace = eml2_1_1NameSpace;
534
			}
535
		}
536

    
537
		return namespace;
538
	}
539
    
540
    /**
541
	 * Return the line from xml that holds the metadata like namespace and
542
	 * schema location
543
	 * 
544
	 * @param xml
545
	 *            the document to parse
546
	 * @return the "second" line of the document
547
	 */
548
    private static String getSchemaLine(StringReader xml) throws IOException {
549
        Logger logMetacat = Logger.getLogger(MetaCatServlet.class);
550
        // find the line
551
        String secondLine = null;
552
        int count = 0;
553
        final int TARGETNUM = 1;
554
        StringBuffer buffer = new StringBuffer();
555
        boolean comment = false;
556
        boolean processingInstruction = false;
557
        char thirdPreviousCharacter = '?';
558
        char secondPreviousCharacter = '?';
559
        char previousCharacter = '?';
560
        char currentCharacter = '?';
561
        int tmp = xml.read();
562
        while (tmp != -1) {
563
            currentCharacter = (char)tmp;
564
            //in a comment
565
            if (currentCharacter == '-' && previousCharacter == '-'
566
                    && secondPreviousCharacter == '!'
567
                    && thirdPreviousCharacter == '<') {
568
                comment = true;
569
            }
570
            //out of comment
571
            if (comment && currentCharacter == '>' && previousCharacter == '-'
572
                    && secondPreviousCharacter == '-') {
573
                comment = false;
574
            }
575
            
576
            //in a processingInstruction
577
            if (currentCharacter == '?' && previousCharacter == '<') {
578
                processingInstruction = true;
579
            }
580
            
581
            //out of processingInstruction
582
            if (processingInstruction && currentCharacter == '>'
583
                    && previousCharacter == '?') {
584
                processingInstruction = false;
585
            }
586
            
587
            //this is not comment or a processingInstruction
588
            if (currentCharacter != '!' && previousCharacter == '<'
589
                    && !comment && !processingInstruction) {
590
                count++;
591
            }
592
            
593
            // get target line
594
            if (count == TARGETNUM && currentCharacter != '>') {
595
                buffer.append(currentCharacter);
596
            }
597
            if (count == TARGETNUM && currentCharacter == '>') {
598
                break;
599
            }
600
            thirdPreviousCharacter = secondPreviousCharacter;
601
            secondPreviousCharacter = previousCharacter;
602
            previousCharacter = currentCharacter;
603
            tmp = xml.read();
604
        }
605
        secondLine = buffer.toString();
606
        logMetacat.debug("XMLSchemaService.getSchemaLine - the second line string is: " + secondLine);
607
        
608
        xml.reset();
609
        return secondLine;
610
    }
611
    
612
    /**
613
	 * Get a schema file name from the schema uri.
614
	 * 
615
	 * @param uri
616
	 *            the uri from which to extract the file name
617
	 * @return a string holding the file name
618
	 */
619
    public static String getSchemaFileNameFromUri(String uri) {
620
		// get filename from systemId
621
		String filename = uri;
622
		
623
		if (filename != null && !(filename.trim()).equals("")) {
624
			int slash = Math.max(filename.lastIndexOf('/'), filename.lastIndexOf('\\'));
625
			if (slash > -1) {
626
				filename = filename.substring(slash + 1);
627
			}
628
		}
629

    
630
		return filename;
631
	}
632
    
633
    /**
634
     * Get a base url from the schema url. If url=http://www.example.com/example.xsd,
635
     * http://www.example.com/ will be returned.
636
     * 
637
     * @param uri
638
     *            the uri from which to extract the base url
639
     * @return a string holding the base url. null will be return if it is not url.
640
     */
641
      public static String getBaseUrlFromSchemaURL(String url) 
642
      {
643
        String baseURL = null;        
644
        if (url != null && (url.indexOf("http://") != -1 || url.indexOf("https://") !=-1)) 
645
        {
646
          int slash = url.lastIndexOf('/');
647
          if (slash > -1) 
648
          {
649
            baseURL = url.substring(0,slash+1);
650
          }
651
        } 
652
        return baseURL;
653
      }
654
}
(5-5/5)