All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.modules.derby.DerbyOptions Maven / Gradle / Ivy

The newest version!
/*
 * 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.netbeans.modules.derby;

import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.netbeans.api.db.explorer.DatabaseException;
import org.netbeans.api.db.explorer.JDBCDriver;
import org.netbeans.api.db.explorer.JDBCDriverManager;
import org.openide.filesystems.FileLock;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileStateInvalidException;
import org.openide.filesystems.FileSystem;
import org.openide.filesystems.FileUtil;
import org.openide.filesystems.URLMapper;
import org.openide.modules.InstalledFileLocator;
import org.openide.nodes.BeanNode;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.openide.util.NbPreferences;

/**
 *
 * @author Andrei Badea
 */
public class DerbyOptions {

    private static final Logger LOGGER = Logger.getLogger(DerbyOptions.class.getName());

    private static final DerbyOptions INSTANCE = new DerbyOptions();

    /**
     * This system property allows setting a default value for the Derby system home directory.
     * Its value will be returned by the {@link getSystemHome} method if the
     * systemHome property is null. See issue 76908.
     */
    public static final String NETBEANS_DERBY_SYSTEM_HOME = "netbeans.derby.system.home"; // NOI18N

    static final String PROP_DERBY_LOCATION = "location"; // NOI18N
    static final String PROP_DERBY_SYSTEM_HOME = "systemHome"; // NOI18N

    static final String INST_DIR = "db-derby-10.14.2.0"; // NOI18N

    public static final String DRIVER_CLASS_NET = "org.apache.derby.jdbc.ClientDriver"; // NOI18N
    public static final String DRIVER_CLASS_NET_MODULAR = "org.apache.derby.client.ClientAutoloadedDriver"; // NOI18N
    public static final String DRIVER_CLASS_EMBEDDED = "org.apache.derby.jdbc.EmbeddedDriver"; // NOI18N
    public static final String DRIVER_CLASS_EMBEDDED_MODULAR = "org.apache.derby.iapi.jdbc.AutoloadedDriver"; // NOI18N

    private static final String DRIVER_PATH_NET = "lib/derbyclient.jar"; // NOI18N
    private static final String DRIVER_PATH_EMBEDDED = "lib/derby.jar"; // NOI18N

    // XXX these should actually be localized, but we'd have to localize
    // DriverListUtil in the db module first
    public static final String DRIVER_DISP_NAME_NET = "Java DB (Network)"; // NOI18N
    public static final String DRIVER_DISP_NAME_EMBEDDED = "Java DB (Embedded)"; // NOI18N

    private static final String DRIVER_NAME_NET = "apache_derby_net"; // NOI18N
    private static final String DRIVER_NAME_EMBEDDED = "apache_derby_embedded"; // NOI18N

    public static DerbyOptions getDefault() {
        return INSTANCE;
    }

    protected final String putProperty(String key, String value, boolean notify) {
        String retval = NbPreferences.forModule(DerbyOptions.class).get(key, null);
        if (value != null) {
            // LOGGER.log(Level.FINE, "Setting property {0} to {1}", key, value); // NOI18N
            NbPreferences.forModule(DerbyOptions.class).put(key, value);
        } else {
            // LOGGER.log(Level.FINE, "Removing property {0}", key); // NOI18N
            NbPreferences.forModule(DerbyOptions.class).remove(key);
        }
        return retval;
    }

    protected final String getProperty(String key) {
        return NbPreferences.forModule(DerbyOptions.class).get(key, null);
    }

    public String displayName() {
        return NbBundle.getMessage(DerbyOptions.class, "LBL_DerbyOptions");
    }

    /**
     * Returns the Derby location or an empty string if the Derby location
     * is not set. Never returns null.
     */
    public String getLocation() {
        DerbyActivator.activate();
        String location = getProperty(PROP_DERBY_LOCATION);
        if (location == null) {
            location = ""; // NOI18N
        }
        Logger.getLogger(DerbyOptions.class.getName()).finest("Derby location is " + location);
        return location;
    }

    private String getCurrentLocation() {
        String location = getProperty(PROP_DERBY_LOCATION);
        if (location == null) {
            location = ""; // NOI18N
        }
        return location;
    }

