001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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(
198                                            previousServiceComponent.getTablesSQL())) {
199    
200                                    if (_log.isInfoEnabled()) {
201                                            _log.info("Upgrading database with tables.sql");
202                                    }
203    
204                                    db.runSQLTemplateString(tablesSQL, true, false);
205    
206                                    upgradeModels(classLoader);
207                            }
208    
209                            if (!sequencesSQL.equals(
210                                            previousServiceComponent.getSequencesSQL())) {
211    
212                                    if (_log.isInfoEnabled()) {
213                                            _log.info("Upgrading database with sequences.sql");
214                                    }
215    
216                                    db.runSQLTemplateString(sequencesSQL, true, false);
217                            }
218    
219                            if (!indexesSQL.equals(
220                                            previousServiceComponent.getIndexesSQL())) {
221    
222                                    if (_log.isInfoEnabled()) {
223                                            _log.info("Upgrading database with indexes.sql");
224                                    }
225    
226                                    db.runSQLTemplateString(indexesSQL, true, false);
227                            }
228                    }
229            }
230    
231            public void verifyDB() throws SystemException {
232                    List<ServiceComponent> serviceComponents =
233                            serviceComponentPersistence.findAll();
234    
235                    for (ServiceComponent serviceComponent : serviceComponents) {
236                            String buildNamespace = serviceComponent.getBuildNamespace();
237                            String tablesSQL = serviceComponent.getTablesSQL();
238                            String sequencesSQL = serviceComponent.getSequencesSQL();
239                            String indexesSQL = serviceComponent.getIndexesSQL();
240    
241                            try {
242                                    serviceComponentLocalService.upgradeDB(
243                                            null, buildNamespace, 0, false, null, tablesSQL,
244                                            sequencesSQL, indexesSQL);
245                            }
246                            catch (Exception e) {
247                                    _log.error(e, e);
248                            }
249                    }
250            }
251    
252            protected void clearCacheRegistry(ServletContext servletContext)
253                    throws DocumentException {
254    
255                    InputStream inputStream = servletContext.getResourceAsStream(
256                            "/WEB-INF/classes/META-INF/portlet-hbm.xml");
257    
258                    if (inputStream == null) {
259                            return;
260                    }
261    
262                    Document document = SAXReaderUtil.read(inputStream);
263    
264                    Element rootElement = document.getRootElement();
265    
266                    List<Element> classElements = rootElement.elements("class");
267    
268                    for (Element classElement : classElements) {
269                            String name = classElement.attributeValue("name");
270    
271                            CacheRegistryUtil.unregister(name);
272                    }
273    
274                    CacheRegistryUtil.clear();
275    
276                    EntityCacheUtil.clearCache();
277                    FinderCacheUtil.clearCache();
278            }
279    
280            protected List<String> getModels(ClassLoader classLoader)
281                    throws DocumentException, IOException {
282    
283                    List<String> models = new ArrayList<String>();
284    
285                    String xml = StringUtil.read(
286                            classLoader, "META-INF/portlet-model-hints.xml");
287    
288                    models.addAll(getModels(xml));
289    
290                    try {
291                            xml = StringUtil.read(
292                                    classLoader, "META-INF/portlet-model-hints-ext.xml");
293    
294                            models.addAll(getModels(xml));
295                    }
296                    catch (Exception e) {
297                            if (_log.isInfoEnabled()) {
298                                    _log.info(
299                                            "No optional file META-INF/portlet-model-hints-ext.xml " +
300                                                    "found");
301                            }
302                    }
303    
304                    return models;
305            }
306    
307            protected List<String> getModels(String xml) throws DocumentException {
308                    List<String> models = new ArrayList<String>();
309    
310                    Document document = SAXReaderUtil.read(xml);
311    
312                    Element rootElement = document.getRootElement();
313    
314                    List<Element> modelElements = rootElement.elements("model");
315    
316                    for (Element modelElement : modelElements) {
317                            String name = modelElement.attributeValue("name");
318    
319                            models.add(name);
320                    }
321    
322                    return models;
323            }
324    
325            protected void upgradeModels(ClassLoader classLoader) throws Exception {
326                    List<String> models = getModels(classLoader);
327    
328                    for (String name : models) {
329                            int pos = name.lastIndexOf(".model.");
330    
331                            name =
332                                    name.substring(0, pos) + ".model.impl." +
333                                            name.substring(pos + 7) + "ModelImpl";
334    
335                            Class<?> modelClass = Class.forName(name, true, classLoader);
336    
337                            Field tableNameField = modelClass.getField("TABLE_NAME");
338                            Field tableColumnsField = modelClass.getField("TABLE_COLUMNS");
339                            Field tableSQLCreateField = modelClass.getField("TABLE_SQL_CREATE");
340                            Field dataSourceField = modelClass.getField("DATA_SOURCE");
341    
342                            String tableName = (String)tableNameField.get(null);
343                            Object[][] tableColumns = (Object[][])tableColumnsField.get(null);
344                            String tableSQLCreate = (String)tableSQLCreateField.get(null);
345                            String dataSource = (String)dataSourceField.get(null);
346    
347                            if (!dataSource.equals(Entity.DEFAULT_DATA_SOURCE)) {
348                                    continue;
349                            }
350    
351                            UpgradeTable upgradeTable = UpgradeTableFactoryUtil.getUpgradeTable(
352                                    tableName, tableColumns);
353    
354                            upgradeTable.setCreateSQL(tableSQLCreate);
355    
356                            upgradeTable.updateTable();
357                    }
358            }
359    
360            protected void removeOldServiceComponents(String buildNamespace)
361                    throws SystemException {
362    
363                    int serviceComponentsCount =
364                            serviceComponentPersistence.countByBuildNamespace(buildNamespace);
365    
366                    if (serviceComponentsCount < _MAX_SERVICE_COMPONENTS) {
367                            return;
368                    }
369    
370                    List<ServiceComponent> serviceComponents =
371                            serviceComponentPersistence.findByBuildNamespace(
372                                    buildNamespace, _MAX_SERVICE_COMPONENTS,
373                                    serviceComponentsCount);
374    
375                    for (int i = 0; i < serviceComponents.size(); i++) {
376                            ServiceComponent serviceComponent = serviceComponents.get(i);
377    
378                            serviceComponentPersistence.remove(serviceComponent);
379                    }
380            }
381    
382            private static final int _MAX_SERVICE_COMPONENTS = 10;
383    
384            private static Log _log = LogFactoryUtil.getLog(
385                    ServiceComponentLocalServiceImpl.class);
386    
387    }