1 /***
2 * Redistribution and use of this software and associated documentation
3 * ("Software"), with or without modification, are permitted provided
4 * that the following conditions are met:
5 *
6 * 1. Redistributions of source code must retain copyright
7 * statements and notices. Redistributions must also contain a
8 * copy of this document.
9 *
10 * 2. Redistributions in binary form must reproduce the
11 * above copyright notice, this list of conditions and the
12 * following disclaimer in the documentation and/or other
13 * materials provided with the distribution.
14 *
15 * 3. The name "Exolab" must not be used to endorse or promote
16 * products derived from this Software without prior written
17 * permission of Exoffice Technologies. For written permission,
18 * please contact info@exolab.org.
19 *
20 * 4. Products derived from this Software may not be called "Exolab"
21 * nor may "Exolab" appear in their names without prior written
22 * permission of Exoffice Technologies. Exolab is a registered
23 * trademark of Exoffice Technologies.
24 *
25 * 5. Due credit should be given to the Exolab Project
26 * (http://www.exolab.org/).
27 *
28 * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
32 * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39 * OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 * Copyright 2005 (C) Exoffice Technologies Inc. All Rights Reserved.
42 *
43 * $Id: Importer.java,v 1.3 2005/11/12 12:47:37 tanderson Exp $
44 */
45 package org.exolab.jms.tools.migration;
46
47 import java.sql.Connection;
48 import java.sql.SQLException;
49 import java.util.Date;
50 import javax.jms.JMSException;
51
52 import org.apache.commons.logging.Log;
53 import org.apache.commons.logging.LogFactory;
54 import org.apache.derby.jdbc.EmbeddedDataSource;
55
56 import org.exolab.jms.config.Configuration;
57 import org.exolab.jms.config.ConfigurationReader;
58 import org.exolab.jms.persistence.DatabaseService;
59 import org.exolab.jms.persistence.PersistenceException;
60 import org.exolab.jms.service.ServiceException;
61 import org.exolab.jms.tools.db.Database;
62 import org.exolab.jms.tools.db.RDBMSTool;
63 import org.exolab.jms.tools.db.SchemaHelper;
64 import org.exolab.jms.tools.migration.master.MasterConsumerStore;
65 import org.exolab.jms.tools.migration.master.MasterDestinationStore;
66 import org.exolab.jms.tools.migration.master.MasterMessageStore;
67 import org.exolab.jms.tools.migration.master.MasterUserStore;
68 import org.exolab.jms.tools.migration.proxy.ConsumerStore;
69 import org.exolab.jms.tools.migration.proxy.DestinationStore;
70 import org.exolab.jms.tools.migration.proxy.MessageStore;
71 import org.exolab.jms.tools.migration.proxy.PropertyStore;
72 import org.exolab.jms.tools.migration.proxy.UserStore;
73 import org.exolab.jms.tools.migration.proxy.VersionInfo;
74 import org.exolab.jms.util.CommandLine;
75
76
77 /***
78 * Imports data from a proxy database into a master.
79 *
80 * @author <a href="mailto:tma@netspace.net.au">Tim Anderson</a>
81 * @version $Revision: 1.3 $ $Date: 2005/11/12 12:47:37 $
82 * @see Exporter
83 */
84
85 public class Importer {
86
87 /***
88 * The database service.
89 */
90 private final DatabaseService _database;
91
92 /***
93 * The connection factory for the source database.
94 */
95 private final EmbeddedDataSource _dataSource;
96
97 /***
98 * The logger.
99 */
100 private final Log _log = LogFactory.getLog(Importer.class);
101
102
103 /***
104 * Construct a new <code>Importer</code>.
105 *
106 * @param config the configuration to use
107 * @param database the database name
108 * @param delete if <code>true</code>, indicates to delete data in the
109 * master database, if it exists
110 * @throws PersistenceException for any persistence error
111 */
112 public Importer(Configuration config, String database, boolean delete)
113 throws PersistenceException {
114 if (config == null) {
115 throw new IllegalArgumentException("Argument 'config' is null");
116 }
117 if (database == null) {
118 throw new IllegalArgumentException("Argument 'database' is null");
119 }
120 _database = new DatabaseService(config);
121 _dataSource = new EmbeddedDataSource();
122 _dataSource.setDatabaseName(database);
123 _dataSource.setCreateDatabase("create");
124 init(config, delete);
125 }
126
127 /***
128 * Import the data from the proxy database to the master database.
129 *
130 * @throws JMSException for any JMS error
131 * @throws PersistenceException for any persistence error
132 * @throws ServiceException for any service error
133 */
134 public void apply()
135 throws JMSException, PersistenceException, ServiceException {
136
137 Connection source;
138 try {
139 source = _dataSource.getConnection();
140 } catch (SQLException exception) {
141 throw new PersistenceException(
142 "Failed to get connection to source database",
143 exception);
144 }
145
146 _database.start();
147
148
149 MasterDestinationStore masterDestinations
150 = new MasterDestinationStore(_database);
151 MasterMessageStore masterMessages = new MasterMessageStore(_database);
152 MasterConsumerStore masterConsumers
153 = new MasterConsumerStore(_database);
154 MasterUserStore masterUsers = new MasterUserStore(_database);
155
156
157 PropertyStore properties = new PropertyStore(source);
158 VersionInfo info = new VersionInfo(properties);
159 String schemaVersion = info.getProxySchemaVersion();
160 if (schemaVersion == null || !schemaVersion.equals("1.0")) {
161 throw new PersistenceException("Cannot import data: unsupported schema version: "
162 + schemaVersion);
163 }
164 Date created = new Date(info.getCreationTimestamp());
165 _log.info("Importing data created on " + created + " by OpenJMS "
166 + info.getOpenJMSVersion());
167
168 DestinationStore destinations = new DestinationStore(source);
169 ConsumerStore consumers = new ConsumerStore(destinations, source);
170 MessageStore messages = new MessageStore(destinations, source);
171 UserStore users = new UserStore(source);
172
173
174 _log.info("Importing destinations...");
175 apply(destinations, masterDestinations);
176 _log.info("Imported " + masterDestinations.size() + " destinations");
177
178 _log.info("Importing messages...");
179 apply(messages, masterMessages);
180 _log.info("Imported " + masterMessages.size() + " messages");
181
182 _log.info("Importing consumers...");
183 apply(consumers, new MasterConsumerStore(_database));
184 _log.info("Imported " + masterConsumers.size() + " consumers");
185
186 _log.info("Importing users...");
187 apply(users, new MasterUserStore(_database));
188 _log.info("Imported " + masterUsers.size() + " users");
189
190 try {
191 source.close();
192 } catch (SQLException exception) {
193 throw new PersistenceException("Failed to close source",
194 exception);
195 }
196 _database.stop();
197 _dataSource.setShutdownDatabase("shutdown");
198
199 _log.info("Import complete");
200 }
201
202 /***
203 * Main line.
204 *
205 * @param args command line arguments
206 */
207 public static void main(String[] args) {
208 CommandLine commands = new CommandLine(args);
209
210 String path = commands.value("config");
211 if (path == null) {
212 usage();
213 System.exit(1);
214 } else {
215 try {
216 Configuration config = ConfigurationReader.read(path);
217
218 String database = commands.value("db");
219 if (database == null) {
220 database = "openjms_migdb";
221 }
222 boolean delete = commands.exists("delete");
223 Importer importer = new Importer(config, database, delete);
224 importer.apply();
225 System.exit(0);
226 } catch (Exception exception) {
227 exception.printStackTrace();
228 System.exit(1);
229 }
230 }
231 }
232
233 /***
234 * Initialise the target database.
235 *
236 * @param config the datbase configuration
237 * @param delete if <code>true</code>, indicates to delete data in the
238 * master database, if it exists
239 * @throws PersistenceException for any persistence error
240 */
241 private void init(Configuration config, boolean delete)
242 throws PersistenceException {
243
244 RDBMSTool tool = new RDBMSTool(config);
245 Database schema = SchemaHelper.getSchema();
246
247 try {
248 if (tool.hasTables(schema.getTable())) {
249 if (delete) {
250 tool.delete(schema);
251 } else {
252 throw new PersistenceException(
253 "Cannot import data: master database already exists "
254 + "but delete not specified");
255 }
256 } else {
257 tool.create(schema);
258 }
259 } finally {
260 tool.close();
261 }
262 }
263
264 /***
265 * Export data from a source store, and import it to a target store.
266 *
267 * @param source the source store
268 * @param target the target store
269 * @throws JMSException for any JMS error
270 * @throws PersistenceException for any persistence error
271 */
272 private void apply(Store source, Store target)
273 throws JMSException, PersistenceException {
274
275 StoreIterator iterator = source.exportCollection();
276 target.importCollection(iterator);
277 }
278
279 /***
280 * Displays usage information for this tool when invoked from the command
281 * line.
282 */
283 private static void usage() {
284 System.err.println("usage: " + Importer.class.getName()
285 + " <arguments> [options]\n" +
286 "arguments:\n"
287 + " -config <path> specifies the path to an OpenJMS "
288 + "configuration file\n"
289 + " -import <path> specifies the path to import data from\n");
290 }
291
292 }