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