package org.springframework.roo.addon.dbre.addon.model;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
import org.springframework.roo.addon.dbre.addon.jdbc.ConnectionProvider;
import org.springframework.roo.addon.propfiles.PropFileOperations;
import org.springframework.roo.file.monitor.event.FileDetails;
import org.springframework.roo.process.manager.FileManager;
import org.springframework.roo.project.LogicalPath;
import org.springframework.roo.project.Path;
import org.springframework.roo.project.ProjectOperations;
import org.springframework.roo.support.logging.HandlerUtils;
import org.springframework.roo.support.util.XmlUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Implementation of {@link DbreModelService}.
*
* @author Alan Stewart
* @since 1.1
*/
@Component
@Service
public class DbreModelServiceImpl implements DbreModelService {
// OSGi Bundle Context
private BundleContext context;
private static final Logger LOGGER = HandlerUtils.getLogger(DbreModelServiceImpl.class);
protected void activate(final ComponentContext cContext) {
this.context = cContext.getBundleContext();
}
private final Set<Database> cachedIntrospections = new HashSet<Database>();
private ConnectionProvider connectionProvider;
private FileManager fileManager;
private Database lastDatabase;
private ProjectOperations projectOperations;
private PropFileOperations propFileOperations;
private void cacheDatabase(final Database database) {
if (database != null) {
lastDatabase = database;
cachedIntrospections.add(database);
}
}
private Connection getConnection(final boolean displayAddOns) {
/*final String dbProps = "database.properties";
final String jndiDataSource = getJndiDataSourceName();
if (StringUtils.isNotBlank(jndiDataSource)) {
final Map<String, String> props = getPropFileOperations().getProperties(
Path.SPRING_CONFIG_ROOT.getModulePathId(getProjectOperations()
.getFocusedModuleName()), "jndi.properties");
return getConnectionProvider().getConnectionViaJndiDataSource(
jndiDataSource, props, displayAddOns);
}
else if (getFileManager().exists(getProjectOperations().getPathResolver()
.getFocusedIdentifier(Path.SPRING_CONFIG_ROOT, dbProps))) {
final Map<String, String> props = getPropFileOperations().getProperties(
Path.SPRING_CONFIG_ROOT.getModulePathId(getProjectOperations()
.getFocusedModuleName()), dbProps);
return getConnectionProvider().getConnection(props, displayAddOns);
}
final Properties connectionProperties = getConnectionPropertiesFromDataNucleusConfiguration();
return getConnectionProvider().getConnection(connectionProperties,
displayAddOns);*/
return null;
}
private Properties getConnectionPropertiesFromDataNucleusConfiguration() {
/*final String persistenceXmlPath = getProjectOperations().getPathResolver()
.getFocusedIdentifier(Path.SRC_MAIN_RESOURCES,
"META-INF/persistence.xml");
if (!getFileManager().exists(persistenceXmlPath)) {
throw new IllegalStateException("Failed to find "
+ persistenceXmlPath);
}
final FileDetails fileDetails = getFileManager()
.readFile(persistenceXmlPath);
Document document = null;
try {
final InputStream is = new BufferedInputStream(new FileInputStream(
fileDetails.getFile()));
final DocumentBuilder builder = XmlUtils.getDocumentBuilder();
builder.setErrorHandler(null);
document = builder.parse(is);
}
catch (final Exception e) {
throw new IllegalStateException(e);
}
final List<Element> propertyElements = XmlUtils.findElements(
"/persistence/persistence-unit/properties/property",
document.getDocumentElement());
Validate.notEmpty(propertyElements,
"Failed to find property elements in %s", persistenceXmlPath);
final Properties properties = new Properties();
for (final Element propertyElement : propertyElements) {
final String key = propertyElement.getAttribute("name");
final String value = propertyElement.getAttribute("value");
if ("datanucleus.ConnectionDriverName".equals(key)) {
properties.put("database.driverClassName", value);
}
if ("datanucleus.ConnectionURL".equals(key)) {
properties.put("database.url", value);
}
if ("datanucleus.ConnectionUserName".equals(key)) {
properties.put("database.username", value);
}
if ("datanucleus.ConnectionPassword".equals(key)) {
properties.put("database.password", value);
}
if (properties.size() == 4) {
// All required properties have been found so ignore rest of
// elements
break;
}
}
return properties;*/
return null;
}
public Database getDatabase(final boolean evictCache) {
if (!evictCache && cachedIntrospections.contains(lastDatabase)) {
for (final Database database : cachedIntrospections) {
if (database.equals(lastDatabase)) {
return lastDatabase;
}
}
}
if (evictCache && cachedIntrospections.contains(lastDatabase)) {
cachedIntrospections.remove(lastDatabase);
}
final String dbreXmlPath = getDbreXmlPath();
if (StringUtils.isBlank(dbreXmlPath) || !getFileManager().exists(dbreXmlPath)) {
return null;
}
Database database = null;
InputStream inputStream = null;
try {
inputStream = getFileManager().getInputStream(dbreXmlPath);
database = DatabaseXmlUtils.readDatabase(inputStream);
cacheDatabase(database);
return database;
} catch (final Exception e) {
throw new IllegalStateException(e);
} finally {
IOUtils.closeQuietly(inputStream);
}
}
private String getDbreXmlPath() {
for (final String moduleName : getProjectOperations().getModuleNames()) {
final LogicalPath logicalPath = LogicalPath.getInstance(Path.SRC_MAIN_RESOURCES, moduleName);
final String dbreXmlPath =
getProjectOperations().getPathResolver().getIdentifier(logicalPath, DBRE_XML);
if (getFileManager().exists(dbreXmlPath)) {
return dbreXmlPath;
}
}
return getProjectOperations().getPathResolver().getFocusedIdentifier(Path.SRC_MAIN_RESOURCES,
DBRE_XML);
}
private String getJndiDataSourceName() {
final String contextPath =
getProjectOperations().getPathResolver().getFocusedIdentifier(Path.SPRING_CONFIG_ROOT,
"applicationContext.xml");
final Document appCtx = XmlUtils.readXml(getFileManager().getInputStream(contextPath));
final Element root = appCtx.getDocumentElement();
final Element dataSourceJndi =
XmlUtils.findFirstElement("/beans/jndi-lookup[@id = 'dataSource']", root);
return dataSourceJndi != null ? dataSourceJndi.getAttribute("jndi-name") : null;
}
public Set<Schema> getSchemas(final boolean displayAddOns) {
Connection connection = null;
try {
connection = getConnection(displayAddOns);
final SchemaIntrospector introspector = new SchemaIntrospector(connection);
return introspector.getSchemas();
} catch (final Exception e) {
return Collections.emptySet();
} finally {
getConnectionProvider().closeConnection(connection);
}
}
public Database refreshDatabase(final Set<Schema> schemas, final boolean view,
final Set<String> includeTables, final Set<String> excludeTables) {
Validate.notNull(schemas, "Schemas required");
Connection connection = null;
try {
connection = getConnection(true);
final DatabaseIntrospector introspector =
new DatabaseIntrospector(connection, schemas, view, includeTables, excludeTables);
final Database database = introspector.createDatabase();
cacheDatabase(database);
return database;
} catch (final Exception e) {
throw new IllegalStateException(e);
} finally {
getConnectionProvider().closeConnection(connection);
}
}
public boolean supportsSchema(final boolean displayAddOns) throws RuntimeException {
Connection connection = null;
try {
connection = getConnection(displayAddOns);
final DatabaseMetaData databaseMetaData = connection.getMetaData();
final String schemaTerm = databaseMetaData.getSchemaTerm();
return StringUtils.isNotBlank(schemaTerm) && schemaTerm.equalsIgnoreCase("schema");
} catch (final Exception e) {
throw new IllegalStateException(e);
} finally {
getConnectionProvider().closeConnection(connection);
}
}
public void writeDatabase(final Database database) {
final Document document = DatabaseXmlUtils.getDatabaseDocument(database);
getFileManager().createOrUpdateTextFileIfRequired(getDbreXmlPath(),
XmlUtils.nodeToString(document), true);
}
/**
* Method to get ConnectionProvider Service implementation
*
* @return
*/
public ConnectionProvider getConnectionProvider() {
if (connectionProvider == null) {
// Get all Services implement ConnectionProvider interface
try {
ServiceReference<?>[] references =
context.getAllServiceReferences(ConnectionProvider.class.getName(), null);
for (ServiceReference<?> ref : references) {
connectionProvider = (ConnectionProvider) context.getService(ref);
return connectionProvider;
}
return null;
} catch (InvalidSyntaxException e) {
LOGGER.warning("Cannot load ConnectionProvider on DbreModelServiceImpl.");
return null;
}
} else {
return connectionProvider;
}
}
/**
* Method to get FileManager Service implementation
*
* @return
*/
public FileManager getFileManager() {
if (fileManager == null) {
// Get all Services implement FileManager interface
try {
ServiceReference<?>[] references =
context.getAllServiceReferences(FileManager.class.getName(), null);
for (ServiceReference<?> ref : references) {
fileManager = (FileManager) context.getService(ref);
return fileManager;
}
return null;
} catch (InvalidSyntaxException e) {
LOGGER.warning("Cannot load FileManager on DbreModelServiceImpl.");
return null;
}
} else {
return fileManager;
}
}
/**
* Method to get ProjectOperations Service implementation
*
* @return
*/
public ProjectOperations getProjectOperations() {
if (projectOperations == null) {
// Get all Services implement ProjectOperations interface
try {
ServiceReference<?>[] references =
context.getAllServiceReferences(ProjectOperations.class.getName(), null);
for (ServiceReference<?> ref : references) {
projectOperations = (ProjectOperations) context.getService(ref);
return projectOperations;
}
return null;
} catch (InvalidSyntaxException e) {
LOGGER.warning("Cannot load ProjectOperations on DbreModelServiceImpl.");
return null;
}
} else {
return projectOperations;
}
}
/**
* Method to get PropFileOperations Service implementation
*
* @return
*/
public PropFileOperations getPropFileOperations() {
if (propFileOperations == null) {
// Get all Services implement PropFileOperations interface
try {
ServiceReference<?>[] references =
context.getAllServiceReferences(PropFileOperations.class.getName(), null);
for (ServiceReference<?> ref : references) {
propFileOperations = (PropFileOperations) context.getService(ref);
return propFileOperations;
}
return null;
} catch (InvalidSyntaxException e) {
LOGGER.warning("Cannot load PropFileOperations on DbreModelServiceImpl.");
return null;
}
} else {
return propFileOperations;
}
}
}