1   /**
2    * Copyright (c) 2000-2007 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.counter.service.CounterLocalServiceUtil;
26  import com.liferay.portal.OldServiceComponentException;
27  import com.liferay.portal.PortalException;
28  import com.liferay.portal.SystemException;
29  import com.liferay.portal.kernel.util.StringUtil;
30  import com.liferay.portal.model.ServiceComponent;
31  import com.liferay.portal.service.base.ServiceComponentLocalServiceBaseImpl;
32  import com.liferay.portal.service.persistence.ServiceComponentUtil;
33  import com.liferay.portal.tools.sql.DBUtil;
34  import com.liferay.portal.upgrade.util.DefaultUpgradeTableImpl;
35  import com.liferay.portal.upgrade.util.UpgradeTable;
36  import com.liferay.util.Http;
37  import com.liferay.util.xml.XMLFormatter;
38  
39  import java.io.IOException;
40  import java.io.StringReader;
41  
42  import java.lang.reflect.Field;
43  
44  import java.util.ArrayList;
45  import java.util.Iterator;
46  import java.util.List;
47  
48  import javax.servlet.ServletContext;
49  
50  import org.apache.commons.logging.Log;
51  import org.apache.commons.logging.LogFactory;
52  
53  import org.dom4j.Document;
54  import org.dom4j.DocumentException;
55  import org.dom4j.DocumentFactory;
56  import org.dom4j.Element;
57  import org.dom4j.io.SAXReader;
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   */
66  public class ServiceComponentLocalServiceImpl
67      extends ServiceComponentLocalServiceBaseImpl {
68  
69      public ServiceComponent updateServiceComponent(
70              ServletContext ctx, ClassLoader portletClassLoader,
71              String buildNamespace, long buildNumber, long buildDate)
72          throws PortalException, SystemException {
73  
74          ServiceComponent serviceComponent = null;
75          ServiceComponent previousServiceComponent = null;
76  
77          List serviceComponents = ServiceComponentUtil.findByBuildNamespace(
78              buildNamespace, 0, 1);
79  
80          if (serviceComponents.size() == 0) {
81              long serviceComponentId = CounterLocalServiceUtil.increment();
82  
83              serviceComponent = ServiceComponentUtil.create(serviceComponentId);
84  
85              serviceComponent.setBuildNamespace(buildNamespace);
86              serviceComponent.setBuildNumber(buildNumber);
87              serviceComponent.setBuildDate(buildDate);
88          }
89          else {
90              serviceComponent = (ServiceComponent)serviceComponents.get(0);
91  
92              if (serviceComponent.getBuildNumber() < buildNumber) {
93                  previousServiceComponent = serviceComponent;
94  
95                  long serviceComponentId = CounterLocalServiceUtil.increment();
96  
97                  serviceComponent =
98                      ServiceComponentUtil.create(serviceComponentId);
99  
100                 serviceComponent.setBuildNamespace(buildNamespace);
101                 serviceComponent.setBuildNumber(buildNumber);
102                 serviceComponent.setBuildDate(buildDate);
103             }
104             else if (serviceComponent.getBuildNumber() > buildNumber) {
105                 throw new OldServiceComponentException(
106                     "Build namespace " + buildNamespace + " has build number " +
107                         serviceComponent.getBuildNumber() +
108                             " which is newer than " + buildNumber);
109             }
110             else {
111                 return serviceComponent;
112             }
113         }
114 
115         try {
116             DocumentFactory docFactory = DocumentFactory.getInstance();
117 
118             Document doc = docFactory.createDocument("UTF-8");
119 
120             Element data = doc.addElement("data");
121 
122             String tablesSQL = Http.URLtoString(ctx.getResource(
123                 "/WEB-INF/sql/tables.sql"));
124 
125             data.addElement("tables-sql").addCDATA(tablesSQL);
126 
127             String sequencesSQL = Http.URLtoString(ctx.getResource(
128                 "/WEB-INF/sql/sequences.sql"));
129 
130             data.addElement("sequences-sql").addCDATA(sequencesSQL);
131 
132             String indexesSQL = Http.URLtoString(ctx.getResource(
133                 "/WEB-INF/sql/indexes.sql"));
134 
135             data.addElement("indexes-sql").addCDATA(indexesSQL);
136 
137             String dataXML = XMLFormatter.toString(doc);
138 
139             serviceComponent.setData(dataXML);
140 
141             ServiceComponentUtil.update(serviceComponent);
142 
143             upgradeDB(
144                 portletClassLoader, buildNamespace, buildNumber,
145                 previousServiceComponent, tablesSQL, sequencesSQL, indexesSQL);
146 
147             removeOldServiceComponents(buildNamespace);
148 
149             return serviceComponent;
150         }
151         catch (Exception e) {
152             throw new SystemException(e);
153         }
154     }
155 
156     protected List getModels(ClassLoader portletClassLoader)
157         throws DocumentException, IOException {
158 
159         List models = new ArrayList();
160 
161         String xml = StringUtil.read(
162             portletClassLoader, "META-INF/portlet-model-hints.xml");
163 
164         SAXReader reader = new SAXReader();
165 
166         Document doc = reader.read(new StringReader(xml));
167 
168         Element root  = doc.getRootElement();
169 
170         Iterator itr = root.elements("model").iterator();
171 
172         while (itr.hasNext()) {
173             Element modelEl = (Element)itr.next();
174 
175             String name = modelEl.attributeValue("name");
176 
177             models.add(name);
178         }
179 
180         return models;
181     }
182 
183     protected void upgradeDB(
184             ClassLoader portletClassLoader, String buildNamespace,
185             long buildNumber, ServiceComponent previousServiceComponent,
186             String tablesSQL, String sequencesSQL, String indexesSQL)
187         throws Exception {
188 
189         DBUtil dbUtil = DBUtil.getInstance();
190 
191         if (previousServiceComponent == null) {
192             if (_log.isInfoEnabled()) {
193                 _log.info(
194                     "Running " + buildNamespace +
195                         " SQL scripts for the first time");
196             }
197 
198             dbUtil.runSQLTemplateString(tablesSQL, true, true);
199             dbUtil.runSQLTemplateString(sequencesSQL, true, true);
200             dbUtil.runSQLTemplateString(indexesSQL, true, true);
201         }
202         else {
203             if (_log.isInfoEnabled()) {
204                 _log.info(
205                     "Upgrading " + buildNamespace +
206                         " database to build number " + buildNumber);
207             }
208 
209             if (!tablesSQL.equals(
210                     previousServiceComponent.getTablesSQL())) {
211 
212                 if (_log.isInfoEnabled()) {
213                     _log.info("Upgrading database with tables.sql");
214                 }
215 
216                 dbUtil.runSQLTemplateString(tablesSQL, true, false);
217 
218                 upgradeModels(portletClassLoader);
219             }
220 
221             if (!sequencesSQL.equals(
222                     previousServiceComponent.getSequencesSQL())) {
223 
224                 if (_log.isInfoEnabled()) {
225                     _log.info("Upgrading database with sequences.sql");
226                 }
227 
228                 dbUtil.runSQLTemplateString(sequencesSQL, true, false);
229             }
230 
231             if (!indexesSQL.equals(
232                     previousServiceComponent.getIndexesSQL())) {
233 
234                 if (_log.isInfoEnabled()) {
235                     _log.info("Upgrading database with indexes.sql");
236                 }
237 
238                 dbUtil.runSQLTemplateString(indexesSQL, true, false);
239             }
240         }
241     }
242 
243     protected void upgradeModels(ClassLoader portletClassLoader)
244         throws Exception {
245 
246         List models = getModels(portletClassLoader);
247 
248         for (int i = 0; i < models.size(); i++) {
249             String name = (String)models.get(i);
250 
251             int pos = name.lastIndexOf(".model.");
252 
253             name =
254                 name.substring(0, pos) + ".model.impl." +
255                     name.substring(pos + 7) + "ModelImpl";
256 
257             Class modelClass = Class.forName(name, true, portletClassLoader);
258 
259             Field tableNameField = modelClass.getField("TABLE_NAME");
260             Field tableColumnsField = modelClass.getField("TABLE_COLUMNS");
261             Field tableSQLCreateField = modelClass.getField("TABLE_SQL_CREATE");
262 
263             String tableName = (String)tableNameField.get(null);
264             Object[][] tableColumns = (Object[][])tableColumnsField.get(null);
265             String tableSQLCreate = (String)tableSQLCreateField.get(null);
266 
267             UpgradeTable upgradeTable = new DefaultUpgradeTableImpl(
268                 tableName, tableColumns);
269 
270             upgradeTable.setCreateSQL(tableSQLCreate);
271 
272             upgradeTable.updateTable();
273         }
274     }
275 
276     protected void removeOldServiceComponents(String buildNamespace)
277         throws SystemException {
278 
279         int serviceComponentsCount =
280             ServiceComponentUtil.countByBuildNamespace(buildNamespace);
281 
282         if (serviceComponentsCount < _MAX_SERVICE_COMPONENTS) {
283             return;
284         }
285 
286         List serviceComponents = ServiceComponentUtil.findByBuildNamespace(
287             buildNamespace, _MAX_SERVICE_COMPONENTS, serviceComponentsCount);
288 
289         for (int i = 0; i < serviceComponents.size(); i++) {
290             ServiceComponent serviceComponent =
291                 (ServiceComponent)serviceComponents.get(i);
292 
293             ServiceComponentUtil.remove(serviceComponent);
294         }
295     }
296 
297     private static final int _MAX_SERVICE_COMPONENTS = 10;
298 
299     private static Log _log =
300         LogFactory.getLog(ServiceComponentLocalServiceImpl.class);
301 
302 }