    /**
     * Returns true if the Derby location is null. This method is needed
     * since getLocation() will never return a null value.
     */
    public boolean isLocationNull() {
        return getProperty(PROP_DERBY_LOCATION) == null;
    }

    /**
     * Sets the Derby location.
     *
     * @param location the Derby location. A null value is valid and
     *        will be returned by getLocation() as an empty
     *        string (meaning "not set"). An empty string is valid
     *        and has the meaning "set to the default location".
     */
    public void setLocation(String location) {
        if (location !=  null && location.length() > 0) {
            File locationFile = new File(location).getAbsoluteFile();
            if (!locationFile.exists()) {
                String message = NbBundle.getMessage(DerbyOptions.class, "ERR_DirectoryDoesNotExist", locationFile);
                IllegalArgumentException e = new IllegalArgumentException(message);
                Exceptions.attachLocalizedMessage(e, message);
                throw e;
            }
            if (!Util.isDerbyInstallLocation(locationFile)) {
                String message = NbBundle.getMessage(DerbyOptions.class, "ERR_InvalidDerbyLocation", locationFile);
                IllegalArgumentException e = new IllegalArgumentException(message);
                Exceptions.attachLocalizedMessage(e, message);
                throw e;
            }
        }

        synchronized (this) {
            stopDerbyServer();
            if (location != null && location.length() <= 0) {
                location = getDefaultInstallLocation();
            }
            registerDrivers(location);
            registerLibrary(location);
            LOGGER.log(Level.FINE, "Setting location to {0}", location); // NOI18N
            putProperty(PROP_DERBY_LOCATION, location, true);
        }
    }

    public synchronized boolean trySetLocation(String location) {
        LOGGER.log(Level.FINE, "trySetLocation: Trying to set location to {0}", location); // NOI18N
        String current = getCurrentLocation();
        if (current.length() == 0) {
            setLocation(location);
            LOGGER.fine("trysetLocation: Succeeded"); // NOI18N
            return true;
        }
        File currentFile = new File(current);
        if (!currentFile.exists() || currentFile.isFile()) {
             setLocation(location);
             LOGGER.fine("trysetLocation: correcting"); // NOI18N
             return true;                
        }
        LOGGER.fine("trySetLocation: Another location already set"); // NOI18N
        return false;
    }

    /**
     * Returns the Derby system home or an empty string if the system home
     * is not set. Never returns null.
     */
    public String getSystemHome() {
        String systemHome = getProperty(PROP_DERBY_SYSTEM_HOME);
        if (systemHome == null) {
            systemHome = System.getProperty(NETBEANS_DERBY_SYSTEM_HOME);
        }
        if (systemHome == null) {
            systemHome = ""; // NOI18N
        }
        return systemHome;
    }

    public void setSystemHome(String derbySystemHome) {
        if (derbySystemHome != null && derbySystemHome.length() > 0) {
            File derbySystemHomeFile = new File(derbySystemHome).getAbsoluteFile();
            if (!derbySystemHomeFile.exists() || !derbySystemHomeFile.isDirectory()) {
                String message = NbBundle.getMessage(DerbyOptions.class, "ERR_DirectoryDoesNotExist", derbySystemHomeFile);
                IllegalArgumentException e = new IllegalArgumentException(message);
                Exceptions.attachLocalizedMessage(e, message);
                throw e;
            }
            if (!derbySystemHomeFile.canWrite()) {
                String message = NbBundle.getMessage(DerbyOptions.class, "ERR_DirectoryIsNotWritable", derbySystemHomeFile);
                IllegalArgumentException e = new IllegalArgumentException(message);
                Exceptions.attachLocalizedMessage(e, message);
                throw e;
            }
        }

        synchronized (this) {
            stopDerbyServer();
            putProperty(PROP_DERBY_SYSTEM_HOME, derbySystemHome, true);
            DerbyDatabasesImpl.getDefault().notifyChange();
        }
    }

    static String getDefaultInstallLocation() {
        File location = InstalledFileLocator.getDefault().locate(INST_DIR, null, false);
        if (location == null) {
            return null;
        }
        if (!Util.isDerbyInstallLocation(location)) {
            return null;
        }
        return location.getAbsolutePath();
    }

    private static void stopDerbyServer() {
        RegisterDerby.getDefault().stop();
    }

