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