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