    private static void registerDrivers(final String newLocation) {
        try {
            // registering the drivers in an atomic action so the Drivers node
            // is refreshed only once
            FileUtil.runAtomicAction(new FileSystem.AtomicAction() {
                @Override
                public void run() {
                    registerDriver(DRIVER_NAME_NET, DRIVER_DISP_NAME_NET, DRIVER_CLASS_NET,
                            new String[]{DRIVER_PATH_NET, DRIVER_PATH_EMBEDDED}, newLocation);
                    registerDriver(DRIVER_NAME_NET, DRIVER_DISP_NAME_NET, DRIVER_CLASS_NET_MODULAR,
                            new String[]{DRIVER_PATH_NET, DRIVER_PATH_EMBEDDED}, newLocation);
                    registerDriver(DRIVER_NAME_EMBEDDED, DRIVER_DISP_NAME_EMBEDDED,
                            DRIVER_CLASS_EMBEDDED, new String[]{DRIVER_PATH_EMBEDDED}, newLocation);
                    registerDriver(DRIVER_NAME_EMBEDDED, DRIVER_DISP_NAME_EMBEDDED,
                            DRIVER_CLASS_EMBEDDED_MODULAR, new String[]{DRIVER_PATH_EMBEDDED}, newLocation);
                }
            });
        } catch (IOException e) {
            Exceptions.printStackTrace(e);
        }
    }

    private static void registerDriver(String driverName, String driverDisplayName, String driverClass, String[] driverRelativeFile, String newLocation) {
        // try to remove the driver first if it exists was registered from the current location
        JDBCDriver[] drivers = JDBCDriverManager.getDefault().getDrivers(driverClass);
        for (int i = 0; i < drivers.length; i++) {
            JDBCDriver driver = drivers[i];
            URL[] urls = driver.getURLs();
            String currentLocation = DerbyOptions.getDefault().getLocation();
            if (currentLocation == null) {
                continue;
            }

            boolean fromCurrentLocation = true;

            for (int j = 0; j < urls.length; j++) {
                File file = null;
                if ("file".equals(urls[j].getProtocol())) { // NOI18N
                    // FileObject's do not work nice if the file urls[j] points to doesn't exist
                    try {
                        file = new File(urls[j].toURI());
                    } catch (URISyntaxException e) {
                        LOGGER.log(Level.WARNING, null, e);
                    }
                } else {
                    FileObject fo = URLMapper.findFileObject(urls[j]);
                    if (fo != null) {
                        file = FileUtil.toFile(fo);
                    }
                }
                if (file != null) {
                    String driverFile = file.getAbsolutePath();
                    if (driverFile.startsWith(currentLocation)) {
                        continue;
                    }
                }
                fromCurrentLocation = false;
                break;
            }

            if (fromCurrentLocation) {
                try {
                    JDBCDriverManager.getDefault().removeDriver(driver);
                } catch (DatabaseException e) {
                    LOGGER.log(Level.WARNING, null, e);
                    // better to return if the existing driver could not be registered
                    // otherwise we would register yet another one
                    return;
                }
            }
        }

        // register the new driver if it exists at the new location
        if (newLocation != null && newLocation.length() >= 0) {
            URL[] driverFileUrls = new URL[driverRelativeFile.length];
            try {
                boolean driverClassFound = false;
                for (int i = 0; i < driverRelativeFile.length; i++) {
                    File drvFile = new File(newLocation, driverRelativeFile[i]);
                    driverClassFound |= containsClass(drvFile, driverClass);
                    if (!drvFile.exists()) {
                        return;
                    }
                    driverFileUrls[i] = drvFile.toURI().toURL();
                }
                if (driverClassFound) {
                    JDBCDriver newDriver = JDBCDriver.create(driverName, driverDisplayName, driverClass, driverFileUrls);
                    JDBCDriverManager.getDefault().addDriver(newDriver);
                }
            } catch (MalformedURLException e) {
                LOGGER.log(Level.WARNING, null, e);
            } catch (DatabaseException e) {
                LOGGER.log(Level.WARNING, null, e);
            }
        }
    }

    private static boolean containsClass(File file, String className) {
        String relativePath = className.replace(".", "/") + ".class";
        if(file.isFile()) {
            try (JarFile jf = new JarFile(file)) {
                return jf.getEntry(relativePath) != null;
            } catch (IOException ex) {
                // Ok, ignore
            }
        } else if (file.isDirectory()) {
            return new File(file, relativePath).exists();
        }
        return false;
    }

