Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you 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. /
 
 
 package org.apache.cayenne.pref;
 
 import java.io.File;
 
 
An implementation of preference service that stores the data using embedded HSQL DB database with Cayenne.

Author(s):
Andrei Adamchik
 
 
     protected File dbDirectory;
     protected String baseName;
     protected String masterBaseName;
     protected String cayenneConfigPackage;

    
Creates a new PreferenceService that stores preferences using Cayenne and embedded HSQLDB engine.

Parameters:
dbLocation path to an HSQL db.
cayenneConfigPackage a Java package that holds cayenne.xml for preferences access (can be null)
defaultDomain root domain name for this service.
 
     public HSQLEmbeddedPreferenceService(String dbLocationString cayenneConfigPackage,
             String defaultDomain) {
         super(defaultDomain);
         if (dbLocation == null) {
             throw new PreferenceException("Null DB location.");
         }
 
         File file = new File(dbLocation);
 
         this. = file.getParentFile();
         this. = file.getName();
         this. = cayenneConfigPackage;
     }

    
If true, this service updates a secondary HSQL instance that may need synchronization with master.
 
     public boolean isSecondaryDB() {
         return !Util.nullSafeEquals();
     }
 
     public File getMasterLock() {
         return new File( + ".lck");
     }

    
Creates a separate Cayenne stack used to work with preferences database only, so that any other use of Cayenne in the app is not affected.
 
     public void startService() {
         // use custom DataSourceFactory to prepare the DB...
         HSQLDataSourceFactory dataSourceFactory = new HSQLDataSourceFactory();
 
         DefaultConfiguration config = new DefaultConfiguration();
         config.setDataSourceFactory(dataSourceFactory);
 
         if ( != null) {
            config.addClassPath();
        }
        try {
            config.initialize();
        }
        catch (Exception ex) {
            throw new CayenneRuntimeException("Error connecting to preference DB."ex);
        }
        config.didInitialize();
         = config.getDomain().createDataContext();
        // create DB if it does not exist...
        if (dataSourceFactory.needSchemaUpdate && !upgradeDB()) {
            initSchema();
        }
        // bootstrap our own preferences...
        initPreferences();
        // start save timer...
        startTimer();
    }
    public void stopService() {
        if ( != null) {
            .cancel();
        }
        if ( != null) {
            // flush changes...
            savePreferences();
            // shutdown HSQL
            
                    .performNonSelectingQuery(new SQLTemplate(Domain.class"SHUTDOWN"));
            // shutdown Cayenne
            .getParentDataDomain().shutdown();
        }
        // attempt to sync primary DB...
        if (isSecondaryDB()) {
            File lock = getMasterLock();
            if (!lock.exists()) {
                // TODO: according to JavaDoc this is not reliable enough...
                // Investigate HSQL API for a better solution.
                try {
                    if (lock.createNewFile()) {
                        try {
                            moveDB();
                        }
                        finally {
                            lock.delete();
                        }
                    }
                }
                catch (Throwable th) {
                    throw new PreferenceException(
                            "Error shutting down database. Preferences may be in invalid state.");
                }
            }
        }
    }

    
Copies database with older version.
    boolean upgradeDB() {
        String versionName = .getName();
        File prefsDir = .getParentFile();
        String[] prefs = prefsDir.list();
        if (prefs == null || prefs.length == 0) {
            return false;
        }
        // find older version
        Version currentVersion = new Version(versionName);
        Version previousVersion = new Version("0");
        File lastDir = null;
        for (int i = 0; i < prefs.lengthi++) {
            File dir = new File(prefsDirprefs[i]);
            if (dir.isDirectory() && new File(dir + ".properties").isFile()) {
                // check that there are DB files
                Version v;
                try {
                    v = new Version(prefs[i]);
                }
                catch (NumberFormatException nfex) {
                    // ignore... not a version dir...
                    continue;
                }
                if (v.compareTo(currentVersion) < 0 && v.compareTo(previousVersion) > 0) {
                    previousVersion = v;
                    lastDir = dir;
                }
            }
        }
        if (lastDir != null) {
            copyDB(lastDir);
            return true;
        }
        return false;
    }

    
Copies one database to another. Caller must provide HSQLDB locks on target for this to work reliably.
    void moveDB(String masterBaseNameString targetBaseName) {
        File[] filesToMove = .listFiles(new HSQLDBFileFilter(masterBaseName));
        if (filesToMove != null) {
            for (int i = 0; i < filesToMove.lengthi++) {
                String ext = Util.extractFileExtension(filesToMove[i].getName());
                File target = new File(targetBaseName + "." + ext);
                if (filesToMove[i].exists()) {
                    filesToMove[i].renameTo(target);
                }
                else {
                    target.delete();
                }
            }
        }
    }

    
