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