001
014
015 package com.liferay.portal.convert;
016
017 import com.liferay.mail.model.CyrusUser;
018 import com.liferay.mail.model.CyrusVirtual;
019 import com.liferay.portal.events.StartupHelperUtil;
020 import com.liferay.portal.kernel.dao.db.DB;
021 import com.liferay.portal.kernel.dao.db.DBFactoryUtil;
022 import com.liferay.portal.kernel.dao.jdbc.DataAccess;
023 import com.liferay.portal.kernel.dao.jdbc.DataSourceFactoryUtil;
024 import com.liferay.portal.kernel.log.Log;
025 import com.liferay.portal.kernel.log.LogFactoryUtil;
026 import com.liferay.portal.kernel.servlet.ServletContextPool;
027 import com.liferay.portal.kernel.util.ClassLoaderUtil;
028 import com.liferay.portal.kernel.util.StringPool;
029 import com.liferay.portal.kernel.util.StringUtil;
030 import com.liferay.portal.kernel.util.Tuple;
031 import com.liferay.portal.model.ModelHintsUtil;
032 import com.liferay.portal.model.ServiceComponent;
033 import com.liferay.portal.service.ServiceComponentLocalServiceUtil;
034 import com.liferay.portal.spring.hibernate.DialectDetector;
035 import com.liferay.portal.upgrade.util.Table;
036 import com.liferay.portal.util.MaintenanceUtil;
037 import com.liferay.portal.util.ShutdownUtil;
038
039 import java.lang.reflect.Field;
040
041 import java.sql.Connection;
042
043 import java.util.HashSet;
044 import java.util.LinkedHashMap;
045 import java.util.List;
046 import java.util.Map;
047 import java.util.Set;
048
049 import javax.servlet.ServletContext;
050
051 import javax.sql.DataSource;
052
053 import org.hibernate.dialect.Dialect;
054
055
058 public class ConvertDatabase extends BaseConvertProcess {
059
060 @Override
061 public String getDescription() {
062 return "migrate-data-from-one-database-to-another";
063 }
064
065 @Override
066 public String getParameterDescription() {
067 return "please-enter-jdbc-information-for-new-database";
068 }
069
070 @Override
071 public String[] getParameterNames() {
072 return new String[] {
073 "jdbc-driver-class-name", "jdbc-url", "jdbc-user-name",
074 "jdbc-password"
075 };
076 }
077
078 @Override
079 public boolean isEnabled() {
080 return true;
081 }
082
083 @Override
084 protected void doConvert() throws Exception {
085 DataSource dataSource = getDataSource();
086
087 Dialect dialect = DialectDetector.getDialect(dataSource);
088
089 DB db = DBFactoryUtil.getDB(dialect, dataSource);
090
091 List<String> modelNames = ModelHintsUtil.getModels();
092
093 Map<String, Tuple> tableDetails = new LinkedHashMap<>();
094
095 Connection connection = dataSource.getConnection();
096
097 try {
098 MaintenanceUtil.appendStatus(
099 "Collecting information for database tables to migration");
100
101 for (String modelName : modelNames) {
102 if (!modelName.contains(".model.")) {
103 continue;
104 }
105
106 String implClassName = modelName.replaceFirst(
107 "(\\.model\\.)(\\p{Upper}.*)", "$1impl.$2Impl");
108
109 if (_log.isDebugEnabled()) {
110 _log.debug("Loading class " + implClassName);
111 }
112
113 Class<?> implClass = getImplClass(implClassName);
114
115 if (implClass == null) {
116 _log.error("Unable to load class " + implClassName);
117
118 continue;
119 }
120
121 Field[] fields = implClass.getFields();
122
123 for (Field field : fields) {
124 Tuple tuple = null;
125
126 String fieldName = field.getName();
127
128 if (fieldName.equals("TABLE_NAME") ||
129 (fieldName.startsWith("MAPPING_TABLE_") &&
130 fieldName.endsWith("_NAME"))) {
131
132 tuple = getTableDetails(implClass, field, fieldName);
133 }
134
135 if (tuple != null) {
136 String table = (String)tuple.getObject(0);
137
138 tableDetails.put(table, tuple);
139 }
140 }
141 }
142
143 for (Tuple tuple : _UNMAPPED_TABLES) {
144 String table = (String)tuple.getObject(0);
145
146 tableDetails.put(table, tuple);
147 }
148
149 if (_log.isDebugEnabled()) {
150 _log.debug("Migrating database tables");
151 }
152
153 int i = 0;
154
155 for (Tuple tuple : tableDetails.values()) {
156 if ((i > 0) && (i % (tableDetails.size() / 4) == 0)) {
157 MaintenanceUtil.appendStatus(
158 (i * 100 / tableDetails.size()) + "%");
159 }
160
161 String table = (String)tuple.getObject(0);
162 Object[][] columns = (Object[][])tuple.getObject(1);
163 String sqlCreate = (String)tuple.getObject(2);
164
165 migrateTable(db, connection, table, columns, sqlCreate);
166
167 i++;
168 }
169
170 if (_log.isDebugEnabled()) {
171 _log.debug("Migrating database indexes");
172 }
173
174 StartupHelperUtil.updateIndexes(db, connection, false);
175
176 List<ServiceComponent> serviceComponents =
177 ServiceComponentLocalServiceUtil.getLatestServiceComponents();
178
179 Set<String> validIndexNames = new HashSet<>();
180
181 for (ServiceComponent serviceComponent : serviceComponents) {
182 String indexesSQL = serviceComponent.getIndexesSQL();
183
184 db.addIndexes(connection, indexesSQL, validIndexNames);
185 }
186 }
187 finally {
188 DataAccess.cleanUp(connection);
189 }
190
191 MaintenanceUtil.appendStatus(
192 "Please change your JDBC settings before restarting server");
193
194 ShutdownUtil.shutdown(0);
195 }
196
197 protected DataSource getDataSource() throws Exception {
198 String[] values = getParameterValues();
199
200 String driverClassName = values[0];
201 String url = values[1];
202 String userName = values[2];
203 String password = values[3];
204 String jndiName = StringPool.BLANK;
205
206 return DataSourceFactoryUtil.initDataSource(
207 driverClassName, url, userName, password, jndiName);
208 }
209
210 protected Class<?> getImplClass(String implClassName) throws Exception {
211 try {
212 ClassLoader classLoader = ClassLoaderUtil.getPortalClassLoader();
213
214 return classLoader.loadClass(implClassName);
215 }
216 catch (Exception e) {
217 }
218
219 for (String servletContextName : ServletContextPool.keySet()) {
220 try {
221 ServletContext servletContext = ServletContextPool.get(
222 servletContextName);
223
224 ClassLoader classLoader = servletContext.getClassLoader();
225
226 return classLoader.loadClass(implClassName);
227 }
228 catch (Exception e) {
229 }
230 }
231
232 return null;
233 }
234
235 protected Tuple getTableDetails(
236 Class<?> implClass, Field tableField, String tableFieldVar) {
237
238 try {
239 String columnsFieldVar = StringUtil.replace(
240 tableFieldVar, "_NAME", "_COLUMNS");
241 String sqlCreateFieldVar = StringUtil.replace(
242 tableFieldVar, "_NAME", "_SQL_CREATE");
243
244 Field columnsField = implClass.getField(columnsFieldVar);
245 Field sqlCreateField = implClass.getField(sqlCreateFieldVar);
246
247 String table = (String)tableField.get(StringPool.BLANK);
248 Object[][] columns = (Object[][])columnsField.get(new Object[0][0]);
249 String sqlCreate = (String)sqlCreateField.get(StringPool.BLANK);
250
251 return new Tuple(table, columns, sqlCreate);
252 }
253 catch (Exception e) {
254 }
255
256 return null;
257 }
258
259 protected void migrateTable(
260 DB db, Connection connection, String tableName, Object[][] columns,
261 String sqlCreate)
262 throws Exception {
263
264 Table table = new Table(tableName, columns);
265
266 try {
267 table.generateTempFile();
268
269 db.runSQL(connection, sqlCreate);
270
271 table.populateTable(connection);
272 }
273 catch (Exception e) {
274 _log.error(e, e);
275
276 MaintenanceUtil.appendStatus(e.getMessage());
277 }
278 }
279
280 private static final Tuple[] _UNMAPPED_TABLES = new Tuple[] {
281 new Tuple(
282 CyrusUser.TABLE_NAME, CyrusUser.TABLE_COLUMNS,
283 CyrusUser.TABLE_SQL_CREATE),
284 new Tuple(
285 CyrusVirtual.TABLE_NAME, CyrusVirtual.TABLE_COLUMNS,
286 CyrusVirtual.TABLE_SQL_CREATE)
287 };
288
289 private static final Log _log = LogFactoryUtil.getLog(
290 ConvertDatabase.class);
291
292 }