Coverage Report - org.apache.ojb.broker.metadata.RepositoryPersistor
 
Classes in this File Line Coverage Branch Coverage Complexity
RepositoryPersistor
N/A
N/A
2.375
RepositoryPersistor$OJBErrorHandler
N/A
N/A
2.375
 
 1  
 package org.apache.ojb.broker.metadata;
 2  
 
 3  
 /* Copyright 2002-2005 The Apache Software Foundation
 4  
  *
 5  
  * Licensed under the Apache License, Version 2.0 (the "License");
 6  
  * you may not use this file except in compliance with the License.
 7  
  * You may obtain a copy of the License at
 8  
  *
 9  
  *     http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 
 18  
 import javax.xml.parsers.ParserConfigurationException;
 19  
 import javax.xml.parsers.SAXParser;
 20  
 import javax.xml.parsers.SAXParserFactory;
 21  
 import java.io.File;
 22  
 import java.io.FileInputStream;
 23  
 import java.io.FileOutputStream;
 24  
 import java.io.IOException;
 25  
 import java.io.InputStream;
 26  
 import java.io.OutputStream;
 27  
 import java.io.PrintWriter;
 28  
 import java.net.MalformedURLException;
 29  
 import java.net.URL;
 30  
 import java.net.URLConnection;
 31  
 import java.util.Date;
 32  
 
 33  
 import org.apache.commons.lang.SerializationUtils;
 34  
 import org.apache.commons.lang.SystemUtils;
 35  
 import org.apache.ojb.broker.util.ClassHelper;
 36  
 import org.apache.ojb.broker.util.configuration.Configurable;
 37  
 import org.apache.ojb.broker.util.configuration.Configuration;
 38  
 import org.apache.ojb.broker.util.configuration.ConfigurationException;
 39  
 import org.apache.ojb.broker.util.configuration.impl.OjbConfigurator;
 40  
 import org.apache.ojb.broker.util.logging.Logger;
 41  
 import org.apache.ojb.broker.util.logging.LoggerFactory;
 42  
 import org.xml.sax.ContentHandler;
 43  
 import org.xml.sax.ErrorHandler;
 44  
 import org.xml.sax.InputSource;
 45  
 import org.xml.sax.SAXException;
 46  
 import org.xml.sax.SAXParseException;
 47  
 import org.xml.sax.XMLReader;
 48  
 
 49  
 /**
 50  
  * This class is responsible for reading and writing DescriptorRepository objects
 51  
  * from and to persistent media.
 52  
  * Currently only XML file based persistence is supported.
 53  
  *
 54  
  * @author <a href="mailto:thma@apache.org">Thomas Mahler<a>
 55  
  * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
 56  
  * @version $Id: RepositoryPersistor.java,v 1.1 2007-08-24 22:17:29 ewestfal Exp $
 57  
  */
 58  
 public class RepositoryPersistor implements Configurable
 59  
 {
 60  
     // TODO: Refactoring of the metadata reading/handling?
 61  
 
 62  
     private static Logger log = LoggerFactory.getLogger(RepositoryPersistor.class);
 63  
 
 64  
     private static final String SER_FILE_SUFFIX = "serialized";
 65  
     private static final String SERIALIZED_REPOSITORY_PATH = "serializedRepositoryPath";
 66  
 
 67  
     private boolean useSerializedRepository = false;
 68  
 
 69  
     public RepositoryPersistor()
 70  
     {
 71  
         OjbConfigurator.getInstance().configure(this);
 72  
     }
 73  
 
 74  
     public void configure(Configuration pConfig) throws ConfigurationException
 75  
     {
 76  
         useSerializedRepository = ((MetadataConfiguration) pConfig).useSerializedRepository();
 77  
     }
 78  
 
 79  
     /**
 80  
      * Write the {@link DescriptorRepository} to the given output object.
 81  
      */
 82  
     public void writeToFile(DescriptorRepository repository, ConnectionRepository conRepository, OutputStream out)
 83  
     {
 84  
         RepositoryTags tags = RepositoryTags.getInstance();
 85  
         try
 86  
         {
 87  
             if (log.isDebugEnabled())
 88  
                 log.debug("## Write repository file ##" +
 89  
                         repository.toXML() +
 90  
                         "## End of repository file ##");
 91  
 
 92  
 
 93  
             String eol = SystemUtils.LINE_SEPARATOR;
 94  
             StringBuffer buf = new StringBuffer();
 95  
             // 1. write XML header
 96  
             buf.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + eol);
 97  
 
 98  
             buf.append("<!DOCTYPE descriptor-repository SYSTEM \"repository.dtd\" >" + eol + eol);
 99  
 //            strReturn += "<!DOCTYPE descriptor-repository SYSTEM \"repository.dtd\" [" + eol;
 100  
 //            strReturn += "<!ENTITY database-metadata SYSTEM \""+ConnectionRepository.DATABASE_METADATA_FILENAME+"\">" + eol;
 101  
 //            strReturn += "<!ENTITY user SYSTEM \"repository_user.xml\">" + eol;
 102  
 //            strReturn += "<!ENTITY junit SYSTEM \"repository_junit.xml\">" + eol;
 103  
 //            strReturn += "<!ENTITY internal SYSTEM \"repository_internal.xml\"> ]>" + eol + eol;
 104  
 
 105  
             buf.append("<!-- OJB RepositoryPersistor generated this file on " + new Date().toString() + " -->" + eol);
 106  
 
 107  
             buf.append(tags.getOpeningTagNonClosingById(RepositoryElements.MAPPING_REPOSITORY) + eol);
 108  
             buf.append("  " + tags.getAttribute(RepositoryElements.REPOSITORY_VERSION, DescriptorRepository.getVersion()) + eol);
 109  
             buf.append("  " + tags.getAttribute(RepositoryElements.ISOLATION_LEVEL, repository.getIsolationLevelAsString()) + eol);
 110  
             buf.append(">" + eol);
 111  
 
 112  
             if(conRepository != null) buf.append(eol + eol + conRepository.toXML() + eol + eol);
 113  
             if(repository != null) buf.append(repository.toXML());
 114  
 
 115  
             buf.append(tags.getClosingTagById(RepositoryElements.MAPPING_REPOSITORY));
 116  
 
 117  
             PrintWriter pw = new PrintWriter(out);
 118  
             pw.print(buf.toString());
 119  
             pw.flush();
 120  
             pw.close();
 121  
         }
 122  
         catch (Exception e)
 123  
         {
 124  
             log.error("Could not write to output stream" + out, e);
 125  
         }
 126  
     }
 127  
 
 128  
     /**
 129  
      * Read the repository configuration file.
 130  
      * <br>
 131  
      * If configuration property <code>useSerializedRepository</code> is <code>true</code>
 132  
      * all subsequent calls read a serialized version of the repository.
 133  
      * The directory where the serialized repository is stored can be specified
 134  
      * with the <code>serializedRepositoryPath</code> entry in OJB.properties.
 135  
      * Once a serialized repository is found changes to repository.xml will be
 136  
      * ignored. To force consideration of these changes the serialized repository
 137  
      * must be deleted manually.
 138  
      */
 139  
     public DescriptorRepository readDescriptorRepository(String filename)
 140  
             throws MalformedURLException, ParserConfigurationException, SAXException, IOException
 141  
     {
 142  
         DescriptorRepository result;
 143  
         if (useSerializedRepository)
 144  
         // use serialized repository
 145  
         {
 146  
             // build File object pointing to serialized repository location
 147  
             Configuration config = OjbConfigurator.getInstance().getConfigurationFor(null);
 148  
             String pathPrefix = config.getString(SERIALIZED_REPOSITORY_PATH, ".");
 149  
             File serFile = new File(pathPrefix + File.separator + filename + "." + SER_FILE_SUFFIX);
 150  
 
 151  
             if (serFile.exists() && serFile.length() > 0)
 152  
             // if file exists load serialized version of repository
 153  
             {
 154  
                 try
 155  
                 {
 156  
                     long duration = System.currentTimeMillis();
 157  
                     result = deserialize(serFile);
 158  
                     log.info("Read serialized repository in " + (System.currentTimeMillis() - duration) + " ms");
 159  
                 }
 160  
                 catch (Exception e)
 161  
                 {
 162  
                     log.error("error in loading serialized repository. Will try to use XML version.", e);
 163  
                     result = (DescriptorRepository) buildRepository(filename, DescriptorRepository.class);
 164  
                 }
 165  
             }
 166  
             else
 167  
             // if no serialized version exists, read it from xml and write serialized file
 168  
             {
 169  
                 long duration = System.currentTimeMillis();
 170  
                 result = (DescriptorRepository) buildRepository(filename, DescriptorRepository.class);
 171  
                 log.info("Read repository from file took " + (System.currentTimeMillis() - duration) + " ms");
 172  
                 serialize(result, serFile);
 173  
             }
 174  
         }
 175  
         // don't use serialized repository
 176  
         else
 177  
         {
 178  
             long duration = System.currentTimeMillis();
 179  
             result = (DescriptorRepository) buildRepository(filename, DescriptorRepository.class);
 180  
             log.info("Read class descriptors took " + (System.currentTimeMillis() - duration) + " ms");
 181  
         }
 182  
         return result;
 183  
     }
 184  
 
 185  
     public DescriptorRepository readDescriptorRepository(InputStream inst)
 186  
             throws MalformedURLException, ParserConfigurationException, SAXException, IOException
 187  
     {
 188  
         long duration = System.currentTimeMillis();
 189  
         InputSource inSource = new InputSource(inst);
 190  
         DescriptorRepository result = (DescriptorRepository) readMetadataFromXML(inSource, DescriptorRepository.class);
 191  
         log.info("Read class descriptors took " + (System.currentTimeMillis() - duration) + " ms");
 192  
         return result;
 193  
     }
 194  
 
 195  
     /**
 196  
      * Read the repository configuration file and extract connection handling information.
 197  
      */
 198  
     public ConnectionRepository readConnectionRepository(String filename)
 199  
             throws MalformedURLException, ParserConfigurationException, SAXException, IOException
 200  
     {
 201  
         long duration = System.currentTimeMillis();
 202  
         ConnectionRepository result = (ConnectionRepository) buildRepository(filename, ConnectionRepository.class);
 203  
         log.info("Read connection repository took " + (System.currentTimeMillis() - duration) + " ms");
 204  
         return result;
 205  
     }
 206  
 
 207  
     /**
 208  
      * Read the repository configuration file and extract connection handling information.
 209  
      */
 210  
     public ConnectionRepository readConnectionRepository(InputStream inst)
 211  
             throws MalformedURLException, ParserConfigurationException, SAXException, IOException
 212  
     {
 213  
         long duration = System.currentTimeMillis();
 214  
         InputSource inSource = new InputSource(inst);
 215  
         ConnectionRepository result = (ConnectionRepository) readMetadataFromXML(inSource, ConnectionRepository.class);
 216  
         log.info("Read connection repository took " + (System.currentTimeMillis() - duration) + " ms");
 217  
         return result;
 218  
     }
 219  
 
 220  
     protected DescriptorRepository deserialize(File serFile)
 221  
     {
 222  
         DescriptorRepository result = null;
 223  
         try
 224  
         {
 225  
             FileInputStream fis = new FileInputStream(serFile);
 226  
             // deserialize repository
 227  
             result = (DescriptorRepository) SerializationUtils.deserialize(fis);
 228  
         }
 229  
         catch (Exception e)
 230  
         {
 231  
             log.error("Deserialisation failed, using input path: " + serFile.getAbsolutePath(), e);
 232  
         }
 233  
         return result;
 234  
     }
 235  
 
 236  
     protected void serialize(DescriptorRepository repository, File file)
 237  
     {
 238  
         try
 239  
         {
 240  
             FileOutputStream fos = new FileOutputStream(file);
 241  
             // serialize repository
 242  
             SerializationUtils.serialize(repository, fos);
 243  
         }
 244  
         catch (Exception e)
 245  
         {
 246  
             log.error("Serialization failed, using output path: " + file.getAbsolutePath(), e);
 247  
         }
 248  
     }
 249  
 
 250  
     /**
 251  
      *
 252  
      * TODO: We should re-design the configuration file reading
 253  
      */
 254  
     private Object buildRepository(String repositoryFileName, Class targetRepository)
 255  
             throws MalformedURLException, ParserConfigurationException, SAXException, IOException
 256  
     {
 257  
         URL url = buildURL(repositoryFileName);
 258  
         /*
 259  
         arminw:
 260  
         strange, when using 'url.openStream()' argument repository
 261  
         could not be parsed
 262  
         ipriha:
 263  
         parser needs a base url to find referenced entities.
 264  
         */
 265  
         // InputSource source = new InputSource(url.openStream());
 266  
         
 267  
         String pathName = url.toExternalForm();
 268  
 
 269  
         log.info("Building repository from :" + pathName);
 270  
         InputSource source = new InputSource(pathName);
 271  
         URLConnection conn = url.openConnection();
 272  
         conn.setUseCaches(false);
 273  
         conn.connect();
 274  
         InputStream in = conn.getInputStream();
 275  
         source.setByteStream(in);
 276  
         try
 277  
                 {
 278  
                 return readMetadataFromXML(source, targetRepository);
 279  
                 }
 280  
         finally
 281  
                 {
 282  
                 try
 283  
                         {
 284  
                         in.close();
 285  
                         }
 286  
                 catch (IOException x)
 287  
                         {
 288  
                 log.warn("unable to close repository input stream [" + x.getMessage() + "]", x);
 289  
                         }
 290  
                 }
 291  
     }
 292  
 
 293  
     /**
 294  
      * Read metadata by populating an instance of the target class
 295  
      * using SAXParser.
 296  
      */
 297  
     private Object readMetadataFromXML(InputSource source, Class target)
 298  
             throws MalformedURLException, ParserConfigurationException, SAXException, IOException
 299  
     {
 300  
         // TODO: make this configurable
 301  
         boolean validate = false;
 302  
         
 303  
         // get a xml reader instance:
 304  
         SAXParserFactory factory = SAXParserFactory.newInstance();
 305  
         log.info("RepositoryPersistor using SAXParserFactory : " + factory.getClass().getName());
 306  
         if (validate)
 307  
         {
 308  
             factory.setValidating(true);
 309  
         }
 310  
         SAXParser p = factory.newSAXParser();
 311  
         XMLReader reader = p.getXMLReader();
 312  
         if (validate)
 313  
         {
 314  
             reader.setErrorHandler(new OJBErrorHandler());
 315  
         }
 316  
 
 317  
         Object result;
 318  
         if (DescriptorRepository.class.equals(target))
 319  
         {
 320  
             // create an empty repository:
 321  
             DescriptorRepository repository = new DescriptorRepository();
 322  
             // create handler for building the repository structure
 323  
             ContentHandler handler = new RepositoryXmlHandler(repository);
 324  
             // tell parser to use our handler:
 325  
             reader.setContentHandler(handler);
 326  
             reader.parse(source);
 327  
             result = repository;
 328  
         }
 329  
         else if (ConnectionRepository.class.equals(target))
 330  
         {
 331  
             // create an empty repository:
 332  
             ConnectionRepository repository = new ConnectionRepository();
 333  
             // create handler for building the repository structure
 334  
             ContentHandler handler = new ConnectionDescriptorXmlHandler(repository);
 335  
             // tell parser to use our handler:
 336  
             reader.setContentHandler(handler);
 337  
             reader.parse(source);
 338  
             //LoggerFactory.getBootLogger().info("loading XML took " + (stop - start) + " msecs");
 339  
             result = repository;
 340  
         }
 341  
         else
 342  
             throw new MetadataException("Could not build a repository instance for '" + target +
 343  
                     "', using source " + source);
 344  
         return result;
 345  
     }
 346  
 
 347  
     private URL buildURL(String repositoryFileName) throws MalformedURLException
 348  
     {
 349  
         //j2ee compliant lookup of resources
 350  
         URL url = ClassHelper.getResource(repositoryFileName);
 351  
 
 352  
         // don't be too strict: if resource is not on the classpath, try ordinary file lookup
 353  
         if (url == null)
 354  
         {
 355  
             try
 356  
             {
 357  
                 url = new File(repositoryFileName).toURL();
 358  
             }
 359  
             catch (MalformedURLException ignore)
 360  
             {
 361  
             }
 362  
         }
 363  
 
 364  
         if (url != null)
 365  
         {
 366  
             log.info("OJB Descriptor Repository: " + url);
 367  
         }
 368  
         else
 369  
         {
 370  
             throw new MalformedURLException("did not find resource " + repositoryFileName);
 371  
         }
 372  
         return url;
 373  
     }
 374  
 
 375  
     // inner class
 376  
     class OJBErrorHandler implements ErrorHandler
 377  
     {
 378  
         public void warning(SAXParseException exception)
 379  
                 throws SAXException
 380  
         {
 381  
             logMessage(exception, false);
 382  
         }
 383  
 
 384  
         public void error(SAXParseException exception)
 385  
                 throws SAXException
 386  
         {
 387  
             logMessage(exception, false);
 388  
         }
 389  
 
 390  
         public void fatalError(SAXParseException exception)
 391  
                 throws SAXException
 392  
         {
 393  
             logMessage(exception, true);
 394  
         }
 395  
 
 396  
         void logMessage(SAXParseException e, boolean isFatal)
 397  
         {
 398  
             String msg = e.getMessage();
 399  
             if (isFatal)
 400  
             {
 401  
                 log.error("## " + e.getSystemId() + " - line " + e.getLineNumber() +  ": " + msg + " ##");
 402  
             }
 403  
             else
 404  
             {
 405  
                 log.warn(e.getSystemId() + " - line " + e.getLineNumber() + ": " + msg);
 406  
             }
 407  
         }
 408  
     }
 409  
 }