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