1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   *
13   */
14  
15  package com.liferay.portal.service.impl;
16  
17  import com.liferay.portal.OldServiceComponentException;
18  import com.liferay.portal.PortalException;
19  import com.liferay.portal.SystemException;
20  import com.liferay.portal.kernel.cache.CacheRegistry;
21  import com.liferay.portal.kernel.dao.db.DB;
22  import com.liferay.portal.kernel.dao.db.DBFactoryUtil;
23  import com.liferay.portal.kernel.dao.orm.EntityCacheUtil;
24  import com.liferay.portal.kernel.dao.orm.FinderCacheUtil;
25  import com.liferay.portal.kernel.dao.shard.ShardUtil;
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.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 document = SAXReaderUtil.createDocument(StringPool.UTF8);
142 
143             Element dataElement = document.addElement("data");
144 
145             String tablesSQL = HttpUtil.URLtoString(servletContext.getResource(
146                 "/WEB-INF/sql/tables.sql"));
147 
148             dataElement.addElement("tables-sql").addCDATA(tablesSQL);
149 
150             String sequencesSQL = HttpUtil.URLtoString(
151                 servletContext.getResource("/WEB-INF/sql/sequences.sql"));
152 
153             dataElement.addElement("sequences-sql").addCDATA(sequencesSQL);
154 
155             String indexesSQL = HttpUtil.URLtoString(servletContext.getResource(
156                 "/WEB-INF/sql/indexes.sql"));
157 
158             dataElement.addElement("indexes-sql").addCDATA(indexesSQL);
159 
160             String dataXML = document.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 {
271 
272         InputStream inputStream = servletContext.getResourceAsStream(
273             "/WEB-INF/classes/META-INF/portlet-hbm.xml");
274 
275         if (inputStream == null) {
276             return;
277         }
278 
279         Document document = SAXReaderUtil.read(inputStream);
280 
281         Element rootElement = document.getRootElement();
282 
283         List<Element> classElements = rootElement.elements("class");
284 
285         for (Element classElement : classElements) {
286             String name = classElement.attributeValue("name");
287 
288             CacheRegistry.unregister(name);
289         }
290 
291         CacheRegistry.clear();
292 
293         EntityCacheUtil.clearCache();
294         FinderCacheUtil.clearCache();
295     }
296 
297     protected List<String> getModels(ClassLoader classLoader)
298         throws DocumentException, IOException {
299 
300         List<String> models = new ArrayList<String>();
301 
302         String xml = StringUtil.read(
303             classLoader, "META-INF/portlet-model-hints.xml");
304 
305         models.addAll(getModels(xml));
306 
307         try {
308             xml = StringUtil.read(
309                 classLoader, "META-INF/portlet-model-hints-ext.xml");
310 
311             models.addAll(getModels(xml));
312         }
313         catch (Exception e) {
314             if (_log.isInfoEnabled()) {
315                 _log.info(
316                     "No optional file META-INF/portlet-model-hints-ext.xml " +
317                         "found");
318             }
319         }
320 
321         return models;
322     }
323 
324     protected List<String> getModels(String xml) throws DocumentException {
325         List<String> models = new ArrayList<String>();
326 
327         Document document = SAXReaderUtil.read(xml);
328 
329         Element rootElement = document.getRootElement();
330 
331         List<Element> modelElements = rootElement.elements("model");
332 
333         for (Element modelElement : modelElements) {
334             String name = modelElement.attributeValue("name");
335 
336             models.add(name);
337         }
338 
339         return models;
340     }
341 
342     protected void upgradeModels(ClassLoader classLoader) throws Exception {
343         List<String> models = getModels(classLoader);
344 
345         for (String name : models) {
346             int pos = name.lastIndexOf(".model.");
347 
348             name =
349                 name.substring(0, pos) + ".model.impl." +
350                     name.substring(pos + 7) + "ModelImpl";
351 
352             Class<?> modelClass = Class.forName(name, true, classLoader);
353 
354             Field tableNameField = modelClass.getField("TABLE_NAME");
355             Field tableColumnsField = modelClass.getField("TABLE_COLUMNS");
356             Field tableSQLCreateField = modelClass.getField("TABLE_SQL_CREATE");
357             Field dataSourceField = modelClass.getField("DATA_SOURCE");
358 
359             String tableName = (String)tableNameField.get(null);
360             Object[][] tableColumns = (Object[][])tableColumnsField.get(null);
361             String tableSQLCreate = (String)tableSQLCreateField.get(null);
362             String dataSource = (String)dataSourceField.get(null);
363 
364             if (!dataSource.equals(Entity.DEFAULT_DATA_SOURCE)) {
365                 continue;
366             }
367 
368             UpgradeTable upgradeTable = UpgradeTableFactoryUtil.getUpgradeTable(
369                 tableName, tableColumns);
370 
371             upgradeTable.setCreateSQL(tableSQLCreate);
372 
373             upgradeTable.updateTable();
374         }
375     }
376 
377     protected void removeOldServiceComponents(String buildNamespace)
378         throws SystemException {
379 
380         int serviceComponentsCount =
381             serviceComponentPersistence.countByBuildNamespace(buildNamespace);
382 
383         if (serviceComponentsCount < _MAX_SERVICE_COMPONENTS) {
384             return;
385         }
386 
387         List<ServiceComponent> serviceComponents =
388             serviceComponentPersistence.findByBuildNamespace(
389                 buildNamespace, _MAX_SERVICE_COMPONENTS,
390                 serviceComponentsCount);
391 
392         for (int i = 0; i < serviceComponents.size(); i++) {
393             ServiceComponent serviceComponent = serviceComponents.get(i);
394 
395             serviceComponentPersistence.remove(serviceComponent);
396         }
397     }
398 
399     private static final int _MAX_SERVICE_COMPONENTS = 10;
400 
401     private static Log _log = LogFactoryUtil.getLog(
402         ServiceComponentLocalServiceImpl.class);
403 
404 }