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