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.upgrade.util.UpgradeTableListener;
030    import com.liferay.portal.kernel.util.HttpUtil;
031    import com.liferay.portal.kernel.util.InstanceFactory;
032    import com.liferay.portal.kernel.util.StringPool;
033    import com.liferay.portal.kernel.util.StringUtil;
034    import com.liferay.portal.kernel.xml.Document;
035    import com.liferay.portal.kernel.xml.DocumentException;
036    import com.liferay.portal.kernel.xml.Element;
037    import com.liferay.portal.kernel.xml.SAXReaderUtil;
038    import com.liferay.portal.model.ModelHintsUtil;
039    import com.liferay.portal.model.ServiceComponent;
040    import com.liferay.portal.security.lang.PortalSecurityManagerThreadLocal;
041    import com.liferay.portal.security.pacl.PACLPolicy;
042    import com.liferay.portal.security.pacl.PACLPolicyManager;
043    import com.liferay.portal.service.base.ServiceComponentLocalServiceBaseImpl;
044    import com.liferay.portal.tools.servicebuilder.Entity;
045    
046    import java.io.IOException;
047    import java.io.InputStream;
048    
049    import java.lang.reflect.Field;
050    
051    import java.util.ArrayList;
052    import java.util.List;
053    
054    import javax.servlet.ServletContext;
055    
056    /**
057     * @author Brian Wing Shun Chan
058     */
059    public class ServiceComponentLocalServiceImpl
060            extends ServiceComponentLocalServiceBaseImpl {
061    
062            public void destroyServiceComponent(
063                            ServletContext servletContext, ClassLoader classLoader)
064                    throws SystemException {
065    
066                    try {
067                            clearCacheRegistry(servletContext);
068                    }
069                    catch (Exception e) {
070                            throw new SystemException(e);
071                    }
072            }
073    
074            public ServiceComponent initServiceComponent(
075                            ServletContext servletContext, ClassLoader classLoader,
076                            String buildNamespace, long buildNumber, long buildDate,
077                            boolean buildAutoUpgrade)
078                    throws PortalException, SystemException {
079    
080                    try {
081                            ModelHintsUtil.read(
082                                    classLoader, "META-INF/portlet-model-hints.xml");
083                    }
084                    catch (Exception e) {
085                            throw new SystemException(e);
086                    }
087    
088                    try {
089                            ModelHintsUtil.read(
090                                    classLoader, "META-INF/portlet-model-hints-ext.xml");
091                    }
092                    catch (Exception e) {
093                            throw new SystemException(e);
094                    }
095    
096                    ServiceComponent serviceComponent = null;
097                    ServiceComponent previousServiceComponent = null;
098    
099                    List<ServiceComponent> serviceComponents =
100                            serviceComponentPersistence.findByBuildNamespace(
101                                    buildNamespace, 0, 1);
102    
103                    if (serviceComponents.isEmpty()) {
104                            long serviceComponentId = counterLocalService.increment();
105    
106                            serviceComponent = serviceComponentPersistence.create(
107                                    serviceComponentId);
108    
109                            serviceComponent.setBuildNamespace(buildNamespace);
110                            serviceComponent.setBuildNumber(buildNumber);
111                            serviceComponent.setBuildDate(buildDate);
112                    }
113                    else {
114                            serviceComponent = serviceComponents.get(0);
115    
116                            if (serviceComponent.getBuildNumber() < buildNumber) {
117                                    previousServiceComponent = serviceComponent;
118    
119                                    long serviceComponentId = counterLocalService.increment();
120    
121                                    serviceComponent = serviceComponentPersistence.create(
122                                            serviceComponentId);
123    
124                                    serviceComponent.setBuildNamespace(buildNamespace);
125                                    serviceComponent.setBuildNumber(buildNumber);
126                                    serviceComponent.setBuildDate(buildDate);
127                            }
128                            else if (serviceComponent.getBuildNumber() > buildNumber) {
129                                    throw new OldServiceComponentException(
130                                            "Build namespace " + buildNamespace + " has build number " +
131                                                    serviceComponent.getBuildNumber() +
132                                                            " which is newer than " + buildNumber);
133                            }
134                            else {
135                                    return serviceComponent;
136                            }
137                    }
138    
139                    try {
140                            Document document = SAXReaderUtil.createDocument(StringPool.UTF8);
141    
142                            Element dataElement = document.addElement("data");
143    
144                            Element tablesSQLElement = dataElement.addElement("tables-sql");
145    
146                            String tablesSQL = HttpUtil.URLtoString(
147                                    servletContext.getResource("/WEB-INF/sql/tables.sql"));
148    
149                            tablesSQLElement.addCDATA(tablesSQL);
150    
151                            Element sequencesSQLElement = dataElement.addElement(
152                                    "sequences-sql");
153    
154                            String sequencesSQL = HttpUtil.URLtoString(
155                                    servletContext.getResource("/WEB-INF/sql/sequences.sql"));
156    
157                            sequencesSQLElement.addCDATA(sequencesSQL);
158    
159                            Element indexesSQLElement = dataElement.addElement("indexes-sql");
160    
161                            String indexesSQL = HttpUtil.URLtoString(
162                                    servletContext.getResource("/WEB-INF/sql/indexes.sql"));
163    
164                            indexesSQLElement.addCDATA(indexesSQL);
165    
166                            String dataXML = document.formattedString();
167    
168                            serviceComponent.setData(dataXML);
169    
170                            serviceComponentPersistence.update(serviceComponent);
171    
172                            serviceComponentLocalService.upgradeDB(
173                                    classLoader, buildNamespace, buildNumber, buildAutoUpgrade,
174                                    previousServiceComponent, tablesSQL, sequencesSQL, indexesSQL);
175    
176                            removeOldServiceComponents(buildNamespace);
177    
178                            return serviceComponent;
179                    }
180                    catch (Exception e) {
181                            throw new SystemException(e);
182                    }
183            }
184    
185            public void upgradeDB(
186                            ClassLoader classLoader, String buildNamespace, long buildNumber,
187                            boolean buildAutoUpgrade, ServiceComponent previousServiceComponent,
188                            String tablesSQL, String sequencesSQL, String indexesSQL)
189                    throws Exception {
190    
191                    PACLPolicy previousPACLPolicy =
192                            PortalSecurityManagerThreadLocal.getPACLPolicy();
193    
194                    boolean checkGetClassLoader =
195                            PortalSecurityManagerThreadLocal.isCheckGetClassLoader();
196                    boolean checkReadFile =
197                            PortalSecurityManagerThreadLocal.isCheckReadFile();
198    
199                    try {
200                            PACLPolicy paclPolicy = PACLPolicyManager.getPACLPolicy(
201                                    classLoader);
202    
203                            PortalSecurityManagerThreadLocal.setPACLPolicy(paclPolicy);
204    
205                            PortalSecurityManagerThreadLocal.setCheckGetClassLoader(false);
206                            PortalSecurityManagerThreadLocal.setCheckReadFile(false);
207    
208                            doUpgradeDB(
209                                    classLoader, buildNamespace, buildNumber, buildAutoUpgrade,
210                                    previousServiceComponent, tablesSQL, sequencesSQL, indexesSQL);
211                    }
212                    finally {
213                            PortalSecurityManagerThreadLocal.setPACLPolicy(previousPACLPolicy);
214    
215                            PortalSecurityManagerThreadLocal.setCheckGetClassLoader(
216                                    checkGetClassLoader);
217                            PortalSecurityManagerThreadLocal.setCheckReadFile(checkReadFile);
218                    }
219            }
220    
221            public void verifyDB() throws SystemException {
222                    List<ServiceComponent> serviceComponents =
223                            serviceComponentPersistence.findAll();
224    
225                    for (ServiceComponent serviceComponent : serviceComponents) {
226                            String buildNamespace = serviceComponent.getBuildNamespace();
227                            String tablesSQL = serviceComponent.getTablesSQL();
228                            String sequencesSQL = serviceComponent.getSequencesSQL();
229                            String indexesSQL = serviceComponent.getIndexesSQL();
230    
231                            try {
232                                    serviceComponentLocalService.upgradeDB(
233                                            null, buildNamespace, 0, false, null, tablesSQL,
234                                            sequencesSQL, indexesSQL);
235                            }
236                            catch (Exception e) {
237                                    _log.error(e, e);
238                            }
239                    }
240            }
241    
242            protected void clearCacheRegistry(ServletContext servletContext)
243                    throws DocumentException {
244    
245                    InputStream inputStream = servletContext.getResourceAsStream(
246                            "/WEB-INF/classes/META-INF/portlet-hbm.xml");
247    
248                    if (inputStream == null) {
249                            return;
250                    }
251    
252                    Document document = SAXReaderUtil.read(inputStream);
253    
254                    Element rootElement = document.getRootElement();
255    
256                    List<Element> classElements = rootElement.elements("class");
257    
258                    for (Element classElement : classElements) {
259                            String name = classElement.attributeValue("name");
260    
261                            CacheRegistryUtil.unregister(name);
262                    }
263    
264                    CacheRegistryUtil.clear();
265    
266                    EntityCacheUtil.clearCache();
267                    FinderCacheUtil.clearCache();
268            }
269    
270            protected void doUpgradeDB(
271                            ClassLoader classLoader, String buildNamespace, long buildNumber,
272                            boolean buildAutoUpgrade, ServiceComponent previousServiceComponent,
273                            String tablesSQL, String sequencesSQL, String indexesSQL)
274                    throws Exception {
275    
276                    DB db = DBFactoryUtil.getDB();
277    
278                    if (previousServiceComponent == null) {
279                            if (_log.isInfoEnabled()) {
280                                    _log.info("Running " + buildNamespace + " SQL scripts");
281                            }
282    
283                            db.runSQLTemplateString(tablesSQL, true, false);
284                            db.runSQLTemplateString(sequencesSQL, true, false);
285                            db.runSQLTemplateString(indexesSQL, true, false);
286                    }
287                    else if (buildAutoUpgrade) {
288                            if (_log.isInfoEnabled()) {
289                                    _log.info(
290                                            "Upgrading " + buildNamespace +
291                                                    " database to build number " + buildNumber);
292                            }
293    
294                            if (!tablesSQL.equals(previousServiceComponent.getTablesSQL())) {
295                                    if (_log.isInfoEnabled()) {
296                                            _log.info("Upgrading database with tables.sql");
297                                    }
298    
299                                    db.runSQLTemplateString(tablesSQL, true, false);
300    
301                                    upgradeModels(classLoader, previousServiceComponent);
302                            }
303    
304                            if (!sequencesSQL.equals(
305                                            previousServiceComponent.getSequencesSQL())) {
306    
307                                    if (_log.isInfoEnabled()) {
308                                            _log.info("Upgrading database with sequences.sql");
309                                    }
310    
311                                    db.runSQLTemplateString(sequencesSQL, true, false);
312                            }
313    
314                            if (!indexesSQL.equals(previousServiceComponent.getIndexesSQL())) {
315                                    if (_log.isInfoEnabled()) {
316                                            _log.info("Upgrading database with indexes.sql");
317                                    }
318    
319                                    db.runSQLTemplateString(indexesSQL, true, false);
320                            }
321                    }
322            }
323    
324            protected List<String> getModels(ClassLoader classLoader)
325                    throws DocumentException, IOException {
326    
327                    List<String> models = new ArrayList<String>();
328    
329                    String xml = StringUtil.read(
330                            classLoader, "META-INF/portlet-model-hints.xml");
331    
332                    models.addAll(getModels(xml));
333    
334                    try {
335                            xml = StringUtil.read(
336                                    classLoader, "META-INF/portlet-model-hints-ext.xml");
337    
338                            models.addAll(getModels(xml));
339                    }
340                    catch (Exception e) {
341                            if (_log.isInfoEnabled()) {
342                                    _log.info(
343                                            "No optional file META-INF/portlet-model-hints-ext.xml " +
344                                                    "found");
345                            }
346                    }
347    
348                    return models;
349            }
350    
351            protected List<String> getModels(String xml) throws DocumentException {
352                    List<String> models = new ArrayList<String>();
353    
354                    Document document = SAXReaderUtil.read(xml);
355    
356                    Element rootElement = document.getRootElement();
357    
358                    List<Element> modelElements = rootElement.elements("model");
359    
360                    for (Element modelElement : modelElements) {
361                            String name = modelElement.attributeValue("name");
362    
363                            models.add(name);
364                    }
365    
366                    return models;
367            }
368    
369            protected UpgradeTableListener getUpgradeTableListener(
370                    ClassLoader classLoader, Class<?> modelClass) {
371    
372                    String modelClassName = modelClass.getName();
373    
374                    String upgradeTableListenerClassName = modelClassName;
375    
376                    upgradeTableListenerClassName = StringUtil.replaceLast(
377                            upgradeTableListenerClassName, ".model.impl.", ".model.upgrade.");
378                    upgradeTableListenerClassName = StringUtil.replaceLast(
379                            upgradeTableListenerClassName, "ModelImpl", "UpgradeTableListener");
380    
381                    try {
382                            UpgradeTableListener upgradeTableListener =
383                                    (UpgradeTableListener)InstanceFactory.newInstance(
384                                            classLoader, upgradeTableListenerClassName);
385    
386                            if (_log.isInfoEnabled()) {
387                                    _log.info("Instantiated " + upgradeTableListenerClassName);
388                            }
389    
390                            return upgradeTableListener;
391                    }
392                    catch (Exception e) {
393                            if (_log.isDebugEnabled()) {
394                                    _log.debug(
395                                            "Unable to instantiate " + upgradeTableListenerClassName);
396                            }
397    
398                            return null;
399                    }
400            }
401    
402            protected void removeOldServiceComponents(String buildNamespace)
403                    throws SystemException {
404    
405                    int serviceComponentsCount =
406                            serviceComponentPersistence.countByBuildNamespace(buildNamespace);
407    
408                    if (serviceComponentsCount < _MAX_SERVICE_COMPONENTS) {
409                            return;
410                    }
411    
412                    List<ServiceComponent> serviceComponents =
413                            serviceComponentPersistence.findByBuildNamespace(
414                                    buildNamespace, _MAX_SERVICE_COMPONENTS,
415                                    serviceComponentsCount);
416    
417                    for (int i = 0; i < serviceComponents.size(); i++) {
418                            ServiceComponent serviceComponent = serviceComponents.get(i);
419    
420                            serviceComponentPersistence.remove(serviceComponent);
421                    }
422            }
423    
424            protected void upgradeModels(
425                            ClassLoader classLoader, ServiceComponent previousServiceComponent)
426                    throws Exception {
427    
428                    List<String> models = getModels(classLoader);
429    
430                    for (String name : models) {
431                            int pos = name.lastIndexOf(".model.");
432    
433                            name =
434                                    name.substring(0, pos) + ".model.impl." +
435                                            name.substring(pos + 7) + "ModelImpl";
436    
437                            Class<?> modelClass = Class.forName(name, true, classLoader);
438    
439                            Field tableNameField = modelClass.getField("TABLE_NAME");
440                            Field tableColumnsField = modelClass.getField("TABLE_COLUMNS");
441                            Field tableSQLCreateField = modelClass.getField("TABLE_SQL_CREATE");
442                            Field dataSourceField = modelClass.getField("DATA_SOURCE");
443    
444                            String tableName = (String)tableNameField.get(null);
445                            Object[][] tableColumns = (Object[][])tableColumnsField.get(null);
446                            String tableSQLCreate = (String)tableSQLCreateField.get(null);
447                            String dataSource = (String)dataSourceField.get(null);
448    
449                            if (!dataSource.equals(Entity.DEFAULT_DATA_SOURCE)) {
450                                    continue;
451                            }
452    
453                            UpgradeTable upgradeTable = UpgradeTableFactoryUtil.getUpgradeTable(
454                                    tableName, tableColumns);
455    
456                            UpgradeTableListener upgradeTableListener = getUpgradeTableListener(
457                                    classLoader, modelClass);
458    
459                            upgradeTable.setCreateSQL(tableSQLCreate);
460    
461                            if (upgradeTableListener != null) {
462                                    upgradeTableListener.onBeforeUpdateTable(
463                                            previousServiceComponent, upgradeTable);
464                            }
465    
466                            upgradeTable.updateTable();
467    
468                            if (upgradeTableListener != null) {
469                                    upgradeTableListener.onAfterUpdateTable(
470                                            previousServiceComponent, upgradeTable);
471                            }
472                    }
473            }
474    
475            private static final int _MAX_SERVICE_COMPONENTS = 10;
476    
477            private static Log _log = LogFactoryUtil.getLog(
478                    ServiceComponentLocalServiceImpl.class);
479    
480    }