1
22
23 package com.liferay.portal.events;
24
25 import com.liferay.portal.kernel.dao.db.DB;
26 import com.liferay.portal.kernel.dao.db.DBFactoryUtil;
27 import com.liferay.portal.kernel.dao.db.Index;
28 import com.liferay.portal.kernel.dao.jdbc.DataAccess;
29 import com.liferay.portal.kernel.log.Log;
30 import com.liferay.portal.kernel.log.LogFactoryUtil;
31 import com.liferay.portal.kernel.search.SearchEngineUtil;
32 import com.liferay.portal.kernel.upgrade.UpgradeException;
33 import com.liferay.portal.kernel.upgrade.UpgradeProcess;
34 import com.liferay.portal.kernel.util.GetterUtil;
35 import com.liferay.portal.kernel.util.InstancePool;
36 import com.liferay.portal.kernel.util.PropertiesUtil;
37 import com.liferay.portal.kernel.util.PropsKeys;
38 import com.liferay.portal.kernel.util.StringUtil;
39 import com.liferay.portal.kernel.util.Validator;
40 import com.liferay.portal.service.persistence.BatchSessionUtil;
41 import com.liferay.portal.util.PropsUtil;
42 import com.liferay.portal.verify.VerifyException;
43 import com.liferay.portal.verify.VerifyProcess;
44
45 import java.io.BufferedReader;
46 import java.io.StringReader;
47
48 import java.sql.Connection;
49 import java.sql.DatabaseMetaData;
50 import java.sql.PreparedStatement;
51 import java.sql.ResultSet;
52
53 import java.util.ArrayList;
54 import java.util.Collections;
55 import java.util.Enumeration;
56 import java.util.HashSet;
57 import java.util.List;
58 import java.util.Properties;
59 import java.util.Set;
60
61
68 public class StartupHelper {
69
70 public void deleteTempImages() {
71 try {
72 DB db = DBFactoryUtil.getDB();
73
74 db.runSQL(_DELETE_TEMP_IMAGES_1);
75 db.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 DB db = DBFactoryUtil.getDB();
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 db.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 DB db = DBFactoryUtil.getDB();
254
255 String type = db.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(DB.TYPE_MYSQL) || type.equals(DB.TYPE_SQLSERVER)) {
323 sql += " on " + tableName;
324 }
325
326 if (_log.isInfoEnabled()) {
327 _log.info(sql);
328 }
329
330 db.runSQL(sql);
331 }
332
333 return validIndexNames;
334 }
335
336 protected List<Index> getDB2Indexes() throws Exception {
337 return null;
338 }
339
340 protected List<Index> getIndexes() throws Exception {
341 List<Index> indexes = null;
342
343 DB db = DBFactoryUtil.getDB();
344
345 String type = db.getType();
346
347 if (type.equals(DB.TYPE_DB2)) {
348 indexes = getDB2Indexes();
349 }
350 else if (type.equals(DB.TYPE_MYSQL)) {
351 indexes = getMySQLIndexes();
352 }
353 else if (type.equals(DB.TYPE_ORACLE)) {
354 indexes = getOracleIndexes();
355 }
356 else if (type.equals(DB.TYPE_POSTGRESQL)) {
357 indexes = getPostgreSQLIndexes();
358 }
359 else if (type.equals(DB.TYPE_SQLSERVER)) {
360 indexes = getSQLServerIndexes();
361 }
362 else if (type.equals(DB.TYPE_SYBASE)) {
363 indexes = getSybaseIndexes();
364 }
365
366 if (indexes == null) {
367 indexes = Collections.EMPTY_LIST;
368 }
369
370 return indexes;
371 }
372
373 protected List<Index> getMySQLIndexes() throws Exception {
374 List<Index> indexes = new ArrayList<Index>();
375
376 Connection con = null;
377 PreparedStatement ps = null;
378 ResultSet rs = null;
379
380 try {
381 con = DataAccess.getConnection();
382
383 StringBuilder sb = new StringBuilder();
384
385 sb.append("select distinct(index_name), table_name, non_unique ");
386 sb.append("from information_schema.statistics where ");
387 sb.append("index_schema = database() and (index_name like ");
388 sb.append("'LIFERAY_%' or index_name like 'IX_%')");
389
390 String sql = sb.toString();
391
392 ps = con.prepareStatement(sql);
393
394 rs = ps.executeQuery();
395
396 while (rs.next()) {
397 String indexName = rs.getString("index_name");
398 String tableName = rs.getString("table_name");
399 boolean unique = !rs.getBoolean("non_unique");
400
401 indexes.add(new Index(indexName, tableName, unique));
402 }
403 }
404 finally {
405 DataAccess.cleanUp(con, ps, rs);
406 }
407
408 return indexes;
409 }
410
411 protected List<Index> getOracleIndexes() throws Exception {
412 List<Index> indexes = new ArrayList<Index>();
413
414 Connection con = null;
415 PreparedStatement ps = null;
416 ResultSet rs = null;
417
418 try {
419 con = DataAccess.getConnection();
420
421 StringBuilder sb = new StringBuilder();
422
423 sb.append("select index_name, table_name, uniqueness from ");
424 sb.append("user_indexes where index_name like 'LIFERAY_%' or ");
425 sb.append("index_name like 'IX_%'");
426
427 String sql = sb.toString();
428
429 ps = con.prepareStatement(sql);
430
431 rs = ps.executeQuery();
432
433 while (rs.next()) {
434 String indexName = rs.getString("index_name");
435 String tableName = rs.getString("table_name");
436 String uniqueness = rs.getString("uniqueness");
437
438 boolean unique = true;
439
440 if (uniqueness.equalsIgnoreCase("NONUNIQUE")) {
441 unique = false;
442 }
443
444 indexes.add(new Index(indexName, tableName, unique));
445 }
446 }
447 finally {
448 DataAccess.cleanUp(con, ps, rs);
449 }
450
451 return indexes;
452 }
453
454 protected List<Index> getPostgreSQLIndexes() throws Exception {
455 List<Index> indexes = new ArrayList<Index>();
456
457 Connection con = null;
458 PreparedStatement ps = null;
459 ResultSet rs = null;
460
461 try {
462 con = DataAccess.getConnection();
463
464 StringBuilder sb = new StringBuilder();
465
466 sb.append("select indexname, tablename, indexdef from pg_indexes ");
467 sb.append("where indexname like 'liferay_%' or indexname like ");
468 sb.append("'ix_%'");
469
470 String sql = sb.toString();
471
472 ps = con.prepareStatement(sql);
473
474 rs = ps.executeQuery();
475
476 while (rs.next()) {
477 String indexName = rs.getString("indexname");
478 String tableName = rs.getString("tablename");
479 String indexSQL = rs.getString("indexdef").toLowerCase().trim();
480
481 boolean unique = true;
482
483 if (indexSQL.startsWith("create index ")) {
484 unique = false;
485 }
486
487 indexes.add(new Index(indexName, tableName, unique));
488 }
489 }
490 finally {
491 DataAccess.cleanUp(con, ps, rs);
492 }
493
494 return indexes;
495 }
496
497 protected List<Index> getSQLServerIndexes() throws Exception {
498 List<Index> indexes = new ArrayList<Index>();
499
500 Connection con = null;
501 PreparedStatement ps = null;
502 ResultSet rs = null;
503
504 try {
505 con = DataAccess.getConnection();
506
507 DatabaseMetaData metaData = con.getMetaData();
508
509 if (metaData.getDatabaseMajorVersion() <= _SQL_SERVER_2000) {
510 return null;
511 }
512
513 StringBuilder sb = new StringBuilder();
514
515 sb.append("select sys.tables.name as table_name, ");
516 sb.append("sys.indexes.name as index_name, is_unique from ");
517 sb.append("sys.indexes inner join sys.tables on ");
518 sb.append("sys.tables.object_id = sys.indexes.object_id where ");
519 sb.append("sys.indexes.name like 'LIFERAY_%' or sys.indexes.name ");
520 sb.append("like 'IX_%'");
521
522 String sql = sb.toString();
523
524 ps = con.prepareStatement(sql);
525
526 rs = ps.executeQuery();
527
528 while (rs.next()) {
529 String indexName = rs.getString("index_name");
530 String tableName = rs.getString("table_name");
531 boolean unique = !rs.getBoolean("is_unique");
532
533 indexes.add(new Index(indexName, tableName, unique));
534 }
535 }
536 finally {
537 DataAccess.cleanUp(con, ps, rs);
538 }
539
540 return indexes;
541 }
542
543 protected List<Index> getSybaseIndexes() throws Exception {
544 return null;
545 }
546
547 protected String readIndexesSQL() throws Exception {
548 Thread currentThread = Thread.currentThread();
549
550 ClassLoader classLoader = currentThread.getContextClassLoader();
551
552 return StringUtil.read(
553 classLoader,
554 "com/liferay/portal/tools/sql/dependencies/indexes.sql");
555 }
556
557 protected void verifyProcess(String className) throws VerifyException {
558 if (_log.isDebugEnabled()) {
559 _log.debug("Initializing verification " + className);
560 }
561
562 try {
563 VerifyProcess verifyProcess = (VerifyProcess)Class.forName(
564 className).newInstance();
565
566 if (_log.isDebugEnabled()) {
567 _log.debug("Running verification " + className);
568 }
569
570 verifyProcess.verify();
571
572 if (_log.isDebugEnabled()) {
573 _log.debug("Finished verification " + className);
574 }
575
576 _verified = true;
577 }
578 catch (ClassNotFoundException cnfe) {
579 _log.error(className + " cannot be found");
580 }
581 catch (IllegalAccessException iae) {
582 _log.error(className + " cannot be accessed");
583 }
584 catch (InstantiationException ie) {
585 _log.error(className + " cannot be initiated");
586 }
587 }
588
589 private static final String _DELETE_TEMP_IMAGES_1 =
590 "delete from Image where imageId IN (SELECT articleImageId FROM " +
591 "JournalArticleImage where tempImage = TRUE)";
592
593 private static final String _DELETE_TEMP_IMAGES_2 =
594 "delete from JournalArticleImage where tempImage = TRUE";
595
596 private static final int _SQL_SERVER_2000 = 8;
597
598 private static Log _log = LogFactoryUtil.getLog(StartupHelper.class);
599
600 private boolean _dropIndexes;
601 private boolean _upgraded;
602 private boolean _verified;
603
604 }