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