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