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