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