/*
* DeployedApplication.java
*
* Created on June 23, 2007, 4:39 PM
*
* CodaServer and related original technologies are copyright 2008, 18th Street Software, LLC.
*
* Permission to use them is granted under the terms of the GNU GPLv2.
*/
package org.codalang.codaserver;
import groovy.lang.GroovyClassLoader;
import org.codalang.codaserver.database.CodaConnection;
import org.codalang.codaserver.database.CodaDatabase;
import org.codalang.codaserver.database.CodaResultSet;
import org.codalang.codaserver.executioncontext.ExecutionContext;
import org.codalang.codaserver.language.types.BaseCodaTable;
import org.codalang.codaserver.language.types.BaseCodaTrigger;
import org.codalang.codaserver.language.types.Database;
import org.codalang.codaserver.security.SecurityApplicationPermission;
import org.codalang.codaserver.security.SecurityApplicationUser;
import org.quartz.Scheduler;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author michaelarace
*/
public class DeployedApplication {
public static final int DEV_ENVIRONMENT = 0;
public static final int TEST_ENVIRONMENT = 1;
public static final int PROD_ENVIRONMENT = 2;
private long applicationId;
private String applicationName;
private String displayName;
private String devDatasourceName;
private String testDatasourceName;
private String prodDatasourceName;
private Datasource production;
private Datasource testing;
private Datasource development;
private CodaDatabase database;
private boolean groupFlag;
private boolean useCacheFlag;
private boolean loadedFlag = false;
private Logger logger;
private Hashtable<Integer,Scheduler> schedulers = new Hashtable();
private FancyGroovyClassLoader prodClassLoader;
private FancyGroovyClassLoader testClassLoader;
private FancyGroovyClassLoader devClassLoader;
private ClassLoader parentLoader;
private HashSet groups = new HashSet();
private Hashtable users = new Hashtable();
/**
* Creates a new instance of DeployedApplication
*/
public DeployedApplication(CodaDatabase database, String applicationName, boolean useCacheFlag, Logger logger, ClassLoader parentLoader) {
this.setDatabase(database);
this.applicationName = applicationName;
this.setUseCacheFlag(useCacheFlag);
this.setLogger(logger);
this.parentLoader = parentLoader;
this.prodClassLoader = new FancyGroovyClassLoader(parentLoader);
this.testClassLoader = new FancyGroovyClassLoader(parentLoader);
this.devClassLoader = new FancyGroovyClassLoader(parentLoader);
}
public boolean reload () {
useCacheFlag = false;
displayName = null;
devDatasourceName = null;
testDatasourceName = null;
prodDatasourceName = null;
production = null;
testing = null;
development = null;
loadedFlag = false;
CodaConnection connection = getDatabase().getConnection();
CodaResultSet rs = connection.runQuery("select a.id, a.application_name, a.display_name, a.group_flag, d1.datasource_name, d2.datasource_name, d3.datasource_name from applications a left outer join datasources d1 on a.dev_datasource_id = d1.id left outer join datasources d2 on a.test_datasource_id = d2.id left outer join datasources d3 on a.prod_datasource_id = d3.id where a.active_flag = 1 and a.application_name = " + connection.formatStringForSQL("applications", "application_name", getApplicationName().toUpperCase()), null);
if (!rs.getErrorStatus() && rs.next()) {
this.applicationId = rs.getDataLong(0);
this.displayName = rs.getData(2);
this.setGroupFlag(rs.getDataBoolean(3));
this.devDatasourceName = rs.getData(4);
reloadDatasource(this.DEV_ENVIRONMENT, getDevDatasourceName());
this.setTestDatasourceName(rs.getData(5));
this.devClassLoader = this.getEnvironmentClassLoader(1, parentLoader);
if (getTestDatasourceName() != null) {
reloadDatasource(this.TEST_ENVIRONMENT, getTestDatasourceName());
this.testClassLoader = this.getEnvironmentClassLoader(2, parentLoader);
}
this.setProdDatasourceName(rs.getData(6));
if (getProdDatasourceName() != null) {
reloadDatasource(this.PROD_ENVIRONMENT, getProdDatasourceName());
this.prodClassLoader = this.getEnvironmentClassLoader(3, parentLoader);
}
loadUsers();
loadGroups();
this.setLoadedFlag(true);
useCacheFlag = true;
return true;
} else {
useCacheFlag = true;
return false;
}
}
public boolean reloadDatasource(int environment, String datasourceName) {
CodaConnection connection = getDatabase().getConnection();
CodaResultSet rs = connection.runQuery("select id, driver_name, host_name, schema_name, user_name, pass_word from datasources where datasource_name = " + connection.formatStringForSQL("datasources", "datasource_name", datasourceName), null);
if (!rs.getErrorStatus() && rs.next()) {
long datasourceId = rs.getDataLong(0);
Hashtable options = new Hashtable();
CodaResultSet rs2 = connection.runQuery("select option_name, option_value from datasource_options where datasource_id = " + connection.formatStringForSQL("datasource_options", "datasource_id", Long.toString(datasourceId)) ,null);
if (!rs2.getErrorStatus()) {
while (rs2.next()) {
options.put(rs2.getData(0), rs2.getData(1));
}
}
CodaDatabase conn;
try {
Class.forName(rs.getData(1));
conn = (CodaDatabase) Class.forName(rs.getData(1)).newInstance();
if (conn.connect(rs.getData(2), rs.getData(4), rs.getData(5), rs.getData(3), options)) {
conn.setLogger(getLogger());
switch (environment) {
case DeployedApplication.PROD_ENVIRONMENT:
this.setProduction(new Datasource(environment, conn, groupFlag, isUseCacheFlag()));
break;
case DeployedApplication.TEST_ENVIRONMENT:
this.setTesting(new Datasource(environment, conn, groupFlag, isUseCacheFlag()));
break;
default:
this.setDevelopment(new Datasource(environment, conn, groupFlag, false));
}
return true;
} else {
return false;
}
} catch (Exception e) {
return false;
}
} else {
return false;
}
}
public boolean reloadDatasource(int environment) {
String columnName = "";
switch (environment) {
case DeployedApplication.PROD_ENVIRONMENT:
columnName = "prod_datasource_id";
break;
case DeployedApplication.TEST_ENVIRONMENT:
columnName = "test_datasource_id";
break;
default:
columnName = "dev_datasource_id";
}
CodaConnection connection = getDatabase().getConnection();
CodaResultSet rs = connection.runQuery("select d.datasource_name from applications a left outer join datasources d on a." +columnName + " = d.id where a.id = " + this.getApplicationId(), null);
if (!rs.getErrorStatus() && rs.next()) {
return reloadDatasource(environment, rs.getData(0));
} else {
return false;
}
}
public void reloadTables(int environment) {
if (this.useCacheFlag) {
CodaConnection connection = this.getEnvironmentDatasource(environment).getDatabase().getConnection();
CodaResultSet rs = connection.runQuery("select table_name, class_file from "+ this.getEnvironmentDatasource(environment).getPrefix() +"tables ", null);
if (!rs.getErrorStatus()) {
while (rs.next()) {
this.loadClass(environment, "org.codalang.codaserver.language.tables." + CodaServer.camelCapitalize(rs.getData(0), true), rs.getData(1));
}
} else {
logger.log(Level.WARNING, "Application " + this.getApplicationName() + ": Couldn't get table class files");
}
}
}
public void loadClass(int environment, String className, String classFile) {
if (this.useCacheFlag) {
this.getEnvironmentClassLoader(environment, parentLoader).parseClass(classFile);
try {
Class.forName(className, true, this.getEnvironmentClassLoader(environment, parentLoader));
} catch (ClassNotFoundException ex) {
logger.log(Level.WARNING, "Class '" + className + "' was not found in the classloader.");
}
}
}
public void loadGroups () {
setGroups(new HashSet());
CodaConnection connection = getDatabase().getConnection();
CodaResultSet rs = connection.runQuery("select g.group_name from group_applications a inner join groups g on a.group_id = g.id where a.application_id = " + connection.formatStringForSQL("group_applications", "application_id", Long.toString(this.getApplicationId())),null);
if (!rs.getErrorStatus()) {
while (rs.next()) {
getGroups().add(rs.getData(0));
}
}
}
private void loadUsers() {
setUsers(new Hashtable());
CodaConnection connection = getDatabase().getConnection();
CodaResultSet rs = connection.runQuery("select user_id, application_permission_name, environment, group_id from user_application_permissions where application_id = " + connection.formatStringForSQL("user_application_permissions", "application_id", Long.toString(this.getApplicationId()) + " order by user_id, environment, group_id"), null);
if (!rs.getErrorStatus()) {
long currentUserId = -1;
String currentPermission = null;
Hashtable tempPermissions = new Hashtable();
while (rs.next()) {
if (currentUserId < 0) {
currentUserId = rs.getDataLong(0);
currentPermission = rs.getData(1).toUpperCase();
tempPermissions.put(currentPermission, new SecurityApplicationPermission((rs.getData(3) == null ? true : false), (rs.getData(2) == null ? true : false)));
} else if (currentUserId != rs.getDataLong(0)) {
getUsers().put(currentUserId, new SecurityApplicationUser(tempPermissions));
tempPermissions = new Hashtable();
currentUserId = rs.getDataLong(0);
currentPermission = rs.getData(1).toUpperCase();
tempPermissions.put(currentPermission, new SecurityApplicationPermission((rs.getData(3) == null ? true : false), (rs.getData(2) == null ? true : false)));
} else if (!currentPermission.equalsIgnoreCase(rs.getData(1))) {
currentPermission = rs.getData(1).toUpperCase();
tempPermissions.put(currentPermission, new SecurityApplicationPermission((rs.getData(3) == null ? true : false), (rs.getData(2) == null ? true : false)));
}
if (rs.getData(3) == null && rs.getData(2) == null) {
//skip
} else if(rs.getData(3) == null) {
((SecurityApplicationPermission)tempPermissions.get(currentPermission)).addEnvironmentGroup(rs.getData(2));
} else if(rs.getData(2) == null) {
((SecurityApplicationPermission)tempPermissions.get(currentPermission)).addEnvironmentGroup(rs.getData(3));
} else {
((SecurityApplicationPermission)tempPermissions.get(currentPermission)).addEnvironmentGroup(rs.getData(2) + ":" + rs.getData(3));
}
}
if (currentUserId >= 0) {
getUsers().put(currentUserId, new SecurityApplicationUser(tempPermissions));
}
}
}
public void reloadUser(long userId) {
if (this.isUseCacheFlag()) {
getUsers().remove(userId);
CodaConnection connection = getDatabase().getConnection();
CodaResultSet rs = connection.runQuery("select application_permission_name, environment, group_id from user_application_permissions where application_id = " + connection.formatStringForSQL("user_application_permissions", "application_id", Long.toString(this.getApplicationId()) + " and user_id = "+ connection.formatStringForSQL("user_application_permissions", "user_id", Long.toString(userId)) +" order by user_id"), null);
if (!rs.getErrorStatus()) {
String currentPermission = null;
Hashtable tempPermissions = new Hashtable();
while (rs.next()) {
if (currentPermission == null) {
currentPermission = rs.getData(0).toUpperCase();
tempPermissions.put(currentPermission, new SecurityApplicationPermission((rs.getData(2) == null ? true : false), (rs.getData(1) == null ? true : false)));
} else if (!currentPermission.equalsIgnoreCase(rs.getData(0))) {
currentPermission = rs.getData(0).toUpperCase();
tempPermissions.put(currentPermission, new SecurityApplicationPermission((rs.getData(2) == null ? true : false), (rs.getData(1) == null ? true : false)));
}
if (rs.getData(2) == null && rs.getData(1) == null) {
//skip
} else if(rs.getData(2) == null) {
((SecurityApplicationPermission)tempPermissions.get(currentPermission)).addEnvironmentGroup(rs.getData(1));
} else if(rs.getData(1) == null) {
((SecurityApplicationPermission)tempPermissions.get(currentPermission)).addEnvironmentGroup(rs.getData(2));
} else {
((SecurityApplicationPermission)tempPermissions.get(currentPermission)).addEnvironmentGroup(rs.getData(1) + ":" + rs.getData(2));
}
}
getUsers().put(userId, new SecurityApplicationUser(tempPermissions));
}
}
}
public boolean hasApplicationPermission(long userId, long groupId, int environment, String permissionName) {
if (this.useCacheFlag && environment != 1) {
if (users.containsKey(userId)) {
return ((SecurityApplicationUser)users.get(userId)).hasPermission(environment, groupId, permissionName);
} else {
return false;
}
} else {
CodaConnection connection = database.getConnection();
CodaResultSet rs = connection.runQuery("select count(uap.user_id) from user_application_permissions uap where uap.user_id = " + connection.formatStringForSQL("user_application_permissions", "user_id", Long.toString(userId)) + (environment > 0 ? " and (uap.environment = "+ connection.formatStringForSQL("user_application_permissions", "environment", Integer.toString(environment)) + " or uap.environment is null )" : "")+ (groupId > 0 ? " and (uap.group_id = "+ connection.formatStringForSQL("user_application_permissions", "group_id", Long.toString(groupId)) + " or uap.group_id is null)" : "") +" and uap.application_id = " + connection.formatStringForSQL("user_application_permissions", "application_id", Long.toString(this.applicationId)) + " and uap.application_permission_name = " + connection.formatStringForSQL("user_application_permissions", "application_permission_name", permissionName.toUpperCase()), null);
if (!rs.getErrorStatus()) {
if(rs.next()) {
return (rs.getDataInt(0) == 1);
}
}
return false;
}
}
public boolean canGroupUseApplication(String groupName) {
if (groupName == null) {
return false;
} else if (this.useCacheFlag) {
return groups.contains(groupName);
} else {
CodaConnection connection = database.getConnection();
CodaResultSet rs = connection.runQuery("select count(a.user_id) from group_applications a left outer join groups g on g.id = a.group_id where a.application_id = "+connection.formatStringForSQL("group_applications", "application_id", Long.toString(this.applicationId))+" and g.group_name = " + connection.formatStringForSQL("groups", "group_name", groupName.toUpperCase()) ,null);
if (!rs.getErrorStatus()) {
if (rs.next()) {
return rs.getDataInt(0) == 1;
}
return false;
}
return false;
}
}
public boolean canUserUseApplication(long userId, int environment) {
if (this.useCacheFlag && environment != 1) {
return users.containsKey(userId);
} else {
CodaConnection connection = database.getConnection();
CodaResultSet rs = connection.runQuery("select count(a.user_id) from user_application_permissions a where a.application_permission_name = 'CONNECT' and (a.environment = "+ connection.formatStringForSQL("user_application_permissions", "environment", Integer.toString(environment)) +" or a.environment is null) and a.application_id = "+connection.formatStringForSQL("user_application_permissions", "application_id", Long.toString(this.applicationId))+" and a.user_id = " + connection.formatStringForSQL("user_application_permissions", "user_id", Long.toString(userId)) ,null);
if (!rs.getErrorStatus()) {
if (rs.next()) {
return rs.getDataInt(0) == 1;
}
return false;
}
return false;
}
}
public boolean canUserUseApplication(long userId, int environment, long groupId) {
if (this.useCacheFlag && environment != 1) {
return users.containsKey(userId);
} else {
CodaConnection connection = database.getConnection();
CodaResultSet rs = connection.runQuery("select count(a.user_id) from user_application_permissions a where a.application_permission_name = 'CONNECT' and (a.environment = "+ connection.formatStringForSQL("user_application_permissions", "environment", Integer.toString(environment)) +" or a.environment is null) and (a.group_id = "+ connection.formatStringForSQL("user_application_permissions", "group_id", Long.toString(groupId)) +" or group_id is null) and a.application_id = "+connection.formatStringForSQL("user_application_permissions", "application_id", Long.toString(this.applicationId))+" and a.user_id = " + connection.formatStringForSQL("user_application_permissions", "user_id", Long.toString(userId)) ,null);
if (!rs.getErrorStatus()) {
if (rs.next()) {
return rs.getDataInt(0) == 1;
}
return false;
}
return false;
}
}
public String getNameForOperationId(int operationId) {
switch (operationId) {
case 1:
return "update";
case 2:
return "insert";
case 3:
return "delete";
default:
return "";
}
}
public long getApplicationId() {
return applicationId;
}
public String getApplicationName() {
return applicationName;
}
public String getDisplayName() {
return displayName;
}
public String getDevDatasourceName() {
return devDatasourceName;
}
public Datasource getProduction() {
return production;
}
public void setProduction(Datasource production) {
this.production = production;
}
public Datasource getTesting() {
return testing;
}
public void setTesting(Datasource testing) {
this.testing = testing;
}
public Datasource getDevelopment() {
return development;
}
public void setDevelopment(Datasource development) {
this.development = development;
}
public CodaDatabase getDatabase() {
return database;
}
public void setDatabase(CodaDatabase database) {
this.database = database;
}
public boolean isGroupFlag() {
return groupFlag;
}
public void setGroupFlag(boolean groupFlag) {
this.groupFlag = groupFlag;
}
public boolean isUseCacheFlag() {
return useCacheFlag;
}
public void setUseCacheFlag(boolean useCacheFlag) {
this.useCacheFlag = useCacheFlag;
}
public boolean isLoadedFlag() {
return loadedFlag;
}
public void setLoadedFlag(boolean loadedFlag) {
this.loadedFlag = loadedFlag;
}
public Logger getLogger() {
return logger;
}
public void setLogger(Logger logger) {
this.logger = logger;
}
public HashSet getGroups() {
return groups;
}
public void setGroups(HashSet groups) {
this.groups = groups;
}
public Hashtable getUsers() {
return users;
}
public void setUsers(Hashtable users) {
this.users = users;
}
public String getTestDatasourceName() {
return testDatasourceName;
}
public void setTestDatasourceName(String testDatasourceName) {
this.testDatasourceName = testDatasourceName;
}
public String getProdDatasourceName() {
return prodDatasourceName;
}
public void setProdDatasourceName(String prodDatasourceName) {
this.prodDatasourceName = prodDatasourceName;
}
public Datasource getEnvironmentDatasource(int environment) {
switch (environment) {
case 1:
return this.getDevelopment();
case 2:
return this.getTesting();
case 3:
return this.getProduction();
}
return null;
}
public FancyGroovyClassLoader getEnvironmentClassLoader(int environment, ClassLoader parentClassLoader) {
//if (this.useCacheFlag && environment != 1) {
if (this.useCacheFlag) {
switch (environment) {
case 1:
return this.devClassLoader;
case 2:
return this.testClassLoader;
case 3:
return this.prodClassLoader;
}
} else {
if (this.getEnvironmentDatasource(environment) == null) {
return null;
}
try {
FancyGroovyClassLoader classLoader = new FancyGroovyClassLoader(parentClassLoader);
CodaConnection connection = this.getEnvironmentDatasource(environment).getDatabase().getConnection();
CodaResultSet rs = connection.runQuery("select table_name, class_file from " + this.getEnvironmentDatasource(environment).getPrefix() + "tables", null);
if (!rs.getErrorStatus()) {
while (rs.next()) {
Class groovyClass = classLoader.parseClass( rs.getData(1));
classLoader.linkClass(groovyClass);
}
}
rs = connection.runQuery("select procedure_name, class_file from " + this.getEnvironmentDatasource(environment).getPrefix() + "procedures", null);
if (!rs.getErrorStatus()) {
while (rs.next()) {
Class groovyClass = classLoader.parseClass( rs.getData(1));
classLoader.linkClass(groovyClass);
}
}
rs = connection.runQuery("select t.table_name, p.before_flag, p.operation_id, fs.verb_status_name, p.class_file from " + this.getEnvironmentDatasource(environment).getPrefix() + "triggers p inner join " + this.getEnvironmentDatasource(environment).getPrefix() + "tables t on t.id = p.table_id left outer join " + this.getEnvironmentDatasource(environment).getPrefix() + "form_statuses fs on fs.id = p.form_status_id", null);
if (!rs.getErrorStatus()) {
while (rs.next()) {
Class groovyClass = classLoader.parseClass( rs.getData(4));
classLoader.linkClass(groovyClass);
}
}
return classLoader;
} catch (Exception e) {
this.logger.log(Level.WARNING, this.getApplicationName() + ": Unable to connect to environment " + environment + " when getting class loader");
}
}
return null;
}
private void setEnvironmentClassLoader(int environment, FancyGroovyClassLoader classLoader) {
if (this.useCacheFlag) {
switch (environment) {
case 1:
this.devClassLoader = classLoader;
case 2:
this.testClassLoader = classLoader;
case 3:
this.prodClassLoader = classLoader;
}
}
}
public void updateEnvironmentClassLoader(int environment, GroovyClassLoader parentClassLoader) {
if (this.useCacheFlag) {
if (this.getEnvironmentDatasource(environment) == null) {
return;
}
try {
FancyGroovyClassLoader classLoader = new FancyGroovyClassLoader(parentClassLoader);
CodaConnection connection = this.getEnvironmentDatasource(environment).getDatabase().getConnection();
CodaResultSet rs = connection.runQuery("select table_name, class_file from " + this.getEnvironmentDatasource(environment).getPrefix() + "tables", null);
if (!rs.getErrorStatus()) {
while (rs.next()) {
Class groovyClass = classLoader.parseClass( rs.getData(1));
classLoader.linkClass(groovyClass);
}
}
rs = connection.runQuery("select procedure_name, class_file from " + this.getEnvironmentDatasource(environment).getPrefix() + "procedures", null);
if (!rs.getErrorStatus()) {
while (rs.next()) {
Class groovyClass = classLoader.parseClass( rs.getData(1));
classLoader.linkClass(groovyClass);
}
}
rs = connection.runQuery("select t.table_name, p.before_flag, p.operation_id, fs.verb_status_name, p.class_file from " + this.getEnvironmentDatasource(environment).getPrefix() + "triggers p inner join " + this.getEnvironmentDatasource(environment).getPrefix() + "tables t on t.id = p.table_id left outer join " + this.getEnvironmentDatasource(environment).getPrefix() + "form_statuses fs on fs.id = p.form_status_id", null);
if (!rs.getErrorStatus()) {
while (rs.next()) {
Class groovyClass = classLoader.parseClass( rs.getData(4));
classLoader.linkClass(groovyClass);
}
}
this.setEnvironmentClassLoader( environment, classLoader);
} catch (Exception e) {
this.logger.log(Level.WARNING, this.getApplicationName() + ": Unable to connect to environment " + environment + " when getting class loader");
}
}
}
public void loadClassInEnvironment(int environment, String className, String classBytes) {
if (this.useCacheFlag) {
Class groovyClass = this.getEnvironmentClassLoader(environment, null).parseClass(classBytes);
this.getEnvironmentClassLoader(environment, null).linkClass(groovyClass);
}
}
public boolean runTrigger (ExecutionContext context, String tableName, String operationName, boolean beforeFlag, Database executingDatabase, Hashtable<String,String> nextHashtable, Hashtable<String, String> prevHashtable) throws ClassNotFoundException, IllegalAccessException, InstantiationException, CodaException {
GroovyClassLoader executingClassLoader = context.getClassLoader();
if (executingClassLoader == null) {
return false;
} else {
BaseCodaTrigger trigger;
try {
Class triggerClass = executingClassLoader.loadClass("org.codalang.codaserver.language.triggers." + CodaServer.camelCapitalize(tableName, true) + CodaServer.camelCapitalize(beforeFlag ? "before" : "after", true) + CodaServer.camelCapitalize(operationName, true));
trigger = (BaseCodaTrigger) triggerClass.newInstance();
} catch (Exception e) {
return false;
}
Class tableClass = executingClassLoader.loadClass("org.codalang.codaserver.language.tables." + CodaServer.camelCapitalize(tableName, true));
BaseCodaTable next = (BaseCodaTable) tableClass.newInstance();
next.setFields(nextHashtable);
BaseCodaTable prev = (BaseCodaTable) tableClass.newInstance();
if (prevHashtable != null)
prev.setFields(prevHashtable);
try {
trigger.fire(executingDatabase, next, prev);
} catch (Exception ex) {
int i = 0;
} catch (Error er) {
int i = 0;
}
}
return true;
}
}