import java.sql.*; import java.io.*; import java.util.*; import PageBoxLib.*; /** *
Generic Installation class.
*Expects to find a sqlinstall directory containing one csv file per table.
*
The table is named after the csv file name.
Each csv file
* contains a first row with the column names, a second column with the column
* type and a row for each database record.
alexis.grandemange@pagebox.net
*Copyright (c) 2002-2003 Alexis Grandemange
*This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; version 2.1 of the * License. * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * A copy of the GNU Lesser General Public License lesser.txt should be * included in the distribution.* @author Alexis Grandemange * @version 0, 0, 1 */ public class Install implements InstallIF { /** Logging object */ LogIF log; /** SQL connection */ Connection conn = null; /** SQL statement used to create and drop tables */ Statement stmt = null; /** Table name */ String name = null; /** Column names */ String[] names = null; /** Column types */ String[] types = null; /** For each initial row contains an array of column values */ ArrayList rows = null; /** * Get the table name. * @param f definition file */ private void getName(File f) { String path = f.getAbsolutePath(); int pos = path.lastIndexOf(File.separatorChar); if (pos != -1) path = path.substring(pos + 1); pos = path.indexOf('.'); if (pos == -1) name = path; else name = path.substring(0, pos); } /** * Parse a definition file. * @param f definition file * @return int -1 in case of error or number of lines */ private int readFile(File f) { int count = 0; rows = null; getName(f); try { BufferedReader br = new BufferedReader(new FileReader(f)); String line = null; while((line = br.readLine()) != null) { StringTokenizer st = new StringTokenizer(line, ","); if (count == 0) { names = new String[st.countTokens()]; int j = 0; while(st.hasMoreTokens()) names[j ++] = st.nextToken().trim(); log.info("toolbox.Install.readFile " + name + " fields " + line); } else if (count == 1) { int k = st.countTokens(); if (k != names.length) { log.error("toolbox.Install.readFile(" + name + ") type #=" + k + " whereas name #=" + names.length); return -1; } types = new String[k]; int j = 0; while(st.hasMoreTokens()) types[j ++] = st.nextToken().trim(); log.info("toolbox.Install.readFile types " + line); } else { if (count == 3) log.info("toolbox.Install.readFile values " + line); int k = st.countTokens(); if (k != names.length) { log.error("toolbox.Install.readFile(" + name + ") row " + (count - 1) + "col #=" + k + " whereas name #=" + names.length); return -1; } if (rows == null) rows = new ArrayList(); String[] fields = new String[k]; int j = 0; while(st.hasMoreTokens()) fields[j ++] = st.nextToken().trim(); rows.add(fields); } ++ count; } } catch(FileNotFoundException fnfe) { log.error("toolbox.Install.readFile(" + name + ") exception " + fnfe.getMessage()); return -1; } catch(IOException ioe) { log.error("toolbox.Install.readFile(" + name + ") exception " + ioe.getMessage()); return -1; } return count; } /** * Populates a table. */ private void createData() throws Exception { Iterator i = rows.iterator(); boolean first = true; while(i.hasNext()) { StringBuffer cmd = new StringBuffer("INSERT INTO "); cmd.append(name); cmd.append(" ("); for (int j = 0; j < names.length; ++j) { cmd.append(names[j]); if (j != (names.length - 1)) cmd.append(", "); } cmd.append(") values(\""); String[] fields = (String[])i.next(); for (int j = 0; j < fields.length; ++j) { cmd.append(fields[j]); if (j != (fields.length - 1)) cmd.append("\", \""); else cmd.append("\")"); } if (first) { log.info("toolbox.Install.createData " + cmd); first = false; } stmt.executeUpdate(cmd.toString()); } } /** * Remove all tables. * @param f csv file */ private void drop(File f) throws Exception { getName(f); stmt.executeUpdate("DROP TABLE " + name); } /** * Creates populates a table from. * @param f csv file * @param toUpdate true when archive installed before */ private void create(File f, boolean toUpdate) throws Exception { int rc = readFile(f); if (rc == -1) return; if (toUpdate && (rc == 2)) return; try { stmt.executeUpdate("DROP TABLE " + name); } catch(SQLException sqle) {} StringBuffer cmd = new StringBuffer("CREATE TABLE "); cmd.append(name); cmd.append(" ("); for (int i = 0; i < names.length; ++i) { cmd.append(names[i]); cmd.append(" "); cmd.append(types[i]); if (i != (names.length - 1)) cmd.append(", "); } cmd.append(")"); log.info("toolbox.Install.create " + cmd); stmt.executeUpdate(cmd.toString()); createData(); } /** * Called to perform the post installation * @param archPath archive root directory * @param pba PageBox API object * @param Application server resource map * @param log logging object * @param toUpdate true when archive installed before * @return null or error message */ public String install(String archPath, PageBoxAPI pba, Map resources, boolean toUpdate) { this.log = pba.getLog(); String rc = null; File f = new File(archPath + File.separator + "sqlinstall"); if (!f.exists() || !f.isDirectory()) { rc = "toolbox.Install.install(" + archPath + ") " + archPath + File.separator + "sqlinstall) doesn't exist"; log.warn(rc); return rc; } File[] files = f.listFiles(); if (files.length == 0) { log.info("toolbox.Install.install(" + archPath + ") found no file"); return rc; } conn = pba.getConnection(); if (conn == null) { rc = "toolbox.Install.install(" + archPath + ") no database defined"; log.warn(rc); return rc; } try { stmt = conn.createStatement(); for (int i = 0; i < files.length; ++i) create(files[i], toUpdate); updateWebXml(archPath); } catch(Throwable t) { rc = "toolbox.Install.install(" + archPath + ", " + ") exception " + t.getMessage(); log.error(rc); } finally { try { if (stmt != null) stmt.close(); conn.close(); } catch (SQLException sqlEx) {} } return rc; } /** * Called to perform the pre deinstallation * @param archPath archive root directory * @param pba PageBox API object * @param Application server resource map * @param toUpdate true when called before an update * @return null or error message */ public String uninstall(String archPath, PageBoxAPI pba, Map resources, boolean toUpdate) { String rc = null; if (!toUpdate) { this.log = pba.getLog(); File f = new File(archPath + File.separator + "sqlinstall"); if (!f.exists() || !f.isDirectory()) { rc = "toolbox.Install.install(" + archPath + File.separator + "sqlinstall) doesn't exist"; log.warn(rc); return rc; } File[] files = f.listFiles(); if (files.length == 0) return rc; conn = pba.getConnection(); if (conn == null) { rc = "toolbox.Install.uninstall(" + archPath + ") no database defined"; log.warn(rc); return rc; } try { stmt = conn.createStatement(); for (int i = 0; i < files.length; ++i) { drop(files[i]); } } catch(Throwable t) { rc = "toolbox.Install.uninstall(" + archPath + ") exception " + t.getMessage(); log.error(rc); } finally { try { if (stmt != null) stmt.close(); conn.close(); } catch (SQLException sqlEx) {} } } pba.relConnections(); return rc; } /** * You may change this method or comment its call. Illustrates the update * of web.xml. Replace a wordir placeholder by the archive directory. * @param archPath archive root directory */ private void updateWebXml(String archPath) { String wxpath = archPath + File.separator + "WEB-INF" + File.separator + "web.xml"; File f = new File(wxpath); if (!f.exists()) { log.warn("Pandora.Install.updateWebXml " + wxpath + " doesn't exist: not a Web application?"); return; } File f2 = new File(archPath + File.separator + "WEB-INF" + File.separator + "web2.xml"); if (f2.exists()) f2.delete(); boolean found = false; try { BufferedReader br = new BufferedReader(new FileReader(f)); PrintWriter pw = new PrintWriter(new FileWriter(f2)); String line = null; while((line = br.readLine()) != null) { if (found) { // Only change the first instance of the placeholder pw.println(line); continue; } int pos = line.indexOf(""); if (pos == -1) { pw.println(line); continue; } pw.println(line.substring(0, pos) + archPath + line.substring(pos + "".length())); found = true; } br.close(); pw.close(); } catch(Exception e) { log.warn("Pandora.Install.updateWebXml exception reading " + wxpath + " " + e.getMessage()); f2.delete(); return; } // Use the new version only when updated if (found) { f.delete(); f2.renameTo(f); } else f2.delete(); } }