1   /**
2    * Copyright (c) 2000-2008 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.util.HttpUtil;
30  import com.liferay.portal.kernel.util.StringPool;
31  import com.liferay.portal.kernel.util.StringUtil;
32  import com.liferay.portal.kernel.xml.Document;
33  import com.liferay.portal.kernel.xml.DocumentException;
34  import com.liferay.portal.kernel.xml.Element;
35  import com.liferay.portal.kernel.xml.SAXReaderUtil;
36  import com.liferay.portal.model.ModelHintsUtil;
37  import com.liferay.portal.model.ServiceComponent;
38  import com.liferay.portal.service.base.ServiceComponentLocalServiceBaseImpl;
39  import com.liferay.portal.tools.servicebuilder.Entity;
40  import com.liferay.portal.tools.sql.DBUtil;
41  import com.liferay.portal.upgrade.util.DefaultUpgradeTableImpl;
42  import com.liferay.portal.upgrade.util.UpgradeTable;
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  import org.apache.commons.logging.Log;
55  import org.apache.commons.logging.LogFactory;
56  
57  /**
58   * <a href="ServiceComponentLocalServiceImpl.java.html"><b><i>View Source</i>
59   * </b></a>
60   *
61   * @author Brian Wing Shun Chan
62   *
63   */
64  public class ServiceComponentLocalServiceImpl
65      extends ServiceComponentLocalServiceBaseImpl {
66  
67      public void destroyServiceComponent(
68              ServletContext servletContext, ClassLoader classLoader)
69          throws SystemException {
70  
71          try {
72              clearCacheRegistry(servletContext);
73          }
74          catch (Exception e) {
75              throw new SystemException(e);
76          }
77      }
78  
79      public ServiceComponent initServiceComponent(
80              ServletContext servletContext, ClassLoader classLoader,
81              String buildNamespace, long buildNumber, long buildDate)
82          throws PortalException, SystemException {
83  
84          try {
85              ModelHintsUtil.read(
86                  classLoader, "META-INF/portlet-model-hints.xml");
87          }
88          catch (Exception e) {
89              throw new SystemException(e);
90          }
91  
92          try {
93              ModelHintsUtil.read(
94                  classLoader, "META-INF/portlet-model-hints-ext.xml");
95          }
96          catch (Exception e) {
97              throw new SystemException(e);
98          }
99  
100         ServiceComponent serviceComponent = null;
101         ServiceComponent previousServiceComponent = null;
102 
103         List<ServiceComponent> serviceComponents =
104             serviceComponentPersistence.findByBuildNamespace(
105                 buildNamespace, 0, 1);
106 
107         if (serviceComponents.size() == 0) {
108             long serviceComponentId = counterLocalService.increment();
109 
110             serviceComponent = serviceComponentPersistence.create(
111                 serviceComponentId);
112 
113             serviceComponent.setBuildNamespace(buildNamespace);
114             serviceComponent.setBuildNumber(buildNumber);
115             serviceComponent.setBuildDate(buildDate);
116         }
117         else {
118             serviceComponent = serviceComponents.get(0);
119 
120             if (serviceComponent.getBuildNumber() < buildNumber) {
121                 previousServiceComponent = serviceComponent;
122 
123                 long serviceComponentId = counterLocalService.increment();
124 
125                 serviceComponent = serviceComponentPersistence.create(
126                     serviceComponentId);
127 
128                 serviceComponent.setBuildNamespace(buildNamespace);
129                 serviceComponent.setBuildNumber(buildNumber);
130                 serviceComponent.setBuildDate(buildDate);
131             }
132             else if (serviceComponent.getBuildNumber() > buildNumber) {
133                 throw new OldServiceComponentException(
134                     "Build namespace " + buildNamespace + " has build number " +
135                         serviceComponent.getBuildNumber() +
136                             " which is newer than " + buildNumber);
137             }
138             else {
139                 return serviceComponent;
140             }
141         }
142 
143         try {
144             Document doc = SAXReaderUtil.createDocument(StringPool.UTF8);
145 
146             Element data = doc.addElement("data");
147 
148             String tablesSQL = HttpUtil.URLtoString(servletContext.getResource(
149                 "/WEB-INF/sql/tables.sql"));
150 
151             data.addElement("tables-sql").addCDATA(tablesSQL);
152 
153             String sequencesSQL = HttpUtil.URLtoString(
154                 servletContext.getResource("/WEB-INF/sql/sequences.sql"));
155 
156             data.addElement("sequences-sql").addCDATA(sequencesSQL);
157 
158             String indexesSQL = HttpUtil.URLtoString(servletContext.getResource(
159                 "/WEB-INF/sql/indexes.sql"));
160 
161             data.addElement("indexes-sql").addCDATA(indexesSQL);
162 
163             String dataXML = doc.formattedString();
164 
165             serviceComponent.setData(dataXML);
166 
167             serviceComponentPersistence.update(serviceComponent, false);
168 
169             upgradeDB(
170                 classLoader, buildNamespace, buildNumber,
171                 previousServiceComponent, tablesSQL, sequencesSQL, indexesSQL);
172 
173             removeOldServiceComponents(buildNamespace);
174 
175             return serviceComponent;
176         }
177         catch (Exception e) {
178             throw new SystemException(e);
179         }
180     }
181 
182     protected void clearCacheRegistry(ServletContext servletContext)
183         throws DocumentException, IOException {
184 
185         String xml = HttpUtil.URLtoString(
186             servletContext.getResource(
187                 "/WEB-INF/classes/META-INF/portlet-hbm.xml"));
188 
189         if (xml == null) {
190             return;
191         }
192 
193         Document doc = SAXReaderUtil.read(xml);
194 
195         Element root = doc.getRootElement();
196 
197         List<Element> classEls = root.elements("class");
198 
199         for (Element classEl : classEls) {
200             String name = classEl.attributeValue("name");
201 
202             CacheRegistry.unregister(name);
203         }
204 
205         CacheRegistry.clear();
206     }
207 
208     protected List<String> getModels(ClassLoader classLoader)
209         throws DocumentException, IOException {
210 
211         List<String> models = new ArrayList<String>();
212 
213         String xml = StringUtil.read(
214             classLoader, "META-INF/portlet-model-hints.xml");
215 
216         models.addAll(getModels(xml));
217 
218         xml = StringUtil.read(
219             classLoader, "META-INF/portlet-model-hints-ext.xml");
220 
221         models.addAll(getModels(xml));
222 
223         return models;
224     }
225 
226     protected List<String> getModels(String xml) throws DocumentException {
227         List<String> models = new ArrayList<String>();
228 
229         Document doc = SAXReaderUtil.read(xml);
230 
231         Element root = doc.getRootElement();
232 
233         Iterator<Element> itr = root.elements("model").iterator();
234 
235         while (itr.hasNext()) {
236             Element modelEl = itr.next();
237 
238             String name = modelEl.attributeValue("name");
239 
240             models.add(name);
241         }
242 
243         return models;
244     }
245 
246     protected void upgradeDB(
247             ClassLoader classLoader, String buildNamespace, long buildNumber,
248             ServiceComponent previousServiceComponent, String tablesSQL,
249             String sequencesSQL, String indexesSQL)
250         throws Exception {
251 
252         DBUtil dbUtil = DBUtil.getInstance();
253 
254         if (previousServiceComponent == null) {
255             if (_log.isInfoEnabled()) {
256                 _log.info(
257                     "Running " + buildNamespace +
258                         " SQL scripts for the first time");
259             }
260 
261             dbUtil.runSQLTemplateString(tablesSQL, true, false);
262             dbUtil.runSQLTemplateString(sequencesSQL, true, false);
263             dbUtil.runSQLTemplateString(indexesSQL, true, false);
264         }
265         else {
266             if (_log.isInfoEnabled()) {
267                 _log.info(
268                     "Upgrading " + buildNamespace +
269                         " database to build number " + buildNumber);
270             }
271 
272             if (!tablesSQL.equals(
273                     previousServiceComponent.getTablesSQL())) {
274 
275                 if (_log.isInfoEnabled()) {
276                     _log.info("Upgrading database with tables.sql");
277                 }
278 
279                 dbUtil.runSQLTemplateString(tablesSQL, true, false);
280 
281                 upgradeModels(classLoader);
282             }
283 
284             if (!sequencesSQL.equals(
285                     previousServiceComponent.getSequencesSQL())) {
286 
287                 if (_log.isInfoEnabled()) {
288                     _log.info("Upgrading database with sequences.sql");
289                 }
290 
291                 dbUtil.runSQLTemplateString(sequencesSQL, true, false);
292             }
293 
294             if (!indexesSQL.equals(
295                     previousServiceComponent.getIndexesSQL())) {
296 
297                 if (_log.isInfoEnabled()) {
298                     _log.info("Upgrading database with indexes.sql");
299                 }
300 
301                 dbUtil.runSQLTemplateString(indexesSQL, true, false);
302             }
303         }
304     }
305 
306     protected void upgradeModels(ClassLoader classLoader) throws Exception {
307         List<String> models = getModels(classLoader);
308 
309         for (String name : models) {
310             int pos = name.lastIndexOf(".model.");
311 
312             name =
313                 name.substring(0, pos) + ".model.impl." +
314                     name.substring(pos + 7) + "ModelImpl";
315 
316             Class<?> modelClass = Class.forName(name, true, classLoader);
317 
318             Field tableNameField = modelClass.getField("TABLE_NAME");
319             Field tableColumnsField = modelClass.getField("TABLE_COLUMNS");
320             Field tableSQLCreateField = modelClass.getField("TABLE_SQL_CREATE");
321             Field dataSourceField = modelClass.getField("DATA_SOURCE");
322 
323             String tableName = (String)tableNameField.get(null);
324             Object[][] tableColumns = (Object[][])tableColumnsField.get(null);
325             String tableSQLCreate = (String)tableSQLCreateField.get(null);
326             String dataSource = (String)dataSourceField.get(null);
327 
328             if (!dataSource.equals(Entity.DEFAULT_DATA_SOURCE)) {
329                 continue;
330             }
331 
332             UpgradeTable upgradeTable = new DefaultUpgradeTableImpl(
333                 tableName, tableColumns);
334 
335             upgradeTable.setCreateSQL(tableSQLCreate);
336 
337             upgradeTable.updateTable();
338         }
339     }
340 
341     protected void removeOldServiceComponents(String buildNamespace)
342         throws SystemException {
343 
344         int serviceComponentsCount =
345             serviceComponentPersistence.countByBuildNamespace(buildNamespace);
346 
347         if (serviceComponentsCount < _MAX_SERVICE_COMPONENTS) {
348             return;
349         }
350 
351         List<ServiceComponent> serviceComponents =
352             serviceComponentPersistence.findByBuildNamespace(
353                 buildNamespace, _MAX_SERVICE_COMPONENTS,
354                 serviceComponentsCount);
355 
356         for (int i = 0; i < serviceComponents.size(); i++) {
357             ServiceComponent serviceComponent = serviceComponents.get(i);
358 
359             serviceComponentPersistence.remove(serviceComponent);
360         }
361     }
362 
363     private static final int _MAX_SERVICE_COMPONENTS = 10;
364 
365     private static Log _log =
366         LogFactory.getLog(ServiceComponentLocalServiceImpl.class);
367 
368 }