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