/**
* '$RCSfile$'
* Purpose: A Class that implements org.xml.sax.EntityResolver interface
* for resolving external entities
* Copyright: 2000 Regents of the University of California and the
* National Center for Ecological Analysis and Synthesis
* Authors: Jivka Bojilova, Matt Jones
*
* '$Author$'
* '$Date$'
* '$Revision$'
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package edu.ucsb.nceas.metacat;
import java.sql.*;
import java.util.Vector;
import java.io.File;
import java.io.BufferedInputStream;
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.IOException;
import org.apache.log4j.Logger;
import org.xml.sax.SAXException;
import edu.ucsb.nceas.metacat.database.DBConnection;
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
import edu.ucsb.nceas.metacat.service.ServiceService;
import edu.ucsb.nceas.metacat.service.XMLSchemaParser;
import edu.ucsb.nceas.metacat.service.XMLSchemaService;
import edu.ucsb.nceas.metacat.util.SystemUtil;
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
/**
* A database aware Class to handle schema location. If namespace is in the
* xml_catalog table (public_id), the schema location specified in xml document
* will be ignored by parser setting external schema location. If the
* name space is not in the table, it will be download to metacat and register
* in table
*/
public class SchemaLocationResolver
{
private String nameSpace = null; //public id
private String schemaLocation = null; // system id
private String WHITESPACESTRING =" ";
private boolean downloadNewSchema = false;
private static Logger logMetacat = Logger.getLogger(SchemaLocationResolver.class);
public SchemaLocationResolver()
{
}
/**
* Construct an instance of the SchemaLocationResolver class
*
* @param myNameSpaceAndLocation it is come from xsi:schemaLocation=
* "namespace location"
*/
public SchemaLocationResolver(String myNameSpaceAndLocation)
{
parse(myNameSpaceAndLocation);
}
/**
* Construct an instance of the SchemaLocationResolver class
*
* @param myNameSpaceAndLocation it is come from xsi:schemaLocation=
* "namespace location"
*/
public SchemaLocationResolver(String myNameSpace, String myLocation)
{
nameSpace = myNameSpace;
schemaLocation = myLocation;
}
/**
* When got a name space, check if it is in the database, if it is do nothing
* else upload it to metacat to store it and register it in catalog table
*/
public void resolveNameSpace ()
{
// if name space is not in table
if (nameSpace !=null && schemaLocation != null &&
!XMLSchemaService.getInstance().getNameSpaceList().contains(nameSpace))
{
try
{
// upload schema into metacat
String newURLInMetacat = uploadSchemaFromURL(schemaLocation);
ServiceService.refreshService("XMLSchemaService");
// check the name space list again. It may not have appeared the first time
// because the schema was in the db but there was no file on disk. If that's
// the case, it will show up in the name space list now. If it doesn't we need
// to register the schema in the database.
if (!XMLSchemaService.getInstance().getNameSpaceList().contains(nameSpace)) {
registerSchema(newURLInMetacat);
ServiceService.refreshService("XMLSchemaService");
}
downloadNewSchema = true;
//handle included schema in above schema
String externalBaseURL = XMLSchemaService.getBaseUrlFromSchemaURL(schemaLocation);
//System.out.println("==========the externalBaseURL is "+externalBaseURL);
handleIncludedSchema(newURLInMetacat, externalBaseURL);
}
catch(Exception e)
{
logMetacat.error("Error in SchemaLocation.resolveNameSpace" +
e.getMessage());
}
}//if
}
/*
* Some schemas (parent schema)also include other schemas (children) in
* its definition. The syntax is:
* The included schemas need to be downloaded as well.
* The included schemas always have the same target namespace. So there
* is no need to register the schema into xml_catalog table.
* Note: the included schemas may have included schemas (grandchildren) as well.
*/
private void handleIncludedSchema(String parentSchemaNewURLInMetacat,
String externalBaseURL)
throws SAXException, IOException,PropertyNotFoundException
{
//Gets the included schema information from parent schema
//System.out.println("the parent schema new url in metacat ============="+parentSchemaNewURLInMetacat);
if(externalBaseURL != null)
{
InputStream in = DBEntityResolver.checkURLConnection(SystemUtil.getInternalContextURL()+parentSchemaNewURLInMetacat);
XMLSchemaParser parser = new XMLSchemaParser(in);
parser.parse();
Vector includedSchemaPaths = parser.getIncludedSchemaFilePathes();
//System.out.println("the include schema paths is ============ "+includedSchemaPaths);
if(includedSchemaPaths!= null)
{
for(int i=0; i -1 )
{
filename = filename.substring(slash + 1);
}
}
else
{
return null;
}
// writing schema text on Metacat file system as filename
try {
InputStream istream = DBEntityResolver.checkURLConnection(schemaLocationURL);
// create a buffering character-input stream
// that uses a default-sized input buffer
BufferedInputStream in = new BufferedInputStream(istream);
// open file writer to write the input into it
File f = new File(fullSchemaPath, filename);
synchronized (f)
{
try
{
if ( f.exists() )
{
throw new IOException("File already exist: " + f.getCanonicalFile());
}
}
catch (SecurityException se)
{
// if a security manager exists,
throw se;
}
// create a buffered character-output stream
// that uses a default-sized output buffer
FileWriter fw = new FileWriter(f);
BufferedWriter out = new BufferedWriter(fw);
// read the input and write into the file writer
int inputByte;
while ( (inputByte = in.read()) != -1 )
{
out.write(inputByte);
//out.newLine(); //instead of out.write('\r\n');
}
// the input and the output streams must be closed
in.close();
out.flush();
out.close();
fw.close();
} // end of synchronized
}
catch (Exception e)
{
throw new Exception
("shemaLocationResolver.uploadSchemaFromURL(): " + e.getMessage());
}
logMetacat.warn("new schema location is: " + schemaURL +
filename);
return relativeSchemaPath + filename;
}
/*
* Register new schema identified by @systemId in Metacat XML Catalog
*/
private void registerSchema(String systemId )
{
// check systemid is not null
if (systemId == null || nameSpace == null || (nameSpace.trim()).equals(""))
{
return;
}
DBConnection conn = null;
int serialNumber = -1;
PreparedStatement pstmt = null;
String sql = "INSERT INTO xml_catalog " +
"(entry_type, public_id, system_id) " +
"VALUES ('" + DocumentImpl.SCHEMA + "', ?, ?)";
try
{
//check out DBConnection
conn=DBConnectionPool.getDBConnection("schemaLocation.registerSchema");
serialNumber=conn.getCheckOutSerialNumber();
pstmt = conn.prepareStatement(sql);
// Bind the values to the query
pstmt.setString(1, nameSpace);
pstmt.setString(2, systemId);
// Do the insertion
pstmt.execute();
pstmt.close();
}
catch (SQLException e)
{
logMetacat.error("SchemaLocation.egisterSchema(): " + e.getMessage());
}
finally
{
try
{
pstmt.close();
}//try
catch (SQLException sqlE)
{
logMetacat.error("Error in SchemaLocation.egisterSchema(): "
+sqlE.getMessage());
}//catch
DBConnectionPool.returnDBConnection(conn, serialNumber);
}//finally
XMLSchemaService.getInstance().populateRegisteredSchemaList();
}
/*
* A method to parse the value for xis:schemaLocation="namespace location"
* and store the namespace in nameSpace and location in schemaLocaion
*/
private void parse(String nameSpaceAndLocation)
{
// check the parameter
if (nameSpaceAndLocation == null||(nameSpaceAndLocation.trim()).equals(""))
{
return;
}
//Get white space index (delimiter)
int indexOfWhiteSpace = nameSpaceAndLocation.lastIndexOf(WHITESPACESTRING);
if (indexOfWhiteSpace != -1)
{
// before white space is namespace
nameSpace = nameSpaceAndLocation.substring(0,indexOfWhiteSpace);
// after white sapce is schema location
schemaLocation = nameSpaceAndLocation.substring(indexOfWhiteSpace+1);
// Gebug message
logMetacat.info("Namespace after parsing: " + nameSpace);
logMetacat.info("Location after parsing: " + schemaLocation);
}
}
/*public static void main(String[] argus)
{
try
{
DBConnectionPool pool = DBConnectionPool.getInstance();
// Print out a empty schema list
SchemaLocationResolver schema = new SchemaLocationResolver();
logMetacat.warn("Namespace and Location String: "+
XMLSchemaService.getInstance().getNameSpaceAndLocationString());
// input a schemalocation
SchemaLocationResolver schema2 = new SchemaLocationResolver(
"eml://ecoinformatics.org/eml-2.0.0 " +
"http://dev.nceas.ucsb.edu/tao/schema/eml.xsd");
schema2.resolveNameSpace();
// input a wrong name space location
SchemaLocationResolver schema3 = new SchemaLocationResolver(
"http://www.xm.org/schema/stmml " +
"http://dev.nceas.ucsb.edu/tao/schema/stmml.xsd");
schema3.resolveNameSpace();
// print out new schema list in db
SchemaLocationResolver schema4 = new SchemaLocationResolver();
logMetacat.warn("Namespace and Location String: "+
XMLSchemaService.getInstance().getNameSpaceAndLocationString());
}
catch(Exception e)
{
logMetacat.error("erorr in Schemalocation.main: " +
e.getMessage());
}
}*/
/**
* Gets the downloadNewSchema's value.
* @return
*/
public boolean getDownloadNewSchema()
{
return this.downloadNewSchema;
}
}