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
 *    Release: @release@
9
 *
10
 *   '$Author: sgarg $'
11
 *     '$Date: 2005-10-10 11:06:55 -0700 (Mon, 10 Oct 2005) $'
12
 * '$Revision: 2663 $'
13
 *
14
 * This program is free software; you can redistribute it and/or modify
15
 * it under the terms of the GNU General Public License as published by
16
 * the Free Software Foundation; either version 2 of the License, or
17
 * (at your option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 * GNU General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU General Public License
25
 * along with this program; if not, write to the Free Software
26
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27
 */
28

    
29
package edu.ucsb.nceas.metacat;
30

    
31

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

    
46
import org.apache.log4j.Logger;
47

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

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

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

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

    
199
  }
200

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

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

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

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

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

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

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

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