package com.cadrlife.devsearch.agent.service.oracle;
import java.io.File;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.ColumnListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.cadrlife.devsearch.agent.service.RepoService;
import com.cadrlife.devsearch.domain.Project;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.FluentIterable;
public class OracleService extends RepoService {
private static final Logger LOG = LoggerFactory.getLogger(OracleService.class);
private final QueryRunner queryRunner;
public OracleService(DataSource ds) {
queryRunner = new QueryRunner(ds);
}
static final String STANDARD_WHERE_STATEMENT = " owner not like '%SYS%' and owner not in ('DBSNMP', 'XDB','TRIPWIRE') and owner not like 'FLOWS_%' and owner not like 'APEX_%'";
public Date getLastUpdateForProject(String owner, boolean quickCheck) throws IOException {
Date sourceUpdate = queryForDate("select max(last_ddl_time) from dba_objects where owner = ?", owner);
// If we have a mview / view, until we find a way to figure out when it was last compiled, we always need to refresh
if (queryForInt("select count(distinct view_name) from dba_views where owner=?", owner) > 0) {
sourceUpdate = new Date();
} else if (queryForInt("select count(distinct mview_name) from dba_views where owner=?", owner) > 0) {
sourceUpdate = new Date();
}
return sourceUpdate;
}
private Date queryForDate(String sql, Object...params) {
ScalarHandler<Date> dateHandler = new ScalarHandler<>();
try {
return queryRunner.query(sql, dateHandler, params);
}
catch (SQLException e) {
throw new RuntimeException(e);
}
}
private String queryForString(String sql, Object...params) {
ScalarHandler<String> stringHandler = new ScalarHandler<>();
try {
return queryRunner.query(sql, stringHandler, params);
}
catch (SQLException e) {
throw new RuntimeException(e);
}
}
private List <String> queryForStringList(String sql, Object...params) {
try {
ColumnListHandler <String> handler = new ColumnListHandler<String>(1);
return queryRunner.query(sql, handler, params);
}
catch (SQLException e) {
throw new RuntimeException(e);
}
}
private int queryForInt(String sql, Object...params) {
ScalarHandler<Integer> dateHandler = new ScalarHandler<>();
try {
return queryRunner.query(sql, dateHandler, params);
}
catch (SQLException e) {
throw new RuntimeException(e);
}
}
// private <T> List <T> queryForBeanList(String sql, Class<T> klass, Object...params) {
// BeanListHandler<T> listHandler = new BeanListHandler<T>(klass);
// try {
// return queryRunner.query(sql, listHandler, params);
// }
// catch (SQLException e) {
// throw new RuntimeException(e);
// }
// }
private List<String> listProjects() {
return queryForStringList("select distinct owner from dba_source where " + STANDARD_WHERE_STATEMENT);
}
public boolean supportsQuickUpdate() {
return false;
}
public Map<String, Date> quickScanForLastUpdatesForAllProjects() {
return Collections.emptyMap();
}
@Override
public List <Project> findAllProjects() {
return FluentIterable.from(listProjects()).transform(new Function <String,Project>() {
@Override
public Project apply(String input) {
return new Project().setName(input).setRepo(getRepoName());
}
}).toList();
}
@Override
public void updateProject(final File file, Project project) {
try {
final String ownerSchema = project.getName();
LOG.info("dumping schema {}", ownerSchema);
ResultSetHandler <Void> sourceHandler = new ResultSetHandler <Void>() {
@Override
public Void handle(ResultSet rs) throws SQLException {
while (rs.next()) {
String sqlName = rs.getString(1);
String sqlType = rs.getString(2);
handleRow(sqlName, sqlType);
}
return null;
}
private void handleRow(String sqlName, String sqlType) {
List <String> sourceLines = queryForStringList("select text from dba_source where owner = ? and name = ? and type = ? order by line",
ownerSchema,
sqlName,
sqlType);
File localFile = file.toPath().resolve(sqlType).resolve(sqlName +".sql").toFile();
try {
saveStringToFile(Joiner.on("").join(sourceLines), localFile);
}
catch (IOException e) {
String message = String.format("Couldn't write %s.%s source to %s", ownerSchema, sqlName, localFile.getAbsolutePath());
throw new RuntimeException(message, e);
}
}
};
ResultSetHandler <Void> viewHandler = new ResultSetHandler <Void>() {
@Override
public Void handle(ResultSet rs) throws SQLException {
while (rs.next()) {
String sqlName = rs.getString(1);
String sqlType = rs.getString(2);
handleRow(sqlName, sqlType);
}
return null;
}
private void handleRow(String sqlName, String sqlType) {
String source = queryForString(selectSourceLines(sqlType),
ownerSchema,
sqlName);
File localFile = file.toPath().resolve(sqlType).resolve(sqlName +".sql").toFile();
try {
saveStringToFile(source, localFile);
}
catch (IOException e) {
String message = String.format("Couldn't write %s.%s source to %s", ownerSchema, sqlName, localFile.getAbsolutePath());
throw new RuntimeException(message, e);
}
}
private String selectSourceLines(String sqlType) {
if ("MVIEW".equalsIgnoreCase(sqlType)) {
return "select query from dba_mviews where owner = ? and mview_name = ?";
}
return "select text from dba_views where owner = ? and view_name = ?";
}
};
queryRunner.query("select view_name, 'VIEW' as type from dba_views where owner = ?", viewHandler, ownerSchema);
queryRunner.query("select mview_name, 'MVIEW' as type from dba_mviews where owner = ?", viewHandler, ownerSchema);
queryRunner.query("select distinct name, type from dba_source where owner = ?", sourceHandler, ownerSchema);
}
catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public String getSourceType() {
return "oracle";
}
}