/**
* 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.tools.db.support.commands;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.beust.jcommander.converters.FileConverter;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashSet;
import java.util.Set;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* @author Andrea Di Giorgi
*/
@Parameters(
commandDescription = "Cleans the Liferay database from the Service Builder tables and rows of a module.",
commandNames = "clean-service-builder"
)
public class CleanServiceBuilderCommand extends BaseCommand {
public void setServiceXmlFile(File serviceXmlFile) {
_serviceXmlFile = serviceXmlFile;
}
public void setServletContextName(String servletContextName) {
_servletContextName = servletContextName;
}
@Override
protected void execute(Connection connection) throws Exception {
DocumentBuilderFactory documentBuilderFactory =
DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder =
documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(_serviceXmlFile);
Element serviceBuilderElement = document.getDocumentElement();
boolean autoNamespaceTables = true;
String autoNamespaceTablesString = serviceBuilderElement.getAttribute(
"auto-namespace-tables");
if ((autoNamespaceTablesString != null) &&
!autoNamespaceTablesString.isEmpty()) {
autoNamespaceTables = Boolean.parseBoolean(
autoNamespaceTablesString);
}
NodeList namespaceNodeList = serviceBuilderElement.getElementsByTagName(
"namespace");
if (namespaceNodeList.getLength() != 1) {
throw new IllegalArgumentException(
"Unable to get namespace from " + _serviceXmlFile);
}
Element namespaceElement = (Element)namespaceNodeList.item(0);
String namespace = namespaceElement.getTextContent();
NodeList entityNodeList = document.getElementsByTagName("entity");
for (int i = 0; i < entityNodeList.getLength(); i++) {
Element entityElement = (Element)entityNodeList.item(i);
String tableName = entityElement.getAttribute("table");
if ((tableName == null) || tableName.isEmpty()) {
String entityName = entityElement.getAttribute("name");
tableName = entityName;
if (_badTableNames.contains(tableName)) {
tableName += '_';
}
if (autoNamespaceTables) {
tableName = namespace + "_" + entityName;
}
}
_dropTable(connection, tableName);
if (_hasLocalizationTable(entityElement)) {
_dropTable(connection, tableName + "Localization");
}
}
_deleteReleaseRows(connection);
_deleteServiceComponentRows(connection, namespace);
}
private void _deleteReleaseRows(Connection connection) throws SQLException {
String sql = "delete from Release_ where servletContextName = ?";
try (PreparedStatement preparedStatement =
connection.prepareStatement(sql)) {
preparedStatement.setString(1, _servletContextName);
preparedStatement.executeUpdate();
}
}
private void _deleteServiceComponentRows(
Connection connection, String namespace)
throws SQLException {
String sql = "delete from ServiceComponent where buildNamespace = ?";
try (PreparedStatement preparedStatement =
connection.prepareStatement(sql)) {
preparedStatement.setString(1, namespace);
preparedStatement.executeUpdate();
}
}
private void _dropTable(Connection connection, String tableName)
throws SQLException {
try (Statement statement = connection.createStatement()) {
statement.executeUpdate("DROP TABLE " + tableName);
}
}
private boolean _hasLocalizationTable(Element entityElement) {
NodeList columnNodeList = entityElement.getElementsByTagName("column");
for (int i = 0; i < columnNodeList.getLength(); i++) {
Element columnElement = (Element)columnNodeList.item(i);
String localized = columnElement.getAttribute("localized");
if ("extra-table".equals(localized)) {
return true;
}
}
return false;
}
private static final Set<String> _badTableNames = new HashSet<>();
static {
ClassLoader classLoader =
CleanServiceBuilderCommand.class.getClassLoader();
try (BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(
classLoader.getResourceAsStream(
"com/liferay/portal/tools/service/builder" +
"/dependencies/bad_table_names.txt"),
StandardCharsets.UTF_8))) {
String line = null;
while ((line = bufferedReader.readLine()) != null) {
_badTableNames.add(line);
}
}
catch (IOException ioe) {
throw new ExceptionInInitializerError(ioe);
}
}
@Parameter(
converter = FileConverter.class, description = "The service.xml file.",
names = {"-x", "--service-xml-file"}, required = true
)
private File _serviceXmlFile;
@Parameter(
description = "The servlet context name (usually the value of the \"Bundle-Symbolic-Name\" manifest header) of the module.",
names = {"-o", "--servlet-context-name"}, required = true
)
private String _servletContextName;
}