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.InstanceFactory;
031 import com.liferay.portal.kernel.util.ListUtil;
032 import com.liferay.portal.kernel.util.StringPool;
033 import com.liferay.portal.kernel.util.StringUtil;
034 import com.liferay.portal.kernel.xml.Document;
035 import com.liferay.portal.kernel.xml.DocumentException;
036 import com.liferay.portal.kernel.xml.Element;
037 import com.liferay.portal.kernel.xml.SAXReaderUtil;
038 import com.liferay.portal.kernel.xml.UnsecureSAXReaderUtil;
039 import com.liferay.portal.model.ModelHintsUtil;
040 import com.liferay.portal.model.ServiceComponent;
041 import com.liferay.portal.service.base.ServiceComponentLocalServiceBaseImpl;
042 import com.liferay.portal.service.configuration.ServiceComponentConfiguration;
043 import com.liferay.portal.util.PropsValues;
044
045 import java.io.IOException;
046 import java.io.InputStream;
047
048 import java.lang.reflect.Field;
049
050 import java.security.PrivilegedExceptionAction;
051
052 import java.util.ArrayList;
053 import java.util.List;
054
055
058 public class ServiceComponentLocalServiceImpl
059 extends ServiceComponentLocalServiceBaseImpl {
060
061 @Override
062 public void destroyServiceComponent(
063 ServiceComponentConfiguration serviceComponentConfiguration,
064 ClassLoader classLoader) {
065
066 try {
067 clearCacheRegistry(serviceComponentConfiguration);
068 }
069 catch (Exception e) {
070 throw new SystemException(e);
071 }
072 }
073
074 @Override
075 public List<ServiceComponent> getLatestServiceComponents() {
076 return serviceComponentFinder.findByMaxBuildNumber();
077 }
078
079 @Override
080 public ServiceComponent initServiceComponent(
081 ServiceComponentConfiguration serviceComponentConfiguration,
082 ClassLoader classLoader, String buildNamespace, long buildNumber,
083 long buildDate, boolean buildAutoUpgrade)
084 throws PortalException {
085
086 try {
087 ModelHintsUtil.read(
088 classLoader,
089 serviceComponentConfiguration.getModelHintsInputStream());
090 }
091 catch (Exception e) {
092 throw new SystemException(e);
093 }
094
095 try {
096 ModelHintsUtil.read(
097 classLoader,
098 serviceComponentConfiguration.getModelHintsExtInputStream());
099 }
100 catch (Exception e) {
101 throw new SystemException(e);
102 }
103
104 ServiceComponent serviceComponent = null;
105 ServiceComponent previousServiceComponent = null;
106
107 List<ServiceComponent> serviceComponents =
108 serviceComponentPersistence.findByBuildNamespace(
109 buildNamespace, 0, 1);
110
111 if (serviceComponents.isEmpty()) {
112 long serviceComponentId = counterLocalService.increment();
113
114 serviceComponent = serviceComponentPersistence.create(
115 serviceComponentId);
116
117 serviceComponent.setBuildNamespace(buildNamespace);
118 serviceComponent.setBuildNumber(buildNumber);
119 serviceComponent.setBuildDate(buildDate);
120 }
121 else {
122 serviceComponent = serviceComponents.get(0);
123
124 if (serviceComponent.getBuildNumber() < buildNumber) {
125 previousServiceComponent = serviceComponent;
126
127 long serviceComponentId = counterLocalService.increment();
128
129 serviceComponent = serviceComponentPersistence.create(
130 serviceComponentId);
131
132 serviceComponent.setBuildNamespace(buildNamespace);
133 serviceComponent.setBuildNumber(buildNumber);
134 serviceComponent.setBuildDate(buildDate);
135 }
136 else if (serviceComponent.getBuildNumber() > buildNumber) {
137 throw new OldServiceComponentException(
138 "Build namespace " + buildNamespace + " has build number " +
139 serviceComponent.getBuildNumber() +
140 " which is newer than " + buildNumber);
141 }
142 else {
143 return serviceComponent;
144 }
145 }
146
147 try {
148 Document document = SAXReaderUtil.createDocument(StringPool.UTF8);
149
150 Element dataElement = document.addElement("data");
151
152 Element tablesSQLElement = dataElement.addElement("tables-sql");
153
154 String tablesSQL = StringUtil.read(
155 serviceComponentConfiguration.getSQLTablesInputStream());
156
157 tablesSQLElement.addCDATA(tablesSQL);
158
159 Element sequencesSQLElement = dataElement.addElement(
160 "sequences-sql");
161
162 String sequencesSQL = StringUtil.read(
163 serviceComponentConfiguration.getSQLSequencesInputStream());
164
165 sequencesSQLElement.addCDATA(sequencesSQL);
166
167 Element indexesSQLElement = dataElement.addElement("indexes-sql");
168
169 String indexesSQL = StringUtil.read(
170 serviceComponentConfiguration.getSQLIndexesInputStream());
171
172 indexesSQLElement.addCDATA(indexesSQL);
173
174 String dataXML = document.formattedString();
175
176 serviceComponent.setData(dataXML);
177
178 serviceComponentPersistence.update(serviceComponent);
179
180 serviceComponentLocalService.upgradeDB(
181 classLoader, buildNamespace, buildNumber, buildAutoUpgrade,
182 previousServiceComponent, tablesSQL, sequencesSQL, indexesSQL);
183
184 removeOldServiceComponents(buildNamespace);
185
186 return serviceComponent;
187 }
188 catch (Exception e) {
189 throw new SystemException(e);
190 }
191 }
192
193 @Override
194 public void upgradeDB(
195 final ClassLoader classLoader, final String buildNamespace,
196 final long buildNumber, final boolean buildAutoUpgrade,
197 final ServiceComponent previousServiceComponent,
198 final String tablesSQL, final String sequencesSQL,
199 final String indexesSQL)
200 throws Exception {
201
202 _pacl.doUpgradeDB(
203 new DoUpgradeDBPrivilegedExceptionAction(
204 classLoader, buildNamespace, buildNumber, buildAutoUpgrade,
205 previousServiceComponent, tablesSQL, sequencesSQL, indexesSQL));
206 }
207
208 @Override
209 public void verifyDB() {
210 List<ServiceComponent> serviceComponents =
211 serviceComponentPersistence.findAll();
212
213 for (ServiceComponent serviceComponent : serviceComponents) {
214 String buildNamespace = serviceComponent.getBuildNamespace();
215 String tablesSQL = serviceComponent.getTablesSQL();
216 String sequencesSQL = serviceComponent.getSequencesSQL();
217 String indexesSQL = serviceComponent.getIndexesSQL();
218
219 try {
220 serviceComponentLocalService.upgradeDB(
221 null, buildNamespace, 0, false, null, tablesSQL,
222 sequencesSQL, indexesSQL);
223 }
224 catch (Exception e) {
225 _log.error(e, e);
226 }
227 }
228 }
229
230 public class DoUpgradeDBPrivilegedExceptionAction
231 implements PrivilegedExceptionAction<Void> {
232
233 public DoUpgradeDBPrivilegedExceptionAction(
234 ClassLoader classLoader, String buildNamespace, long buildNumber,
235 boolean buildAutoUpgrade, ServiceComponent previousServiceComponent,
236 String tablesSQL, String sequencesSQL, String indexesSQL) {
237
238 _classLoader = classLoader;
239 _buildNamespace = buildNamespace;
240 _buildNumber = buildNumber;
241 _buildAutoUpgrade = buildAutoUpgrade;
242 _previousServiceComponent = previousServiceComponent;
243 _tablesSQL = tablesSQL;
244 _sequencesSQL = sequencesSQL;
245 _indexesSQL = indexesSQL;
246 }
247
248 public ClassLoader getClassLoader() {
249 return _classLoader;
250 }
251
252 @Override
253 public Void run() throws Exception {
254 doUpgradeDB(
255 _classLoader, _buildNamespace, _buildNumber, _buildAutoUpgrade,
256 _previousServiceComponent, _tablesSQL, _sequencesSQL,
257 _indexesSQL);
258
259 return null;
260 }
261
262 private final boolean _buildAutoUpgrade;
263 private final String _buildNamespace;
264 private final long _buildNumber;
265 private final ClassLoader _classLoader;
266 private final String _indexesSQL;
267 private final ServiceComponent _previousServiceComponent;
268 private final String _sequencesSQL;
269 private final String _tablesSQL;
270
271 }
272
273 public interface PACL {
274
275 public void doUpgradeDB(
276 DoUpgradeDBPrivilegedExceptionAction
277 doUpgradeDBPrivilegedExceptionAction)
278 throws Exception;
279
280 }
281
282 protected void clearCacheRegistry(
283 ServiceComponentConfiguration serviceComponentConfiguration)
284 throws DocumentException {
285
286 InputStream inputStream =
287 serviceComponentConfiguration.getHibernateInputStream();
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 (PropsValues.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<>();
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<>();
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<>();
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 int serviceComponentsCount =
471 serviceComponentPersistence.countByBuildNamespace(buildNamespace);
472
473 if (serviceComponentsCount < _SERVICE_COMPONENTS_MAX) {
474 return;
475 }
476
477 List<ServiceComponent> serviceComponents =
478 serviceComponentPersistence.findByBuildNamespace(
479 buildNamespace, _SERVICE_COMPONENTS_MAX,
480 serviceComponentsCount);
481
482 for (int i = 0; i < serviceComponents.size(); i++) {
483 ServiceComponent serviceComponent = serviceComponents.get(i);
484
485 serviceComponentPersistence.remove(serviceComponent);
486 }
487 }
488
489 protected void upgradeModels(
490 ClassLoader classLoader, ServiceComponent previousServiceComponent,
491 String tablesSQL)
492 throws Exception {
493
494 List<String> modifiedTableNames = getModifiedTableNames(
495 previousServiceComponent.getTablesSQL(), tablesSQL);
496
497 List<String> modelNames = getModelNames(classLoader);
498
499 for (String modelName : modelNames) {
500 int pos = modelName.lastIndexOf(".model.");
501
502 Class<?> modelClass = Class.forName(
503 modelName.substring(0, pos) + ".model.impl." +
504 modelName.substring(pos + 7) + "ModelImpl",
505 true, classLoader);
506
507 Field dataSourceField = modelClass.getField("DATA_SOURCE");
508
509 String dataSource = (String)dataSourceField.get(null);
510
511 if (!dataSource.equals(_DATA_SOURCE_DEFAULT)) {
512 continue;
513 }
514
515 Field tableNameField = modelClass.getField("TABLE_NAME");
516
517 String tableName = (String)tableNameField.get(null);
518
519 if (!modifiedTableNames.contains(tableName)) {
520 continue;
521 }
522
523 Field tableColumnsField = modelClass.getField("TABLE_COLUMNS");
524
525 Object[][] tableColumns = (Object[][])tableColumnsField.get(null);
526
527 UpgradeTable upgradeTable = UpgradeTableFactoryUtil.getUpgradeTable(
528 tableName, tableColumns);
529
530 UpgradeTableListener upgradeTableListener = getUpgradeTableListener(
531 classLoader, modelClass);
532
533 Field tableSQLCreateField = modelClass.getField("TABLE_SQL_CREATE");
534
535 String tableSQLCreate = (String)tableSQLCreateField.get(null);
536
537 upgradeTable.setCreateSQL(tableSQLCreate);
538
539 if (upgradeTableListener != null) {
540 upgradeTableListener.onBeforeUpdateTable(
541 previousServiceComponent, upgradeTable);
542 }
543
544 upgradeTable.updateTable();
545
546 if (upgradeTableListener != null) {
547 upgradeTableListener.onAfterUpdateTable(
548 previousServiceComponent, upgradeTable);
549 }
550 }
551 }
552
553 private static final String _DATA_SOURCE_DEFAULT = "liferayDataSource";
554
555 private static final int _SERVICE_COMPONENTS_MAX = 10;
556
557 private static final Log _log = LogFactoryUtil.getLog(
558 ServiceComponentLocalServiceImpl.class);
559
560 private static final 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 }