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