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