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