diff --git a/src/main/org/apache/tools/ant/Project.java b/src/main/org/apache/tools/ant/Project.java index 1e5d6c4b3..bdf5716d1 100644 --- a/src/main/org/apache/tools/ant/Project.java +++ b/src/main/org/apache/tools/ant/Project.java @@ -176,10 +176,11 @@ public class Project { log("Setting project property: " + name + " to " + value, MSG_VERBOSE); userProperties.put(name, value); - properties.put( name,value); + properties.put(name, value); } public String getProperty(String name) { + if (name == null) return null; String property = (String) properties.get(name); return property; } diff --git a/src/main/org/apache/tools/ant/ProjectHelper.java b/src/main/org/apache/tools/ant/ProjectHelper.java index 116d0cec7..355257a87 100644 --- a/src/main/org/apache/tools/ant/ProjectHelper.java +++ b/src/main/org/apache/tools/ant/ProjectHelper.java @@ -1,7 +1,7 @@ /* * The Apache Software License, Version 1.1 * - * Copyright (c) 1999 The Apache Software Foundation. All rights + * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -9,7 +9,7 @@ * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in @@ -17,15 +17,15 @@ * distribution. * * 3. The end-user documentation included with the redistribution, if - * any, must include the following acknowlegement: - * "This product includes software developed by the + * any, must include the following acknowlegement: + * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software * Foundation" must not be used to endorse or promote products derived - * from this software without prior written permission. For written + * from this software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache" @@ -61,7 +61,7 @@ import java.lang.reflect.*; import java.util.*; import org.xml.sax.SAXException; import org.w3c.dom.*; - + /** * Configures a Project (complete with Targets and Tasks) based on * a XML build file. @@ -72,281 +72,284 @@ import org.w3c.dom.*; public class ProjectHelper { public static void configureProject(Project project, File buildFile) - throws BuildException + throws BuildException { - // XXX - // need to get rid of the DOM layer and use SAX - - Document doc; - - try { - doc=Parser.getParser(project).parse(buildFile); - } catch (IOException ioe) { - String msg = "Can't open config file: " + buildFile + - " due to: " + ioe; - throw new BuildException(msg); - } catch (SAXException se) { - String msg = "Can't open config file: " + buildFile + - " due to: " + se; - throw new BuildException(msg); - } - - Element root = doc.getDocumentElement(); - - // sanity check, make sure that we have the right element - // as we aren't validating the input - - if (!root.getTagName().equals("project")) { - String msg = "Config file is not of expected XML type"; - throw new BuildException(msg); - } - - project.setName(root.getAttribute("name")); - project.setDefaultTarget(root.getAttribute("default")); - - String baseDir = project.getProperty("basedir"); - if (baseDir == null) { - baseDir = root.getAttribute("basedir"); - if (baseDir.equals("")) { - // Using clunky JDK1.1 methods here - baseDir = new File(buildFile.getAbsolutePath()).getParent(); - } - } - project.setBasedir(baseDir); - - // set up any properties that may be in the config file - - // configureProperties(project, root); - - // set up any task defs that may be in the config file - - // configureTaskDefs(project, root); - - // set up the targets into the project - init(project, root ); - configureTargets(project, root); + // XXX + // need to get rid of the DOM layer and use SAX + + Document doc; + + try { + doc=Parser.getParser(project).parse(buildFile); + } catch (IOException ioe) { + String msg = "Can't open config file: " + buildFile + + " due to: " + ioe; + throw new BuildException(msg); + } catch (SAXException se) { + String msg = "Can't open config file: " + buildFile + + " due to: " + se; + throw new BuildException(msg); + } + + Element root = doc.getDocumentElement(); + + // sanity check, make sure that we have the right element + // as we aren't validating the input + + if (!root.getTagName().equals("project")) { + String msg = "Config file is not of expected XML type"; + throw new BuildException(msg); + } + + project.setName(root.getAttribute("name")); + project.setDefaultTarget(root.getAttribute("default")); + + String baseDir = project.getProperty("basedir"); + if (baseDir == null) { + baseDir = root.getAttribute("basedir"); + if (baseDir.equals("")) { + // Using clunky JDK1.1 methods here + baseDir = new File(buildFile.getAbsolutePath()).getParent(); + } + } + project.setBasedir(baseDir); + + // set up any properties that may be in the config file + + // configureProperties(project, root); + + // set up any task defs that may be in the config file + + // configureTaskDefs(project, root); + + // set up the targets into the project + init(project, root ); + configureTargets(project, root); } /** Read and execute init - all other targets will be loaded after ( to * make sure all properties are set ). - * + * */ private static void init(Project project, Element root) - throws BuildException + throws BuildException { - // Hack - all tasks outside init target will be added to init - // ( will be removed when / if build.xml will start using init ) - Target initTarget = new Target(); - initTarget.setProject(project); - initTarget.setName( "init" ); - project.addTarget( "init", initTarget ); - configureTasks( project, initTarget, root ); - - NodeList list = root.getElementsByTagName("target"); - for (int i = 0; i < list.getLength(); i++) { - Element element = (Element)list.item(i); - String targetName = element.getAttribute("name"); - - if( targetName.equals("init") ) - configureTasks(project, initTarget, element); - } - initTarget.execute(); + // Hack - all tasks outside init target will be added to init + // ( will be removed when / if build.xml will start using init ) + Target initTarget = new Target(); + initTarget.setProject(project); + initTarget.setName( "init" ); + project.addTarget( "init", initTarget ); + configureTasks( project, initTarget, root ); + + NodeList list = root.getElementsByTagName("target"); + for (int i = 0; i < list.getLength(); i++) { + Element element = (Element)list.item(i); + String targetName = element.getAttribute("name"); + + if( targetName.equals("init") ) + configureTasks(project, initTarget, element); + } + initTarget.execute(); } private static void configureTargets(Project project, Element root) - throws BuildException + throws BuildException { - // configure targets - NodeList list = root.getElementsByTagName("target"); - for (int i = 0; i < list.getLength(); i++) { - Element element = (Element)list.item(i); - String targetName = element.getAttribute("name"); - String targetDep = element.getAttribute("depends"); - - // all targets must have a name - if (targetName.equals("")) { - String msg = "target element appears without a name attribute"; - throw new BuildException(msg); - } - - // init is done already - if( targetName.equals("init") ) - continue; - - Target target = new Target(); - target.setName(targetName); - project.addTarget(targetName, target); - - // take care of dependencies - - if (targetDep.length() > 0) { - StringTokenizer tok = - new StringTokenizer(targetDep, ",", false); - while (tok.hasMoreTokens()) { - target.addDependency(tok.nextToken().trim()); - } - } - - // populate target with tasks - - configureTasks(project, target, element); - } + // configure targets + NodeList list = root.getElementsByTagName("target"); + for (int i = 0; i < list.getLength(); i++) { + Element element = (Element)list.item(i); + String targetName = element.getAttribute("name"); + String targetDep = element.getAttribute("depends"); + String targetCond = element.getAttribute("if"); + + // all targets must have a name + if (targetName.equals("")) { + String msg = "target element appears without a name attribute"; + throw new BuildException(msg); + } + + // init is done already + if( targetName.equals("init") ) + continue; + + Target target = new Target(); + target.setName(targetName); + target.setCondition(targetCond); + project.addTarget(targetName, target); + + // take care of dependencies + + if (targetDep.length() > 0) { + StringTokenizer tok = + new StringTokenizer(targetDep, ",", false); + while (tok.hasMoreTokens()) { + target.addDependency(tok.nextToken().trim()); + } + } + + // populate target with tasks + + configureTasks(project, target, element); + } } private static void configureTasks(Project project, - Target target, - Element targetElement) - throws BuildException + Target target, + Element targetElement) + throws BuildException { - NodeList list = targetElement.getChildNodes(); - for (int i = 0; i < list.getLength(); i++) { - Node node = list.item(i); - - // right now, all we are interested in is element nodes - // not quite sure what to do with others except drop 'em - - if (node.getNodeType() == Node.ELEMENT_NODE) { - Element element = (Element)node; - String taskType = element.getTagName(); - - // special case - no target in a target. - // hack to allow this method to set "init" target - // using root element - if( ! taskType.equals( "target" ) ) { - // XXX - // put in some sanity checking - - Task task = project.createTask(taskType); - - // get the attributes of this element and reflect them - // into the task - - NamedNodeMap nodeMap = element.getAttributes(); - configureTask(project, task, nodeMap); - target.addTask(task); - } - } - } + NodeList list = targetElement.getChildNodes(); + for (int i = 0; i < list.getLength(); i++) { + Node node = list.item(i); + + // right now, all we are interested in is element nodes + // not quite sure what to do with others except drop 'em + + if (node.getNodeType() == Node.ELEMENT_NODE) { + Element element = (Element)node; + String taskType = element.getTagName(); + + // special case - no target in a target. + // hack to allow this method to set "init" target + // using root element + if( ! taskType.equals( "target" ) ) { + // XXX + // put in some sanity checking + + Task task = project.createTask(taskType); + + // get the attributes of this element and reflect them + // into the task + + NamedNodeMap nodeMap = element.getAttributes(); + configureTask(project, task, nodeMap); + task.init(); + target.addTask(task); + } + } + } } private static void configureTask(Project project, - Task taskInst, - NamedNodeMap nodeMap) - throws BuildException + Task taskInst, + NamedNodeMap nodeMap) + throws BuildException { - Object task=taskInst; - if( task instanceof TaskAdapter ) - task=((TaskAdapter)task).getProxy(); - - // XXX - // instead of doing this introspection each time around, I - // should have a helper class to keep this info around for - // each kind of class - - Hashtable propertySetters = new Hashtable(); - BeanInfo beanInfo; - try { - beanInfo = Introspector.getBeanInfo(task.getClass()); - } catch (IntrospectionException ie) { - String msg = "Can't introspect task class: " + task.getClass(); - throw new BuildException(msg); - } - - PropertyDescriptor[] pda = beanInfo.getPropertyDescriptors(); - for (int i = 0; i < pda.length; i++) { - PropertyDescriptor pd = pda[i]; - String property = pd.getName(); - Method setMethod = pd.getWriteMethod(); - if (setMethod != null) { - - // make sure that there's only 1 param and that it - // takes a String object, all other setMethods need - // to get screened out - - Class[] ma =setMethod.getParameterTypes(); - if (ma.length == 1) { - Class c = ma[0]; - if (c.getName().equals("java.lang.String")) { - propertySetters.put(property, setMethod); - } - } - } - } - - for (int i = 0; i < nodeMap.getLength(); i++) { - Node node = nodeMap.item(i); - - // these should only be attribs, we won't see anything - // else here. - - if (node.getNodeType() == Node.ATTRIBUTE_NODE) { - Attr attr = (Attr)node; - - // reflect these into the task - - Method setMethod = (Method)propertySetters.get(attr.getName()); - if (setMethod == null) { - String msg = "Configuration property \"" + attr.getName() + - "\" does not have a setMethod in " + task.getClass(); - throw new BuildException(msg); - } - - String value=replaceProperties( attr.getValue(), project.getProperties() ); - try { - setMethod.invoke(task, new String[] {value}); - } catch (IllegalAccessException iae) { - String msg = "Error setting value for attrib: " + - attr.getName(); - iae.printStackTrace(); - throw new BuildException(msg); - } catch (InvocationTargetException ie) { - String msg = "Error setting value for attrib: " + - attr.getName() + " in " + task.getClass().getName(); - ie.printStackTrace(); - ie.getTargetException().printStackTrace(); - throw new BuildException(msg); - } - } - } + Object task=taskInst; + if( task instanceof TaskAdapter ) + task=((TaskAdapter)task).getProxy(); + + // XXX + // instead of doing this introspection each time around, I + // should have a helper class to keep this info around for + // each kind of class + + Hashtable propertySetters = new Hashtable(); + BeanInfo beanInfo; + try { + beanInfo = Introspector.getBeanInfo(task.getClass()); + } catch (IntrospectionException ie) { + String msg = "Can't introspect task class: " + task.getClass(); + throw new BuildException(msg); + } + + PropertyDescriptor[] pda = beanInfo.getPropertyDescriptors(); + for (int i = 0; i < pda.length; i++) { + PropertyDescriptor pd = pda[i]; + String property = pd.getName(); + Method setMethod = pd.getWriteMethod(); + if (setMethod != null) { + + // make sure that there's only 1 param and that it + // takes a String object, all other setMethods need + // to get screened out + + Class[] ma =setMethod.getParameterTypes(); + if (ma.length == 1) { + Class c = ma[0]; + if (c.getName().equals("java.lang.String")) { + propertySetters.put(property, setMethod); + } + } + } + } + + for (int i = 0; i < nodeMap.getLength(); i++) { + Node node = nodeMap.item(i); + + // these should only be attribs, we won't see anything + // else here. + + if (node.getNodeType() == Node.ATTRIBUTE_NODE) { + Attr attr = (Attr)node; + + // reflect these into the task + + Method setMethod = (Method)propertySetters.get(attr.getName()); + if (setMethod == null) { + String msg = "Configuration property \"" + attr.getName() + + "\" does not have a setMethod in " + task.getClass(); + throw new BuildException(msg); + } + + String value=replaceProperties( attr.getValue(), project.getProperties() ); + try { + setMethod.invoke(task, new String[] {value}); + } catch (IllegalAccessException iae) { + String msg = "Error setting value for attrib: " + + attr.getName(); + iae.printStackTrace(); + throw new BuildException(msg); + } catch (InvocationTargetException ie) { + String msg = "Error setting value for attrib: " + + attr.getName() + " in " + task.getClass().getName(); + ie.printStackTrace(); + ie.getTargetException().printStackTrace(); + throw new BuildException(msg); + } + } + } } /** Replace ${NAME} with the property value */ public static String replaceProperties( String value, Hashtable keys ) - throws BuildException + throws BuildException { - // XXX use Map instead of proj, it's too heavy - - // XXX need to replace this code with something better. - StringBuffer sb=new StringBuffer(); - int i=0; - int prev=0; - // assert value!=nil - int pos; - while( (pos=value.indexOf( "$", prev )) >= 0 ) { - if(pos>0) - sb.append( value.substring( prev, pos ) ); - if( value.charAt( pos + 1 ) != '{' ) { - sb.append( value.charAt( pos + 1 ) ); - prev=pos+2; // XXX - } else { - int endName=value.indexOf( '}', pos ); - if( endName < 0 ) { - throw new BuildException("Syntax error in prop: " + - value ); - } - String n=value.substring( pos+2, endName ); - String v=(String) keys.get( n ); - //System.out.println("N: " + n + " " + " V:" + v); - sb.append( v ); - prev=endName+1; - } - } - if( prev < value.length() ) sb.append( value.substring( prev ) ); - // System.out.println("After replace: " + sb.toString()); - // System.out.println("Before replace: " + value); - return sb.toString(); + // XXX use Map instead of proj, it's too heavy + + // XXX need to replace this code with something better. + StringBuffer sb=new StringBuffer(); + int i=0; + int prev=0; + // assert value!=nil + int pos; + while( (pos=value.indexOf( "$", prev )) >= 0 ) { + if(pos>0) + sb.append( value.substring( prev, pos ) ); + if( value.charAt( pos + 1 ) != '{' ) { + sb.append( value.charAt( pos + 1 ) ); + prev=pos+2; // XXX + } else { + int endName=value.indexOf( '}', pos ); + if( endName < 0 ) { + throw new BuildException("Syntax error in prop: " + + value ); + } + String n=value.substring( pos+2, endName ); + String v=(String) keys.get( n ); + //System.out.println("N: " + n + " " + " V:" + v); + sb.append( v ); + prev=endName+1; + } + } + if( prev < value.length() ) sb.append( value.substring( prev ) ); + // System.out.println("After replace: " + sb.toString()); + // System.out.println("Before replace: " + value); + return sb.toString(); } } diff --git a/src/main/org/apache/tools/ant/Target.java b/src/main/org/apache/tools/ant/Target.java index 23266e88e..9c48d1be6 100644 --- a/src/main/org/apache/tools/ant/Target.java +++ b/src/main/org/apache/tools/ant/Target.java @@ -1,7 +1,7 @@ /* * The Apache Software License, Version 1.1 * - * Copyright (c) 1999 The Apache Software Foundation. All rights + * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -9,7 +9,7 @@ * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in @@ -17,15 +17,15 @@ * distribution. * * 3. The end-user documentation included with the redistribution, if - * any, must include the following acknowlegement: - * "This product includes software developed by the + * any, must include the following acknowlegement: + * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software * Foundation" must not be used to endorse or promote products derived - * from this software without prior written permission. For written + * from this software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache" @@ -54,73 +54,79 @@ package org.apache.tools.ant; -import java.util.Enumeration; -import java.util.Vector; -import java.util.StringTokenizer; +import java.util.*; /** + * This class implements a target object with required parameters. * - * - * @author duncan@x180.com + * @author James Davidson duncan@x180.com */ public class Target { private String name; - private Vector dependencies = new Vector(); - private Vector tasks = new Vector(); - Project project; - - public void setProject( Project project) { - this.project=project; + private String condition = ""; + private Vector dependencies = new Vector(2); + private Vector tasks = new Vector(5); + private Project project; + + public void setProject(Project project) { + this.project = project; } public Project getProject() { - return project; + return project; } - public void setDepends( String depS ) { - if (depS.length() > 0) { - StringTokenizer tok = - new StringTokenizer(depS, ",", false); - while (tok.hasMoreTokens()) { - addDependency(tok.nextToken().trim()); - } - } + public void setDepends(String depS) { + if (depS.length() > 0) { + StringTokenizer tok = + new StringTokenizer(depS, ",", false); + while (tok.hasMoreTokens()) { + addDependency(tok.nextToken().trim()); + } + } } - + public void setAttribute(String name, Object value) { - // XXX - if( value instanceof Task) - addTask( (Task)value); - + if (value instanceof Task) { + addTask((Task) value); + } } - + public void setName(String name) { - this.name = name; + this.name = name; } public String getName() { - return name; + return name; } public void addTask(Task task) { - tasks.addElement(task); + tasks.addElement(task); } public void addDependency(String dependency) { - dependencies.addElement(dependency); + dependencies.addElement(dependency); } public Enumeration getDependencies() { - return dependencies.elements(); + return dependencies.elements(); + } + + public void setCondition(String property) { + this.condition = property; } public void execute() throws BuildException { - Enumeration enum = tasks.elements(); - while (enum.hasMoreElements()) { - Task task = (Task)enum.nextElement(); - task.execute(); - } + if ((this.condition != null) || (this.condition.equals("")) || (project.getProperty(this.condition) != null)) { + Enumeration enum = tasks.elements(); + while (enum.hasMoreElements()) { + Task task = (Task) enum.nextElement(); + task.execute(); + } + } else { + project.log("Skipped because property '" + this.condition + "' not set.", this.name, Project.MSG_VERBOSE); + } } } diff --git a/src/main/org/apache/tools/ant/Task.java b/src/main/org/apache/tools/ant/Task.java index daee18085..e59b3e301 100644 --- a/src/main/org/apache/tools/ant/Task.java +++ b/src/main/org/apache/tools/ant/Task.java @@ -1,7 +1,7 @@ /* * The Apache Software License, Version 1.1 * - * Copyright (c) 1999 The Apache Software Foundation. All rights + * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -9,7 +9,7 @@ * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in @@ -17,15 +17,15 @@ * distribution. * * 3. The end-user documentation included with the redistribution, if - * any, must include the following acknowlegement: - * "This product includes software developed by the + * any, must include the following acknowlegement: + * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software * Foundation" must not be used to endorse or promote products derived - * from this software without prior written permission. For written + * from this software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache" @@ -54,24 +54,18 @@ package org.apache.tools.ant; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.util.StringTokenizer; -import java.util.Vector; +import java.io.*; +import java.util.*; /** - * Base class for all tasks in the + * Base class for all tasks. * * @author duncan@x180.com */ - public abstract class Task { protected Project project = null; - Target target; + protected Target target = null; /** * Sets the project object of this task. This method is used by @@ -81,75 +75,80 @@ public abstract class Task { * * @param project Project in whose scope this task belongs. */ - void setProject(Project project) { - this.project = project; + this.project = project; } - public void setAttribute( String name, Object v) { - if("target".equals( name ) ) { - Target t=(Target)v; - target=t; - project=t.getProject(); - return; - } - // System.out.println("Set Att " +name + " = " + v ); - // if( v!=null) System.out.println(v.getClass()); + /** + * Sets a task attribute. + * + * @param name the attribute name + * @param value the attribute value + */ + public void setAttribute(String name, Object value) { + if (name.equals("target")) { + this.target = (Target) value; + this.project = this.target.getProject(); + } } - + + /** + * Called by the project to let the task initialize properly. Normally it does nothing. + * + * @throws BuildException if someting goes wrong with the build + */ + public void init() throws BuildException {} + /** - * Called by the project to let the task do it's work. + * Called by the project to let the task do it's work. Normally it does nothing. * * @throws BuildException if someting goes wrong with the build */ - - public abstract void execute() throws BuildException; + public void execute() throws BuildException {}; /** * Convienence method to copy a file from a source to a destination * * @throws IOException */ - protected void copyFile(String sourceFile, String destFile) - throws IOException + throws IOException { - copyFile(new File(sourceFile), new File(destFile)); + copyFile(new File(sourceFile), new File(destFile)); } - + /** * Convienence method to copy a file from a source to a destination. * * @throws IOException */ - - protected void copyFile(File sourceFile,File destFile) throws IOException { - - if (destFile.lastModified() < sourceFile.lastModified()) { - project.log("Copy: " + sourceFile.getAbsolutePath() + " > " - + destFile.getAbsolutePath(), project.MSG_VERBOSE); - - // ensure that parent dir of dest file exists! - // not using getParentFile method to stay 1.1 compat - - File parent = new File(destFile.getParent()); - if (!parent.exists()) { - parent.mkdirs(); - } - - // open up streams and copy using a decent buffer - - FileInputStream in = new FileInputStream(sourceFile); - FileOutputStream out = new FileOutputStream(destFile); - byte[] buffer = new byte[8 * 1024]; - int count = 0; - do { - out.write(buffer, 0, count); - count = in.read(buffer, 0, buffer.length); - } while (count != -1); - in.close(); - out.close(); - } + protected void copyFile(File sourceFile, File destFile) throws IOException { + + if (destFile.lastModified() < sourceFile.lastModified()) { + project.log("Copy: " + sourceFile.getAbsolutePath() + " > " + + destFile.getAbsolutePath(), project.MSG_VERBOSE); + + // ensure that parent dir of dest file exists! + // not using getParentFile method to stay 1.1 compat + File parent = new File(destFile.getParent()); + if (!parent.exists()) { + parent.mkdirs(); + } + + // open up streams and copy using a decent buffer + FileInputStream in = new FileInputStream(sourceFile); + FileOutputStream out = new FileOutputStream(destFile); + + byte[] buffer = new byte[8 * 1024]; + int count = 0; + do { + out.write(buffer, 0, count); + count = in.read(buffer, 0, buffer.length); + } while (count != -1); + + in.close(); + out.close(); + } } }