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