/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2010 Oracle and/or its affiliates. All rights reserved. * * Oracle and Java are registered trademarks of Oracle and/or its affiliates. * Other names may be trademarks of their respective owners. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common * Development and Distribution License("CDDL") (collectively, the * "License"). You may not use this file except in compliance with the * License. You can obtain a copy of the License at * http://www.netbeans.org/cddl-gplv2.html * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the * specific language governing permissions and limitations under the * License. When distributing the software, include this License Header * Notice in each file and include the License file at * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the GPL Version 2 section of the License file that * accompanied this code. If applicable, add the following below the * License Header, with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * If you wish your version of this file to be governed by only the CDDL * or only the GPL Version 2, indicate your decision by adding * "[Contributor] elects to include this software in this distribution * under the [CDDL or GPL Version 2] license." If you do not indicate a * single choice of license, a recipient has the option to distribute * your version of this file under either the CDDL, the GPL Version 2 or * to extend the choice of license to its licensees as provided above. * However, if you add GPL Version 2 code and therefore, elected the GPL * Version 2 license, then the option applies only if the new code is * made subject to such option by the copyright holder. * * Contributor(s): * * Portions Copyrighted 2008 Sun Microsystems, Inc. */ package org.netbeans.modules.ruby.railsprojects.database; import java.io.IOException; import java.util.logging.Logger; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.PlainDocument; import org.netbeans.modules.ruby.railsprojects.RailsProject; import org.openide.LifecycleManager; import org.openide.cookies.EditorCookie; import org.openide.cookies.SaveCookie; import org.openide.filesystems.FileObject; import org.openide.loaders.DataObject; import org.openide.loaders.DataObjectNotFoundException; import org.openide.util.Exceptions; /** * Wraps a <code>RailsDatabaseConfiguration</code> and modifies database.yml * so that the specified extra parameters are put into it. * * @author Erno Mononen */ public class ConfigurableRailsAdapter extends RailsDatabaseConfiguration { private static final Logger LOGGER = Logger.getLogger(ConfigurableRailsAdapter.class.getName()); private final RailsDatabaseConfiguration delegate; private final String userName; private final String password; private final String database; private final boolean jdbc; /** * Creates a new instance of ConfigurableRailsAdapter. * * @param delegate the configuration representing the original configuration. * @param userName the user name to be put into the generated configuration, * i.e. value for the <code>username:</code> attribute. * @param password the user name to be put into the generated configuration, * i.e. value for the <code>password:</code> attribute. * @param database the name of the database to be put into the generated configuration, * i.e. value for the <code>database:</code> attribute. * @param jdbc specifies whether the generated configuration should use JDBC * to access the database. */ public ConfigurableRailsAdapter(RailsDatabaseConfiguration delegate, String userName, String password, String database, boolean jdbc) { this.delegate = delegate; this.userName = userName; this.password = password; this.database = database; this.jdbc = jdbc; } public String railsGenerationParam() { return delegate.railsGenerationParam(); } public void editConfig(RailsProject project) { delegate.editConfig(project); edit(project.getProjectDirectory()); JdbcInfo jdbcInfo = getJdbcInfo(); if (jdbc && jdbcInfo != null) { // try to bundle a driver RailsJdbcConnection.bundleDrivers(project, jdbcInfo.getDriverClass()); } } public String getDisplayName() { return delegate.getDisplayName(); } private void edit(FileObject dir) { FileObject fo = dir.getFileObject("config/database.yml"); // NOI18N if (fo != null) { try { DataObject dobj = DataObject.find(fo); EditorCookie ec = dobj.getCookie(EditorCookie.class); if (ec != null) { Document doc = ec.openDocument(); setDatabase(doc); // see #132383 - need to force the creation of these attributes // for the javadb adapter RailsAdapters.changeAttribute(doc, "username:", userName, "url:"); //NOI18N RailsAdapters.changeAttribute(doc, "password:", password, "username:"); //NOI18N // see #138294 handleTestAndProduction(doc); SaveCookie sc = dobj.getCookie(SaveCookie.class); if (sc != null) { sc.save(); } else { LifecycleManager.getDefault().saveAll(); } } } catch (BadLocationException ble) { Exceptions.printStackTrace(ble); } catch (DataObjectNotFoundException dnfe) { Exceptions.printStackTrace(dnfe); } catch (IOException ioe) { Exceptions.printStackTrace(ioe); } } } /** * Changes the test and production database configs to match that of the development * database config. Basically just copies the development config and changes the database * name. * * @param databaseYml the document for database.yml that already contains correctly generated * development database config and the default configs for test and production databases. * * @throws javax.swing.text.BadLocationException */ private void handleTestAndProduction(Document databaseYml) throws BadLocationException { String text = getText(databaseYml); int start = text.indexOf("development:\n"); //NOI18N int end = text.indexOf("test:\n"); //NOI18N if (end == -1) { // log a warning and return. "test:" should be present, // if it is not, we will do more harm than good by trying to // modify the document further LOGGER.warning("Could not find 'test:' in database.yml. Its content is: " + text); return; } databaseYml.remove(end, databaseYml.getLength() - end); String developmentConfig = databaseYml.getText(start, end - start); String developmentDbName = !isEmpty(database) ? database : RailsAdapters.getPropertyValue(databaseYml, "database:"); //NOI18N PlainDocument test = new PlainDocument(); String testConfig = developmentConfig.replace("development:\n", "test:\n");//NOI18N // remove the comment that rails generates for the test database. removes // it from the end so that it doesn't get added for the production database too, // the comment will still be there for the test database. int warningIndex = testConfig.lastIndexOf("# Warning: The database defined as \"test\" will be erased");//NOI18N if (warningIndex != -1) { testConfig = testConfig.substring(0, warningIndex); } test.insertString(0, testConfig, null); changeDatabase(test, getTestDatabaseName(developmentDbName)); PlainDocument production = new PlainDocument(); String productionConfig = testConfig.replace("test:\n", "production:\n");//NOI18N production.insertString(0, productionConfig, null); changeDatabase(production, getProductionDatabaseName(developmentDbName)); databaseYml.insertString(databaseYml.getLength(), getText(test) + getText(production), null); } /** * Changes the database name specified in the given document. If using JDBC, * changes the url instead. * * @param doc * @param databaseName the new name for the database. * @throws javax.swing.text.BadLocationException */ private void changeDatabase(Document doc, String databaseName) throws BadLocationException { JdbcInfo jdbcInfo = getJdbcInfo(); if (!jdbc || jdbcInfo == null) { RailsAdapters.changeAttribute(doc, "database:", databaseName, null); //NOI18N } else { RailsAdapters.changeAttribute(doc, "url:", jdbcInfo.getURL("localhost", databaseName), "adapter:"); //NOI18N } } private String getText(Document doc) throws BadLocationException { return doc.getText(0, doc.getLength()); } private void setDatabase(Document databaseYml) throws BadLocationException { JdbcInfo jdbcInfo = getJdbcInfo(); if (!jdbc || jdbcInfo == null) { // not using jdbc, so just set the database RailsAdapters.changeAttribute(databaseYml, "database:", database, null); //NOI18N return; } // use the default database name if none was specified String dbName = !isEmpty(database) ? database : RailsAdapters.getPropertyValue(databaseYml, "database:"); // change the adapter RailsAdapters.changeAttribute(databaseYml, "adapter:", "jdbc", null); //NOI18N // add url and driver RailsAdapters.addProperty(databaseYml, "url:", jdbcInfo.getURL("localhost", dbName), "adapter:"); //NOI18N RailsAdapters.addProperty(databaseYml, "driver:", jdbcInfo.getDriverClass(), "adapter:"); //NOI18N // remove database, since we now have url and driver RailsAdapters.removeProperty(databaseYml, "database:"); //NOI18N } private boolean isEmpty(String str) { return str == null || "".equals(str.trim()); } public JdbcInfo getJdbcInfo() { return delegate.getJdbcInfo(); } public String getDatabaseName(String projectName) { return delegate.getDatabaseName(projectName); } public String getTestDatabaseName(String developmentDbName) { return delegate.getTestDatabaseName(developmentDbName); } public String getProductionDatabaseName(String developmentDbName) { return delegate.getProductionDatabaseName(developmentDbName); } }