1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    *
5    *
6    *
7    * The contents of this file are subject to the terms of the Liferay Enterprise
8    * Subscription License ("License"). You may not use this file except in
9    * compliance with the License. You can obtain a copy of the License by
10   * contacting Liferay, Inc. See the License for the specific language governing
11   * permissions and limitations under the License, including but not limited to
12   * distribution rights 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.db.DB;
30  import com.liferay.portal.kernel.dao.db.DBFactoryUtil;
31  import com.liferay.portal.kernel.dao.orm.EntityCacheUtil;
32  import com.liferay.portal.kernel.dao.orm.FinderCacheUtil;
33  import com.liferay.portal.kernel.log.Log;
34  import com.liferay.portal.kernel.log.LogFactoryUtil;
35  import com.liferay.portal.kernel.upgrade.util.UpgradeTable;
36  import com.liferay.portal.kernel.upgrade.util.UpgradeTableFactoryUtil;
37  import com.liferay.portal.kernel.util.HttpUtil;
38  import com.liferay.portal.kernel.util.StringPool;
39  import com.liferay.portal.kernel.util.StringUtil;
40  import com.liferay.portal.kernel.xml.Document;
41  import com.liferay.portal.kernel.xml.DocumentException;
42  import com.liferay.portal.kernel.xml.Element;
43  import com.liferay.portal.kernel.xml.SAXReaderUtil;
44  import com.liferay.portal.model.ModelHintsUtil;
45  import com.liferay.portal.model.ServiceComponent;
46  import com.liferay.portal.service.base.ServiceComponentLocalServiceBaseImpl;
47  import com.liferay.portal.tools.servicebuilder.Entity;
48  
49  import java.io.IOException;
50  
51  import java.lang.reflect.Field;
52  
53  import java.util.ArrayList;
54  import java.util.Iterator;
55  import java.util.List;
56  
57  import javax.servlet.ServletContext;
58  
59  /**
60   * <a href="ServiceComponentLocalServiceImpl.java.html"><b><i>View Source</i>
61   * </b></a>
62   *
63   * @author Brian Wing Shun Chan
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             serviceComponentLocalService.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     public void upgradeDB(
185             ClassLoader classLoader, String buildNamespace, long buildNumber,
186             boolean buildAutoUpgrade, ServiceComponent previousServiceComponent,
187             String tablesSQL, String sequencesSQL, String indexesSQL)
188         throws Exception {
189 
190         DB db = DBFactoryUtil.getDB();
191 
192         if (previousServiceComponent == null) {
193             if (_log.isInfoEnabled()) {
194                 _log.info(
195                     "Running " + buildNamespace +
196                         " SQL scripts for the first time");
197             }
198 
199             db.runSQLTemplateString(tablesSQL, true, false);
200             db.runSQLTemplateString(sequencesSQL, true, false);
201             db.runSQLTemplateString(indexesSQL, true, false);
202         }
203         else if (buildAutoUpgrade) {
204             if (_log.isInfoEnabled()) {
205                 _log.info(
206                     "Upgrading " + buildNamespace +
207                         " database to build number " + buildNumber);
208             }
209 
210             if (!tablesSQL.equals(
211                     previousServiceComponent.getTablesSQL())) {
212 
213                 if (_log.isInfoEnabled()) {
214                     _log.info("Upgrading database with tables.sql");
215                 }
216 
217                 db.runSQLTemplateString(tablesSQL, true, false);
218 
219                 upgradeModels(classLoader);
220             }
221 
222             if (!sequencesSQL.equals(
223                     previousServiceComponent.getSequencesSQL())) {
224 
225                 if (_log.isInfoEnabled()) {
226                     _log.info("Upgrading database with sequences.sql");
227                 }
228 
229                 db.runSQLTemplateString(sequencesSQL, true, false);
230             }
231 
232             if (!indexesSQL.equals(
233                     previousServiceComponent.getIndexesSQL())) {
234 
235                 if (_log.isInfoEnabled()) {
236                     _log.info("Upgrading database with indexes.sql");
237                 }
238 
239                 db.runSQLTemplateString(indexesSQL, true, false);
240             }
241         }
242     }
243 
244     protected void clearCacheRegistry(ServletContext servletContext)
245         throws DocumentException, IOException {
246 
247         String xml = HttpUtil.URLtoString(
248             servletContext.getResource(
249                 "/WEB-INF/classes/META-INF/portlet-hbm.xml"));
250 
251         if (xml == null) {
252             return;
253         }
254 
255         Document doc = SAXReaderUtil.read(xml);
256 
257         Element root = doc.getRootElement();
258 
259         List<Element> classEls = root.elements("class");
260 
261         for (Element classEl : classEls) {
262             String name = classEl.attributeValue("name");
263 
264             CacheRegistry.unregister(name);
265         }
266 
267         CacheRegistry.clear();
268 
269         EntityCacheUtil.clearCache();
270         FinderCacheUtil.clearCache();
271     }
272 
273     protected List<String> getModels(ClassLoader classLoader)
274         throws DocumentException, IOException {
275 
276         List<String> models = new ArrayList<String>();
277 
278         String xml = StringUtil.read(
279             classLoader, "META-INF/portlet-model-hints.xml");
280 
281         models.addAll(getModels(xml));
282 
283         try {
284             xml = StringUtil.read(
285                 classLoader, "META-INF/portlet-model-hints-ext.xml");
286 
287             models.addAll(getModels(xml));
288         }
289         catch (Exception e) {
290             if (_log.isInfoEnabled()) {
291                 _log.info(
292                     "No optional file META-INF/portlet-model-hints-ext.xml " +
293                         "found");
294             }
295         }
296 
297         return models;
298     }
299 
300     protected List<String> getModels(String xml) throws DocumentException {
301         List<String> models = new ArrayList<String>();
302 
303         Document doc = SAXReaderUtil.read(xml);
304 
305         Element root = doc.getRootElement();
306 
307         Iterator<Element> itr = root.elements("model").iterator();
308 
309         while (itr.hasNext()) {
310             Element modelEl = itr.next();
311 
312             String name = modelEl.attributeValue("name");
313 
314             models.add(name);
315         }
316 
317         return models;
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 = UpgradeTableFactoryUtil.getUpgradeTable(
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 }