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