1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portal.service.impl;
16  
17  import com.liferay.portal.OldServiceComponentException;
18  import com.liferay.portal.dao.shard.ShardUtil;
19  import com.liferay.portal.kernel.cache.CacheRegistry;
20  import com.liferay.portal.kernel.dao.db.DB;
21  import com.liferay.portal.kernel.dao.db.DBFactoryUtil;
22  import com.liferay.portal.kernel.dao.orm.EntityCacheUtil;
23  import com.liferay.portal.kernel.dao.orm.FinderCacheUtil;
24  import com.liferay.portal.kernel.exception.PortalException;
25  import com.liferay.portal.kernel.exception.SystemException;
26  import com.liferay.portal.kernel.log.Log;
27  import com.liferay.portal.kernel.log.LogFactoryUtil;
28  import com.liferay.portal.kernel.upgrade.util.UpgradeTable;
29  import com.liferay.portal.kernel.upgrade.util.UpgradeTableFactoryUtil;
30  import com.liferay.portal.kernel.util.HttpUtil;
31  import com.liferay.portal.kernel.util.StringPool;
32  import com.liferay.portal.kernel.util.StringUtil;
33  import com.liferay.portal.kernel.xml.Document;
34  import com.liferay.portal.kernel.xml.DocumentException;
35  import com.liferay.portal.kernel.xml.Element;
36  import com.liferay.portal.kernel.xml.SAXReaderUtil;
37  import com.liferay.portal.model.Company;
38  import com.liferay.portal.model.ModelHintsUtil;
39  import com.liferay.portal.model.ServiceComponent;
40  import com.liferay.portal.service.base.ServiceComponentLocalServiceBaseImpl;
41  import com.liferay.portal.tools.servicebuilder.Entity;
42  import com.liferay.portal.util.PropsValues;
43  
44  import java.io.IOException;
45  
46  import java.lang.reflect.Field;
47  
48  import java.util.ArrayList;
49  import java.util.Iterator;
50  import java.util.List;
51  
52  import javax.servlet.ServletContext;
53  
54  /**
55   * <a href="ServiceComponentLocalServiceImpl.java.html"><b><i>View Source</i>
56   * </b></a>
57   *
58   * @author Brian Wing Shun Chan
59   */
60  public class ServiceComponentLocalServiceImpl
61      extends ServiceComponentLocalServiceBaseImpl {
62  
63      public void destroyServiceComponent(
64              ServletContext servletContext, ClassLoader classLoader)
65          throws SystemException {
66  
67          try {
68              clearCacheRegistry(servletContext);
69          }
70          catch (Exception e) {
71              throw new SystemException(e);
72          }
73      }
74  
75      public ServiceComponent initServiceComponent(
76              ServletContext servletContext, ClassLoader classLoader,
77              String buildNamespace, long buildNumber, long buildDate,
78              boolean buildAutoUpgrade)
79          throws PortalException, SystemException {
80  
81          try {
82              ModelHintsUtil.read(
83                  classLoader, "META-INF/portlet-model-hints.xml");
84          }
85          catch (Exception e) {
86              throw new SystemException(e);
87          }
88  
89          try {
90              ModelHintsUtil.read(
91                  classLoader, "META-INF/portlet-model-hints-ext.xml");
92          }
93          catch (Exception e) {
94              throw new SystemException(e);
95          }
96  
97          ServiceComponent serviceComponent = null;
98          ServiceComponent previousServiceComponent = null;
99  
100         List<ServiceComponent> serviceComponents =
101             serviceComponentPersistence.findByBuildNamespace(
102                 buildNamespace, 0, 1);
103 
104         if (serviceComponents.size() == 0) {
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 doc = SAXReaderUtil.createDocument(StringPool.UTF8);
142 
143             Element data = doc.addElement("data");
144 
145             String tablesSQL = HttpUtil.URLtoString(servletContext.getResource(
146                 "/WEB-INF/sql/tables.sql"));
147 
148             data.addElement("tables-sql").addCDATA(tablesSQL);
149 
150             String sequencesSQL = HttpUtil.URLtoString(
151                 servletContext.getResource("/WEB-INF/sql/sequences.sql"));
152 
153             data.addElement("sequences-sql").addCDATA(sequencesSQL);
154 
155             String indexesSQL = HttpUtil.URLtoString(servletContext.getResource(
156                 "/WEB-INF/sql/indexes.sql"));
157 
158             data.addElement("indexes-sql").addCDATA(indexesSQL);
159 
160             String dataXML = doc.formattedString();
161 
162             serviceComponent.setData(dataXML);
163 
164             serviceComponentPersistence.update(serviceComponent, false);
165 
166             serviceComponentLocalService.upgradeDB(
167                 classLoader, buildNamespace, buildNumber, buildAutoUpgrade,
168                 previousServiceComponent, tablesSQL, sequencesSQL, indexesSQL);
169 
170             removeOldServiceComponents(buildNamespace);
171 
172             return serviceComponent;
173         }
174         catch (Exception e) {
175             throw new SystemException(e);
176         }
177     }
178 
179     public void upgradeDB(
180             ClassLoader classLoader, String buildNamespace, long buildNumber,
181             boolean buildAutoUpgrade, ServiceComponent previousServiceComponent,
182             String tablesSQL, String sequencesSQL, String indexesSQL)
183         throws Exception {
184 
185         DB db = DBFactoryUtil.getDB();
186 
187         if (previousServiceComponent == null) {
188             if (_log.isInfoEnabled()) {
189                 _log.info("Running " + buildNamespace + " SQL scripts");
190             }
191 
192             db.runSQLTemplateString(tablesSQL, true, false);
193             db.runSQLTemplateString(sequencesSQL, true, false);
194             db.runSQLTemplateString(indexesSQL, true, false);
195         }
196         else if (buildAutoUpgrade) {
197             if (_log.isInfoEnabled()) {
198                 _log.info(
199                     "Upgrading " + buildNamespace +
200                         " database to build number " + buildNumber);
201             }
202 
203             if (!tablesSQL.equals(
204                     previousServiceComponent.getTablesSQL())) {
205 
206                 if (_log.isInfoEnabled()) {
207                     _log.info("Upgrading database with tables.sql");
208                 }
209 
210                 db.runSQLTemplateString(tablesSQL, true, false);
211 
212                 upgradeModels(classLoader);
213             }
214 
215             if (!sequencesSQL.equals(
216                     previousServiceComponent.getSequencesSQL())) {
217 
218                 if (_log.isInfoEnabled()) {
219                     _log.info("Upgrading database with sequences.sql");
220                 }
221 
222                 db.runSQLTemplateString(sequencesSQL, true, false);
223             }
224 
225             if (!indexesSQL.equals(
226                     previousServiceComponent.getIndexesSQL())) {
227 
228                 if (_log.isInfoEnabled()) {
229                     _log.info("Upgrading database with indexes.sql");
230                 }
231 
232                 db.runSQLTemplateString(indexesSQL, true, false);
233             }
234         }
235     }
236 
237     public void verifyDB() throws PortalException, SystemException {
238         Company defaultCompany = companyPersistence.findByWebId(
239             PropsValues.COMPANY_DEFAULT_WEB_ID);
240 
241         ShardUtil.pushCompanyService(defaultCompany.getCompanyId());
242 
243         List<ServiceComponent> serviceComponents = null;
244 
245         try {
246             serviceComponents = serviceComponentPersistence.findAll();
247         }
248         finally {
249             ShardUtil.popCompanyService();
250         }
251 
252         for (ServiceComponent serviceComponent : serviceComponents) {
253             String buildNamespace = serviceComponent.getBuildNamespace();
254             String tablesSQL = serviceComponent.getTablesSQL();
255             String sequencesSQL = serviceComponent.getSequencesSQL();
256             String indexesSQL = serviceComponent.getIndexesSQL();
257 
258             try {
259                 serviceComponentLocalService.upgradeDB(
260                     null, buildNamespace, 0, false, null, tablesSQL,
261                     sequencesSQL, indexesSQL);
262             }
263             catch (Exception e) {
264                 _log.error(e, e);
265             }
266         }
267     }
268 
269     protected void clearCacheRegistry(ServletContext servletContext)
270         throws DocumentException, IOException {
271 
272         String xml = HttpUtil.URLtoString(
273             servletContext.getResource(
274                 "/WEB-INF/classes/META-INF/portlet-hbm.xml"));
275 
276         if (xml == null) {
277             return;
278         }
279 
280         Document doc = SAXReaderUtil.read(xml);
281 
282         Element root = doc.getRootElement();
283 
284         List<Element> classEls = root.elements("class");
285 
286         for (Element classEl : classEls) {
287             String name = classEl.attributeValue("name");
288 
289             CacheRegistry.unregister(name);
290         }
291 
292         CacheRegistry.clear();
293 
294         EntityCacheUtil.clearCache();
295         FinderCacheUtil.clearCache();
296     }
297 
298     protected List<String> getModels(ClassLoader classLoader)
299         throws DocumentException, IOException {
300 
301         List<String> models = new ArrayList<String>();
302 
303         String xml = StringUtil.read(
304             classLoader, "META-INF/portlet-model-hints.xml");
305 
306         models.addAll(getModels(xml));
307 
308         try {
309             xml = StringUtil.read(
310                 classLoader, "META-INF/portlet-model-hints-ext.xml");
311 
312             models.addAll(getModels(xml));
313         }
314         catch (Exception e) {
315             if (_log.isInfoEnabled()) {
316                 _log.info(
317                     "No optional file META-INF/portlet-model-hints-ext.xml " +
318                         "found");
319             }
320         }
321 
322         return models;
323     }
324 
325     protected List<String> getModels(String xml) throws DocumentException {
326         List<String> models = new ArrayList<String>();
327 
328         Document doc = SAXReaderUtil.read(xml);
329 
330         Element root = doc.getRootElement();
331 
332         Iterator<Element> itr = root.elements("model").iterator();
333 
334         while (itr.hasNext()) {
335             Element modelEl = itr.next();
336 
337             String name = modelEl.attributeValue("name");
338 
339             models.add(name);
340         }
341 
342         return models;
343     }
344 
345     protected void upgradeModels(ClassLoader classLoader) throws Exception {
346         List<String> models = getModels(classLoader);
347 
348         for (String name : models) {
349             int pos = name.lastIndexOf(".model.");
350 
351             name =
352                 name.substring(0, pos) + ".model.impl." +
353                     name.substring(pos + 7) + "ModelImpl";
354 
355             Class<?> modelClass = Class.forName(name, true, classLoader);
356 
357             Field tableNameField = modelClass.getField("TABLE_NAME");
358             Field tableColumnsField = modelClass.getField("TABLE_COLUMNS");
359             Field tableSQLCreateField = modelClass.getField("TABLE_SQL_CREATE");
360             Field dataSourceField = modelClass.getField("DATA_SOURCE");
361 
362             String tableName = (String)tableNameField.get(null);
363             Object[][] tableColumns = (Object[][])tableColumnsField.get(null);
364             String tableSQLCreate = (String)tableSQLCreateField.get(null);
365             String dataSource = (String)dataSourceField.get(null);
366 
367             if (!dataSource.equals(Entity.DEFAULT_DATA_SOURCE)) {
368                 continue;
369             }
370 
371             UpgradeTable upgradeTable = UpgradeTableFactoryUtil.getUpgradeTable(
372                 tableName, tableColumns);
373 
374             upgradeTable.setCreateSQL(tableSQLCreate);
375 
376             upgradeTable.updateTable();
377         }
378     }
379 
380     protected void removeOldServiceComponents(String buildNamespace)
381         throws SystemException {
382 
383         int serviceComponentsCount =
384             serviceComponentPersistence.countByBuildNamespace(buildNamespace);
385 
386         if (serviceComponentsCount < _MAX_SERVICE_COMPONENTS) {
387             return;
388         }
389 
390         List<ServiceComponent> serviceComponents =
391             serviceComponentPersistence.findByBuildNamespace(
392                 buildNamespace, _MAX_SERVICE_COMPONENTS,
393                 serviceComponentsCount);
394 
395         for (int i = 0; i < serviceComponents.size(); i++) {
396             ServiceComponent serviceComponent = serviceComponents.get(i);
397 
398             serviceComponentPersistence.remove(serviceComponent);
399         }
400     }
401 
402     private static final int _MAX_SERVICE_COMPONENTS = 10;
403 
404     private static Log _log = LogFactoryUtil.getLog(
405         ServiceComponentLocalServiceImpl.class);
406 
407 }