1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.service.impl;
24  
25  import com.liferay.portal.OldServiceComponentException;
26  import com.liferay.portal.PortalException;
27  import com.liferay.portal.SystemException;
28  import com.liferay.portal.kernel.cache.CacheRegistry;
29  import com.liferay.portal.kernel.dao.orm.EntityCacheUtil;
30  import com.liferay.portal.kernel.dao.orm.FinderCacheUtil;
31  import com.liferay.portal.kernel.log.Log;
32  import com.liferay.portal.kernel.log.LogFactoryUtil;
33  import com.liferay.portal.kernel.util.HttpUtil;
34  import com.liferay.portal.kernel.util.StringPool;
35  import com.liferay.portal.kernel.util.StringUtil;
36  import com.liferay.portal.kernel.xml.Document;
37  import com.liferay.portal.kernel.xml.DocumentException;
38  import com.liferay.portal.kernel.xml.Element;
39  import com.liferay.portal.kernel.xml.SAXReaderUtil;
40  import com.liferay.portal.model.ModelHintsUtil;
41  import com.liferay.portal.model.ServiceComponent;
42  import com.liferay.portal.service.base.ServiceComponentLocalServiceBaseImpl;
43  import com.liferay.portal.tools.servicebuilder.Entity;
44  import com.liferay.portal.tools.sql.DBUtil;
45  import com.liferay.portal.upgrade.util.DefaultUpgradeTableImpl;
46  import com.liferay.portal.upgrade.util.UpgradeTable;
47  
48  import java.io.IOException;
49  
50  import java.lang.reflect.Field;
51  
52  import java.util.ArrayList;
53  import java.util.Iterator;
54  import java.util.List;
55  
56  import javax.servlet.ServletContext;
57  
58  /**
59   * <a href="ServiceComponentLocalServiceImpl.java.html"><b><i>View Source</i>
60   * </b></a>
61   *
62   * @author Brian Wing Shun Chan
63   *
64   */
65  public class ServiceComponentLocalServiceImpl
66      extends ServiceComponentLocalServiceBaseImpl {
67  
68      public void destroyServiceComponent(
69              ServletContext servletContext, ClassLoader classLoader)
70          throws SystemException {
71  
72          try {
73              clearCacheRegistry(servletContext);
74          }
75          catch (Exception e) {
76              throw new SystemException(e);
77          }
78      }
79  
80      public ServiceComponent initServiceComponent(
81              ServletContext servletContext, ClassLoader classLoader,
82              String buildNamespace, long buildNumber, long buildDate,
83              boolean buildAutoUpgrade)
84          throws PortalException, SystemException {
85  
86          try {
87              ModelHintsUtil.read(
88                  classLoader, "META-INF/portlet-model-hints.xml");
89          }
90          catch (Exception e) {
91              throw new SystemException(e);
92          }
93  
94          try {
95              ModelHintsUtil.read(
96                  classLoader, "META-INF/portlet-model-hints-ext.xml");
97          }
98          catch (Exception e) {
99              throw new SystemException(e);
100         }
101 
102         ServiceComponent serviceComponent = null;
103         ServiceComponent previousServiceComponent = null;
104 
105         List<ServiceComponent> serviceComponents =
106             serviceComponentPersistence.findByBuildNamespace(
107                 buildNamespace, 0, 1);
108 
109         if (serviceComponents.size() == 0) {
110             long serviceComponentId = counterLocalService.increment();
111 
112             serviceComponent = serviceComponentPersistence.create(
113                 serviceComponentId);
114 
115             serviceComponent.setBuildNamespace(buildNamespace);
116             serviceComponent.setBuildNumber(buildNumber);
117             serviceComponent.setBuildDate(buildDate);
118         }
119         else {
120             serviceComponent = serviceComponents.get(0);
121 
122             if (serviceComponent.getBuildNumber() < buildNumber) {
123                 previousServiceComponent = serviceComponent;
124 
125                 long serviceComponentId = counterLocalService.increment();
126 
127                 serviceComponent = serviceComponentPersistence.create(
128                     serviceComponentId);
129 
130                 serviceComponent.setBuildNamespace(buildNamespace);
131                 serviceComponent.setBuildNumber(buildNumber);
132                 serviceComponent.setBuildDate(buildDate);
133             }
134             else if (serviceComponent.getBuildNumber() > buildNumber) {
135                 throw new OldServiceComponentException(
136                     "Build namespace " + buildNamespace + " has build number " +
137                         serviceComponent.getBuildNumber() +
138                             " which is newer than " + buildNumber);
139             }
140             else {
141                 return serviceComponent;
142             }
143         }
144 
145         try {
146             Document doc = SAXReaderUtil.createDocument(StringPool.UTF8);
147 
148             Element data = doc.addElement("data");
149 
150             String tablesSQL = HttpUtil.URLtoString(servletContext.getResource(
151                 "/WEB-INF/sql/tables.sql"));
152 
153             data.addElement("tables-sql").addCDATA(tablesSQL);
154 
155             String sequencesSQL = HttpUtil.URLtoString(
156                 servletContext.getResource("/WEB-INF/sql/sequences.sql"));
157 
158             data.addElement("sequences-sql").addCDATA(sequencesSQL);
159 
160             String indexesSQL = HttpUtil.URLtoString(servletContext.getResource(
161                 "/WEB-INF/sql/indexes.sql"));
162 
163             data.addElement("indexes-sql").addCDATA(indexesSQL);
164 
165             String dataXML = doc.formattedString();
166 
167             serviceComponent.setData(dataXML);
168 
169             serviceComponentPersistence.update(serviceComponent, false);
170 
171             upgradeDB(
172                 classLoader, buildNamespace, buildNumber, buildAutoUpgrade,
173                 previousServiceComponent, tablesSQL, sequencesSQL, indexesSQL);
174 
175             removeOldServiceComponents(buildNamespace);
176 
177             return serviceComponent;
178         }
179         catch (Exception e) {
180             throw new SystemException(e);
181         }
182     }
183 
184     protected void clearCacheRegistry(ServletContext servletContext)
185         throws DocumentException, IOException {
186 
187         String xml = HttpUtil.URLtoString(
188             servletContext.getResource(
189                 "/WEB-INF/classes/META-INF/portlet-hbm.xml"));
190 
191         if (xml == null) {
192             return;
193         }
194 
195         Document doc = SAXReaderUtil.read(xml);
196 
197         Element root = doc.getRootElement();
198 
199         List<Element> classEls = root.elements("class");
200 
201         for (Element classEl : classEls) {
202             String name = classEl.attributeValue("name");
203 
204             CacheRegistry.unregister(name);
205         }
206 
207         CacheRegistry.clear();
208 
209         EntityCacheUtil.clearCache();
210         FinderCacheUtil.clearCache();
211     }
212 
213     protected List<String> getModels(ClassLoader classLoader)
214         throws DocumentException, IOException {
215 
216         List<String> models = new ArrayList<String>();
217 
218         String xml = StringUtil.read(
219             classLoader, "META-INF/portlet-model-hints.xml");
220 
221         models.addAll(getModels(xml));
222 
223         try {
224             xml = StringUtil.read(
225                 classLoader, "META-INF/portlet-model-hints-ext.xml");
226 
227             models.addAll(getModels(xml));
228         }
229         catch (Exception e) {
230             if (_log.isInfoEnabled()) {
231                 _log.info(
232                     "No optional file META-INF/portlet-model-hints-ext.xml " +
233                         "found");
234             }
235         }
236 
237         return models;
238     }
239 
240     protected List<String> getModels(String xml) throws DocumentException {
241         List<String> models = new ArrayList<String>();
242 
243         Document doc = SAXReaderUtil.read(xml);
244 
245         Element root = doc.getRootElement();
246 
247         Iterator<Element> itr = root.elements("model").iterator();
248 
249         while (itr.hasNext()) {
250             Element modelEl = itr.next();
251 
252             String name = modelEl.attributeValue("name");
253 
254             models.add(name);
255         }
256 
257         return models;
258     }
259 
260     protected void upgradeDB(
261             ClassLoader classLoader, String buildNamespace, long buildNumber,
262             boolean buildAutoUpgrade, ServiceComponent previousServiceComponent,
263             String tablesSQL, String sequencesSQL, String indexesSQL)
264         throws Exception {
265 
266         DBUtil dbUtil = DBUtil.getInstance();
267 
268         if (previousServiceComponent == null) {
269             if (_log.isInfoEnabled()) {
270                 _log.info(
271                     "Running " + buildNamespace +
272                         " SQL scripts for the first time");
273             }
274 
275             dbUtil.runSQLTemplateString(tablesSQL, true, false);
276             dbUtil.runSQLTemplateString(sequencesSQL, true, false);
277             dbUtil.runSQLTemplateString(indexesSQL, true, false);
278         }
279         else if (buildAutoUpgrade) {
280             if (_log.isInfoEnabled()) {
281                 _log.info(
282                     "Upgrading " + buildNamespace +
283                         " database to build number " + buildNumber);
284             }
285 
286             if (!tablesSQL.equals(
287                     previousServiceComponent.getTablesSQL())) {
288 
289                 if (_log.isInfoEnabled()) {
290                     _log.info("Upgrading database with tables.sql");
291                 }
292 
293                 dbUtil.runSQLTemplateString(tablesSQL, true, false);
294 
295                 upgradeModels(classLoader);
296             }
297 
298             if (!sequencesSQL.equals(
299                     previousServiceComponent.getSequencesSQL())) {
300 
301                 if (_log.isInfoEnabled()) {
302                     _log.info("Upgrading database with sequences.sql");
303                 }
304 
305                 dbUtil.runSQLTemplateString(sequencesSQL, true, false);
306             }
307 
308             if (!indexesSQL.equals(
309                     previousServiceComponent.getIndexesSQL())) {
310 
311                 if (_log.isInfoEnabled()) {
312                     _log.info("Upgrading database with indexes.sql");
313                 }
314 
315                 dbUtil.runSQLTemplateString(indexesSQL, true, false);
316             }
317         }
318     }
319 
320     protected void upgradeModels(ClassLoader classLoader) throws Exception {
321         List<String> models = getModels(classLoader);
322 
323         for (String name : models) {
324             int pos = name.lastIndexOf(".model.");
325 
326             name =
327                 name.substring(0, pos) + ".model.impl." +
328                     name.substring(pos + 7) + "ModelImpl";
329 
330             Class<?> modelClass = Class.forName(name, true, classLoader);
331 
332             Field tableNameField = modelClass.getField("TABLE_NAME");
333             Field tableColumnsField = modelClass.getField("TABLE_COLUMNS");
334             Field tableSQLCreateField = modelClass.getField("TABLE_SQL_CREATE");
335             Field dataSourceField = modelClass.getField("DATA_SOURCE");
336 
337             String tableName = (String)tableNameField.get(null);
338             Object[][] tableColumns = (Object[][])tableColumnsField.get(null);
339             String tableSQLCreate = (String)tableSQLCreateField.get(null);
340             String dataSource = (String)dataSourceField.get(null);
341 
342             if (!dataSource.equals(Entity.DEFAULT_DATA_SOURCE)) {
343                 continue;
344             }
345 
346             UpgradeTable upgradeTable = new DefaultUpgradeTableImpl(
347                 tableName, tableColumns);
348 
349             upgradeTable.setCreateSQL(tableSQLCreate);
350 
351             upgradeTable.updateTable();
352         }
353     }
354 
355     protected void removeOldServiceComponents(String buildNamespace)
356         throws SystemException {
357 
358         int serviceComponentsCount =
359             serviceComponentPersistence.countByBuildNamespace(buildNamespace);
360 
361         if (serviceComponentsCount < _MAX_SERVICE_COMPONENTS) {
362             return;
363         }
364 
365         List<ServiceComponent> serviceComponents =
366             serviceComponentPersistence.findByBuildNamespace(
367                 buildNamespace, _MAX_SERVICE_COMPONENTS,
368                 serviceComponentsCount);
369 
370         for (int i = 0; i < serviceComponents.size(); i++) {
371             ServiceComponent serviceComponent = serviceComponents.get(i);
372 
373             serviceComponentPersistence.remove(serviceComponent);
374         }
375     }
376 
377     private static final int _MAX_SERVICE_COMPONENTS = 10;
378 
379     private static Log _log =
380         LogFactoryUtil.getLog(ServiceComponentLocalServiceImpl.class);
381 
382 }