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