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 public void destroyServiceComponent(
065 ServletContext servletContext, ClassLoader classLoader)
066 throws SystemException {
067
068 try {
069 clearCacheRegistry(servletContext);
070 }
071 catch (Exception e) {
072 throw new SystemException(e);
073 }
074 }
075
076 public ServiceComponent initServiceComponent(
077 ServletContext servletContext, ClassLoader classLoader,
078 String buildNamespace, long buildNumber, long buildDate,
079 boolean buildAutoUpgrade)
080 throws PortalException, SystemException {
081
082 try {
083 ModelHintsUtil.read(
084 classLoader, "META-INF/portlet-model-hints.xml");
085 }
086 catch (Exception e) {
087 throw new SystemException(e);
088 }
089
090 try {
091 ModelHintsUtil.read(
092 classLoader, "META-INF/portlet-model-hints-ext.xml");
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 = HttpUtil.URLtoString(
149 servletContext.getResource("/WEB-INF/sql/tables.sql"));
150
151 tablesSQLElement.addCDATA(tablesSQL);
152
153 Element sequencesSQLElement = dataElement.addElement(
154 "sequences-sql");
155
156 String sequencesSQL = HttpUtil.URLtoString(
157 servletContext.getResource("/WEB-INF/sql/sequences.sql"));
158
159 sequencesSQLElement.addCDATA(sequencesSQL);
160
161 Element indexesSQLElement = dataElement.addElement("indexes-sql");
162
163 String indexesSQL = HttpUtil.URLtoString(
164 servletContext.getResource("/WEB-INF/sql/indexes.sql"));
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 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 ProtectionDomain protectionDomain = new ProtectionDomain(
196 null, null, classLoader, null);
197
198 AccessControlContext accessControlContext = new AccessControlContext(
199 new ProtectionDomain[] {protectionDomain});
200
201 AccessController.doPrivileged(
202 new PrivilegedExceptionAction<Void>() {
203
204 public Void run() throws Exception {
205 doUpgradeDB(
206 classLoader, buildNamespace, buildNumber,
207 buildAutoUpgrade, previousServiceComponent, tablesSQL,
208 sequencesSQL, indexesSQL);
209
210 return null;
211 }
212
213 },
214 accessControlContext
215 );
216 }
217
218 public void verifyDB() throws SystemException {
219 List<ServiceComponent> serviceComponents =
220 serviceComponentPersistence.findAll();
221
222 for (ServiceComponent serviceComponent : serviceComponents) {
223 String buildNamespace = serviceComponent.getBuildNamespace();
224 String tablesSQL = serviceComponent.getTablesSQL();
225 String sequencesSQL = serviceComponent.getSequencesSQL();
226 String indexesSQL = serviceComponent.getIndexesSQL();
227
228 try {
229 serviceComponentLocalService.upgradeDB(
230 null, buildNamespace, 0, false, null, tablesSQL,
231 sequencesSQL, indexesSQL);
232 }
233 catch (Exception e) {
234 _log.error(e, e);
235 }
236 }
237 }
238
239 protected void clearCacheRegistry(ServletContext servletContext)
240 throws DocumentException {
241
242 InputStream inputStream = servletContext.getResourceAsStream(
243 "/WEB-INF/classes/META-INF/portlet-hbm.xml");
244
245 if (inputStream == null) {
246 return;
247 }
248
249 Document document = SAXReaderUtil.read(inputStream);
250
251 Element rootElement = document.getRootElement();
252
253 List<Element> classElements = rootElement.elements("class");
254
255 for (Element classElement : classElements) {
256 String name = classElement.attributeValue("name");
257
258 CacheRegistryUtil.unregister(name);
259 }
260
261 CacheRegistryUtil.clear();
262
263 EntityCacheUtil.clearCache();
264 FinderCacheUtil.clearCache();
265 }
266
267 protected void doUpgradeDB(
268 ClassLoader classLoader, String buildNamespace, long buildNumber,
269 boolean buildAutoUpgrade, ServiceComponent previousServiceComponent,
270 String tablesSQL, String sequencesSQL, String indexesSQL)
271 throws Exception {
272
273 DB db = DBFactoryUtil.getDB();
274
275 if (previousServiceComponent == null) {
276 if (_log.isInfoEnabled()) {
277 _log.info("Running " + buildNamespace + " SQL scripts");
278 }
279
280 db.runSQLTemplateString(tablesSQL, true, false);
281 db.runSQLTemplateString(sequencesSQL, true, false);
282 db.runSQLTemplateString(indexesSQL, true, false);
283 }
284 else if (buildAutoUpgrade) {
285 if (_log.isInfoEnabled()) {
286 _log.info(
287 "Upgrading " + buildNamespace +
288 " database to build number " + buildNumber);
289 }
290
291 if (!tablesSQL.equals(previousServiceComponent.getTablesSQL())) {
292 if (_log.isInfoEnabled()) {
293 _log.info("Upgrading database with tables.sql");
294 }
295
296 db.runSQLTemplateString(tablesSQL, true, false);
297
298 upgradeModels(classLoader, previousServiceComponent);
299 }
300
301 if (!sequencesSQL.equals(
302 previousServiceComponent.getSequencesSQL())) {
303
304 if (_log.isInfoEnabled()) {
305 _log.info("Upgrading database with sequences.sql");
306 }
307
308 db.runSQLTemplateString(sequencesSQL, true, false);
309 }
310
311 if (!indexesSQL.equals(previousServiceComponent.getIndexesSQL())) {
312 if (_log.isInfoEnabled()) {
313 _log.info("Upgrading database with indexes.sql");
314 }
315
316 db.runSQLTemplateString(indexesSQL, true, false);
317 }
318 }
319 }
320
321 protected List<String> getModels(ClassLoader classLoader)
322 throws DocumentException, IOException {
323
324 List<String> models = new ArrayList<String>();
325
326 String xml = StringUtil.read(
327 classLoader, "META-INF/portlet-model-hints.xml");
328
329 models.addAll(getModels(xml));
330
331 try {
332 xml = StringUtil.read(
333 classLoader, "META-INF/portlet-model-hints-ext.xml");
334
335 models.addAll(getModels(xml));
336 }
337 catch (Exception e) {
338 if (_log.isInfoEnabled()) {
339 _log.info(
340 "No optional file META-INF/portlet-model-hints-ext.xml " +
341 "found");
342 }
343 }
344
345 return models;
346 }
347
348 protected List<String> getModels(String xml) throws DocumentException {
349 List<String> models = new ArrayList<String>();
350
351 Document document = SAXReaderUtil.read(xml);
352
353 Element rootElement = document.getRootElement();
354
355 List<Element> modelElements = rootElement.elements("model");
356
357 for (Element modelElement : modelElements) {
358 String name = modelElement.attributeValue("name");
359
360 models.add(name);
361 }
362
363 return models;
364 }
365
366 protected UpgradeTableListener getUpgradeTableListener(
367 ClassLoader classLoader, Class<?> modelClass) {
368
369 String modelClassName = modelClass.getName();
370
371 String upgradeTableListenerClassName = modelClassName;
372
373 upgradeTableListenerClassName = StringUtil.replaceLast(
374 upgradeTableListenerClassName, ".model.impl.", ".model.upgrade.");
375 upgradeTableListenerClassName = StringUtil.replaceLast(
376 upgradeTableListenerClassName, "ModelImpl", "UpgradeTableListener");
377
378 try {
379 UpgradeTableListener upgradeTableListener =
380 (UpgradeTableListener)InstanceFactory.newInstance(
381 classLoader, upgradeTableListenerClassName);
382
383 if (_log.isInfoEnabled()) {
384 _log.info("Instantiated " + upgradeTableListenerClassName);
385 }
386
387 return upgradeTableListener;
388 }
389 catch (Exception e) {
390 if (_log.isDebugEnabled()) {
391 _log.debug(
392 "Unable to instantiate " + upgradeTableListenerClassName);
393 }
394
395 return null;
396 }
397 }
398
399 protected void removeOldServiceComponents(String buildNamespace)
400 throws SystemException {
401
402 int serviceComponentsCount =
403 serviceComponentPersistence.countByBuildNamespace(buildNamespace);
404
405 if (serviceComponentsCount < _MAX_SERVICE_COMPONENTS) {
406 return;
407 }
408
409 List<ServiceComponent> serviceComponents =
410 serviceComponentPersistence.findByBuildNamespace(
411 buildNamespace, _MAX_SERVICE_COMPONENTS,
412 serviceComponentsCount);
413
414 for (int i = 0; i < serviceComponents.size(); i++) {
415 ServiceComponent serviceComponent = serviceComponents.get(i);
416
417 serviceComponentPersistence.remove(serviceComponent);
418 }
419 }
420
421 protected void upgradeModels(
422 ClassLoader classLoader, ServiceComponent previousServiceComponent)
423 throws Exception {
424
425 List<String> models = getModels(classLoader);
426
427 for (String name : models) {
428 int pos = name.lastIndexOf(".model.");
429
430 name =
431 name.substring(0, pos) + ".model.impl." +
432 name.substring(pos + 7) + "ModelImpl";
433
434 Class<?> modelClass = Class.forName(name, true, classLoader);
435
436 Field tableNameField = modelClass.getField("TABLE_NAME");
437 Field tableColumnsField = modelClass.getField("TABLE_COLUMNS");
438 Field tableSQLCreateField = modelClass.getField("TABLE_SQL_CREATE");
439 Field dataSourceField = modelClass.getField("DATA_SOURCE");
440
441 String tableName = (String)tableNameField.get(null);
442 Object[][] tableColumns = (Object[][])tableColumnsField.get(null);
443 String tableSQLCreate = (String)tableSQLCreateField.get(null);
444 String dataSource = (String)dataSourceField.get(null);
445
446 if (!dataSource.equals(Entity.DEFAULT_DATA_SOURCE)) {
447 continue;
448 }
449
450 UpgradeTable upgradeTable = UpgradeTableFactoryUtil.getUpgradeTable(
451 tableName, tableColumns);
452
453 UpgradeTableListener upgradeTableListener = getUpgradeTableListener(
454 classLoader, modelClass);
455
456 upgradeTable.setCreateSQL(tableSQLCreate);
457
458 if (upgradeTableListener != null) {
459 upgradeTableListener.onBeforeUpdateTable(
460 previousServiceComponent, upgradeTable);
461 }
462
463 upgradeTable.updateTable();
464
465 if (upgradeTableListener != null) {
466 upgradeTableListener.onAfterUpdateTable(
467 previousServiceComponent, upgradeTable);
468 }
469 }
470 }
471
472 private static final int _MAX_SERVICE_COMPONENTS = 10;
473
474 private static Log _log = LogFactoryUtil.getLog(
475 ServiceComponentLocalServiceImpl.class);
476
477 }