org.apache.ojb.broker.metadata.RepositoryPersistor.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.ojb.broker.metadata.RepositoryPersistor.java

Source

package org.apache.ojb.broker.metadata;

/* Copyright 2002-2005 The Apache Software Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Date;

import org.apache.commons.lang.SerializationUtils;
import org.apache.commons.lang.SystemUtils;
import org.apache.ojb.broker.util.ClassHelper;
import org.apache.ojb.broker.util.configuration.Configurable;
import org.apache.ojb.broker.util.configuration.Configuration;
import org.apache.ojb.broker.util.configuration.ConfigurationException;
import org.apache.ojb.broker.util.configuration.impl.OjbConfigurator;
import org.apache.ojb.broker.util.logging.Logger;
import org.apache.ojb.broker.util.logging.LoggerFactory;
import org.xml.sax.ContentHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;

/**
 * This class is responsible for reading and writing DescriptorRepository objects
 * from and to persistent media.
 * Currently only XML file based persistence is supported.
 *
 * @author <a href="mailto:thma@apache.org">Thomas Mahler<a>
 * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
 * @version $Id: RepositoryPersistor.java,v 1.24.2.4 2005/12/21 22:26:11 tomdz Exp $
 */
public class RepositoryPersistor implements Configurable {
    // TODO: Refactoring of the metadata reading/handling?

    private static Logger log = LoggerFactory.getLogger(RepositoryPersistor.class);

    private static final String SER_FILE_SUFFIX = "serialized";
    private static final String SERIALIZED_REPOSITORY_PATH = "serializedRepositoryPath";

    private boolean useSerializedRepository = false;

    public RepositoryPersistor() {
        OjbConfigurator.getInstance().configure(this);
    }

    public void configure(Configuration pConfig) throws ConfigurationException {
        useSerializedRepository = ((MetadataConfiguration) pConfig).useSerializedRepository();
    }

