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