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  import java.io.InputStream;
46  
47  import java.lang.reflect.Field;
48  
49  import java.util.ArrayList;
50  import java.util.Iterator;
51  import java.util.List;
52  
53  import javax.servlet.ServletContext;
54  
55  /**
56   * <a href="ServiceComponentLocalServiceImpl.java.html"><b><i>View Source</i>
57   * </b></a>
58   *
59   * @author Brian Wing Shun Chan
60   */
61  public class ServiceComponentLocalServiceImpl
62      extends ServiceComponentLocalServiceBaseImpl {
63  
64      public void destroyServiceComponent(
65              ServletContext servletContext, ClassLoader classLoader)
66          throws SystemException {
67  
68          try {
69              clearCacheRegistry(servletContext);
70          }
71          catch (Exception e) {
72              throw new SystemException(e);
73          }
74      }
75  
76      public ServiceComponent initServiceComponent(
77              ServletContext servletContext, ClassLoader classLoader,
78              String buildNamespace, long buildNumber, long buildDate,
79              boolean buildAutoUpgrade)
80          throws PortalException, SystemException {
81  
82          try {
83              ModelHintsUtil.read(
84                  classLoader, "META-INF/portlet-model-hints.xml");
85          }
86          catch (Exception e) {
87              throw new SystemException(e);
88          }
89  
90          try {
91              ModelHintsUtil.read(
92                  classLoader, "META-INF/portlet-model-hints-ext.xml");
93          }
94          catch (Exception e) {
95              throw new SystemException(e);
96          }
97  
98          ServiceComponent serviceComponent = null;
99          ServiceComponent previousServiceComponent = null;
100 
101         List<ServiceComponent> serviceComponents =
102             serviceComponentPersistence.findByBuildNamespace(
103                 buildNamespace, 0, 1);
104 
105         if (serviceComponents.size() == 0) {
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 doc = SAXReaderUtil.createDocument(StringPool.UTF8);
143 
144             Element data = doc.addElement("data");
145 
146             String tablesSQL = HttpUtil.URLtoString(servletContext.getResource(
147                 "/WEB-INF/sql/tables.sql"));
148 
149             data.addElement("tables-sql").addCDATA(tablesSQL);
150 
151             String sequencesSQL = HttpUtil.URLtoString(
152                 servletContext.getResource("/WEB-INF/sql/sequences.sql"));
153 
154             data.addElement("sequences-sql").addCDATA(sequencesSQL);
155 
156             String indexesSQL = HttpUtil.URLtoString(servletContext.getResource(
157                 "/WEB-INF/sql/indexes.sql"));
158 
159             data.addElement("indexes-sql").addCDATA(indexesSQL);
160 
161             String dataXML = doc.formattedString();
162 
163             serviceComponent.setData(dataXML);
164 
165             serviceComponentPersistence.update(serviceComponent, false);
166 
167             serviceComponentLocalService.upgradeDB(
168                 classLoader, buildNamespace, buildNumber, buildAutoUpgrade,
169                 previousServiceComponent, tablesSQL, sequencesSQL, indexesSQL);
170 
171             removeOldServiceComponents(buildNamespace);
172 
173             return serviceComponent;
174         }
175         catch (Exception e) {
176             throw new SystemException(e);
177         }
178     }
179 
180     public void upgradeDB(
181             ClassLoader classLoader, String buildNamespace, long buildNumber,
182             boolean buildAutoUpgrade, ServiceComponent previousServiceComponent,
183             String tablesSQL, String sequencesSQL, String indexesSQL)
184         throws Exception {
185 
186         DB db = DBFactoryUtil.getDB();
187 
188         if (previousServiceComponent == null) {
189             if (_log.isInfoEnabled()) {
190                 _log.info("Running " + buildNamespace + " SQL scripts");
191             }
192 
193             db.runSQLTemplateString(tablesSQL, true, false);
194             db.runSQLTemplateString(sequencesSQL, true, false);
195             db.runSQLTemplateString(indexesSQL, true, false);
196         }
197         else if (buildAutoUpgrade) {
198             if (_log.isInfoEnabled()) {
199                 _log.info(
200                     "Upgrading " + buildNamespace +
201                         " database to build number " + buildNumber);
202             }
203 
204             if (!tablesSQL.equals(
205                     previousServiceComponent.getTablesSQL())) {
206 
207                 if (_log.isInfoEnabled()) {
208                     _log.info("Upgrading database with tables.sql");
209                 }
210 
211                 db.runSQLTemplateString(tablesSQL, true, false);
212 
213                 upgradeModels(classLoader);
214             }
215 
216             if (!sequencesSQL.equals(
217                     previousServiceComponent.getSequencesSQL())) {
218 
219                 if (_log.isInfoEnabled()) {
220                     _log.info("Upgrading database with sequences.sql");
221                 }
222 
223                 db.runSQLTemplateString(sequencesSQL, true, false);
224             }
225 
226             if (!indexesSQL.equals(
227                     previousServiceComponent.getIndexesSQL())) {
228 
229                 if (_log.isInfoEnabled()) {
230                     _log.info("Upgrading database with indexes.sql");
231                 }
232 
233                 db.runSQLTemplateString(indexesSQL, true, false);
234             }
235         }
236     }
237 
238     public void verifyDB() throws PortalException, SystemException {
239         Company defaultCompany = companyPersistence.findByWebId(
240             PropsValues.COMPANY_DEFAULT_WEB_ID);
241 
242         ShardUtil.pushCompanyService(defaultCompany.getCompanyId());
243 
244         List<ServiceComponent> serviceComponents = null;
245 
246         try {
247             serviceComponents = serviceComponentPersistence.findAll();
248         }
249         finally {
250             ShardUtil.popCompanyService();
251         }
252 
253         for (ServiceComponent serviceComponent : serviceComponents) {
254             String buildNamespace = serviceComponent.getBuildNamespace();
255             String tablesSQL = serviceComponent.getTablesSQL();
256             String sequencesSQL = serviceComponent.getSequencesSQL();
257             String indexesSQL = serviceComponent.getIndexesSQL();
258 
259             try {
260                 serviceComponentLocalService.upgradeDB(
261                     null, buildNamespace, 0, false, null, tablesSQL,
262                     sequencesSQL, indexesSQL);
263             }
264             catch (Exception e) {
265                 _log.error(e, e);
266             }
267         }
268     }
269 
270     protected void clearCacheRegistry(ServletContext servletContext)
271         throws DocumentException {
272 
273         InputStream is = servletContext.getResourceAsStream(
274             "/WEB-INF/classes/META-INF/portlet-hbm.xml");
275 
276         if (is == null) {
277             return;
278         }
279 
280         Document doc = SAXReaderUtil.read(is);
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 }