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