com.liferay.portal.service.impl.ServiceComponentLocalServiceImpl Maven / Gradle / Ivy
/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.service.impl;
import com.liferay.petra.string.StringBundler;
import com.liferay.petra.string.StringPool;
import com.liferay.portal.kernel.bean.BeanReference;
import com.liferay.portal.kernel.dao.db.DB;
import com.liferay.portal.kernel.dao.db.DBContext;
import com.liferay.portal.kernel.dao.db.DBManagerUtil;
import com.liferay.portal.kernel.dao.db.DBProcessContext;
import com.liferay.portal.kernel.exception.OldServiceComponentException;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.model.ModelHintsUtil;
import com.liferay.portal.kernel.model.Release;
import com.liferay.portal.kernel.model.ServiceComponent;
import com.liferay.portal.kernel.module.util.SystemBundleUtil;
import com.liferay.portal.kernel.service.ReleaseLocalService;
import com.liferay.portal.kernel.service.configuration.ServiceComponentConfiguration;
import com.liferay.portal.kernel.service.configuration.servlet.ServletServiceContextComponentConfiguration;
import com.liferay.portal.kernel.upgrade.UpgradeStep;
import com.liferay.portal.kernel.upgrade.util.UpgradeTable;
import com.liferay.portal.kernel.upgrade.util.UpgradeTableFactoryUtil;
import com.liferay.portal.kernel.upgrade.util.UpgradeTableListener;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.InstanceFactory;
import com.liferay.portal.kernel.util.ListUtil;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.xml.Document;
import com.liferay.portal.kernel.xml.DocumentException;
import com.liferay.portal.kernel.xml.Element;
import com.liferay.portal.kernel.xml.SAXReaderUtil;
import com.liferay.portal.kernel.xml.UnsecureSAXReaderUtil;
import com.liferay.portal.service.base.ServiceComponentLocalServiceBaseImpl;
import com.liferay.portal.util.PropsValues;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Filter;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
/**
* @author Brian Wing Shun Chan
*/
public class ServiceComponentLocalServiceImpl
extends ServiceComponentLocalServiceBaseImpl {
public ServiceComponentLocalServiceImpl() {
Filter filter = SystemBundleUtil.createFilter(
StringBundler.concat(
"(&(objectClass=", UpgradeStep.class.getName(),
")(upgrade.from.schema.version=0.0.0)(upgrade.initial.",
"database.creation=true))"));
_upgradeStepServiceTracker = new ServiceTracker<>(
_bundleContext, filter, new UpgradeStepServiceTrackerCustomizer());
_upgradeStepServiceTracker.open();
}
@Override
public void destroy() {
super.destroy();
_upgradeStepServiceTracker.close();
}
@Override
public List getLatestServiceComponents() {
return serviceComponentFinder.findByMaxBuildNumber();
}
@Override
public ServiceComponent initServiceComponent(
ServiceComponentConfiguration serviceComponentConfiguration,
ClassLoader classLoader, String buildNamespace, long buildNumber,
long buildDate)
throws PortalException {
try {
ModelHintsUtil.read(
classLoader,
serviceComponentConfiguration.getModelHintsInputStream());
}
catch (Exception exception) {
throw new SystemException(exception);
}
try {
ModelHintsUtil.read(
classLoader,
serviceComponentConfiguration.getModelHintsExtInputStream());
}
catch (Exception exception) {
throw new SystemException(exception);
}
long previousBuildNumber = 0;
ServiceComponent previousServiceComponent = null;
Map serviceComponents =
_getServiceComponents();
ServiceComponent serviceComponent = serviceComponents.get(
buildNamespace);
if (serviceComponent == null) {
long serviceComponentId = counterLocalService.increment();
serviceComponent = serviceComponentPersistence.create(
serviceComponentId);
serviceComponent.setBuildNamespace(buildNamespace);
serviceComponent.setBuildNumber(buildNumber);
serviceComponent.setBuildDate(buildDate);
}
else {
previousBuildNumber = serviceComponent.getBuildNumber();
if (previousBuildNumber < buildNumber) {
List currentServiceComponents =
serviceComponentPersistence.findByBuildNamespace(
buildNamespace, 0, 1);
ServiceComponent currentServiceComponent =
currentServiceComponents.get(0);
long currentBuildNumber =
currentServiceComponent.getBuildNumber();
if (currentBuildNumber > previousBuildNumber) {
serviceComponent = currentServiceComponent;
previousBuildNumber = currentBuildNumber;
_serviceComponents.put(buildNamespace, serviceComponent);
}
}
if (previousBuildNumber < buildNumber) {
previousServiceComponent = serviceComponent;
long serviceComponentId = counterLocalService.increment();
serviceComponent = serviceComponentPersistence.create(
serviceComponentId);
serviceComponent.setBuildNamespace(buildNamespace);
serviceComponent.setBuildNumber(buildNumber);
serviceComponent.setBuildDate(buildDate);
}
else if (previousBuildNumber > buildNumber) {
throw new OldServiceComponentException(
StringBundler.concat(
"Build namespace ", buildNamespace,
" has build number ", previousBuildNumber,
" which is newer than ", buildNumber));
}
else {
return serviceComponent;
}
}
try {
Document document = SAXReaderUtil.createDocument(StringPool.UTF8);
Element dataElement = document.addElement("data");
Element tablesSQLElement = dataElement.addElement("tables-sql");
String tablesSQL = StringUtil.read(
serviceComponentConfiguration.getSQLTablesInputStream());
tablesSQLElement.addCDATA(tablesSQL);
Element sequencesSQLElement = dataElement.addElement(
"sequences-sql");
String sequencesSQL = StringUtil.read(
serviceComponentConfiguration.getSQLSequencesInputStream());
sequencesSQLElement.addCDATA(sequencesSQL);
Element indexesSQLElement = dataElement.addElement("indexes-sql");
String indexesSQL = StringUtil.read(
serviceComponentConfiguration.getSQLIndexesInputStream());
indexesSQLElement.addCDATA(indexesSQL);
String dataXML = document.formattedString();
serviceComponent.setData(dataXML);
serviceComponent = serviceComponentPersistence.update(
serviceComponent);
if (((serviceComponentConfiguration instanceof
ServletServiceContextComponentConfiguration) &&
(previousServiceComponent == null)) ||
((previousBuildNumber < buildNumber) &&
(previousServiceComponent != null))) {
serviceComponentLocalService.upgradeDB(
classLoader, buildNamespace, buildNumber,
previousServiceComponent, tablesSQL, sequencesSQL,
indexesSQL);
}
serviceComponents.put(buildNamespace, serviceComponent);
removeOldServiceComponents(buildNamespace);
return serviceComponent;
}
catch (Exception exception) {
throw new SystemException(exception);
}
}
@Override
public void upgradeDB(
ClassLoader classLoader, String buildNamespace, long buildNumber,
ServiceComponent previousServiceComponent, String tablesSQL,
String sequencesSQL, String indexesSQL)
throws Exception {
_upgradeDB(
classLoader, buildNamespace, buildNumber, previousServiceComponent,
tablesSQL, sequencesSQL, indexesSQL);
}
@Override
public void verifyDB() {
for (Object service : _upgradeStepServiceTracker.getServices()) {
UpgradeStepHolder upgradeStepHolder = (UpgradeStepHolder)service;
String servletContextName = upgradeStepHolder._servletContextName;
Release release = _releaseLocalService.fetchRelease(
upgradeStepHolder._servletContextName);
if ((release != null) &&
!Objects.equals(release.getSchemaVersion(), "0.0.0")) {
continue;
}
try {
UpgradeStep upgradeStep = upgradeStepHolder._upgradeStep;
upgradeStep.upgrade(
new DBProcessContext() {
@Override
public DBContext getDBContext() {
return new DBContext();
}
@Override
public OutputStream getOutputStream() {
return null;
}
});
_releaseLocalService.updateRelease(
servletContextName, "0.0.1", "0.0.0");
release = _releaseLocalService.fetchRelease(servletContextName);
int buildNumber = upgradeStepHolder._buildNumber;
release.setBuildNumber(buildNumber);
_releaseLocalService.updateRelease(release);
}
catch (Exception exception) {
_log.error(exception);
}
}
}
protected List getModelNames(ClassLoader classLoader)
throws DocumentException, IOException {
List modelNames = new ArrayList<>();
String xml = StringUtil.read(
classLoader, "META-INF/portlet-model-hints.xml");
modelNames.addAll(getModelNames(xml));
try {
xml = StringUtil.read(
classLoader, "META-INF/portlet-model-hints-ext.xml");
modelNames.addAll(getModelNames(xml));
}
catch (Exception exception) {
if (_log.isInfoEnabled()) {
_log.info(
"No optional file META-INF/portlet-model-hints-ext.xml " +
"found",
exception);
}
}
return modelNames;
}
protected List getModelNames(String xml) throws DocumentException {
List modelNames = new ArrayList<>();
Document document = UnsecureSAXReaderUtil.read(xml);
Element rootElement = document.getRootElement();
List modelElements = rootElement.elements("model");
for (Element modelElement : modelElements) {
String name = modelElement.attributeValue("name");
modelNames.add(name);
}
return modelNames;
}
protected List getModifiedTableNames(
String previousTablesSQL, String tablesSQL) {
List modifiedTableNames = new ArrayList<>();
List previousTablesSQLParts = ListUtil.fromArray(
StringUtil.split(previousTablesSQL, StringPool.SEMICOLON));
List tablesSQLParts = ListUtil.fromArray(
StringUtil.split(tablesSQL, StringPool.SEMICOLON));
tablesSQLParts.removeAll(previousTablesSQLParts);
for (String tablesSQLPart : tablesSQLParts) {
int x = tablesSQLPart.indexOf("create table ");
int y = tablesSQLPart.indexOf(" (");
modifiedTableNames.add(tablesSQLPart.substring(x + 13, y));
}
return modifiedTableNames;
}
protected UpgradeTableListener getUpgradeTableListener(
ClassLoader classLoader, Class> modelClass) {
String modelClassName = modelClass.getName();
String upgradeTableListenerClassName = modelClassName;
upgradeTableListenerClassName = StringUtil.replaceLast(
upgradeTableListenerClassName, ".model.impl.", ".model.upgrade.");
upgradeTableListenerClassName = StringUtil.replaceLast(
upgradeTableListenerClassName, "ModelImpl", "UpgradeTableListener");
try {
UpgradeTableListener upgradeTableListener =
(UpgradeTableListener)InstanceFactory.newInstance(
classLoader, upgradeTableListenerClassName);
if (_log.isInfoEnabled()) {
_log.info("Instantiated " + upgradeTableListenerClassName);
}
return upgradeTableListener;
}
catch (Exception exception) {
if (_log.isDebugEnabled()) {
_log.debug(
"Unable to instantiate " + upgradeTableListenerClassName,
exception);
}
return null;
}
}
protected void removeOldServiceComponents(String buildNamespace) {
int serviceComponentsCount =
serviceComponentPersistence.countByBuildNamespace(buildNamespace);
if (serviceComponentsCount < _SERVICE_COMPONENTS_MAX) {
return;
}
List serviceComponents =
serviceComponentPersistence.findByBuildNamespace(
buildNamespace, _SERVICE_COMPONENTS_MAX,
serviceComponentsCount);
for (ServiceComponent serviceComponent : serviceComponents) {
serviceComponentPersistence.remove(serviceComponent);
}
}
protected void upgradeModels(
ClassLoader classLoader, ServiceComponent previousServiceComponent,
String tablesSQL)
throws Exception {
List modifiedTableNames = getModifiedTableNames(
previousServiceComponent.getTablesSQL(), tablesSQL);
List modelNames = getModelNames(classLoader);
for (String modelName : modelNames) {
int pos = modelName.lastIndexOf(".model.");
Class> modelClass = Class.forName(
StringBundler.concat(
modelName.substring(0, pos), ".model.impl.",
modelName.substring(pos + 7), "ModelImpl"),
true, classLoader);
Field dataSourceField = modelClass.getField("DATA_SOURCE");
String dataSource = (String)dataSourceField.get(null);
if (!dataSource.equals(_DATA_SOURCE_DEFAULT)) {
continue;
}
Field tableNameField = modelClass.getField("TABLE_NAME");
String tableName = (String)tableNameField.get(null);
if (!modifiedTableNames.contains(tableName)) {
continue;
}
Field tableColumnsField = modelClass.getField("TABLE_COLUMNS");
Object[][] tableColumns = (Object[][])tableColumnsField.get(null);
UpgradeTable upgradeTable = UpgradeTableFactoryUtil.getUpgradeTable(
tableName, tableColumns);
UpgradeTableListener upgradeTableListener = getUpgradeTableListener(
classLoader, modelClass);
Field tableSQLCreateField = modelClass.getField("TABLE_SQL_CREATE");
String tableSQLCreate = (String)tableSQLCreateField.get(null);
upgradeTable.setCreateSQL(tableSQLCreate);
if (upgradeTableListener != null) {
upgradeTableListener.onBeforeUpdateTable(
previousServiceComponent, upgradeTable);
}
upgradeTable.updateTable();
if (upgradeTableListener != null) {
upgradeTableListener.onAfterUpdateTable(
previousServiceComponent, upgradeTable);
}
}
}
private Map _getServiceComponents() {
if (_serviceComponents != null) {
return _serviceComponents;
}
synchronized (this) {
if (_serviceComponents != null) {
return _serviceComponents;
}
Map serviceComponents =
new ConcurrentHashMap<>();
for (ServiceComponent serviceComponent :
serviceComponentPersistence.findAll()) {
String buildNamespace = serviceComponent.getBuildNamespace();
ServiceComponent previousServiceComponent =
serviceComponents.get(buildNamespace);
if ((previousServiceComponent == null) ||
(serviceComponent.getBuildNumber() >
previousServiceComponent.getBuildNumber())) {
serviceComponents.put(buildNamespace, serviceComponent);
}
}
_serviceComponents = serviceComponents;
}
return _serviceComponents;
}
private void _upgradeDB(
ClassLoader classLoader, String buildNamespace, long buildNumber,
ServiceComponent previousServiceComponent, String tablesSQL,
String sequencesSQL, String indexesSQL)
throws Exception {
DB db = DBManagerUtil.getDB();
if (previousServiceComponent == null) {
if (_log.isInfoEnabled()) {
_log.info("Running " + buildNamespace + " SQL scripts");
}
db.runSQLTemplateString(tablesSQL, false);
db.runSQLTemplateString(sequencesSQL, false);
db.runSQLTemplateString(indexesSQL, false);
}
else if (PropsValues.SCHEMA_MODULE_BUILD_AUTO_UPGRADE) {
if (_log.isWarnEnabled()) {
_log.warn(
StringBundler.concat(
"Auto upgrading ", buildNamespace,
" database to build number ", buildNumber,
" is not supported for a production environment. ",
"Write an UpgradeStep to ensure data is upgraded ",
"correctly."));
}
if (!tablesSQL.equals(previousServiceComponent.getTablesSQL())) {
if (_log.isInfoEnabled()) {
_log.info("Upgrading database with tables.sql");
}
db.runSQLTemplateString(tablesSQL, false);
upgradeModels(classLoader, previousServiceComponent, tablesSQL);
}
if (!sequencesSQL.equals(
previousServiceComponent.getSequencesSQL())) {
if (_log.isInfoEnabled()) {
_log.info("Upgrading database with sequences.sql");
}
db.runSQLTemplateString(sequencesSQL, false);
}
if (!indexesSQL.equals(previousServiceComponent.getIndexesSQL()) ||
!tablesSQL.equals(previousServiceComponent.getTablesSQL())) {
if (_log.isInfoEnabled()) {
_log.info("Upgrading database with indexes.sql");
}
db.runSQLTemplateString(indexesSQL, false);
}
}
}
private static final String _DATA_SOURCE_DEFAULT = "liferayDataSource";
private static final int _SERVICE_COMPONENTS_MAX = 10;
private static final Log _log = LogFactoryUtil.getLog(
ServiceComponentLocalServiceImpl.class);
private final BundleContext _bundleContext =
SystemBundleUtil.getBundleContext();
@BeanReference(type = ReleaseLocalService.class)
private ReleaseLocalService _releaseLocalService;
private volatile Map _serviceComponents;
private final ServiceTracker
_upgradeStepServiceTracker;
private static class UpgradeStepHolder {
private UpgradeStepHolder(
String servletContextName, int buildNumber,
UpgradeStep upgradeStep) {
_servletContextName = servletContextName;
_buildNumber = buildNumber;
_upgradeStep = upgradeStep;
}
private final int _buildNumber;
private final String _servletContextName;
private final UpgradeStep _upgradeStep;
}
private class UpgradeStepServiceTrackerCustomizer
implements ServiceTrackerCustomizer {
@Override
public UpgradeStepHolder addingService(
ServiceReference serviceReference) {
String servletContextName = (String)serviceReference.getProperty(
"upgrade.bundle.symbolic.name");
int buildNumber = GetterUtil.getInteger(
serviceReference.getProperty("build.number"));
UpgradeStep upgradeStep = _bundleContext.getService(
serviceReference);
return new UpgradeStepHolder(
servletContextName, buildNumber, upgradeStep);
}
@Override
public void modifiedService(
ServiceReference serviceReference,
UpgradeStepHolder upgradeStepHolder) {
addingService(serviceReference);
}
@Override
public void removedService(
ServiceReference serviceReference,
UpgradeStepHolder upgradeStepHolder) {
_bundleContext.ungetService(serviceReference);
}
}
} © 2015 - 2025 Weber Informatics LLC | Privacy Policy