001
014
015 package com.liferay.portal.service.impl;
016
017 import com.liferay.portal.OldServiceComponentException;
018 import com.liferay.portal.kernel.cache.CacheRegistryUtil;
019 import com.liferay.portal.kernel.dao.db.DB;
020 import com.liferay.portal.kernel.dao.db.DBFactoryUtil;
021 import com.liferay.portal.kernel.dao.orm.EntityCacheUtil;
022 import com.liferay.portal.kernel.dao.orm.FinderCacheUtil;
023 import com.liferay.portal.kernel.exception.PortalException;
024 import com.liferay.portal.kernel.exception.SystemException;
025 import com.liferay.portal.kernel.log.Log;
026 import com.liferay.portal.kernel.log.LogFactoryUtil;
027 import com.liferay.portal.kernel.upgrade.util.UpgradeTable;
028 import com.liferay.portal.kernel.upgrade.util.UpgradeTableFactoryUtil;
029 import com.liferay.portal.kernel.upgrade.util.UpgradeTableListener;
030 import com.liferay.portal.kernel.util.GetterUtil;
031 import com.liferay.portal.kernel.util.HttpUtil;
032 import com.liferay.portal.kernel.util.InstanceFactory;
033 import com.liferay.portal.kernel.util.ListUtil;
034 import com.liferay.portal.kernel.util.StringPool;
035 import com.liferay.portal.kernel.util.StringUtil;
036 import com.liferay.portal.kernel.xml.Document;
037 import com.liferay.portal.kernel.xml.DocumentException;
038 import com.liferay.portal.kernel.xml.Element;
039 import com.liferay.portal.kernel.xml.SAXReaderUtil;
040 import com.liferay.portal.kernel.xml.UnsecureSAXReaderUtil;
041 import com.liferay.portal.model.ModelHintsUtil;
042 import com.liferay.portal.model.ServiceComponent;
043 import com.liferay.portal.service.base.ServiceComponentLocalServiceBaseImpl;
044 import com.liferay.portal.tools.servicebuilder.Entity;
045 import com.liferay.portal.util.PropsUtil;
046
047 import java.io.IOException;
048 import java.io.InputStream;
049
050 import java.lang.reflect.Field;
051
052 import java.security.PrivilegedExceptionAction;
053
054 import java.util.ArrayList;
055 import java.util.List;
056
057 import javax.servlet.ServletContext;
058
059
062 public class ServiceComponentLocalServiceImpl
063 extends ServiceComponentLocalServiceBaseImpl {
064
065 public static final boolean CACHE_CLEAR_ON_PLUGIN_UNDEPLOY =
066 GetterUtil.getBoolean(
067 PropsUtil.get("cache.clear.on.plugin.undeploy"));
068
069 @Override
070 public void destroyServiceComponent(
071 ServletContext servletContext, ClassLoader classLoader)
072 throws SystemException {
073
074 try {
075 clearCacheRegistry(servletContext);
076 }
077 catch (Exception e) {
078 throw new SystemException(e);
079 }
080 }
081
082 @Override
083 public ServiceComponent initServiceComponent(
084 ServletContext servletContext, ClassLoader classLoader,
085 String buildNamespace, long buildNumber, long buildDate,
086 boolean buildAutoUpgrade)
087 throws PortalException, SystemException {
088
089 try {
090 ModelHintsUtil.read(
091 classLoader, "META-INF/portlet-model-hints.xml");
092 }
093 catch (Exception e) {
094 throw new SystemException(e);
095 }
096
097 try {
098 ModelHintsUtil.read(
099 classLoader, "META-INF/portlet-model-hints-ext.xml");
100 }
101 catch (Exception e) {
102 throw new SystemException(e);
103 }
104
105 ServiceComponent serviceComponent = null;
106 ServiceComponent previousServiceComponent = null;
107
108 List<ServiceComponent> serviceComponents =
109 serviceComponentPersistence.findByBuildNamespace(
110 buildNamespace, 0, 1);
111
112 if (serviceComponents.isEmpty()) {
113 long serviceComponentId = counterLocalService.increment();
114
115 serviceComponent = serviceComponentPersistence.create(
116 serviceComponentId);
117
118 serviceComponent.setBuildNamespace(buildNamespace);
119 serviceComponent.setBuildNumber(buildNumber);
120 serviceComponent.setBuildDate(buildDate);
121 }
122 else {
123 serviceComponent = serviceComponents.get(0);
124
125 if (serviceComponent.getBuildNumber() < buildNumber) {
126 previousServiceComponent = serviceComponent;
127
128 long serviceComponentId = counterLocalService.increment();
129
130 serviceComponent = serviceComponentPersistence.create(
131 serviceComponentId);
132
133 serviceComponent.setBuildNamespace(buildNamespace);
134 serviceComponent.setBuildNumber(buildNumber);
135 serviceComponent.setBuildDate(buildDate);
136 }
137 else if (serviceComponent.getBuildNumber() > buildNumber) {
138 throw new OldServiceComponentException(
139 "Build namespace " + buildNamespace + " has build number " +
140 serviceComponent.getBuildNumber() +
141 " which is newer than " + buildNumber);
142 }
143 else {
144 return serviceComponent;
145 }
146 }
147
148 try {
149 Document document = SAXReaderUtil.createDocument(StringPool.UTF8);
150
151 Element dataElement = document.addElement("data");
152
153 Element tablesSQLElement = dataElement.addElement("tables-sql");
154
155 String tablesSQL = HttpUtil.URLtoString(
156 servletContext.getResource("/WEB-INF/sql/tables.sql"));
157
158 tablesSQLElement.addCDATA(tablesSQL);
159
160 Element sequencesSQLElement = dataElement.addElement(
161 "sequences-sql");
162
163 String sequencesSQL = HttpUtil.URLtoString(
164 servletContext.getResource("/WEB-INF/sql/sequences.sql"));
165
166 sequencesSQLElement.addCDATA(sequencesSQL);
167
168 Element indexesSQLElement = dataElement.addElement("indexes-sql");
169
170 String indexesSQL = HttpUtil.URLtoString(
171 servletContext.getResource("/WEB-INF/sql/indexes.sql"));
172
173 indexesSQLElement.addCDATA(indexesSQL);
174
175 String dataXML = document.formattedString();
176
177 serviceComponent.setData(dataXML);
178
179 serviceComponentPersistence.update(serviceComponent);
180
181 serviceComponentLocalService.upgradeDB(
182 classLoader, buildNamespace, buildNumber, buildAutoUpgrade,
183 previousServiceComponent, tablesSQL, sequencesSQL, indexesSQL);
184
185 removeOldServiceComponents(buildNamespace);
186
187 return serviceComponent;
188 }
189 catch (Exception e) {
190 throw new SystemException(e);
191 }
192 }
193
194 @Override
195 public void upgradeDB(
196 final ClassLoader classLoader, final String buildNamespace,
197 final long buildNumber, final boolean buildAutoUpgrade,
198 final ServiceComponent previousServiceComponent,
199 final String tablesSQL, final String sequencesSQL,
200 final String indexesSQL)
201 throws Exception {
202
203 _pacl.doUpgradeDB(
204 new DoUpgradeDBPrivilegedExceptionAction(
205 classLoader, buildNamespace, buildNumber, buildAutoUpgrade,
206 previousServiceComponent, tablesSQL, sequencesSQL, indexesSQL));
207 }
208
209 @Override
210 public void verifyDB() throws SystemException {
211 List<ServiceComponent> serviceComponents =
212 serviceComponentPersistence.findAll();
213
214 for (ServiceComponent serviceComponent : serviceComponents) {
215 String buildNamespace = serviceComponent.getBuildNamespace();
216 String tablesSQL = serviceComponent.getTablesSQL();
217 String sequencesSQL = serviceComponent.getSequencesSQL();
218 String indexesSQL = serviceComponent.getIndexesSQL();
219
220 try {
221 serviceComponentLocalService.upgradeDB(
222 null, buildNamespace, 0, false, null, tablesSQL,
223 sequencesSQL, indexesSQL);
224 }
225 catch (Exception e) {
226 _log.error(e, e);
227 }
228 }
229 }
230
231 public static interface PACL {
232
233 public void doUpgradeDB(
234 DoUpgradeDBPrivilegedExceptionAction
235 doUpgradeDBPrivilegedExceptionAction)
236 throws Exception;
237
238 }
239
240 public class DoUpgradeDBPrivilegedExceptionAction
241 implements PrivilegedExceptionAction<Void> {
242
243 public DoUpgradeDBPrivilegedExceptionAction(
244 ClassLoader classLoader, String buildNamespace, long buildNumber,
245 boolean buildAutoUpgrade, ServiceComponent previousServiceComponent,
246 String tablesSQL, String sequencesSQL, String indexesSQL) {
247
248 _classLoader = classLoader;
249 _buildNamespace = buildNamespace;
250 _buildNumber = buildNumber;
251 _buildAutoUpgrade = buildAutoUpgrade;
252 _previousServiceComponent = previousServiceComponent;
253 _tablesSQL = tablesSQL;
254 _sequencesSQL = sequencesSQL;
255 _indexesSQL = indexesSQL;
256 }
257
258 public ClassLoader getClassLoader() {
259 return _classLoader;
260 }
261
262 @Override
263 public Void run() throws Exception {
264 doUpgradeDB(
265 _classLoader, _buildNamespace, _buildNumber, _buildAutoUpgrade,
266 _previousServiceComponent, _tablesSQL, _sequencesSQL,
267 _indexesSQL);
268
269 return null;
270 }
271
272 private boolean _buildAutoUpgrade;
273 private String _buildNamespace;
274 private long _buildNumber;
275 private ClassLoader _classLoader;
276 private String _indexesSQL;
277 private ServiceComponent _previousServiceComponent;
278 private String _sequencesSQL;
279 private String _tablesSQL;
280
281 }
282
283 protected void clearCacheRegistry(ServletContext servletContext)
284 throws DocumentException {
285
286 InputStream inputStream = servletContext.getResourceAsStream(
287 "/WEB-INF/classes/META-INF/portlet-hbm.xml");
288
289 if (inputStream == null) {
290 return;
291 }
292
293 Document document = UnsecureSAXReaderUtil.read(inputStream);
294
295 Element rootElement = document.getRootElement();
296
297 List<Element> classElements = rootElement.elements("class");
298
299 for (Element classElement : classElements) {
300 String name = classElement.attributeValue("name");
301
302 CacheRegistryUtil.unregister(name);
303 }
304
305 CacheRegistryUtil.clear();
306
307 if (CACHE_CLEAR_ON_PLUGIN_UNDEPLOY) {
308 EntityCacheUtil.clearCache();
309 FinderCacheUtil.clearCache();
310 }
311 }
312
313 protected void doUpgradeDB(
314 ClassLoader classLoader, String buildNamespace, long buildNumber,
315 boolean buildAutoUpgrade, ServiceComponent previousServiceComponent,
316 String tablesSQL, String sequencesSQL, String indexesSQL)
317 throws Exception {
318
319 DB db = DBFactoryUtil.getDB();
320
321 if (previousServiceComponent == null) {
322 if (_log.isInfoEnabled()) {
323 _log.info("Running " + buildNamespace + " SQL scripts");
324 }
325
326 db.runSQLTemplateString(tablesSQL, true, false);
327 db.runSQLTemplateString(sequencesSQL, true, false);
328 db.runSQLTemplateString(indexesSQL, true, false);
329 }
330 else if (buildAutoUpgrade) {
331 if (_log.isInfoEnabled()) {
332 _log.info(
333 "Upgrading " + buildNamespace +
334 " database to build number " + buildNumber);
335 }
336
337 if (!tablesSQL.equals(previousServiceComponent.getTablesSQL())) {
338 if (_log.isInfoEnabled()) {
339 _log.info("Upgrading database with tables.sql");
340 }
341
342 db.runSQLTemplateString(tablesSQL, true, false);
343
344 upgradeModels(classLoader, previousServiceComponent, tablesSQL);
345 }
346
347 if (!sequencesSQL.equals(
348 previousServiceComponent.getSequencesSQL())) {
349
350 if (_log.isInfoEnabled()) {
351 _log.info("Upgrading database with sequences.sql");
352 }
353
354 db.runSQLTemplateString(sequencesSQL, true, false);
355 }
356
357 if (!indexesSQL.equals(previousServiceComponent.getIndexesSQL()) ||
358 !tablesSQL.equals(previousServiceComponent.getTablesSQL())) {
359
360 if (_log.isInfoEnabled()) {
361 _log.info("Upgrading database with indexes.sql");
362 }
363
364 db.runSQLTemplateString(indexesSQL, true, false);
365 }
366 }
367 }
368
369 protected List<String> getModelNames(ClassLoader classLoader)
370 throws DocumentException, IOException {
371
372 List<String> modelNames = new ArrayList<String>();
373
374 String xml = StringUtil.read(
375 classLoader, "META-INF/portlet-model-hints.xml");
376
377 modelNames.addAll(getModelNames(xml));
378
379 try {
380 xml = StringUtil.read(
381 classLoader, "META-INF/portlet-model-hints-ext.xml");
382
383 modelNames.addAll(getModelNames(xml));
384 }
385 catch (Exception e) {
386 if (_log.isInfoEnabled()) {
387 _log.info(
388 "No optional file META-INF/portlet-model-hints-ext.xml " +
389 "found");
390 }
391 }
392
393 return modelNames;
394 }
395
396 protected List<String> getModelNames(String xml) throws DocumentException {
397 List<String> modelNames = new ArrayList<String>();
398
399 Document document = UnsecureSAXReaderUtil.read(xml);
400
401 Element rootElement = document.getRootElement();
402
403 List<Element> modelElements = rootElement.elements("model");
404
405 for (Element modelElement : modelElements) {
406 String name = modelElement.attributeValue("name");
407
408 modelNames.add(name);
409 }
410
411 return modelNames;
412 }
413
414 protected List<String> getModifiedTableNames(
415 String previousTablesSQL, String tablesSQL) {
416
417 List<String> modifiedTableNames = new ArrayList<String>();
418
419 List<String> previousTablesSQLParts = ListUtil.toList(
420 StringUtil.split(previousTablesSQL, StringPool.SEMICOLON));
421 List<String> tablesSQLParts = ListUtil.toList(
422 StringUtil.split(tablesSQL, StringPool.SEMICOLON));
423
424 tablesSQLParts.removeAll(previousTablesSQLParts);
425
426 for (String tablesSQLPart : tablesSQLParts) {
427 int x = tablesSQLPart.indexOf("create table ");
428 int y = tablesSQLPart.indexOf(" (");
429
430 modifiedTableNames.add(tablesSQLPart.substring(x + 13, y));
431 }
432
433 return modifiedTableNames;
434 }
435
436 protected UpgradeTableListener getUpgradeTableListener(
437 ClassLoader classLoader, Class<?> modelClass) {
438
439 String modelClassName = modelClass.getName();
440
441 String upgradeTableListenerClassName = modelClassName;
442
443 upgradeTableListenerClassName = StringUtil.replaceLast(
444 upgradeTableListenerClassName, ".model.impl.", ".model.upgrade.");
445 upgradeTableListenerClassName = StringUtil.replaceLast(
446 upgradeTableListenerClassName, "ModelImpl", "UpgradeTableListener");
447
448 try {
449 UpgradeTableListener upgradeTableListener =
450 (UpgradeTableListener)InstanceFactory.newInstance(
451 classLoader, upgradeTableListenerClassName);
452
453 if (_log.isInfoEnabled()) {
454 _log.info("Instantiated " + upgradeTableListenerClassName);
455 }
456
457 return upgradeTableListener;
458 }
459 catch (Exception e) {
460 if (_log.isDebugEnabled()) {
461 _log.debug(
462 "Unable to instantiate " + upgradeTableListenerClassName);
463 }
464
465 return null;
466 }
467 }
468
469 protected void removeOldServiceComponents(String buildNamespace)
470 throws SystemException {
471
472 int serviceComponentsCount =
473 serviceComponentPersistence.countByBuildNamespace(buildNamespace);
474
475 if (serviceComponentsCount < _MAX_SERVICE_COMPONENTS) {
476 return;
477 }
478
479 List<ServiceComponent> serviceComponents =
480 serviceComponentPersistence.findByBuildNamespace(
481 buildNamespace, _MAX_SERVICE_COMPONENTS,
482 serviceComponentsCount);
483
484 for (int i = 0; i < serviceComponents.size(); i++) {
485 ServiceComponent serviceComponent = serviceComponents.get(i);
486
487 serviceComponentPersistence.remove(serviceComponent);
488 }
489 }
490
491 protected void upgradeModels(
492 ClassLoader classLoader, ServiceComponent previousServiceComponent,
493 String tablesSQL)
494 throws Exception {
495
496 List<String> modifiedTableNames = getModifiedTableNames(
497 previousServiceComponent.getTablesSQL(), tablesSQL);
498
499 List<String> modelNames = getModelNames(classLoader);
500
501 for (String modelName : modelNames) {
502 int pos = modelName.lastIndexOf(".model.");
503
504 Class<?> modelClass = Class.forName(
505 modelName.substring(0, pos) + ".model.impl." +
506 modelName.substring(pos + 7) + "ModelImpl",
507 true, classLoader);
508
509 Field dataSourceField = modelClass.getField("DATA_SOURCE");
510
511 String dataSource = (String)dataSourceField.get(null);
512
513 if (!dataSource.equals(Entity.DEFAULT_DATA_SOURCE)) {
514 continue;
515 }
516
517 Field tableNameField = modelClass.getField("TABLE_NAME");
518
519 String tableName = (String)tableNameField.get(null);
520
521 if (!modifiedTableNames.contains(tableName)) {
522 continue;
523 }
524
525 Field tableColumnsField = modelClass.getField("TABLE_COLUMNS");
526
527 Object[][] tableColumns = (Object[][])tableColumnsField.get(null);
528
529 UpgradeTable upgradeTable = UpgradeTableFactoryUtil.getUpgradeTable(
530 tableName, tableColumns);
531
532 UpgradeTableListener upgradeTableListener = getUpgradeTableListener(
533 classLoader, modelClass);
534
535 Field tableSQLCreateField = modelClass.getField("TABLE_SQL_CREATE");
536
537 String tableSQLCreate = (String)tableSQLCreateField.get(null);
538
539 upgradeTable.setCreateSQL(tableSQLCreate);
540
541 if (upgradeTableListener != null) {
542 upgradeTableListener.onBeforeUpdateTable(
543 previousServiceComponent, upgradeTable);
544 }
545
546 upgradeTable.updateTable();
547
548 if (upgradeTableListener != null) {
549 upgradeTableListener.onAfterUpdateTable(
550 previousServiceComponent, upgradeTable);
551 }
552 }
553 }
554
555 private static final int _MAX_SERVICE_COMPONENTS = 10;
556
557 private static Log _log = LogFactoryUtil.getLog(
558 ServiceComponentLocalServiceImpl.class);
559
560 private static PACL _pacl = new NoPACL();
561
562 private static class NoPACL implements PACL {
563
564 @Override
565 public void doUpgradeDB(
566 DoUpgradeDBPrivilegedExceptionAction
567 doUpgradeDBPrivilegedExceptionAction)
568 throws Exception {
569
570 doUpgradeDBPrivilegedExceptionAction.run();
571 }
572
573 }
574
575 }