Copies one database to another. Caller must provide HSQLDB locks for this to work reliably.
    void copyDB(String masterBaseNameString targetBaseName) {
        copyDB(masterBaseNametargetBaseName);
    }
    void copyDB(File sourceDirectoryString masterBaseNameString targetBaseName) {
        File[] filesToCopy = sourceDirectory.listFiles(new HSQLDBFileFilter(
                masterBaseName));
        if (filesToCopy != null) {
            for (int i = 0; i < filesToCopy.lengthi++) {
                String ext = Util.extractFileExtension(filesToCopy[i].getName());
                File target = new File(targetBaseName + "." + ext);
                if (filesToCopy[i].exists()) {
                    Util.copy(filesToCopy[i], target);
                }
                else {
                    target.delete();
                }
            }
        }
    }
    // filers HSQLDB files
    final class HSQLDBFileFilter implements FileFilter {
        String baseName;
        HSQLDBFileFilter(String baseName) {
            this. = baseName;
        }
        public boolean accept(File pathname) {
            if (!pathname.isFile()) {
                return false;
            }
            String fullName = pathname.getName();
            if (fullName.endsWith(".lck")) {
                return false;
            }
            int dot = fullName.indexOf('.');
            String name = (dot > 0) ? fullName.substring(0, dot) : fullName;
            return .equals(name);
        }
    }
    // addresses various issues with embedded database...
    final class HSQLDataSourceFactory implements DataSourceFactory {
        boolean needSchemaUpdate;
        String url;
        void prepareDB() throws IOException {
            // try master DB
            if (checkMainDB()) {
                return;
            }
            // try last active DB
            if ( != null && checkMainDB()) {
                return;
            }
            // file locked... need to switch to a secondary DB
            // arbitrary big but finite number of attempts...
            for (int i = 1; i < 200; i++) {
                String name =  + i;
                File lock = new File(name + ".lck");
                if (!lock.exists()) {
                    // TODO: according to JavaDoc this is not reliable enough...
                    // Investigate HSQL API for a better solution.
                    if (!lock.createNewFile()) {
                        continue;
                    }
                    try {
                        copyDB(name);
                    }
                    finally {
                        lock.delete();
                    }
                     = false;
                     = "jdbc:hsqldb:file:"
                            + Util.substBackslashes(new File(name)
                                    .getAbsolutePath());
                     = name;
                    return;
                }
            }
            throw new IOException("Can't create preferences DB");
        }
        boolean checkMainDB(String sessionBaseName) {
            File dbFile = new File(sessionBaseName + ".properties");
            // no db file exists
            if (!dbFile.exists()) {
                 = true;
                 = "jdbc:hsqldb:file:"
                        + Util.substBackslashes(new File(sessionBaseName)
                                .getAbsolutePath());
                 = sessionBaseName;
                return true;
            }
            // no lock exists... continue...
            File lockFile = new File(sessionBaseName + ".lck");
            // on Windows try deleting the lock... OS locking should prevent
            // this operation if another process is running...
            if (lockFile.exists()
                    && System.getProperty("os.name").toLowerCase().indexOf("windows") >= 0) {
                lockFile.delete();
            }
            if (!lockFile.exists()) {
                 = false;
                 = "jdbc:hsqldb:file:"
                        + Util.substBackslashes(new File(sessionBaseName)
                                .getAbsolutePath());
                 = sessionBaseName;
                return true;
            }
            return false;
        }

        

Deprecated:
since 1.2
        public DataSource getDataSource(String locationLevel logLevelthrows Exception {
            return getDataSource(location);
        }
        public DataSource getDataSource(String locationthrows Exception {
            try {
                prepareDB();
                PoolManager pm = new PoolManager(
                        org.hsqldb.jdbcDriver.class.getName(),
                        ,
                        1,
                        1,
                        "sa",
                        null,
                        new ConnectionLogger());
                return pm;
            }
            catch (Throwable th) {
                QueryLogger.logConnectFailure(th);
                throw new PreferenceException("Error connecting to DB"th);
            }
        }
        public void initializeWithParentConfiguration(Configuration conf) {
        }
    }
New to GrepCode? Check out our FAQ X