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