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: jones $'
10
 *     '$Date: 2006-11-10 10:25:38 -0800 (Fri, 10 Nov 2006) $'
11
 * '$Revision: 3077 $'
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
/**
48
 * A database aware Class to handle schema location. If namespace is in the
49
 * xml_catalog table (public_id), the schema location specified in xml document
50
 * will be ignored by parser setting external schema location. If the
51
 * name space is not in the table, it will be download to metacat and register
52
 * in table
53
 */
54
public class SchemaLocationResolver
55
{
56
  
57
  private String nameSpace = null; //public id
58
  private String schemaLocation = null; // system id
59
  private Vector nameSpaceList = new Vector();// name space in the table
60
  private String nameSpaceAndLocationString = null; // the parameter will be set
61
                                              // in external property in parser
62
  //private String schemaFileName = null;
63
  // constant
64
  //private String SCHEMATYPE ="Schema"; 
65
  private String WHITESPACESTRING =" ";                                                         
66

    
67
  private static Logger logMetacat = Logger.getLogger(SchemaLocationResolver.class);
68

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

    
129
  /* This method will take look xml_catalog table and create a string look like
130
   * "namespace1 location namespacke2 location". This string will be set as 
131
   * a extenalschemalocation in SAX parser. Then when parser check the 
132
   * it will ignore the schema location specified by xml document
133
   */
134
  private void createNameSpaceAndLocationStringFromDB()
135
  {
136
    DBConnection conn = null;
137
    int serialNumber = -1;
138
    PreparedStatement pstmt = null;
139
    ResultSet result = null;
140
    String sql = "SELECT public_id, system_id FROM xml_catalog where " +
141
                 "entry_type ='" + DocumentImpl.SCHEMA +"'";
142
    try 
143
    {
144
      //check out DBConnection
145
      conn=DBConnectionPool.getDBConnection("SchemaLocationResl.createName");
146
      serialNumber=conn.getCheckOutSerialNumber();
147
      pstmt = conn.prepareStatement(sql);
148
      pstmt.execute();
149
      result = pstmt.getResultSet();
150
      
151
      // Get string for namespace and location form DB
152
      boolean hasRow = result.next();
153
      StringBuffer buffer = new StringBuffer();
154
      boolean firstTime = true;
155
      while (hasRow)
156
      {
157
        String namespace = result.getString(1);
158
        String location  = result.getString(2);
159
        String pairOfNameSpaceAndLocation = namespace + WHITESPACESTRING 
160
                                            +location;
161
        if (!firstTime)
162
        {
163
          buffer.append(WHITESPACESTRING);
164
        }
165
        buffer.append(pairOfNameSpaceAndLocation);
166
        firstTime = false;
167
        hasRow = result.next();
168
        
169
      }
170
      // give the buffer to the string if buffer has something in it
171
      if (buffer.length() != 0)
172
      {
173
        nameSpaceAndLocationString = buffer.toString();
174
      }
175
      result.close();
176
      pstmt.close();
177
    } 
178
    catch (SQLException e) 
179
    {
180
      logMetacat.error("schemaLocation.createNameSpaceAndLocationString: " + 
181
                         e.getMessage());
182
    }
183
    finally
184
    {
185
      try
186
      {
187
        pstmt.close();
188
      }//try
189
      catch (SQLException sqlE)
190
      {
191
        logMetacat.error("Error in schema.createNameSpaceAndLocation "
192
                                    + sqlE.getMessage());
193
      }//catch
194
      DBConnectionPool.returnDBConnection(conn, serialNumber);
195
    }//finally
196
    
197

    
198
  }
199

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

    
255
  /**
256
   * Upload new Schema located at outside URL to Metacat file system
257
   */
258
  private String uploadSchemaFromURL(InputStream istream) throws Exception
259
  {
260
   
261
    String schemaPath = MetaCatUtil.getOption("schemaPath");
262
    String schemaURL = MetaCatUtil.getOption("schemaURL");
263

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

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

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

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

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

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