1
22
23 package com.liferay.portal.events;
24
25 import com.liferay.portal.kernel.dao.jdbc.DataAccess;
26 import com.liferay.portal.kernel.log.Log;
27 import com.liferay.portal.kernel.log.LogFactoryUtil;
28 import com.liferay.portal.kernel.search.SearchEngineUtil;
29 import com.liferay.portal.kernel.util.GetterUtil;
30 import com.liferay.portal.kernel.util.InstancePool;
31 import com.liferay.portal.kernel.util.PropertiesUtil;
32 import com.liferay.portal.kernel.util.StringUtil;
33 import com.liferay.portal.kernel.util.Validator;
34 import com.liferay.portal.service.persistence.BatchSessionUtil;
35 import com.liferay.portal.tools.sql.DBUtil;
36 import com.liferay.portal.tools.sql.Index;
37 import com.liferay.portal.upgrade.UpgradeException;
38 import com.liferay.portal.upgrade.UpgradeProcess;
39 import com.liferay.portal.util.PropsKeys;
40 import com.liferay.portal.util.PropsUtil;
41 import com.liferay.portal.verify.VerifyException;
42 import com.liferay.portal.verify.VerifyProcess;
43
44 import java.io.BufferedReader;
45 import java.io.StringReader;
46
47 import java.sql.Connection;
48 import java.sql.DatabaseMetaData;
49 import java.sql.PreparedStatement;
50 import java.sql.ResultSet;
51
52 import java.util.ArrayList;
53 import java.util.Collections;
54 import java.util.Enumeration;
55 import java.util.HashSet;
56 import java.util.List;
57 import java.util.Properties;
58 import java.util.Set;
59
60
68 public class StartupHelper {
69
70 public void deleteTempImages() {
71 try {
72 DBUtil dbUtil = DBUtil.getInstance();
73
74 dbUtil.runSQL(_DELETE_TEMP_IMAGES_1);
75 dbUtil.runSQL(_DELETE_TEMP_IMAGES_2);
76 }
77 catch (Exception e) {
78 _log.error(e, e);
79 }
80 }
81
82 public void setDropIndexes(boolean dropIndexes) {
83 _dropIndexes = dropIndexes;
84 }
85
86 public void updateIndexes() {
87 try {
88 List<Index> indexes = getIndexes();
89
90 Set<String> validIndexNames = dropIndexes(indexes);
91
92 addIndexes(validIndexNames);
93 }
94 catch (Exception e) {
95 _log.error(e, e);
96 }
97 }
98
99 public void upgradeProcess(int buildNumber) throws UpgradeException {
100 String[] upgradeProcesses = PropsUtil.getArray(
101 PropsKeys.UPGRADE_PROCESSES);
102
103 for (int i = 0; i < upgradeProcesses.length; i++) {
104 if (_log.isDebugEnabled()) {
105 _log.debug("Initializing upgrade " + upgradeProcesses[i]);
106 }
107
108 UpgradeProcess upgradeProcess = (UpgradeProcess)InstancePool.get(
109 upgradeProcesses[i]);
110
111 if (upgradeProcess == null) {
112 _log.error(upgradeProcesses[i] + " cannot be found");
113
114 continue;
115 }
116
117 if ((upgradeProcess.getThreshold() == 0) ||
118 (upgradeProcess.getThreshold() > buildNumber)) {
119
120 if (_log.isDebugEnabled()) {
121 _log.debug("Running upgrade " + upgradeProcesses[i]);
122 }
123
124 upgradeProcess.upgrade();
125
126 if (_log.isDebugEnabled()) {
127 _log.debug("Finished upgrade " + upgradeProcesses[i]);
128 }
129
130 _upgraded = true;
131 }
132 else {
133 if (_log.isDebugEnabled()) {
134 _log.debug(
135 "Upgrade threshold " + upgradeProcess.getThreshold() +
136 " will not trigger upgrade");
137
138 _log.debug("Skipping upgrade " + upgradeProcesses[i]);
139 }
140 }
141 }
142 }
143
144 public void verifyProcess(boolean verified) throws VerifyException {
145
146
148 int verifyFrequency = GetterUtil.getInteger(
149 PropsUtil.get(PropsKeys.VERIFY_FREQUENCY));
150
151 if ((verifyFrequency == VerifyProcess.ALWAYS) ||
152 ((verifyFrequency == VerifyProcess.ONCE) && !verified) ||
153 (_upgraded)) {
154
155 if (!_upgraded) {
156 PropsUtil.set(PropsKeys.INDEX_ON_STARTUP, "true");
157 }
158
159 String[] verifyProcesses = PropsUtil.getArray(
160 PropsKeys.VERIFY_PROCESSES);
161
162 BatchSessionUtil.setEnabled(true);
163
164 boolean tempIndexReadOnly = SearchEngineUtil.isIndexReadOnly();
165
166 SearchEngineUtil.setIndexReadOnly(true);
167
168 try {
169 for (String className : verifyProcesses) {
170 verifyProcess(className);
171 }
172 }
173 finally {
174 BatchSessionUtil.setEnabled(false);
175
176 SearchEngineUtil.setIndexReadOnly(tempIndexReadOnly);
177 }
178 }
179 }
180
181 public boolean isUpgraded() {
182 return _upgraded;
183 }
184
185 public boolean isVerified() {
186 return _verified;
187 }
188
189 protected void addIndexes(Set<String> validIndexNames) throws Exception {
190 if (_log.isInfoEnabled()) {
191 _log.info("Adding indexes");
192 }
193
194 DBUtil dbUtil = DBUtil.getInstance();
195
196 BufferedReader bufferedReader = new BufferedReader(new StringReader(
197 readIndexesSQL()));
198
199 String sql = null;
200
201 while ((sql = bufferedReader.readLine()) != null) {
202 if (Validator.isNull(sql)) {
203 continue;
204 }
205
206 int y = sql.indexOf(" on ");
207 int x = sql.lastIndexOf(" ", y - 1);
208
209 String indexName = sql.substring(x + 1, y);
210
211 if (validIndexNames.contains(indexName)) {
212 continue;
213 }
214
215 if (_dropIndexes) {
216 if (_log.isInfoEnabled()) {
217 _log.info(sql);
218 }
219 }
220
221 try {
222 dbUtil.runSQL(sql);
223 }
224 catch (Exception e) {
225 if (_log.isWarnEnabled()) {
226 _log.warn(e.getMessage());
227 }
228 }
229 }
230 }
231
232 protected Set<String> dropIndexes(List<Index> indexes) throws Exception {
233 Set<String> validIndexNames = new HashSet<String>();
234
235 if (indexes.isEmpty()) {
236 return validIndexNames;
237 }
238
239 if (_dropIndexes) {
240 for (Index index : indexes) {
241 String indexName = index.getIndexName().toUpperCase();
242
243 validIndexNames.add(indexName);
244 }
245
246 return validIndexNames;
247 }
248
249 if (_log.isInfoEnabled()) {
250 _log.info("Dropping stale indexes");
251 }
252
253 DBUtil dbUtil = DBUtil.getInstance();
254
255 String type = dbUtil.getType();
256
257 Thread currentThread = Thread.currentThread();
258
259 ClassLoader classLoader = currentThread.getContextClassLoader();
260
261 String indexPropertiesString = StringUtil.read(
262 classLoader,
263 "com/liferay/portal/tools/sql/dependencies/indexes.properties");
264
265 Properties indexProperties = PropertiesUtil.load(indexPropertiesString);
266
267 Enumeration<String> indexPropertiesEnu =
268 (Enumeration<String>)indexProperties.propertyNames();
269
270 while (indexPropertiesEnu.hasMoreElements()) {
271 String key = indexPropertiesEnu.nextElement();
272
273 String value = indexProperties.getProperty(key);
274
275 indexProperties.setProperty(key.toLowerCase(), value);
276 }
277
278 String indexesSQLString = readIndexesSQL().toLowerCase();
279
280 String portalTablesSQLString = StringUtil.read(
281 classLoader,
282 "com/liferay/portal/tools/sql/dependencies/portal-tables.sql");
283
284 portalTablesSQLString = portalTablesSQLString.toLowerCase();
285
286 for (Index index : indexes) {
287 String indexName = index.getIndexName().toUpperCase();
288 String indexNameLowerCase = indexName.toLowerCase();
289 String tableName = index.getTableName();
290 String tableNameLowerCase = tableName.toLowerCase();
291 boolean unique = index.isUnique();
292
293 validIndexNames.add(indexName);
294
295 if (indexProperties.containsKey(indexNameLowerCase)) {
296 if (unique &&
297 indexesSQLString.contains(
298 "create unique index " + indexNameLowerCase + " ")) {
299
300 continue;
301 }
302
303 if (!unique &&
304 indexesSQLString.contains(
305 "create index " + indexNameLowerCase + " ")) {
306
307 continue;
308 }
309 }
310 else {
311 if (!portalTablesSQLString.contains(
312 "create table " + tableNameLowerCase + " (")) {
313
314 continue;
315 }
316 }
317
318 validIndexNames.remove(indexName);
319
320 String sql = "drop index " + indexName;
321
322 if (type.equals(DBUtil.TYPE_MYSQL) ||
323 type.equals(DBUtil.TYPE_SQLSERVER)) {
324
325 sql += " on " + tableName;
326 }
327
328 if (_log.isInfoEnabled()) {
329 _log.info(sql);
330 }
331
332 dbUtil.runSQL(sql);
333 }
334
335 return validIndexNames;
336 }
337
338 protected List<Index> getDB2Indexes() throws Exception {
339 return null;
340 }
341
342 protected List<Index> getIndexes() throws Exception {
343 List<Index> indexes = null;
344
345 DBUtil dbUtil = DBUtil.getInstance();
346
347 String type = dbUtil.getType();
348
349 if (type.equals(DBUtil.TYPE_DB2)) {
350 indexes = getDB2Indexes();
351 }
352 else if (type.equals(DBUtil.TYPE_MYSQL)) {
353 indexes = getMySQLIndexes();
354 }
355 else if (type.equals(DBUtil.TYPE_ORACLE)) {
356 indexes = getOracleIndexes();
357 }
358 else if (type.equals(DBUtil.TYPE_POSTGRESQL)) {
359 indexes = getPostgreSQLIndexes();
360 }
361 else if (type.equals(DBUtil.TYPE_SQLSERVER)) {
362 indexes = getSQLServerIndexes();
363 }
364 else if (type.equals(DBUtil.TYPE_SYBASE)) {
365 indexes = getSybaseIndexes();
366 }
367
368 if (indexes == null) {
369 indexes = Collections.EMPTY_LIST;
370 }
371
372 return indexes;
373 }
374
375 protected List<Index> getMySQLIndexes() throws Exception {
376 List<Index> indexes = new ArrayList<Index>();
377
378 Connection con = null;
379 PreparedStatement ps = null;
380 ResultSet rs = null;
381
382 try {
383 con = DataAccess.getConnection();
384
385 StringBuilder sb = new StringBuilder();
386
387 sb.append("select distinct(index_name), table_name, non_unique ");
388 sb.append("from information_schema.statistics where ");
389 sb.append("index_schema = database() and (index_name like ");
390 sb.append("'LIFERAY_%' or index_name like 'IX_%')");
391
392 String sql = sb.toString();
393
394 ps = con.prepareStatement(sql);
395
396 rs = ps.executeQuery();
397
398 while (rs.next()) {
399 String indexName = rs.getString("index_name");
400 String tableName = rs.getString("table_name");
401 boolean unique = !rs.getBoolean("non_unique");
402
403 indexes.add(new Index(indexName, tableName, unique));
404 }
405 }
406 finally {
407 DataAccess.cleanUp(con, ps, rs);
408 }
409
410 return indexes;
411 }
412
413 protected List<Index> getOracleIndexes() throws Exception {
414 List<Index> indexes = new ArrayList<Index>();
415
416 Connection con = null;
417 PreparedStatement ps = null;
418 ResultSet rs = null;
419
420 try {
421 con = DataAccess.getConnection();
422
423 StringBuilder sb = new StringBuilder();
424
425 sb.append("select index_name, table_name, uniqueness from ");
426 sb.append("user_indexes where index_name like 'LIFERAY_%' or ");
427 sb.append("index_name like 'IX_%'");
428
429 String sql = sb.toString();
430
431 ps = con.prepareStatement(sql);
432
433 rs = ps.executeQuery();
434
435 while (rs.next()) {
436 String indexName = rs.getString("index_name");
437 String tableName = rs.getString("table_name");
438 String uniqueness = rs.getString("uniqueness");
439
440 boolean unique = true;
441
442 if (uniqueness.equalsIgnoreCase("NONUNIQUE")) {
443 unique = false;
444 }
445
446 indexes.add(new Index(indexName, tableName, unique));
447 }
448 }
449 finally {
450 DataAccess.cleanUp(con, ps, rs);
451 }
452
453 return indexes;
454 }
455
456 protected List<Index> getPostgreSQLIndexes() throws Exception {
457 List<Index> indexes = new ArrayList<Index>();
458
459 Connection con = null;
460 PreparedStatement ps = null;
461 ResultSet rs = null;
462
463 try {
464 con = DataAccess.getConnection();
465
466 StringBuilder sb = new StringBuilder();
467
468 sb.append("select indexname, tablename, indexdef from pg_indexes ");
469 sb.append("where indexname like 'liferay_%' or indexname like ");
470 sb.append("'ix_%'");
471
472 String sql = sb.toString();
473
474 ps = con.prepareStatement(sql);
475
476 rs = ps.executeQuery();
477
478 while (rs.next()) {
479 String indexName = rs.getString("indexname");
480 String tableName = rs.getString("tablename");
481 String indexSQL = rs.getString("indexdef").toLowerCase().trim();
482
483 boolean unique = true;
484
485 if (indexSQL.startsWith("create index ")) {
486 unique = false;
487 }
488
489 indexes.add(new Index(indexName, tableName, unique));
490 }
491 }
492 finally {
493 DataAccess.cleanUp(con, ps, rs);
494 }
495
496 return indexes;
497 }
498
499 protected List<Index> getSQLServerIndexes() throws Exception {
500 List<Index> indexes = new ArrayList<Index>();
501
502 Connection con = null;
503 PreparedStatement ps = null;
504 ResultSet rs = null;
505
506 try {
507 con = DataAccess.getConnection();
508
509 DatabaseMetaData metaData = con.getMetaData();
510
511 if (metaData.getDatabaseMajorVersion() <= _SQL_SERVER_2000) {
512 return null;
513 }
514
515 StringBuilder sb = new StringBuilder();
516
517 sb.append("select sys.tables.name as table_name, ");
518 sb.append("sys.indexes.name as index_name, is_unique from ");
519 sb.append("sys.indexes inner join sys.tables on ");
520 sb.append("sys.tables.object_id = sys.indexes.object_id where ");
521 sb.append("sys.indexes.name like 'LIFERAY_%' or sys.indexes.name ");
522 sb.append("like 'IX_%'");
523
524 String sql = sb.toString();
525
526 ps = con.prepareStatement(sql);
527
528 rs = ps.executeQuery();
529
530 while (rs.next()) {
531 String indexName = rs.getString("index_name");
532 String tableName = rs.getString("table_name");
533 boolean unique = !rs.getBoolean("is_unique");
534
535 indexes.add(new Index(indexName, tableName, unique));
536 }
537 }
538 finally {
539 DataAccess.cleanUp(con, ps, rs);
540 }
541
542 return indexes;
543 }
544
545 protected List<Index> getSybaseIndexes() throws Exception {
546 return null;
547 }
548
549 protected String readIndexesSQL() throws Exception {
550 Thread currentThread = Thread.currentThread();
551
552 ClassLoader classLoader = currentThread.getContextClassLoader();
553
554 return StringUtil.read(
555 classLoader,
556 "com/liferay/portal/tools/sql/dependencies/indexes.sql");
557 }
558
559 protected void verifyProcess(String className) throws VerifyException {
560 if (_log.isDebugEnabled()) {
561 _log.debug("Initializing verification " + className);
562 }
563
564 try {
565 VerifyProcess verifyProcess = (VerifyProcess)Class.forName(
566 className).newInstance();
567
568 if (_log.isDebugEnabled()) {
569 _log.debug("Running verification " + className);
570 }
571
572 verifyProcess.verify();
573
574 if (_log.isDebugEnabled()) {
575 _log.debug("Finished verification " + className);
576 }
577
578 _verified = true;
579 }
580 catch (ClassNotFoundException cnfe) {
581 _log.error(className + " cannot be found");
582 }
583 catch (IllegalAccessException iae) {
584 _log.error(className + " cannot be accessed");
585 }
586 catch (InstantiationException ie) {
587 _log.error(className + " cannot be initiated");
588 }
589 }
590
591 private static final String _DELETE_TEMP_IMAGES_1 =
592 "delete from Image where imageId IN (SELECT articleImageId FROM " +
593 "JournalArticleImage where tempImage = TRUE)";
594
595 private static final String _DELETE_TEMP_IMAGES_2 =
596 "delete from JournalArticleImage where tempImage = TRUE";
597
598 private static final int _SQL_SERVER_2000 = 8;
599
600 private static Log _log = LogFactoryUtil.getLog(StartupHelper.class);
601
602 private boolean _dropIndexes;
603 private boolean _upgraded;
604 private boolean _verified;
605
606 }