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

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

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

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

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

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

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

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

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

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

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

    
495

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

    
501
		String targetLine = getSchemaLine(xml);
502

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

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

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

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

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