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.StringPool;
032 import com.liferay.portal.kernel.util.StringUtil;
033 import com.liferay.portal.kernel.xml.Document;
034 import com.liferay.portal.kernel.xml.DocumentException;
035 import com.liferay.portal.kernel.xml.Element;
036 import com.liferay.portal.kernel.xml.SAXReaderUtil;
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.tools.servicebuilder.Entity;
042 import com.liferay.portal.util.PropsValues;
043
044 import java.io.IOException;
045 import java.io.InputStream;
046
047 import java.lang.reflect.Field;
048
049 import java.security.PrivilegedExceptionAction;
050
051 import java.util.ArrayList;
052 import java.util.List;
053
054
057 public class ServiceComponentLocalServiceImpl
058 extends ServiceComponentLocalServiceBaseImpl {
059
060 @Override
061 public void destroyServiceComponent(
062 ServiceComponentConfiguration serviceComponentConfiguration,
063 ClassLoader classLoader) {
064
065 try {
066 clearCacheRegistry(serviceComponentConfiguration);
067 }
068 catch (Exception e) {
069 throw new SystemException(e);
070 }
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 boolean _buildAutoUpgrade;
257 private String _buildNamespace;
258 private long _buildNumber;
259 private ClassLoader _classLoader;
260 private String _indexesSQL;
261 private ServiceComponent _previousServiceComponent;
262 private String _sequencesSQL;
263 private 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 clearCacheRegistry(
277 ServiceComponentConfiguration serviceComponentConfiguration)
278 throws DocumentException {
279
280 InputStream inputStream =
281 serviceComponentConfiguration.getHibernateInputStream();
282
283 if (inputStream == null) {
284 return;
285 }
286
287 Document document = SAXReaderUtil.read(inputStream);
288
289 Element rootElement = document.getRootElement();
290
291 List<Element> classElements = rootElement.elements("class");
292
293 for (Element classElement : classElements) {
294 String name = classElement.attributeValue("name");
295
296 CacheRegistryUtil.unregister(name);
297 }
298
299 CacheRegistryUtil.clear();
300
301 if (PropsValues.CACHE_CLEAR_ON_PLUGIN_UNDEPLOY) {
302 EntityCacheUtil.clearCache();
303 FinderCacheUtil.clearCache();
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 = DBFactoryUtil.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);
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> getModels(ClassLoader classLoader)
364 throws DocumentException, IOException {
365
366 List<String> models = new ArrayList<String>();
367
368 String xml = StringUtil.read(
369 classLoader, "META-INF/portlet-model-hints.xml");
370
371 models.addAll(getModels(xml));
372
373 try {
374 xml = StringUtil.read(
375 classLoader, "META-INF/portlet-model-hints-ext.xml");
376
377 models.addAll(getModels(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 models;
388 }
389
390 protected List<String> getModels(String xml) throws DocumentException {
391 List<String> models = new ArrayList<String>();
392
393 Document document = SAXReaderUtil.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 models.add(name);
403 }
404
405 return models;
406 }
407
408 protected UpgradeTableListener getUpgradeTableListener(
409 ClassLoader classLoader, Class<?> modelClass) {
410
411 String modelClassName = modelClass.getName();
412
413 String upgradeTableListenerClassName = modelClassName;
414
415 upgradeTableListenerClassName = StringUtil.replaceLast(
416 upgradeTableListenerClassName, ".model.impl.", ".model.upgrade.");
417 upgradeTableListenerClassName = StringUtil.replaceLast(
418 upgradeTableListenerClassName, "ModelImpl", "UpgradeTableListener");
419
420 try {
421 UpgradeTableListener upgradeTableListener =
422 (UpgradeTableListener)InstanceFactory.newInstance(
423 classLoader, upgradeTableListenerClassName);
424
425 if (_log.isInfoEnabled()) {
426 _log.info("Instantiated " + upgradeTableListenerClassName);
427 }
428
429 return upgradeTableListener;
430 }
431 catch (Exception e) {
432 if (_log.isDebugEnabled()) {
433 _log.debug(
434 "Unable to instantiate " + upgradeTableListenerClassName);
435 }
436
437 return null;
438 }
439 }
440
441 protected void removeOldServiceComponents(String buildNamespace) {
442 int serviceComponentsCount =
443 serviceComponentPersistence.countByBuildNamespace(buildNamespace);
444
445 if (serviceComponentsCount < _MAX_SERVICE_COMPONENTS) {
446 return;
447 }
448
449 List<ServiceComponent> serviceComponents =
450 serviceComponentPersistence.findByBuildNamespace(
451 buildNamespace, _MAX_SERVICE_COMPONENTS,
452 serviceComponentsCount);
453
454 for (int i = 0; i < serviceComponents.size(); i++) {
455 ServiceComponent serviceComponent = serviceComponents.get(i);
456
457 serviceComponentPersistence.remove(serviceComponent);
458 }
459 }
460
461 protected void upgradeModels(
462 ClassLoader classLoader, ServiceComponent previousServiceComponent)
463 throws Exception {
464
465 List<String> models = getModels(classLoader);
466
467 for (String name : models) {
468 int pos = name.lastIndexOf(".model.");
469
470 name =
471 name.substring(0, pos) + ".model.impl." +
472 name.substring(pos + 7) + "ModelImpl";
473
474 Class<?> modelClass = Class.forName(name, true, classLoader);
475
476 Field tableNameField = modelClass.getField("TABLE_NAME");
477 Field tableColumnsField = modelClass.getField("TABLE_COLUMNS");
478 Field tableSQLCreateField = modelClass.getField("TABLE_SQL_CREATE");
479 Field dataSourceField = modelClass.getField("DATA_SOURCE");
480
481 String tableName = (String)tableNameField.get(null);
482 Object[][] tableColumns = (Object[][])tableColumnsField.get(null);
483 String tableSQLCreate = (String)tableSQLCreateField.get(null);
484 String dataSource = (String)dataSourceField.get(null);
485
486 if (!dataSource.equals(Entity.DEFAULT_DATA_SOURCE)) {
487 continue;
488 }
489
490 UpgradeTable upgradeTable = UpgradeTableFactoryUtil.getUpgradeTable(
491 tableName, tableColumns);
492
493 UpgradeTableListener upgradeTableListener = getUpgradeTableListener(
494 classLoader, modelClass);
495
496 upgradeTable.setCreateSQL(tableSQLCreate);
497
498 if (upgradeTableListener != null) {
499 upgradeTableListener.onBeforeUpdateTable(
500 previousServiceComponent, upgradeTable);
501 }
502
503 upgradeTable.updateTable();
504
505 if (upgradeTableListener != null) {
506 upgradeTableListener.onAfterUpdateTable(
507 previousServiceComponent, upgradeTable);
508 }
509 }
510 }
511
512 private static final int _MAX_SERVICE_COMPONENTS = 10;
513
514 private static Log _log = LogFactoryUtil.getLog(
515 ServiceComponentLocalServiceImpl.class);
516
517 private static PACL _pacl = new NoPACL();
518
519 private static class NoPACL implements PACL {
520
521 @Override
522 public void doUpgradeDB(
523 DoUpgradeDBPrivilegedExceptionAction
524 doUpgradeDBPrivilegedExceptionAction)
525 throws Exception {
526
527 doUpgradeDBPrivilegedExceptionAction.run();
528 }
529
530 }
531
532 }