View Javadoc

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         // get a connection to the proxy database
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         // init master stores
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         // init proxy stores
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         // import data from the proxy database to the master database
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         // init master tables
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 }