Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that implements org.xml.sax.EntityResolver interface
4
 *             for resolving external entities
5
 *  Copyright: 2000 Regents of the University of California and the
6
 *             National Center for Ecological Analysis and Synthesis
7
 *    Authors: Jivka Bojilova, Matt Jones
8
 *
9
 *   '$Author: daigle $'
10
 *     '$Date: 2008-07-15 09:58:15 -0700 (Tue, 15 Jul 2008) $'
11
 * '$Revision: 4123 $'
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

    
31
import java.sql.*;
32
import java.io.File;
33
import java.io.Reader;
34
import java.io.BufferedReader;
35
import java.io.BufferedInputStream;
36
import java.io.FileWriter;
37
import java.io.BufferedWriter;
38
import java.io.InputStream;
39
import java.io.IOException;
40
import java.net.URL;
41
import java.net.URLConnection;
42
import java.net.MalformedURLException;
43
import java.util.Vector;
44

    
45
import org.apache.log4j.Logger;
46

    
47
import edu.ucsb.nceas.metacat.util.SystemUtil;
48
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
49

    
50
/**
51
 * A database aware Class to handle schema location. If namespace is in the
52
 * xml_catalog table (public_id), the schema location specified in xml document
53
 * will be ignored by parser setting external schema location. If the
54
 * name space is not in the table, it will be download to metacat and register
55
 * in table
56
 */
