View Javadoc

1   /**
2    * Copyright 2010-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.common.util.service;
17  
18  import java.io.File;
19  import java.io.IOException;
20  import java.io.PrintStream;
21  import java.util.ArrayList;
22  import java.util.List;
23  
24  import org.apache.commons.io.IOUtils;
25  import org.apache.commons.lang3.StringUtils;
26  import org.kuali.common.util.Assert;
27  import org.kuali.common.util.CollectionUtils;
28  import org.kuali.common.util.FormatUtils;
29  import org.kuali.common.util.LocationUtils;
30  import org.kuali.common.util.PrintlnStreamConsumer;
31  import org.slf4j.Logger;
32  import org.slf4j.LoggerFactory;
33  
34  public class DefaultMySqlDumpService extends DefaultExecService implements MySqlDumpService {
35  
36  	private static final Logger logger = LoggerFactory.getLogger(DefaultMySqlDumpService.class);
37  
38  	@Override
39  	public void dump(String username, String password, String hostname, String database, File outputFile) {
40  		MySqlDumpContext context = new MySqlDumpContext();
41  		context.setExecutable(DEFAULT_EXECUTABLE);
42  		context.setUsername(username);
43  		context.setPassword(password);
44  		context.setHostname(hostname);
45  		context.setDatabase(database);
46  		context.setOutputFile(outputFile);
47  		dump(context);
48  	}
49  
50  	@Override
51  	public void dump(List<String> options, String database, File outputFile) {
52  		MySqlDumpContext context = new MySqlDumpContext();
53  		context.setExecutable(DEFAULT_EXECUTABLE);
54  		context.setOptions(options);
55  		context.setDatabase(database);
56  		context.setOutputFile(outputFile);
57  		dump(context);
58  	}
59  
60  	@Override
61  	public void dump(MySqlDumpContext context) {
62  		Assert.notNull(context.getDatabase(), "database is null");
63  		Assert.notNull(context.getOutputFile(), "output file is null");
64  		Assert.notNull(context.getExecutable(), "executable is null");
65  		fillInOptions(context);
66  		DefaultExecContext dec = getExecContext(context);
67  		beforeDump(context);
68  		dump(dec, context);
69  	}
70  
71  	protected void beforeDump(MySqlDumpContext context) {
72  		String username = StringUtils.trimToEmpty(context.getUsername());
73  		String hostname = StringUtils.trimToEmpty(context.getHostname());
74  		int port = context.getPort();
75  		String database = context.getDatabase();
76  		String path = LocationUtils.getCanonicalPath(context.getOutputFile());
77  		Object[] args = { username, hostname, port, database, path };
78  		logger.info("Dumping [{}@{}:{}/{}] -> [{}]", args);
79  	}
80  
81  	protected void dump(DefaultExecContext context, MySqlDumpContext msdc) {
82  		PrintStream out = null;
83  		try {
84  			out = LocationUtils.openPrintStream(msdc.getOutputFile());
85  			PrintlnStreamConsumer standardOutConsumer = new PrintlnStreamConsumer(out, msdc.getIgnorers());
86  			context.setStandardOutConsumer(standardOutConsumer);
87  			long start = System.currentTimeMillis();
88  			int result = execute(context);
89  			long elapsed = System.currentTimeMillis() - start;
90  			if (result != 0) {
91  				throw new IllegalStateException("Non-zero exit value - " + result);
92  			}
93  			afterDump(msdc, elapsed, standardOutConsumer.getLineCount(), standardOutConsumer.getSkipCount());
94  		} catch (IOException e) {
95  			throw new IllegalStateException("Unexpected IO error", e);
96  		} finally {
97  			IOUtils.closeQuietly(out);
98  		}
99  	}
100 
101 	protected void afterDump(MySqlDumpContext context, long elapsed, long lineCount, long skippedCount) {
102 		long length = context.getOutputFile().length();
103 		String time = FormatUtils.getTime(elapsed);
104 		String size = FormatUtils.getSize(length);
105 		String rate = FormatUtils.getRate(elapsed, length);
106 		String lines = FormatUtils.getCount(lineCount);
107 		String skipped = FormatUtils.getCount(skippedCount);
108 		Object[] args = { time, size, rate, lines, skipped };
109 		logger.info("Dump completed. [Time:{}, Size:{}, Rate:{}, Lines:{}  Skipped:{}]", args);
110 	}
111 
112 	protected DefaultExecContext getExecContext(MySqlDumpContext context) {
113 		List<String> args = getArgs(context);
114 		DefaultExecContext dec = new DefaultExecContext();
115 		dec.setExecutable(context.getExecutable());
116 		dec.setArgs(args);
117 		return dec;
118 	}
119 
120 	/**
121 	 * <code>mysqldump</code> invocation looks like this:
122 	 *
123 	 * <pre>
124 	 * mysqldump [OPTIONS] database [tables]
125 	 * </pre>
126 	 */
127 	protected List<String> getArgs(MySqlDumpContext context) {
128 		List<String> args = new ArrayList<String>();
129 		args.addAll(CollectionUtils.toEmptyList(context.getOptions()));
130 		args.add(context.getDatabase());
131 		args.addAll(CollectionUtils.toEmptyList(context.getTables()));
132 		return args;
133 	}
134 
135 	/**
136 	 * Create (or update) the list of options for this context
137 	 */
138 	protected void fillInOptions(MySqlDumpContext context) {
139 		// Get a handle to the existing options list, or create new one
140 		List<String> options = context.getOptions() == null ? new ArrayList<String>() : context.getOptions();
141 		// Insert the options we are explicitly managing at the front of the list
142 		options.add(0, "--port=" + context.getPort());
143 		if (!StringUtils.isBlank(context.getHostname())) {
144 			options.add(0, "--host=" + context.getHostname());
145 		}
146 		if (!StringUtils.isBlank(context.getPassword())) {
147 			options.add(0, "--password=" + context.getPassword());
148 		}
149 		if (!StringUtils.isBlank(context.getUsername())) {
150 			options.add(0, "--user=" + context.getUsername());
151 		}
152 		// Just in case there were no options to begin with
153 		context.setOptions(options);
154 	}
155 }