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: tao $'
10
 *     '$Date: 2008-09-29 18:23:24 -0700 (Mon, 29 Sep 2008) $'
11
 * '$Revision: 4409 $'
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
  private boolean downloadNewSchema = false;
70

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

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

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

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

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

    
201
	}
202

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

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

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

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

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

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

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

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