57
public class SchemaLocationResolver
58
{
59
  
60
  private String nameSpace = null; //public id
61
  private String schemaLocation = null; // system id
62
  private Vector nameSpaceList = new Vector();// name space in the table
63
  private String nameSpaceAndLocationString = null; // the parameter will be set
64
                                              // in external property in parser
65
  //private String schemaFileName = null;
66
  // constant
67
  //private String SCHEMATYPE ="Schema"; 
68
  private String WHITESPACESTRING =" ";                                                         
69

    
70
  private static Logger logMetacat = Logger.getLogger(SchemaLocationResolver.class);
71

    
72
  public SchemaLocationResolver()
73
  {
74
    createNameSpaceAndLocationStringFromDB();
75
  }
76
  /**
77
   * Construct an instance of the SchemaLocationResolver class
78
   *
79
   * @param  myNameSpaceAndLocation it is come from xsi:schemaLocation=
80
   *         "namespace location"
81
   */
82
  public SchemaLocationResolver(String myNameSpaceAndLocation)
83
  {
84
    parse(myNameSpaceAndLocation);
85
  }
86
  
87
  /**
88
   * A method to get nameSpaceAndLocationString
89
   */
90
  public String getNameSpaceAndLocationString()
91
  {
92
    logMetacat.info("namespace and location list is: " +
93
                             nameSpaceAndLocationString);
94
    return nameSpaceAndLocationString;
95
  }
96
  
97
  /**
98
   * When got a name space, check if it is in the database, if it is do nothing
99
   * else upload it to metacat to store it and register it in catalog table
100
   */
101
  public void resolveNameSpace ()
102
  {
103
    //get name space lists
104
    createNameSpaceListFromDB();
105
  
106
    // if name space is not in table
107
    if (nameSpace !=null && schemaLocation != null &&
108
        !nameSpaceList.contains(nameSpace))
109
    {
110
       try
111
       {
112
        
113
        // upload schema into metacat
114
        InputStream in = DBEntityResolver.checkURLConnection(schemaLocation);
115
       
116
        String newURLInMetacat = uploadSchemaFromURL(in);
117
       
118
        // reigister schema
119
        registerSchema(newURLInMetacat);
120
     
121
       }
122
       catch(Exception e)
123
       {
124
         logMetacat.error("Error in SchemaLocation.resolveNameSpace" +
125
                                  e.getMessage());
126
       }
127
 
128
    }//if
129
 
130
  }
131

    
132
  /*
133
	 * This method will take look xml_catalog table and create a string look
134
	 * like "namespace1 location namespacke2 location". This string will be set
135
	 * as a extenalschemalocation in SAX parser. Then when parser check the it
136
	 * will ignore the schema location specified by xml document
137
	 */
138
	private void createNameSpaceAndLocationStringFromDB() {
139
		DBConnection conn = null;
140
		int serialNumber = -1;
141
		PreparedStatement pstmt = null;
142
		ResultSet result = null;
143
		String sql = "SELECT public_id, system_id FROM xml_catalog where "
144
				+ "entry_type ='" + DocumentImpl.SCHEMA + "'";
145
		try {
146
			// check out DBConnection
147
			conn = DBConnectionPool.getDBConnection("SchemaLocationResl.createName");
148
			serialNumber = conn.getCheckOutSerialNumber();
149
			pstmt = conn.prepareStatement(sql);
150
			pstmt.execute();
151
			result = pstmt.getResultSet();
152

    
153
			// Get string for namespace and location form DB
154
			boolean hasRow = result.next();
155
			StringBuffer buffer = new StringBuffer();
156
			boolean firstTime = true;
157
			while (hasRow) {
158
				String namespace = result.getString(1);
159
				String location = result.getString(2);
160
				// system id may not have server url on front. Add it if not.
161
				if (!location.startsWith("http://")) {
162
					try {
163
						location = SystemUtil.getContextURL() + location;
164
					} catch (PropertyNotFoundException pnfe) {
165
						throw new SQLException("Could not find property: "
166
								+ pnfe.getMessage());
167
					}
168
				}
169
				String pairOfNameSpaceAndLocation = namespace + WHITESPACESTRING
170
						+ location;
171
				if (!firstTime) {
172
					buffer.append(WHITESPACESTRING);
173
				}
174
				buffer.append(pairOfNameSpaceAndLocation);
175
				firstTime = false;
176
				hasRow = result.next();
177

    
178
			}
179
			// give the buffer to the string if buffer has something in it
180
			if (buffer.length() != 0) {
181
				nameSpaceAndLocationString = buffer.toString();
182
			}
183
			result.close();
184
			pstmt.close();
185
		} catch (SQLException e) {
186
			logMetacat.error("schemaLocation.createNameSpaceAndLocationString: "
187
					+ e.getMessage());
188
		} finally {
189
			try {
190
				pstmt.close();
191
			}// try
192
			catch (SQLException sqlE) {
193
				logMetacat.error("Error in schema.createNameSpaceAndLocation "
194
						+ sqlE.getMessage());
195
			}// catch
196
			DBConnectionPool.returnDBConnection(conn, serialNumber);
197
		}// finally
198

    
199
	}
200

    
201
  /*
202
	 * This method will take look xml_catalog table and create a name space
203
	 * vector already in the table
204
	 */
205
  private void createNameSpaceListFromDB()
206
  {
207
    DBConnection conn = null;
208
    int serialNumber = -1;
209
    PreparedStatement pstmt = null;
210
    ResultSet result = null;
211
    String sql = "SELECT public_id FROM xml_catalog where " +
212
                 "entry_type ='" + DocumentImpl.SCHEMA +"'";
213
    try 
214
    {
215
      //check out DBConnection
216
      conn=DBConnectionPool.getDBConnection("SchemaLocationResl.createNameList");
217
      serialNumber=conn.getCheckOutSerialNumber();
218
      pstmt = conn.prepareStatement(sql);
219
      pstmt.execute();
220
      result = pstmt.getResultSet();
221
      
222
      // Get string for namespace form DB and store in the vector
223
      boolean hasRow = result.next();
224
      while (hasRow)
225
      {
226
        String namespace = result.getString(1);
227
        nameSpaceList.addElement(namespace);
228
        hasRow = result.next();
229
        
230
      }
231
      pstmt.close();
232
      result.close();
233
    } 
234
    catch (SQLException e) 
235
    {
236
      logMetacat.error("schemaLocation.createNameSpaceList: " + 
237
                         e.getMessage());
238
    }
239
    finally
240
    {
241
      try
242
      {
243
        pstmt.close();
244
      }//try
245
      catch (SQLException sqlE)
246
      {
247
        logMetacat.error("Error in schemaLocation.createNameSpaceList: "
248
                                    +sqlE.getMessage());
249
      }//catch
250
      DBConnectionPool.returnDBConnection(conn, serialNumber);
251
    }//finally
252
  
253
  }
254
  
255
   
256

    
257
  /**
258
   * Upload new Schema located at outside URL to Metacat file system
259
   */
260
  private String uploadSchemaFromURL(InputStream istream) throws Exception
261
  {
262
   
263
    String schemaPath = SystemUtil.getContextDir() + "/schema/";
264
    String schemaURL = SystemUtil.getContextURL()  + "/schema/";
265

    
266
    // get filename from systemId
267
    String filename = schemaLocation;
268
  
269
    if (filename != null && !(filename.trim()).equals(""))
270
    {
271
      int slash = Math.max(filename.lastIndexOf('/'), filename.lastIndexOf('\\'));
272
      if ( slash > -1 ) 
273
      {
274
        filename = filename.substring(slash + 1);
275
      }
276
    }
277
    else
278
    {
279
      return null;
280
    }
281
    // writing schema text on Metacat file system as filename
282
    try {
283
      // create a buffering character-input stream
284
      // that uses a default-sized input buffer
285
      BufferedInputStream in = new BufferedInputStream(istream);
286

    
287
      // open file writer to write the input into it
288
      File f = new File(schemaPath, filename);
289
      synchronized (f) 
290
      {
291
        try 
292
        {
293
          if ( f.exists() ) 
294
          {
295
           throw new IOException("File already exist: " + f.getCanonicalFile());
296
          }
297
        } 
298
        catch (SecurityException se) 
299
        {
300
         // if a security manager exists,
301
          throw se;
302
       }
303
      // create a buffered character-output stream
304
      // that uses a default-sized output buffer
305
      FileWriter fw = new FileWriter(f);
306
      BufferedWriter out = new BufferedWriter(fw);
307

    
308
      // read the input and write into the file writer
309
      int inputByte;
310
      while ( (inputByte = in.read()) != -1 ) 
311
      {
312
        out.write(inputByte);
313
        //out.newLine(); //instead of out.write('\r\n');
314
      }
315

    
316
      // the input and the output streams must be closed
317
      in.close();
318
      out.flush();
319
      out.close();
320
      fw.close();
321
     } // end of synchronized
322
    } 
323
    catch (Exception e) 
324
    {
325
      throw new Exception
326
      ("shemaLocationResolver.uploadSchemaFromURL(): " + e.getMessage());
327
    } 
328
    logMetacat.warn("new schema location is: " + schemaURL + 
329
                              filename);
330
    return  schemaURL + filename;
331
  }
332

    
333
  
334
  /*
335
   * Register new schema identified by @systemId in Metacat XML Catalog
336
   */
337
  private void registerSchema(String systemId )
338
  {
339
    // check systemid is not null
340
    if (systemId == null || nameSpace == null || (nameSpace.trim()).equals(""))
341
    {
342
     
343
      return;
344
    }
345
    
346
    DBConnection conn = null;
347
    int serialNumber = -1;
348
    PreparedStatement pstmt = null;
349
    String sql = "INSERT INTO xml_catalog " +
350
             "(entry_type, public_id, system_id) " +
351
             "VALUES ('" + DocumentImpl.SCHEMA + "', ?, ?)";
352
    
353
 
354
    try 
355
    {
356
      //check out DBConnection
357
      conn=DBConnectionPool.getDBConnection("schemaLocation.registerSchema");
358
      serialNumber=conn.getCheckOutSerialNumber();
359
      pstmt = conn.prepareStatement(sql);
360
     
361
      // Bind the values to the query
362
      pstmt.setString(1, nameSpace);
363
      pstmt.setString(2, systemId);
364
      // Do the insertion
365
      pstmt.execute();
366
      pstmt.close();
367
    } 
368
    catch (SQLException e) 
369
    {
370
      logMetacat.error("SchemaLocation.egisterSchema(): " + e.getMessage());
371
    }
372
    finally
373
    {
374
      try
375
      {
376
        pstmt.close();
377
      }//try
378
      catch (SQLException sqlE)
379
      {
380
        logMetacat.error("Error in SchemaLocation.egisterSchema(): "
381
                                    +sqlE.getMessage());
382
      }//catch
383
      DBConnectionPool.returnDBConnection(conn, serialNumber);
384
    }//finally
385

    
386
  }
387
  
388
  /*
389
   * A method to parse the value for xis:schemaLocation="namespace location"
390
   * and store the namespace in nameSpace and location in schemaLocaion
391
   */
392
  private void parse(String nameSpaceAndLocation)
393
  {
394
    // check the parameter
395
    if (nameSpaceAndLocation == null||(nameSpaceAndLocation.trim()).equals(""))
396
    {
397
      return;
398
    }
399
    //Get white space index (delimiter)
400
    int indexOfWhiteSpace = nameSpaceAndLocation.lastIndexOf(WHITESPACESTRING);
401
    if (indexOfWhiteSpace != -1)
402
    {
403
      // before white space is namespace
404
      nameSpace = nameSpaceAndLocation.substring(0,indexOfWhiteSpace);
405
      // after white sapce is schema location
406
      schemaLocation = nameSpaceAndLocation.substring(indexOfWhiteSpace+1);
407
      // Gebug message
408
      logMetacat.info("Namespace after parsing: " + nameSpace);
409
      logMetacat.info("Location after parsing: " + schemaLocation);
410
    } 
411
  }
412
  
413
  public static void main(String[] argus)
414
  {
415
     try
416
     {
417
       DBConnectionPool pool = DBConnectionPool.getInstance();
418
       // Print out a empty schema list
419
       SchemaLocationResolver schema = new SchemaLocationResolver();
420
       logMetacat.warn("Namespace and Location String: "+ 
421
                                schema.getNameSpaceAndLocationString());
422
       // input a schemalocation
423
       SchemaLocationResolver schema2 = new SchemaLocationResolver(
424
                                        "eml://ecoinformatics.org/eml-2.0.0 " +
425
                                "http://dev.nceas.ucsb.edu/tao/schema/eml.xsd");
426
       schema2.resolveNameSpace();
427
       // input a wrong name space location
428
       SchemaLocationResolver schema3 = new SchemaLocationResolver(
429
                                        "http://www.xm.org/schema/stmml " +
430
                              "http://dev.nceas.ucsb.edu/tao/schema/stmml.xsd");
431
       schema3.resolveNameSpace();
432
       // print out new schema list in db
433
       SchemaLocationResolver schema4 = new SchemaLocationResolver();
434
       logMetacat.warn("Namespace and Location String: "+ 
435
                                schema4.getNameSpaceAndLocationString());
436
     }
437
     catch(Exception e)
438
     {
439
       logMetacat.error("erorr in Schemalocation.main: " + 
440
                                e.getMessage());
441
     }
442
  }
443
}
(63-63/67)