001: package liquibase.change;
002:
003: import liquibase.FileOpener;
004: import liquibase.database.structure.DatabaseObject;
005: import liquibase.exception.SetupException;
006: import liquibase.log.LogFactory;
007: import liquibase.util.MD5Util;
008: import liquibase.util.StreamUtil;
009: import org.w3c.dom.Document;
010: import org.w3c.dom.Element;
011:
012: import java.io.FileInputStream;
013: import java.io.FileNotFoundException;
014: import java.io.IOException;
015: import java.io.InputStream;
016: import java.util.Set;
017: import java.util.logging.Logger;
018:
019: /**
020: * Represents a Change for custom SQL stored in a File.
021: *
022: * To create an instance call the constructor as normal and then call
023: * @{#setFileOpener(FileOpener)} before calling setPath otherwise the
024: * file will likely not be found.
025: *
026: *
027: * @author <a href="mailto:csuml@yahoo.co.uk">Paul Keeble</a>
028: *
029: */
030: public class SQLFileChange extends AbstractSQLChange {
031: private static final Logger log = LogFactory.getLogger();
032: private String file;
033: private String encoding = null;
034:
035: public SQLFileChange() {
036: super ("sqlFile", "SQL From File");
037: }
038:
039: public String getPath() {
040: return file;
041: }
042:
043: /**
044: * Sets the file name but setUp must be called for the change to have impact.
045: *
046: * @param fileName The file to use
047: */
048: public void setPath(String fileName) {
049: file = fileName;
050: }
051:
052: /**
053: * The encoding of the file containing SQL statements
054: * @return the encoding
055: */
056: public String getEncoding() {
057: return encoding;
058: }
059:
060: /**
061: * @param encoding the encoding to set
062: */
063: public void setEncoding(String encoding) {
064: this .encoding = encoding;
065: }
066:
067: public void setUp() throws SetupException {
068: if (file == null) {
069: throw new SetupException("<sqlfile> - No path specified");
070: }
071: log.fine("SQLFile file:" + file);
072: boolean loaded = loadFromClasspath(file);
073: if (!loaded) {
074: loaded = loadFromFileSystem(file);
075: }
076:
077: if (!loaded) {
078: throw new SetupException("<sqlfile path=" + file
079: + "> - Could not find file");
080: }
081: log.finer("SQLFile file contents is:" + getSql());
082: }
083:
084: /**
085: * Tries to load the file from the file system.
086: *
087: * @param file The name of the file to search for
088: * @return True if the file was found, false otherwise.
089: */
090: private boolean loadFromFileSystem(String file)
091: throws SetupException {
092:
093: FileInputStream fis = null;
094: try {
095: fis = new FileInputStream(file);
096: setSql(StreamUtil.getStreamContents(fis, encoding));
097: return true;
098: } catch (FileNotFoundException fnfe) {
099: return false;
100: } catch (IOException e) {
101: throw new SetupException("<sqlfile path=" + file
102: + "> -Unable to read file", e);
103: } finally {
104: if (fis != null) {
105: try {
106: fis.close();
107: } catch (IOException ioe) {//NOPMD
108: // safe to ignore
109: }
110: }
111: }
112:
113: }
114:
115: /**
116: * Tries to load a file using the FileOpener.
117: *
118: * If the fileOpener can not be found then the attempt to load from the
119: * classpath the return is false.
120: *
121: * @param file The file name to try and find.
122: * @return True if the file was found and loaded, false otherwise.
123: */
124: private boolean loadFromClasspath(String file)
125: throws SetupException {
126: InputStream in = null;
127: try {
128: FileOpener fo = getFileOpener();
129: if (fo == null) {
130: return false;
131: }
132:
133: in = fo.getResourceAsStream(file);
134: if (in == null) {
135: return false;
136: }
137: setSql(StreamUtil.getStreamContents(in, encoding));
138: return true;
139: } catch (IOException ioe) {
140: throw new SetupException("<sqlfile path=" + file
141: + "> -Unable to read file", ioe);
142: } finally {
143: if (in != null) {
144: try {
145: in.close();
146: } catch (IOException ioe) {//NOPMD
147: // safe to ignore
148: }
149: }
150: }
151: }
152:
153: /**
154: * Calculates an MD5 from the contents of the file.
155: *
156: * @see liquibase.change.AbstractChange#getMD5Sum()
157: */
158: public String getMD5Sum() {
159: return MD5Util.computeMD5(getSql());
160: }
161:
162: public Element createNode(Document currentChangeLogDOM) {
163: Element sqlElement = currentChangeLogDOM
164: .createElement("sqlFile");
165: sqlElement.setAttribute("path", file);
166: if (encoding != null) {
167: sqlElement.setAttribute("encoding", encoding);
168: }
169: return sqlElement;
170: }
171:
172: public String getConfirmationMessage() {
173: return "SQL in file " + file + " executed";
174: }
175:
176: public Set<DatabaseObject> getAffectedDatabaseObjects() {
177: return null;
178: }
179: }
|