1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portal.convert;
16  
17  import com.liferay.counter.model.Counter;
18  import com.liferay.mail.model.CyrusUser;
19  import com.liferay.mail.model.CyrusVirtual;
20  import com.liferay.portal.dao.jdbc.util.DataSourceFactoryBean;
21  import com.liferay.portal.kernel.dao.db.DB;
22  import com.liferay.portal.kernel.dao.db.DBFactoryUtil;
23  import com.liferay.portal.kernel.dao.jdbc.DataAccess;
24  import com.liferay.portal.kernel.log.Log;
25  import com.liferay.portal.kernel.log.LogFactoryUtil;
26  import com.liferay.portal.kernel.util.InstancePool;
27  import com.liferay.portal.kernel.util.StringPool;
28  import com.liferay.portal.kernel.util.StringUtil;
29  import com.liferay.portal.kernel.util.Tuple;
30  import com.liferay.portal.model.ModelHintsUtil;
31  import com.liferay.portal.spring.hibernate.DialectDetector;
32  import com.liferay.portal.upgrade.util.Table;
33  import com.liferay.portal.util.MaintenanceUtil;
34  import com.liferay.portal.util.ShutdownUtil;
35  
36  import java.lang.reflect.Field;
37  
38  import java.sql.Connection;
39  
40  import java.util.ArrayList;
41  import java.util.List;
42  import java.util.Properties;
43  
44  import javax.sql.DataSource;
45  
46  import org.hibernate.dialect.Dialect;
47  
48  /**
49   * <a href="ConvertDatabase.java.html"><b><i>View Source</i></b></a>
50   *
51   * @author Alexander Chow
52   */
53  public class ConvertDatabase extends ConvertProcess {
54  
55      public String getDescription() {
56          return "migrate-data-from-one-database-to-another";
57      }
58  
59      public String getParameterDescription() {
60          return "please-enter-jdbc-information-for-new-database";
61      }
62  
63      public String[] getParameterNames() {
64          return new String[] {
65              "jdbc-driver-class-name", "jdbc-url", "jdbc-user-name",
66              "jdbc-password"
67          };
68      }
69  
70      public boolean isEnabled() {
71          return true;
72      }
73  
74      protected void doConvert() throws Exception {
75          DataSource dataSource = getDataSource();
76  
77          Dialect dialect = DialectDetector.getDialect(dataSource);
78  
79          DB db = DBFactoryUtil.getDB(dialect);
80  
81          List<String> modelNames = ModelHintsUtil.getModels();
82  
83          List<Tuple> tableDetails = new ArrayList<Tuple>();
84  
85          Connection connection = dataSource.getConnection();
86  
87          try {
88              MaintenanceUtil.appendStatus(
89                  "Collecting information for database tables to migration");
90  
91              for (String modelName : modelNames) {
92                  String implClassName = modelName.replaceFirst(
93                      "(\\.model\\.)(\\p{Upper}.*)", "$1impl.$2Impl");
94  
95                  Class<?> implClass = InstancePool.get(implClassName).getClass();
96  
97                  Field[] fields = implClass.getFields();
98  
99                  for (Field field : fields) {
100                     Tuple tuple = null;
101 
102                     String fieldName = field.getName();
103 
104                     if (fieldName.equals("TABLE_NAME")) {
105                         tuple = getTableDetails(implClass, field, fieldName);
106                     }
107                     else if (fieldName.startsWith("MAPPING_TABLE_") &&
108                              fieldName.endsWith("_NAME")) {
109 
110                         tuple = getTableDetails(implClass, field, fieldName);
111                     }
112 
113                     if (tuple != null) {
114                         tableDetails.add(tuple);
115                     }
116                 }
117             }
118 
119             for (Tuple tuple : _UNMAPPED_TABLES) {
120                 tableDetails.add(tuple);
121             }
122 
123             if (_log.isDebugEnabled()) {
124                 _log.debug("Migrating database tables");
125             }
126 
127             for (int i = 0; i < tableDetails.size(); i++) {
128                 if ((i > 0) && (i % (tableDetails.size() / 4) == 0)) {
129                     MaintenanceUtil.appendStatus(
130                          (i * 100 / tableDetails.size()) + "%");
131                 }
132 
133                 Tuple tuple = tableDetails.get(i);
134 
135                 String table = (String)tuple.getObject(0);
136                 Object[][] columns = (Object[][])tuple.getObject(1);
137                 String sqlCreate = (String)tuple.getObject(2);
138 
139                 migrateTable(db, connection, table, columns, sqlCreate);
140             }
141         }
142         finally {
143             DataAccess.cleanUp(connection);
144         }
145 
146         MaintenanceUtil.appendStatus(
147             "Please change your JDBC settings before restarting server");
148 
149         ShutdownUtil.shutdown(0);
150     }
151 
152     protected DataSource getDataSource() throws Exception {
153         String[] values = getParameterValues();
154 
155         String jdbcDriverClassName = values[0];
156         String jdbcURL = values[1];
157         String jdbcUserName = values[2];
158         String jdbcPassword = values[3];
159 
160         Properties properties = new Properties();
161 
162         properties.setProperty(
163             _JDBC_PREFIX + "driverClassName", jdbcDriverClassName);
164         properties.setProperty(_JDBC_PREFIX + "url", jdbcURL);
165         properties.setProperty(_JDBC_PREFIX + "username", jdbcUserName);
166         properties.setProperty(_JDBC_PREFIX + "password", jdbcPassword);
167 
168         DataSourceFactoryBean dataSourceFactory = new DataSourceFactoryBean();
169 
170         dataSourceFactory.setProperties(properties);
171         dataSourceFactory.setPropertyPrefix(_JDBC_PREFIX);
172 
173         return dataSourceFactory.createInstance();
174     }
175 
176     protected Tuple getTableDetails(
177         Class<?> implClass, Field tableField, String tableFieldVar) {
178 
179         try {
180             String columnsFieldVar = StringUtil.replace(
181                 tableFieldVar, "_NAME", "_COLUMNS");
182             String sqlCreateFieldVar = StringUtil.replace(
183                 tableFieldVar, "_NAME", "_SQL_CREATE");
184 
185             Field columnsField = implClass.getField(columnsFieldVar);
186             Field sqlCreateField = implClass.getField(sqlCreateFieldVar);
187 
188             String table = (String)tableField.get(StringPool.BLANK);
189             Object[][] columns = (Object[][])columnsField.get(new Object[0][0]);
190             String sqlCreate = (String)sqlCreateField.get(StringPool.BLANK);
191 
192             return new Tuple(table, columns, sqlCreate);
193         }
194         catch (Exception e) {
195         }
196 
197         return null;
198     }
199 
200     protected void migrateTable(
201             DB db, Connection connection, String tableName, Object[][] columns,
202             String sqlCreate)
203         throws Exception {
204 
205         Table table = new Table(tableName, columns);
206 
207         String tempFileName = table.generateTempFile();
208 
209         db.runSQL(connection, sqlCreate);
210 
211         if (tempFileName != null) {
212             table.populateTable(tempFileName, connection);
213         }
214     }
215 
216     private static final String _JDBC_PREFIX = "jdbc.upgrade.";
217 
218     private static final Tuple[] _UNMAPPED_TABLES = new Tuple[] {
219         new Tuple(
220             Counter.TABLE_NAME, Counter.TABLE_COLUMNS,
221             Counter.TABLE_SQL_CREATE),
222         new Tuple(
223             CyrusUser.TABLE_NAME, CyrusUser.TABLE_COLUMNS,
224             CyrusUser.TABLE_SQL_CREATE),
225         new Tuple(
226             CyrusVirtual.TABLE_NAME, CyrusVirtual.TABLE_COLUMNS,
227             CyrusVirtual.TABLE_SQL_CREATE)
228     };
229 
230     private static Log _log = LogFactoryUtil.getLog(ConvertDatabase.class);
231 
232 }