    private void registerLibrary(final String newLocation) {
        final FileObject libsFolder = FileUtil.getConfigFile(
                "org-netbeans-api-project-libraries/Libraries");        //NOI18N
        if (libsFolder != null && newLocation != null) {
            try {
                File location = new File(newLocation);
                if (location.exists() && location.isDirectory()) {
                    location = FileUtil.normalizeFile(location);
                    libsFolder.getFileSystem().runAtomicAction(
                            new DerbyLibraryRegistrar(location, libsFolder));
                }
            } catch (FileStateInvalidException ex) {
                LOGGER.log(Level.INFO, ex.getLocalizedMessage(), ex);   //NOI18N
            } catch (IOException ex) {
                LOGGER.log(Level.INFO, ex.getLocalizedMessage(), ex);   //NOI18N
            }
        }
    }

    private static BeanNode createViewNode() throws java.beans.IntrospectionException {
        return new BeanNode(DerbyOptions.getDefault());
    }

    static class DerbyLibraryRegistrar implements FileSystem.AtomicAction {

        private File location;
        private FileObject libsFolder;

        DerbyLibraryRegistrar(File location, FileObject libsFolder) {
            this.location = location;
            this.libsFolder = libsFolder;
        }

        @Override
        public void run() throws IOException {

            FileLock ld = null;
            java.io.OutputStream outStreamd = null;
            Writer outd = null;
            OutputStreamWriter osw = null;
            try {
                // the derby lib driver:
                FileObject derbyLib = null;
                derbyLib = libsFolder.getFileObject("JavaDB", "xml");//NOI18N
                if (null == derbyLib) {
                    derbyLib = libsFolder.createData("JavaDB", "xml");//NOI18N
                    ld = derbyLib.lock();
                    outStreamd = derbyLib.getOutputStream(ld);
                    osw = new OutputStreamWriter(outStreamd);
                    outd = new BufferedWriter(osw);
                    outd.write("\n");//NOI18N
                    outd.write("\n");//NOI18N
                    outd.write("JAVADB_DRIVER_LABEL\n");//NOI18N
                    outd.write("j2se\n");//NOI18N
                    outd.write("org.netbeans.modules.derby.Bundle\n");//NOI18N
                    outd.write("\nclasspath\n"); //NOI18N
                    outd.write("jar:" + new File(location.getAbsolutePath() + "/lib/derby.jar").toURI().toURL() + "!/\n"); //NOI18N
                    outd.write("jar:" + new File(location.getAbsolutePath() + "/lib/derbyclient.jar").toURI().toURL() + "!/\n"); //NOI18N
                    outd.write("jar:" + new File(location.getAbsolutePath() + "/lib/derbynet.jar").toURI().toURL() + "!/\n"); //NOI18N
                    outd.write("\n\nsrc\n\n"); //NOI18N
                    outd.write("\njavadoc\n");  //NOI18N
                    outd.write("\n"); //NOI18N
                    outd.write("\n\n"); //NOI18N
                    outd.write("maven-dependencies\n"); //NOI18N
                    outd.write("\n"); //NOI18N
                    outd.write("org.apache.derby:derby:10.14.2.0:jar\n"); //NOI18N
                    outd.write("org.apache.derby:derbyclient:10.14.2.0:jar\n"); //NOI18N
                    outd.write("org.apache.derby:derbynet:10.14.2.0:jar\n"); //NOI18N
                    outd.write("\n"); //NOI18N
                    outd.write("\n\n"); //NOI18N
                    outd.write("\n"); //NOI18N
                }
            } finally {
                if (null != outd) {
                    try {
                        outd.close();
                    } catch (IOException ioe) {
                        LOGGER.log(Level.INFO, ioe.getLocalizedMessage(), ioe); //NOI18N
                    }
                }
                if (null != outStreamd) {
                    try {
                        outStreamd.close();
                    } catch (IOException ioe) {
                        LOGGER.log(Level.INFO, ioe.getLocalizedMessage(), ioe); //NOI18N
                    }
                }
                if (null != ld) {
                    ld.releaseLock();
                }
            }
        } //run
    } //DerbyLibraryRegistrar
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy