/** * Helios, OpenSource Monitoring * Brought to you by the Helios Development Group * * Copyright 2007, Helios Development Group and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This 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; either version 2.1 of * the License, or (at your option) any later version. * * This software 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. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. * */ package org.helios.apmrouter.catalog.jdbc.h2; import java.io.File; import java.io.FileOutputStream; import java.net.URL; import java.sql.Connection; import java.sql.PreparedStatement; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import javax.sql.DataSource; import org.apache.log4j.Logger; import org.helios.apmrouter.util.URLHelper; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; /** * <p>Title: ScriptExecution</p> * <p>Description: Executes SQL scripts</p> * <p>Company: Helios Development Group LLC</p> * @author Whitehead (nwhitehead AT heliosdev DOT org) * <p><code>org.helios.apmrouter.catalog.jdbc.ScriptExecution</code></p> */ public class ScriptExecution { /** The datasource to get the connection from */ protected final DataSource dataSource; /** The script source to run */ protected String scriptSource; /** Instance logger */ protected Logger log = Logger.getLogger(getClass()); /** File to delete after start */ protected final Set<File> toDelete = new HashSet<File>(); /** The relative resource root for DDL resources */ public static String DEFAULT_DDL_RESOURCE_ROOT = "/ddl/"; /** The sysprop name defining the root config resource */ public static final String ROOT_CONFIG = "org.helios.apmrouter.root.config"; /** The runscript template */ public static final String URL_SCRIPT_TEMPLATE = "RUNSCRIPT FROM '%s'"; /** * Creates a new ScriptExecution * @param dataSource The datasource to get the connection from * @param scriptSource The script source to run */ public ScriptExecution(DataSource dataSource, String scriptSource) { this.dataSource = dataSource; this.scriptSource = resolveScriptSource(scriptSource); } protected String resolveScriptSource(String src) { if(src==null || src.trim().isEmpty()) throw new IllegalArgumentException("The passed source was null or empty", new Throwable()); src = src.trim(); if(src.toLowerCase().startsWith("runscript ")) { return src.trim(); } if(URLHelper.isValidURL(src)) { File tmpFile = extractTempFile(URLHelper.toURL(src)); return String.format(URL_SCRIPT_TEMPLATE, tmpFile.getAbsolutePath()); } String configRoot = System.getProperty(ROOT_CONFIG); if(configRoot==null) { throw new RuntimeException("No root configs defined in [" + ROOT_CONFIG + "]", new Throwable()); } String[] configRoots = configRoot.indexOf(',')==-1 ? new String[]{configRoot.trim()} : configRoot.split(","); PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); for(String cr: configRoots) { if(!URLHelper.isValidURL(cr)) { cr = "classpath:" + cr + DEFAULT_DDL_RESOURCE_ROOT + src; } else { cr = cr + DEFAULT_DDL_RESOURCE_ROOT + src; File tmpFile = extractTempFile(URLHelper.toURL(cr)); tmpFile.deleteOnExit(); return String.format(URL_SCRIPT_TEMPLATE, tmpFile.getAbsolutePath()); } try { Resource resource = resolver.getResource(cr); File tmpFile = extractTempFile(resource.getURL()); tmpFile.deleteOnExit(); return String.format(URL_SCRIPT_TEMPLATE, tmpFile.getAbsolutePath()); } catch (Exception e) { log.debug("Script resource not found at [" + cr + "]"); } } throw new RuntimeException("No script resources found in " + Arrays.toString(configRoots) + "]", new Throwable()); } /** * Creates a new ScriptExecution * @param dataSource The datasource to get the connection from * @param scriptSource The script source to run */ public ScriptExecution(DataSource dataSource, URL scriptSource) { this.dataSource = dataSource; File scriptFile = extractTempFile(scriptSource); this.scriptSource = scriptFile.getAbsolutePath(); } /** * Extracts the content from the passed URL and writes it to a temp file * @param urlResource The URL to read the content from * @return the temp file */ protected File extractTempFile(String urlResource) { return extractTempFile(URLHelper.toURL(urlResource)); } /** * Extracts the content from the passed URL and writes it to a temp file * @param url The URL to read the content from * @return the temp file */ protected File extractTempFile(URL url) { FileOutputStream fos = null; try { byte[] content = URLHelper.getBytesFromURL(url); String[] frags = url.toString().split("/"); String fileName = frags[frags.length-1].split("\\.")[0]; File tmpFile = File.createTempFile("apmrouter-ddl-" + fileName, ".sql"); tmpFile.deleteOnExit(); toDelete.add(tmpFile); fos = new FileOutputStream(tmpFile); fos.write(content); fos.flush(); fos.close(); return tmpFile; } catch (Exception ex) { throw new RuntimeException("Failed to load DDL from URL [" + url + "]", ex); } finally { if(fos!=null) try { fos.close(); } catch (Exception ex) {} } } public void startUrl() { File f = null; try { URL url = ClassLoader.getSystemResource(scriptSource); f = extractTempFile(url); scriptSource = String.format(URL_SCRIPT_TEMPLATE, f.getAbsolutePath()); start(); } catch (Exception ex) { throw new RuntimeException(ex); } finally { if(f!=null) f.delete(); } } /** * Executes the configured script */ public void start() { Connection conn = null; PreparedStatement ps = null; try { conn = dataSource.getConnection(); ps = conn.prepareStatement(scriptSource); ps.execute(); log.info("Executed Startup Script [" + scriptSource + "]"); } catch (Exception e) { throw new RuntimeException("Failed to execute script [" + scriptSource + "]", e); } finally { if(ps!=null) try { ps.close(); } catch (Exception e) {} if(conn!=null) try { conn.close(); } catch (Exception e) {} for(Iterator<File> fiter = toDelete.iterator(); fiter.hasNext();) { File f = fiter.next(); f.delete(); fiter.remove(); } } } }