    /**
     * Write the {@link DescriptorRepository} to the given output object.
     */
    public void writeToFile(DescriptorRepository repository, ConnectionRepository conRepository, OutputStream out) {
        RepositoryTags tags = RepositoryTags.getInstance();
        try {
            if (log.isDebugEnabled())
                log.debug("## Write repository file ##" + repository.toXML() + "## End of repository file ##");

            String eol = SystemUtils.LINE_SEPARATOR;
            StringBuffer buf = new StringBuffer();
            // 1. write XML header
            buf.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + eol);

            buf.append("<!DOCTYPE descriptor-repository SYSTEM \"repository.dtd\" >" + eol + eol);
            //            strReturn += "<!DOCTYPE descriptor-repository SYSTEM \"repository.dtd\" [" + eol;
            //            strReturn += "<!ENTITY database-metadata SYSTEM \""+ConnectionRepository.DATABASE_METADATA_FILENAME+"\">" + eol;
            //            strReturn += "<!ENTITY user SYSTEM \"repository_user.xml\">" + eol;
            //            strReturn += "<!ENTITY junit SYSTEM \"repository_junit.xml\">" + eol;
            //            strReturn += "<!ENTITY internal SYSTEM \"repository_internal.xml\"> ]>" + eol + eol;

            buf.append(
                    "<!-- OJB RepositoryPersistor generated this file on " + new Date().toString() + " -->" + eol);

            buf.append(tags.getOpeningTagNonClosingById(RepositoryElements.MAPPING_REPOSITORY) + eol);
            buf.append("  "
                    + tags.getAttribute(RepositoryElements.REPOSITORY_VERSION, DescriptorRepository.getVersion())
                    + eol);
            buf.append("  "
                    + tags.getAttribute(RepositoryElements.ISOLATION_LEVEL, repository.getIsolationLevelAsString())
                    + eol);
            buf.append(">" + eol);

            if (conRepository != null)
                buf.append(eol + eol + conRepository.toXML() + eol + eol);
            if (repository != null)
                buf.append(repository.toXML());

            buf.append(tags.getClosingTagById(RepositoryElements.MAPPING_REPOSITORY));

            PrintWriter pw = new PrintWriter(out);
            pw.print(buf.toString());
            pw.flush();
            pw.close();
        } catch (Exception e) {
            log.error("Could not write to output stream" + out, e);
        }
    }

    /**
     * Read the repository configuration file.
     * <br>
     * If configuration property <code>useSerializedRepository</code> is <code>true</code>
     * all subsequent calls read a serialized version of the repository.
     * The directory where the serialized repository is stored can be specified
     * with the <code>serializedRepositoryPath</code> entry in OJB.properties.
     * Once a serialized repository is found changes to repository.xml will be
     * ignored. To force consideration of these changes the serialized repository
     * must be deleted manually.
     */
    public DescriptorRepository readDescriptorRepository(String filename)
            throws MalformedURLException, ParserConfigurationException, SAXException, IOException {
        DescriptorRepository result;
        if (useSerializedRepository)
        // use serialized repository
        {
            // build File object pointing to serialized repository location
            Configuration config = OjbConfigurator.getInstance().getConfigurationFor(null);
            String pathPrefix = config.getString(SERIALIZED_REPOSITORY_PATH, ".");
            File serFile = new File(pathPrefix + File.separator + filename + "." + SER_FILE_SUFFIX);

            if (serFile.exists() && serFile.length() > 0)
            // if file exists load serialized version of repository
            {
                try {
                    long duration = System.currentTimeMillis();
                    result = deserialize(serFile);
                    log.info("Read serialized repository in " + (System.currentTimeMillis() - duration) + " ms");
                } catch (Exception e) {
                    log.error("error in loading serialized repository. Will try to use XML version.", e);
                    result = (DescriptorRepository) buildRepository(filename, DescriptorRepository.class);
                }
            } else
            // if no serialized version exists, read it from xml and write serialized file
            {
                long duration = System.currentTimeMillis();
                result = (DescriptorRepository) buildRepository(filename, DescriptorRepository.class);
                log.info("Read repository from file took " + (System.currentTimeMillis() - duration) + " ms");
                serialize(result, serFile);
            }
        }
        // don't use serialized repository
        else {
            long duration = System.currentTimeMillis();
            result = (DescriptorRepository) buildRepository(filename, DescriptorRepository.class);
            log.info("Read class descriptors took " + (System.currentTimeMillis() - duration) + " ms");
        }
        return result;
    }

    public DescriptorRepository readDescriptorRepository(InputStream inst)
            throws MalformedURLException, ParserConfigurationException, SAXException, IOException {
        long duration = System.currentTimeMillis();
        InputSource inSource = new InputSource(inst);
        DescriptorRepository result = (DescriptorRepository) readMetadataFromXML(inSource,
                DescriptorRepository.class);
        log.info("Read class descriptors took " + (System.currentTimeMillis() - duration) + " ms");
        return result;
    }

    /**
     * Read the repository configuration file and extract connection handling information.
     */
    public ConnectionRepository readConnectionRepository(String filename)
            throws MalformedURLException, ParserConfigurationException, SAXException, IOException {
        long duration = System.currentTimeMillis();
        ConnectionRepository result = (ConnectionRepository) buildRepository(filename, ConnectionRepository.class);
        log.info("Read connection repository took " + (System.currentTimeMillis() - duration) + " ms");
        return result;
    }

    /**
     * Read the repository configuration file and extract connection handling information.
     */
    public ConnectionRepository readConnectionRepository(InputStream inst)
            throws MalformedURLException, ParserConfigurationException, SAXException, IOException {
        long duration = System.currentTimeMillis();
        InputSource inSource = new InputSource(inst);
        ConnectionRepository result = (ConnectionRepository) readMetadataFromXML(inSource,
                ConnectionRepository.class);
        log.info("Read connection repository took " + (System.currentTimeMillis() - duration) + " ms");
        return result;
    }

    protected DescriptorRepository deserialize(File serFile) {
        DescriptorRepository result = null;
        try {
            FileInputStream fis = new FileInputStream(serFile);
            // deserialize repository
            result = (DescriptorRepository) SerializationUtils.deserialize(fis);
        } catch (Exception e) {
            log.error("Deserialisation failed, using input path: " + serFile.getAbsolutePath(), e);
        }
        return result;
    }

    protected void serialize(DescriptorRepository repository, File file) {
        try {
            FileOutputStream fos = new FileOutputStream(file);
            // serialize repository
            SerializationUtils.serialize(repository, fos);
        } catch (Exception e) {
            log.error("Serialization failed, using output path: " + file.getAbsolutePath(), e);
        }
    }

    /**
     *
     * TODO: We should re-design the configuration file reading
     */
    private Object buildRepository(String repositoryFileName, Class targetRepository)
            throws MalformedURLException, ParserConfigurationException, SAXException, IOException {
        URL url = buildURL(repositoryFileName);
        /*
        arminw:
        strange, when using 'url.openStream()' argument repository
        could not be parsed
        ipriha:
        parser needs a base url to find referenced entities.
        */
        // InputSource source = new InputSource(url.openStream());

        String pathName = url.toExternalForm();

        log.info("Building repository from :" + pathName);
        InputSource source = new InputSource(pathName);
        URLConnection conn = url.openConnection();
        conn.setUseCaches(false);
        conn.connect();
        InputStream in = conn.getInputStream();
        source.setByteStream(in);
        try {
            return readMetadataFromXML(source, targetRepository);
        } finally {
            try {
                in.close();
            } catch (IOException x) {
                log.warn("unable to close repository input stream [" + x.getMessage() + "]", x);
            }
        }
    }

    /**
     * Read metadata by populating an instance of the target class
     * using SAXParser.
     */
    private Object readMetadataFromXML(InputSource source, Class target)
            throws MalformedURLException, ParserConfigurationException, SAXException, IOException {
        // TODO: make this configurable
        boolean validate = false;

        // get a xml reader instance:
        SAXParserFactory factory = SAXParserFactory.newInstance();
        log.info("RepositoryPersistor using SAXParserFactory : " + factory.getClass().getName());
        if (validate) {
            factory.setValidating(true);
        }
        SAXParser p = factory.newSAXParser();
        XMLReader reader = p.getXMLReader();
        if (validate) {
            reader.setErrorHandler(new OJBErrorHandler());
        }

        Object result;
        if (DescriptorRepository.class.equals(target)) {
            // create an empty repository:
            DescriptorRepository repository = new DescriptorRepository();
            // create handler for building the repository structure
            ContentHandler handler = new RepositoryXmlHandler(repository);
            // tell parser to use our handler:
            reader.setContentHandler(handler);
            reader.parse(source);
            result = repository;
        } else if (ConnectionRepository.class.equals(target)) {
            // create an empty repository:
            ConnectionRepository repository = new ConnectionRepository();
            // create handler for building the repository structure
            ContentHandler handler = new ConnectionDescriptorXmlHandler(repository);
            // tell parser to use our handler:
            reader.setContentHandler(handler);
            reader.parse(source);
            //LoggerFactory.getBootLogger().info("loading XML took " + (stop - start) + " msecs");
            result = repository;
        } else
            throw new MetadataException(
                    "Could not build a repository instance for '" + target + "', using source " + source);
        return result;
    }

    private URL buildURL(String repositoryFileName) throws MalformedURLException {
        //j2ee compliant lookup of resources
        URL url = ClassHelper.getResource(repositoryFileName);

        // don't be too strict: if resource is not on the classpath, try ordinary file lookup
        if (url == null) {
            try {
                url = new File(repositoryFileName).toURL();
            } catch (MalformedURLException ignore) {
            }
        }

        if (url != null) {
            log.info("OJB Descriptor Repository: " + url);
        } else {
            throw new MalformedURLException("did not find resource " + repositoryFileName);
        }
        return url;
    }

    // inner class
    class OJBErrorHandler implements ErrorHandler {
        public void warning(SAXParseException exception) throws SAXException {
            logMessage(exception, false);
        }

        public void error(SAXParseException exception) throws SAXException {
            logMessage(exception, false);
        }

        public void fatalError(SAXParseException exception) throws SAXException {
            logMessage(exception, true);
        }

        void logMessage(SAXParseException e, boolean isFatal) {
            String msg = e.getMessage();
            if (isFatal) {
                log.error("## " + e.getSystemId() + " - line " + e.getLineNumber() + ": " + msg + " ##");
            } else {
                log.warn(e.getSystemId() + " - line " + e.getLineNumber() + ": " + msg);
            }
        }
    }
}