001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.service.impl;
016    
017    import com.liferay.portal.OldServiceComponentException;
018    import com.liferay.portal.kernel.cache.CacheRegistryUtil;
019    import com.liferay.portal.kernel.dao.db.DB;
020    import com.liferay.portal.kernel.dao.db.DBFactoryUtil;
021    import com.liferay.portal.kernel.dao.orm.EntityCacheUtil;
022    import com.liferay.portal.kernel.dao.orm.FinderCacheUtil;
023    import com.liferay.portal.kernel.exception.PortalException;
024    import com.liferay.portal.kernel.exception.SystemException;
025    import com.liferay.portal.kernel.log.Log;
026    import com.liferay.portal.kernel.log.LogFactoryUtil;
027    import com.liferay.portal.kernel.upgrade.util.UpgradeTable;
028    import com.liferay.portal.kernel.upgrade.util.UpgradeTableFactoryUtil;
029    import com.liferay.portal.kernel.util.HttpUtil;
030    import com.liferay.portal.kernel.util.StringPool;
031    import com.liferay.portal.kernel.util.StringUtil;
032    import com.liferay.portal.kernel.xml.Document;
033    import com.liferay.portal.kernel.xml.DocumentException;
034    import com.liferay.portal.kernel.xml.Element;
035    import com.liferay.portal.kernel.xml.SAXReaderUtil;
036    import com.liferay.portal.model.ModelHintsUtil;
037    import com.liferay.portal.model.ServiceComponent;
038    import com.liferay.portal.service.base.ServiceComponentLocalServiceBaseImpl;
039    import com.liferay.portal.tools.servicebuilder.Entity;
040    
041    import java.io.IOException;
042    import java.io.InputStream;
043    
044    import java.lang.reflect.Field;
045    
046    import java.util.ArrayList;
047    import java.util.List;
048    
049    import javax.servlet.ServletContext;
050    
051    /**
052     * @author Brian Wing Shun Chan
053     */
054    public class ServiceComponentLocalServiceImpl
055            extends ServiceComponentLocalServiceBaseImpl {
056    
057            public void destroyServiceComponent(
058                            ServletContext servletContext, ClassLoader classLoader)
059                    throws SystemException {
060    
061                    try {
062                            clearCacheRegistry(servletContext);
063                    }
064                    catch (Exception e) {
065                            throw new SystemException(e);
066                    }
067            }
068    
069            public ServiceComponent initServiceComponent(
070                            ServletContext servletContext, ClassLoader classLoader,
071                            String buildNamespace, long buildNumber, long buildDate,
072                            boolean buildAutoUpgrade)
073                    throws PortalException, SystemException {
074    
075                    try {
076                            ModelHintsUtil.read(
077                                    classLoader, "META-INF/portlet-model-hints.xml");
078                    }
079                    catch (Exception e) {
080                            throw new SystemException(e);
081                    }
082    
083                    try {
084                            ModelHintsUtil.read(
085                                    classLoader, "META-INF/portlet-model-hints-ext.xml");
086                    }
087                    catch (Exception e) {
088                            throw new SystemException(e);
089                    }
090    
091                    ServiceComponent serviceComponent = null;
092                    ServiceComponent previousServiceComponent = null;
093    
094                    List<ServiceComponent> serviceComponents =
095                            serviceComponentPersistence.findByBuildNamespace(
096                                    buildNamespace, 0, 1);
097    
098                    if (serviceComponents.size() == 0) {
099                            long serviceComponentId = counterLocalService.increment();
100    
101                            serviceComponent = serviceComponentPersistence.create(
102                                    serviceComponentId);
103    
104                            serviceComponent.setBuildNamespace(buildNamespace);
105                            serviceComponent.setBuildNumber(buildNumber);
106                            serviceComponent.setBuildDate(buildDate);
107                    }
108                    else {
109                            serviceComponent = serviceComponents.get(0);
110    
111                            if (serviceComponent.getBuildNumber() < buildNumber) {
112                                    previousServiceComponent = serviceComponent;
113    
114                                    long serviceComponentId = counterLocalService.increment();
115    
116                                    serviceComponent = serviceComponentPersistence.create(
117                                            serviceComponentId);
118    
119                                    serviceComponent.setBuildNamespace(buildNamespace);
120                                    serviceComponent.setBuildNumber(buildNumber);
121                                    serviceComponent.setBuildDate(buildDate);
122                            }
123                            else if (serviceComponent.getBuildNumber() > buildNumber) {
124                                    throw new OldServiceComponentException(
125                                            "Build namespace " + buildNamespace + " has build number " +
126                                                    serviceComponent.getBuildNumber() +
127                                                            " which is newer than " + buildNumber);
128                            }
129                            else {
130                                    return serviceComponent;
131                            }
132                    }
133    
134                    try {
135                            Document document = SAXReaderUtil.createDocument(StringPool.UTF8);
136    
137                            Element dataElement = document.addElement("data");
138    
139                            String tablesSQL = HttpUtil.URLtoString(servletContext.getResource(
140                                    "/WEB-INF/sql/tables.sql"));
141    
142                            dataElement.addElement("tables-sql").addCDATA(tablesSQL);
143    
144                            String sequencesSQL = HttpUtil.URLtoString(
145                                    servletContext.getResource("/WEB-INF/sql/sequences.sql"));
146    
147                            dataElement.addElement("sequences-sql").addCDATA(sequencesSQL);
148    
149                            String indexesSQL = HttpUtil.URLtoString(servletContext.getResource(
150                                    "/WEB-INF/sql/indexes.sql"));
151    
152                            dataElement.addElement("indexes-sql").addCDATA(indexesSQL);
153    
154                            String dataXML = document.formattedString();
155    
156                            serviceComponent.setData(dataXML);
157    
158                            serviceComponentPersistence.update(serviceComponent, false);
159    
160                            serviceComponentLocalService.upgradeDB(
161                                    classLoader, buildNamespace, buildNumber, buildAutoUpgrade,
162                                    previousServiceComponent, tablesSQL, sequencesSQL, indexesSQL);
163    
164                            removeOldServiceComponents(buildNamespace);
165    
166                            return serviceComponent;
167                    }
168                    catch (Exception e) {
169                            throw new SystemException(e);
170                    }
171            }
172    
173            public void upgradeDB(
174                            ClassLoader classLoader, String buildNamespace, long buildNumber,
175                            boolean buildAutoUpgrade, ServiceComponent previousServiceComponent,
176                            String tablesSQL, String sequencesSQL, String indexesSQL)
177                    throws Exception {
178    
179                    DB db = DBFactoryUtil.getDB();
180    
181                    if (previousServiceComponent == null) {
182                            if (_log.isInfoEnabled()) {
183                                    _log.info("Running " + buildNamespace + " SQL scripts");
184                            }
185    
186                            db.runSQLTemplateString(tablesSQL, true, false);
187                            db.runSQLTemplateString(sequencesSQL, true, false);
188                            db.runSQLTemplateString(indexesSQL, true, false);
189                    }
190                    else if (buildAutoUpgrade) {
191                            if (_log.isInfoEnabled()) {
192                                    _log.info(
193                                            "Upgrading " + buildNamespace +
194                                                    " database to build number " + buildNumber);
195                            }
196    
197                            if (!tablesSQL.equals(previousServiceComponent.getTablesSQL())) {
198                                    if (_log.isInfoEnabled()) {
199                                            _log.info("Upgrading database with tables.sql");
200                                    }
201    
202                                    db.runSQLTemplateString(tablesSQL, true, false);
203    
204                                    upgradeModels(classLoader);
205                            }
206    
207                            if (!sequencesSQL.equals(
208                                            previousServiceComponent.getSequencesSQL())) {
209    
210                                    if (_log.isInfoEnabled()) {
211                                            _log.info("Upgrading database with sequences.sql");
212                                    }
213    
214                                    db.runSQLTemplateString(sequencesSQL, true, false);
215                            }
216    
217                            if (!indexesSQL.equals(previousServiceComponent.getIndexesSQL())) {
218                                    if (_log.isInfoEnabled()) {
219                                            _log.info("Upgrading database with indexes.sql");
220                                    }
221    
222                                    db.runSQLTemplateString(indexesSQL, true, false);
223                            }
224                    }
225            }
226    
227            public void verifyDB() throws SystemException {
228                    List<ServiceComponent> serviceComponents =
229                            serviceComponentPersistence.findAll();
230    
231                    for (ServiceComponent serviceComponent : serviceComponents) {
232                            String buildNamespace = serviceComponent.getBuildNamespace();
233                            String tablesSQL = serviceComponent.getTablesSQL();
234                            String sequencesSQL = serviceComponent.getSequencesSQL();
235                            String indexesSQL = serviceComponent.getIndexesSQL();
236    
237                            try {
238                                    serviceComponentLocalService.upgradeDB(
239                                            null, buildNamespace, 0, false, null, tablesSQL,
240                                            sequencesSQL, indexesSQL);
241                            }
242                            catch (Exception e) {
243                                    _log.error(e, e);
244                            }
245                    }
246            }
247    
248            protected void clearCacheRegistry(ServletContext servletContext)
249                    throws DocumentException {
250    
251                    InputStream inputStream = servletContext.getResourceAsStream(
252                            "/WEB-INF/classes/META-INF/portlet-hbm.xml");
253    
254                    if (inputStream == null) {
255                            return;
256                    }
257    
258                    Document document = SAXReaderUtil.read(inputStream);
259    
260                    Element rootElement = document.getRootElement();
261    
262                    List<Element> classElements = rootElement.elements("class");
263    
264                    for (Element classElement : classElements) {
265                            String name = classElement.attributeValue("name");
266    
267                            CacheRegistryUtil.unregister(name);
268                    }
269    
270                    CacheRegistryUtil.clear();
271    
272                    EntityCacheUtil.clearCache();
273                    FinderCacheUtil.clearCache();
274            }
275    
276            protected List<String> getModels(ClassLoader classLoader)
277                    throws DocumentException, IOException {
278    
279                    List<String> models = new ArrayList<String>();
280    
281                    String xml = StringUtil.read(
282                            classLoader, "META-INF/portlet-model-hints.xml");
283    
284                    models.addAll(getModels(xml));
285    
286                    try {
287                            xml = StringUtil.read(
288                                    classLoader, "META-INF/portlet-model-hints-ext.xml");
289    
290                            models.addAll(getModels(xml));
291                    }
292                    catch (Exception e) {
293                            if (_log.isInfoEnabled()) {
294                                    _log.info(
295                                            "No optional file META-INF/portlet-model-hints-ext.xml " +
296                                                    "found");
297                            }
298                    }
299    
300                    return models;
301            }
302    
303            protected List<String> getModels(String xml) throws DocumentException {
304                    List<String> models = new ArrayList<String>();
305    
306                    Document document = SAXReaderUtil.read(xml);
307    
308                    Element rootElement = document.getRootElement();
309    
310                    List<Element> modelElements = rootElement.elements("model");
311    
312                    for (Element modelElement : modelElements) {
313                            String name = modelElement.attributeValue("name");
314    
315                            models.add(name);
316                    }
317    
318                    return models;
319            }
320    
321            protected void removeOldServiceComponents(String buildNamespace)
322                    throws SystemException {
323    
324                    int serviceComponentsCount =
325                            serviceComponentPersistence.countByBuildNamespace(buildNamespace);
326    
327                    if (serviceComponentsCount < _MAX_SERVICE_COMPONENTS) {
328                            return;
329                    }
330    
331                    List<ServiceComponent> serviceComponents =
332                            serviceComponentPersistence.findByBuildNamespace(
333                                    buildNamespace, _MAX_SERVICE_COMPONENTS,
334                                    serviceComponentsCount);
335    
336                    for (int i = 0; i < serviceComponents.size(); i++) {
337                            ServiceComponent serviceComponent = serviceComponents.get(i);
338    
339                            serviceComponentPersistence.remove(serviceComponent);
340                    }
341            }
342    
343            protected void upgradeModels(ClassLoader classLoader) throws Exception {
344                    List<String> models = getModels(classLoader);
345    
346                    for (String name : models) {
347                            int pos = name.lastIndexOf(".model.");
348    
349                            name =
350                                    name.substring(0, pos) + ".model.impl." +
351                                            name.substring(pos + 7) + "ModelImpl";
352    
353                            Class<?> modelClass = Class.forName(name, true, classLoader);
354    
355                            Field tableNameField = modelClass.getField("TABLE_NAME");
356                            Field tableColumnsField = modelClass.getField("TABLE_COLUMNS");
357                            Field tableSQLCreateField = modelClass.getField("TABLE_SQL_CREATE");
358                            Field dataSourceField = modelClass.getField("DATA_SOURCE");
359    
360                            String tableName = (String)tableNameField.get(null);
361                            Object[][] tableColumns = (Object[][])tableColumnsField.get(null);
362                            String tableSQLCreate = (String)tableSQLCreateField.get(null);
363                            String dataSource = (String)dataSourceField.get(null);
364    
365                            if (!dataSource.equals(Entity.DEFAULT_DATA_SOURCE)) {
366                                    continue;
367                            }
368    
369                            UpgradeTable upgradeTable = UpgradeTableFactoryUtil.getUpgradeTable(
370                                    tableName, tableColumns);
371    
372                            upgradeTable.setCreateSQL(tableSQLCreate);
373    
374                            upgradeTable.updateTable();
375                    }
376            }
377    
378            private static final int _MAX_SERVICE_COMPONENTS = 10;
379    
380            private static Log _log = LogFactoryUtil.getLog(
381                    ServiceComponentLocalServiceImpl.class);
382    
383    }