Java tutorial
package pt.iflow.flows; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.sql.DataSource; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringUtils; import org.exolab.castor.xml.MarshalException; import org.exolab.castor.xml.ValidationException; import pt.iflow.api.core.AdministrationFlowScheduleInterface; import pt.iflow.api.core.BeanFactory; import pt.iflow.api.core.ProcessCatalogue; import pt.iflow.api.core.ProcessManager; import pt.iflow.api.db.DBQueryManager; import pt.iflow.api.db.DatabaseInterface; import pt.iflow.api.flowSchedule.FlowScheduleDataInterface; import pt.iflow.api.flows.Flow; import pt.iflow.api.flows.FlowDeployListener; import pt.iflow.api.flows.FlowHolder; import pt.iflow.api.flows.FlowSetting; import pt.iflow.api.flows.FlowSettings; import pt.iflow.api.flows.FlowTemplate; import pt.iflow.api.flows.FlowType; import pt.iflow.api.flows.FlowVersionListener; import pt.iflow.api.flows.IFlowData; import pt.iflow.api.flows.NewFlowListener; import pt.iflow.api.licensing.LicenseService; import pt.iflow.api.licensing.LicenseServiceException; import pt.iflow.api.licensing.LicenseServiceFactory; import pt.iflow.api.presentation.DateUtility; import pt.iflow.api.utils.Const; import pt.iflow.api.utils.Logger; import pt.iflow.api.utils.UserInfoInterface; import pt.iflow.api.utils.Utils; import pt.iflow.api.xml.FlowMarshaller; import pt.iflow.api.xml.codegen.flow.XmlAttribute; import pt.iflow.api.xml.codegen.flow.XmlBlock; import pt.iflow.api.xml.codegen.flow.XmlCatalogVarAttribute; import pt.iflow.api.xml.codegen.flow.XmlFlow; import pt.iknow.utils.security.SecurityException; /** * * Flow resource manager/loader/"cache" * * @author oscar * */ public class FlowHolderBean implements FlowHolder { private static final int MAX_COMMENT_SIZE = 512; // KEY: flowid(Integer) | VALUE: data (FlowData) final private HashMap<String, Map<Integer, FlowData>> _hmFlowData = new HashMap<String, Map<Integer, FlowData>>(); // KEY: flowid(Integer) | VALUE: date (java.util.Date) final private HashMap<Integer, Date> _hmFlowBuildDate = new HashMap<Integer, Date>(); // used in Logger methods private static FlowHolder instance = null; private Map<String, NewFlowListener> newflowListeners = Collections .synchronizedMap(new HashMap<String, NewFlowListener>()); private Map<String, FlowDeployListener> deploylisteners = Collections .synchronizedMap(new HashMap<String, FlowDeployListener>()); private Map<String, FlowVersionListener> versionlisteners = Collections .synchronizedMap(new HashMap<String, FlowVersionListener>()); public static FlowHolder getInstance() { if (null == instance) instance = new FlowHolderBean(); return instance; } // wait 5 seconds between flow building to avoid infinite looping private static final long BUILD_WAIT = (long) (1000 * 5); // Flow filtering codes private static final int nLIST_ALL = 0; private static final int nLIST_ONLINE = 1; private static final int nLIST_OFFLINE = 2; // aux methods /** * Read every byte from input stream and return as a byte array * * @param is * Data input stream * @return byte array */ private static byte[] getBytes(InputStream is) throws IOException { if (is == null) return null; ByteArrayOutputStream bout = new ByteArrayOutputStream(); byte[] b = new byte[8092]; int r; while ((r = is.read(b)) != -1) bout.write(b, 0, r); is.close(); return bout.toByteArray(); } private static final class State { /** * Flow ID number */ int flowid; /** * Flow was created */ boolean created; /** * Everything ended successfully */ boolean success; /** * New (or current) version */ int version; } private static final class DBFlow { @SuppressWarnings("unused") int flowid; String organizationId; byte[] data; String name; String file; boolean online; long created; long lastModified; int seriesId; String typeCode; String[] indexFields = new String[Const.INDEX_COLUMN_COUNT]; } // interface methods /** * Check if the flow is online * * @param userInfo * @param flowId * @return true if the flow is marked as online */ public synchronized boolean isOnline(UserInfoInterface userInfo, int flowId) { // check if this flow is cached if (hasCachedFlow(userInfo, flowId)) { // only if the user is the same user IFlowData theFlow = getCachedFlow(userInfo, flowId); return theFlow.isOnline(); } Connection db = null; Statement st = null; ResultSet rs = null; boolean result = false; // check if flow exists in DB and is enabled try { db = Utils.getDataSource().getConnection(); st = db.createStatement(); String stmp = "select organizationid from flow where flowid=" + flowId + " and enabled=1"; rs = st.executeQuery(stmp); if (rs.next()) { if (userInfo.isSysAdmin() || rs.getString("organizationid").equalsIgnoreCase(userInfo.getOrganization()) || BeanFactory.getFlowSettingsBean().isGuestAccessible(userInfo, flowId)) { result = true; } } rs.close(); st.close(); } catch (Exception e) { e.printStackTrace(); } finally { DatabaseInterface.closeResources(db, st, rs); } return result; } /** * Return the flow file name * * @param userInfo * @param flowId * @return Flow file name or null if not found */ public synchronized String getFlowFileName(UserInfoInterface userInfo, int flowId) { // check if this flow is cached if (hasCachedFlow(userInfo, flowId)) { IFlowData theFlow = getCachedFlow(userInfo, flowId); // only if the // user is the // same user return theFlow.getFileName(); } Connection db = null; Statement st = null; ResultSet rs = null; String result = null; // check if flow exists in db and is disabled try { db = Utils.getDataSource().getConnection(); // check if flow exists in db and is disabled st = db.createStatement(); String stmp = "select flowfile from flow where flowid=" + flowId + " and organizationid='" + userInfo.getOrganization() + "'"; rs = st.executeQuery(stmp); if (rs.next()) { result = rs.getString("flowfile"); } rs.close(); st.close(); } catch (Exception e) { e.printStackTrace(); } finally { DatabaseInterface.closeResources(db, st, rs); } return result; } /** * Return a list of all flows available to the user organization. <br> * <em>Do not return template flows!</em> * * @param userInfo * @return */ public IFlowData[] listFlows(UserInfoInterface userInfo) { return listFlows(userInfo, nLIST_ALL, null, null, false); } /** * Return a list of all flows available to the user organization. <br> * <em>Do not return template flows!</em> * * @param userInfo * @return */ public IFlowData[] listFlows(UserInfoInterface userInfo, FlowType type) { return listFlows(userInfo, nLIST_ALL, type, null, false); } /** * Return a list of online flows available to the user organization. <br> * <em>Do not return template flows!</em> * * @param userInfo * @return */ public FlowData[] listFlowsOnline(UserInfoInterface userInfo) { return listFlows(userInfo, nLIST_ONLINE, null, null, false); } /** * Return a list of online flows available to the user organization. <br> * <em>Do not return template flows!</em> * * @param userInfo * @return */ public FlowData[] listFlowsOnline(UserInfoInterface userInfo, FlowType type) { return listFlows(userInfo, nLIST_ONLINE, type, null, false); } public FlowData[] listFlowsOnline(UserInfoInterface userInfo, FlowType type, boolean showOnlyFlowsToBePresentInMenu) { return listFlows(userInfo, nLIST_ONLINE, type, null, showOnlyFlowsToBePresentInMenu); } public IFlowData[] listFlowsOnline(UserInfoInterface userInfo, FlowType type, FlowType[] typeExcluded) { return listFlows(userInfo, nLIST_ONLINE, type, typeExcluded, false); } public IFlowData[] listFlowsOnline(UserInfoInterface userInfo, FlowType type, FlowType[] typeExcluded, boolean showOnlyFlowsToBePresentInMenu) { return listFlows(userInfo, nLIST_ONLINE, type, typeExcluded, showOnlyFlowsToBePresentInMenu); } /** * Return a list of offline flows available to the user organization. <br> * <em>Do not return template flows!</em> * * @param userInfo * @return */ public IFlowData[] listFlowsOffline(UserInfoInterface userInfo) { return listFlows(userInfo, nLIST_OFFLINE, null, null, false); } /** * Return a list of offline flows available to the user organization. <br> * <em>Do not return template flows!</em> * * @param userInfo * @return */ public IFlowData[] listFlowsOffline(UserInfoInterface userInfo, FlowType type) { return listFlows(userInfo, nLIST_OFFLINE, type, null, false); } public IFlowData[] listFlowsOffline(UserInfoInterface userInfo, FlowType type, FlowType[] typeExcluded) { return listFlows(userInfo, nLIST_OFFLINE, type, typeExcluded, false); } private synchronized FlowData[] listFlows(UserInfoInterface userInfo, int anSelection, FlowType type, FlowType[] typeExcluded, boolean showOnlyFlowsToBePresentInMenu) { FlowData[] retObj = new FlowData[] {}; ArrayList<FlowScheduleDataInterface> listOfFlowJobs = new ArrayList<FlowScheduleDataInterface>(); try { AdministrationFlowScheduleInterface adminFlowScheduleBean = BeanFactory .getAdministrationFlowScheduleBean(); listOfFlowJobs = adminFlowScheduleBean.getScheduledFlowsJobs(userInfo, null); // o segundo parametro ao ser null devolve os agendamentos de todos os utilizadores } catch (Exception e) { Logger.error(userInfo.getUtilizador(), this, "listFlows", "Unhindered error", e); } DataSource ds = null; Connection db = null; Statement st = null; ResultSet rs = null; FlowData fd = null; try { ds = Utils.getDataSource(); db = ds.getConnection(); st = db.createStatement(); rs = null; StringBuffer sQuery = new StringBuffer(); sQuery.append("select "); if (showOnlyFlowsToBePresentInMenu) { sQuery.append("Distinct "); } sQuery.append( "F.flowid, F.flowname, F.flowfile, F.enabled, F.organizationid, F.created, F.modified, F.seriesId, F.type_code "); sQuery.append("from flow F"); if (showOnlyFlowsToBePresentInMenu) { sQuery.append(", flow_settings FS"); } sQuery.append(" where organizationid='").append(userInfo.getOrganization()).append("' "); if (anSelection != nLIST_ALL) { sQuery.append("and enabled=").append((anSelection == nLIST_ONLINE ? 1 : 0)); } if (null != type) { sQuery.append(" and type_code='").append(type.getCode()).append("'"); } if (null != typeExcluded) { for (int i = 0; i < typeExcluded.length; i++) { sQuery.append(" and type_code<>'").append(typeExcluded[i].getCode()).append("'"); } } if (showOnlyFlowsToBePresentInMenu) { sQuery.append(" and F.flowid = FS.flowid"); sQuery.append(" and FS.name like '").append(Const.sFLOW_MENU_ACCESSIBLE).append("'"); sQuery.append(" and ("); sQuery.append(" FS.value is null "); sQuery.append(" or "); sQuery.append(" FS.value like '").append(Const.sFLOW_MENU_ACCESSIBLE_YES).append("'"); sQuery.append(" )"); } sQuery.append(" order by F.flowid"); rs = st.executeQuery(sQuery.toString()); ArrayList<FlowData> altmp = new ArrayList<FlowData>(); while (rs.next()) { int flowId = rs.getInt("flowid"); if (hasCachedFlow(userInfo, flowId)) { fd = getCachedFlow(userInfo, flowId); } else { fd = new FlowData(flowId, rs.getString("flowname"), rs.getString("flowfile"), rs.getBoolean("enabled"), rs.getString("organizationid"), rs.getTimestamp("created").getTime(), rs.getTimestamp("modified").getTime(), rs.getInt("seriesId"), rs.getString("type_code")); } try { if (listOfFlowJobs != null && listOfFlowJobs.size() > 0) { for (FlowScheduleDataInterface flowJob : listOfFlowJobs) { if (flowJob.getFlowId() == flowId) { fd.setHasSchedules(true); break; } } } } catch (Exception e) { Logger.error(userInfo.getUtilizador(), this, "listFlows", "Unhindered error", e); } altmp.add(fd); } // while retObj = altmp.toArray(new FlowData[altmp.size()]); } catch (Exception e) { Logger.error(userInfo.getUtilizador(), this, "listFlows", "exception (" + e.getClass().getName() + ") caught: " + e.getMessage(), e); } finally { DatabaseInterface.closeResources(db, st, rs); } return retObj; } /** * Return a list of names of every flow available to the user. <br> * <em>This method returns template flow names!</em> * * @param userInfo * @return */ public String[] listFlowNames(UserInfoInterface userInfo) { return listFlowNames(userInfo, nLIST_ALL); } /** * Return a list of names of online flows available to the user. <br> * <em>This method returns template flow names!</em> * * @param userInfo * @return */ public String[] listFlowNamesOnline(UserInfoInterface userInfo) { return listFlowNames(userInfo, nLIST_ONLINE); } /** * Return a list of names of offline flows available to the user. <br> * <em>This method returns template flow names!</em> * * @param userInfo * @return */ public String[] listFlowNamesOffline(UserInfoInterface userInfo) { return listFlowNames(userInfo, nLIST_OFFLINE); } private synchronized String[] listFlowNames(UserInfoInterface userInfo, int anSelection) { String[] retObj = null; DataSource ds = null; Connection db = null; Statement st = null; ResultSet rs = null; try { ds = Utils.getDataSource(); db = ds.getConnection(); st = db.createStatement(); rs = null; // return every flowfile in orgnaizationid. Union will remove // duplicates (according to SQL specs) final String allOrgFlows = "select flowfile from flow where organizationid='" + userInfo.getOrganization() + "' UNION select name as flowfile from flow_template"; // return all online names. templates are never online final String onlineOrgFlows = "select flowfile from flow where organizationid='" + userInfo.getOrganization() + "' and enabled=1"; // return every disabled flowfile in orgnaizationid. The unioned // query will exclude all org flows so it will not list an online // flow as offline final String offlineOrgFlows = "select flowfile from flow where organizationid='" + userInfo.getOrganization() + "' and enabled=0 UNION select name as flowfile from flow_template where name not in (select flowfile from flow where organizationid='" + userInfo.getOrganization() + "')"; String query; if (anSelection == nLIST_OFFLINE) query = offlineOrgFlows; else if (anSelection == nLIST_ONLINE) query = onlineOrgFlows; else query = allOrgFlows; rs = st.executeQuery(query); ArrayList<String> altmp = new ArrayList<String>(); while (rs.next()) { altmp.add(rs.getString("flowfile")); } // while retObj = altmp.toArray(new String[altmp.size()]); } catch (Exception e) { Logger.error(userInfo.getUtilizador(), this, "listFlowNames", "exception (" + e.getClass().getName() + ") caught: " + e.getMessage(), e); } finally { DatabaseInterface.closeResources(db, st, rs); } return retObj; } /** * Return a list of names of every sub flow available to the user. <br> * <em>This method returns template flow names!</em> * * @param userInfo * @return */ public synchronized String[] listSubFlows(UserInfoInterface userInfo) { Connection db = null; PreparedStatement pst = null; ResultSet rs = null; String[] flows = null; try { db = Utils.getDataSource().getConnection(); pst = db.prepareStatement( "SELECT flowfile FROM sub_flow WHERE organizationid=? UNION SELECT name as flowfile from sub_flow_template"); // 1st read user flow pst.setString(1, userInfo.getOrganization()); rs = pst.executeQuery(); ArrayList<String> lst = new ArrayList<String>(); while (rs.next()) { lst.add(rs.getString(1)); } flows = lst.toArray(new String[lst.size()]); } catch (Exception e) { Logger.error(userInfo.getUtilizador(), this, "listSubFlows", "exception (" + e.getClass().getName() + ") caught: " + e.getMessage(), e); } finally { DatabaseInterface.closeResources(db, pst, rs); } return flows; } /** * Get the XML contents of the named flow. * * If the requested name is a flow template, return template contents. * * <br> * <em>This method will not create a new flow!</em> * * @param userInfo * @param name * file name * @return XML bytes */ public synchronized byte[] readFlowData(UserInfoInterface userInfo, String name) { return readData(userInfo, name, true, -1); } /** * Get the XML contents of the named sub flow. * * If the requested name is a sub flow template, return template contents. * * <br> * <em>This method will not create a new sub flow!</em> * * @param userInfo * @param name * file name * @return XML bytes */ public synchronized byte[] readSubFlowData(UserInfoInterface userInfo, String name) { return readData(userInfo, name, false, -1); } /** * Create or update a flow. <br> * The user must be organization administrator in order to create/update a * flow. <br> * <br> * If the flow is already online, it will be redeployed. * * @param userInfo * @param file * @param name * Used in flow creation. If null, assumes name=file. * @param data * @return updated/created flow id or -1 if an error occured */ public int writeFlowData(UserInfoInterface userInfo, String file, String name, byte[] data) { return writeFlowData(userInfo, file, name, data, false, null); } /** * Create or update a flow. <br> * The user must be organization administrator in order to create/update a * flow. <br> * <br> * If the flow is already online, it will be redeployed. * * @param userInfo * @param file * @param name * Used in flow creation. If null, assumes name=file. * @param data * @return updated/created flow id or -1 if an error occured */ public int writeFlowData(UserInfoInterface userInfo, String file, String name, byte[] data, String comment) { return writeFlowData(userInfo, file, name, data, true, comment); } private synchronized int writeFlowData(UserInfoInterface userInfo, String file, String name, byte[] data, boolean newVersion, String comment) { if (!userInfo.isOrgAdmin()) { Logger.debug(userInfo.getUtilizador(), this, "writeFlowData", "No Adm privilege!!"); return -1; } if (data == null) return -1; State result = insertOrUpdateFlow(userInfo, file, name, data, true, newVersion, comment); if (result.success && !result.created && hasCachedFlow(userInfo, result.flowid)) { IFlowData fd = getCachedFlow(userInfo, result.flowid); if (fd.isDeployed()) { refreshFlow(userInfo, result.flowid); notifyVersion(userInfo, result.flowid); } } return result.flowid; } private synchronized State insertOrUpdateFlow(UserInfoInterface userInfo, String file, String name, byte[] data, boolean forceCreate, boolean makeVersion, String comment) { // recorrer a um metodo privado para efectuar a actualizacao // propriamente dita. // Esse mesmo metodo sera usado pelo deploy no caso de ser necessario // actualizar o catalogo. State result = new State(); Connection db = null; PreparedStatement pst = null; ResultSet rs = null; boolean flowFound = false; int flowid = -1; try { db = Utils.getDataSource().getConnection(); db.setAutoCommit(false); String query = "select flowid,flowversion from flow where flowfile=? and organizationid=?"; Logger.debug(userInfo.getUtilizador(), this, "insertOrUpdateFlow", "Query1: " + query); pst = db.prepareStatement(query); pst.setString(1, file); pst.setString(2, userInfo.getOrganization()); rs = pst.executeQuery(); if (rs.next()) { flowFound = true; flowid = rs.getInt("flowid"); result.version = rs.getInt("flowversion"); } Logger.debug(userInfo.getUtilizador(), this, "insertOrUpdateFlow", "Flow exists " + flowFound + "id: " + flowid + "; version " + result.version); rs.close(); pst.close(); boolean copyToHistory = false; if (flowFound) { int arg = 0; query = "update flow set " + (StringUtils.isNotEmpty(name) ? "flowname=?," : "") + "flowdata=?," + (makeVersion ? "flowversion=flowversion+1," : "") + "modified=? where flowid=?"; Logger.debug(userInfo.getUtilizador(), this, "insertOrUpdateFlow", "Query2a: " + query); pst = db.prepareStatement(query); if (StringUtils.isNotEmpty(name)) pst.setString(++arg, name); pst.setBinaryStream(++arg, new ByteArrayInputStream(data), data.length); pst.setTimestamp(++arg, new Timestamp(System.currentTimeMillis())); pst.setInt(++arg, flowid); int upd = pst.executeUpdate(); pst.close(); result.created = false; copyToHistory = (upd != 0); } else if (forceCreate) { if (null == name) name = file; Timestamp now = new Timestamp(System.currentTimeMillis()); query = DBQueryManager.getQuery("FlowHolder.INSERT_FLOW"); Logger.debug(userInfo.getUtilizador(), this, "insertOrUpdateFlow", "Query2b: " + query); pst = db.prepareStatement(query, new String[] { "flowid" }); pst.setString(1, name); pst.setString(2, file); pst.setTimestamp(3, now); pst.setString(4, userInfo.getOrganization()); pst.setBinaryStream(5, new ByteArrayInputStream(data), data.length); pst.setTimestamp(6, now); pst.executeUpdate(); rs = pst.getGeneratedKeys(); if (rs.next()) { result.version = 1; result.created = true; flowid = rs.getInt(1); copyToHistory = true; } rs.close(); pst.close(); notifyNewFlow(userInfo, flowid); } else { throw new Exception("Cannot create flow."); } if (copyToHistory && makeVersion) { if (null != comment && comment.length() > MAX_COMMENT_SIZE) comment = comment.substring(0, MAX_COMMENT_SIZE); query = DBQueryManager.getQuery("FlowHolder.COPY_FLOW_TO_HISTORY"); Logger.debug(userInfo.getUtilizador(), this, "insertOrUpdateFlow", "Query3: " + query); pst = db.prepareStatement(query); pst.setString(1, comment); pst.setInt(2, flowid); pst.executeUpdate(); pst.close(); result.version++; } db.commit(); result.success = true; } catch (Exception e) { try { db.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); result.success = false; } finally { DatabaseInterface.closeResources(db, pst, rs); } result.flowid = flowid; return result; } public synchronized int writeSubFlowData(UserInfoInterface userInfo, String file, String name, byte[] data) { if (!userInfo.isOrgAdmin()) { Logger.debug(userInfo.getUtilizador(), this, "writeSubFlowData", "No Adm privilege!!"); return -1; } if (data == null) { return -1; } if (existsFlowWithSameVariable(userInfo, name, data)) { return -2; } State result = insertOrUpdateSubFlow(userInfo, file, name, data, true, false, null); if (result.success && !result.created) { // a subflow was updated. // redeploy deployed flows... Iterator<FlowData> iter = getCachedFlows(userInfo).iterator(); while (iter.hasNext()) { IFlowData flow = (IFlowData) iter.next(); if (flow.getOrganizationId().equals(userInfo.getOrganization()) && flow.isDeployed()) refreshFlow(userInfo, flow.getId()); } } return result.flowid; } private boolean existsFlowWithSameVariable(UserInfoInterface userInfo, String subFlowName, byte[] subFlowData) { XmlFlow subFlow = null; try { subFlow = FlowMarshaller.unmarshal(subFlowData); } catch (Exception e1) { } IFlowData[] allFlowData = this.listFlows(userInfo); for (IFlowData flowData : allFlowData) { DBFlow dbFlow = readFlow(userInfo, flowData.getId()); try { XmlFlow flow = FlowMarshaller.unmarshal(dbFlow.data); for (XmlBlock xmlBlock : flow.getXmlBlock()) { if (xmlBlock.getType().equals("BlockSubFlow")) { for (XmlAttribute xmlAttribute : xmlBlock.getXmlAttribute()) { if (xmlAttribute.getName().equals("MNome do SubFluxo") && xmlAttribute.getValue().equals(subFlowName)) { for (XmlCatalogVarAttribute xmlCatalogueVar : flow.getXmlCatalogVars() .getXmlCatalogVarAttribute()) { for (XmlCatalogVarAttribute xmlCatalogueVarSub : subFlow.getXmlCatalogVars() .getXmlCatalogVarAttribute()) { if (xmlCatalogueVar.getName().equals(xmlCatalogueVarSub.getName()) && !isVarMappedToSubflow(xmlCatalogueVar.getName(), xmlCatalogueVarSub.getName(), xmlBlock)) { Logger.error(userInfo.getUtilizador(), this, "uploadSubFlow", " exception caught: " + "In MainFlow" + flow.getName() + " variables with the same name must be mapped one to the other! Main:" + xmlCatalogueVar.getName() + " Sub:" + xmlCatalogueVarSub.getName()); return true; } } } } } } } } catch (MarshalException e) { Logger.debug(userInfo.getUtilizador(), this, "writeSubFlowData", "MarshalException in flow " + flowData.getName()); } catch (ValidationException e) { Logger.debug(userInfo.getUtilizador(), this, "writeSubFlowData", "ValidationException in flow " + flowData.getName()); } } return false; } private boolean isVarMappedToSubflow(String flowVarName, String subFlowVarName, XmlBlock subFlowXmlBlock) { String[][] saInVars = SubFlowDataExpander.retrieveSubflowVarMappings(subFlowXmlBlock); for (int in = 0; in < saInVars.length; in++) { if (saInVars[in][SubFlowDataExpander.FLOW].equals(flowVarName) && saInVars[in][SubFlowDataExpander.SUBFLOW].equals(subFlowVarName)) return true; else if (saInVars[in][SubFlowDataExpander.FLOW].equals("") && saInVars[in][SubFlowDataExpander.SUBFLOW].equals(subFlowVarName)) return true; } return false; } public synchronized int writeSubFlowData(UserInfoInterface userInfo, String file, String name, byte[] data, String comment) { if (!userInfo.isOrgAdmin()) { Logger.debug(userInfo.getUtilizador(), this, "writeSubFlowData", "No Adm privilege!!"); return -1; } if (data == null) { return -1; } if (existsFlowWithSameVariable(userInfo, name, data)) { return -2; } State result = insertOrUpdateSubFlow(userInfo, file, name, data, true, true, comment); if (result.success && !result.created) { // a subflow was updated. // redeploy deployed flows... Iterator<FlowData> iter = getCachedFlows(userInfo).iterator(); while (iter.hasNext()) { IFlowData flow = (IFlowData) iter.next(); if (flow.getOrganizationId().equals(userInfo.getOrganization()) && flow.isDeployed()) refreshFlow(userInfo, flow.getId()); } } return result.flowid; } private synchronized State insertOrUpdateSubFlow(UserInfoInterface userInfo, String file, String name, byte[] data, boolean forceCreate, boolean makeVersion, String comment) { // recorrer a um metodo privado para efectuar a actualizacao // propriamente dita. // Esse mesmo metodo sera usado pelo deploy no caso de ser necessario // actualizar o catalogo. State result = new State(); Connection db = null; PreparedStatement pst = null; ResultSet rs = null; boolean flowFound = false; int flowid = -1; try { db = Utils.getDataSource().getConnection(); db.setAutoCommit(false); String query = "select flowid,flowversion from sub_flow where flowfile=? and organizationid=?"; Logger.debug(userInfo.getUtilizador(), this, "insertOrUpdateSubFlow", "Query1: " + query); pst = db.prepareStatement(query); pst.setString(1, file); pst.setString(2, userInfo.getOrganization()); rs = pst.executeQuery(); if (rs.next()) { flowFound = true; flowid = rs.getInt("flowid"); result.version = rs.getInt("flowversion"); } rs.close(); pst.close(); boolean copyToHistory = false; if (flowFound) { query = "update sub_flow set flowdata=?," + (makeVersion ? "flowversion=flowversion+1," : "") + "modified=? where flowid=?"; Logger.debug(userInfo.getUtilizador(), this, "insertOrUpdateSubFlow", "Query2a: " + query); pst = db.prepareStatement(query); pst.setBinaryStream(1, new ByteArrayInputStream(data), data.length); pst.setTimestamp(2, new Timestamp(System.currentTimeMillis())); pst.setInt(3, flowid); int upd = pst.executeUpdate(); pst.close(); result.created = false; copyToHistory = (upd != 0); } else if (forceCreate) { if (null == name) name = file; Timestamp now = new Timestamp(System.currentTimeMillis()); query = DBQueryManager.getQuery("FlowHolder.INSERT_SUBFLOW"); Logger.debug(userInfo.getUtilizador(), this, "insertOrUpdateSubFlow", "Query2b: " + query); pst = db.prepareStatement(query, new String[] { "flowid" }); pst.setString(1, name); pst.setString(2, file); pst.setTimestamp(3, now); pst.setString(4, userInfo.getOrganization()); pst.setBinaryStream(5, new ByteArrayInputStream(data), data.length); pst.setTimestamp(6, now); pst.executeUpdate(); rs = pst.getGeneratedKeys(); if (rs.next()) { result.created = true; flowid = rs.getInt(1); copyToHistory = true; } rs.close(); pst.close(); } else { throw new Exception("Cannot create sub flow."); } // Copy to flow history. if (copyToHistory && makeVersion) { if (null != comment && comment.length() > MAX_COMMENT_SIZE) comment = comment.substring(0, MAX_COMMENT_SIZE); query = DBQueryManager.getQuery("FlowHolder.COPY_SUB_FLOW_TO_HISTORY"); Logger.debug(userInfo.getUtilizador(), this, "insertOrUpdateSubFlow", "Query3: " + query); pst = db.prepareStatement(query); pst.setString(1, comment); pst.setInt(2, flowid); pst.executeUpdate(); pst.close(); result.version++; } db.commit(); result.success = true; } catch (Exception e) { try { db.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); result.success = false; } finally { DatabaseInterface.closeResources(db, pst, rs); } result.flowid = flowid; return result; } /** * Return a flow from the flow cache or create a new one if necessary. * * @param userInfo * @param flowId * @return */ public synchronized FlowData getFlow(UserInfoInterface userInfo, int flowId) { return getFlow(userInfo, flowId, true); } /** * Return a flow from the flow cache or create a new one if necessary. * * @param userInfo * @param flowId * @return */ public synchronized FlowData getFlow(UserInfoInterface userInfo, int flowId, boolean create) { FlowData fd = null; if (hasCachedFlow(userInfo, flowId)) { fd = getCachedFlow(userInfo, flowId); if (!create) return fd; else { if (fd.isDeployed()) return fd; // if it is deployed, return. } } try { fd = buildFlowData(userInfo, flowId, create); } catch (FlowSecurityException e) { Logger.error(userInfo.getUtilizador(), this, "getFlow", "Error building flow id = " + flowId + " returning customized flowdata"); fd = e.getFlowData(); } catch (Throwable t) { t.printStackTrace(); } if (null == fd) { Logger.error(userInfo.getUtilizador(), this, "getFlow", "Build a null flow for flow id = " + flowId); } else { setCachedFlow(userInfo, fd); } return fd; } private synchronized FlowData buildFlowData(UserInfoInterface userInfo, int flowId, boolean deploy) throws FlowSecurityException { // TODO externalize this // Messages msg = Messages.getInstance(BeanFactory.getSettingsBean() // .getOrganizationLocale(userInfo.getOrganization())); String fileName = null; XmlFlow flow = null; FlowData fd = null; LicenseService licService = LicenseServiceFactory.getLicenseService(); try { // first check if timewait period has already passed if (deploy && buildDateNotOk(userInfo, flowId)) { Logger.error(userInfo.getUtilizador(), this, "buildFlow", "Trying to build flow " + flowId + " during timewait build period. returning..."); return null; } DBFlow dbFlow = readFlow(userInfo, flowId); if (null == dbFlow) { Logger.error(userInfo.getUtilizador(), this, "buildFlow", "ReadFlow return null for flowid " + flowId); return null; } fileName = dbFlow.file; if (deploy && dbFlow.online) { // Se o fluxo esta offline nao ha problema. boolean flowsOk = false; try { licService.canInstantiateFlows(userInfo, getCachedFlows(userInfo).size()); flowsOk = true; } catch (LicenseServiceException e) { Logger.debug(userInfo.getUtilizador(), this, "buildFlow", "a LicenseServiceException was captured."); } if (!flowsOk) { // FIXME est errado Logger.warning(userInfo.getUtilizador(), this, "buildFlow", "Maximum number of deployed flows exceeded"); fd = new FlowData(flowId, dbFlow.name, dbFlow.file, dbFlow.online, dbFlow.organizationId, dbFlow.created, dbFlow.lastModified, dbFlow.seriesId, dbFlow.typeCode); fd.setError("Maximum number of deployed flows exceeded"); throw new MaximumFlowsException(fd); } else { Logger.info(userInfo.getUtilizador(), this, "buildFlow", "Number of flows accepted. (" + getCachedFlows(userInfo).size() + ")"); } } if (dbFlow.data.length > 0) { Logger.debug(userInfo.getUtilizador(), this, "buildFlow", "Instantiating flow " + fileName + " (ID=" + flowId + ")"); flow = FlowMarshaller.unmarshal(dbFlow.data); Logger.debug(userInfo.getUtilizador(), this, "buildFlow", "Flow name = " + flow.getName()); Logger.debug(userInfo.getUtilizador(), this, "buildFlow", "Flow version = " + flow.getVersion()); Logger.debug(userInfo.getUtilizador(), this, "buildFlow", "Flow author = " + flow.getAuthor()); Logger.debug(userInfo.getUtilizador(), this, "buildFlow", "Flow description = " + flow.getDescription()); Logger.debug(userInfo.getUtilizador(), this, "buildFlow", "Total Number of Blocks read = " + flow.getXmlBlockCount()); //Resolve subflows inside the main flow SubFlowDataExpander subFlowDataExpander = new SubFlowDataExpander(flow, new Integer(flowId)); List<SubFlowMapping> subFlowBlockMappings = subFlowDataExpander.expandSubFlow(userInfo); // Resolve form templates FormTemplateResolver formTemplateResolver = new FormTemplateResolver(flow); flow = formTemplateResolver.resolveTemplates(userInfo); if (deploy) { XmlBlock block = null; for (int b = 0; b < flow.getXmlBlockCount(); b++) { block = flow.getXmlBlock(b); Logger.debug(userInfo.getUtilizador(), this, "buildFlow", "Block Name is " + block.getName()); } } String description = flow.getDescription(); // backward compatibility. Older versions use "--" as // description if (StringUtils.isEmpty(description) || "--".equals(description)) description = flow.getName(); fd = new FlowData(userInfo, flowId, description, fileName, dbFlow.created, dbFlow.lastModified, dbFlow.seriesId, dbFlow.typeCode, flow, deploy); fd.setOrganizationId(dbFlow.organizationId); if (deploy) { reindexFlow(userInfo, fd); if (fd.hasError()) { Logger.error(userInfo.getUtilizador(), this, "buildFlow", "FlowData object NOT Constructed"); } else { // verificar num blocos no fd.. se > que permitido, faz // reset ao fd e lanca excepcao! boolean blocksOk = false; try { licService.canInstantiateFlowBlocks(userInfo, fd.getFlow().size()); blocksOk = true; } catch (LicenseServiceException e) { Logger.debug(userInfo.getUtilizador(), this, "buildFlow", "a LicenseServiceException was captured."); } if (!blocksOk) { Logger.warning(userInfo.getUtilizador(), this, "buildFlow", "Maximum number of flow blocks exceeded"); clearCachedFlow(userInfo, flowId); fd = new FlowData(flowId, description, fileName, dbFlow.online, dbFlow.organizationId, dbFlow.created, dbFlow.lastModified, dbFlow.seriesId, dbFlow.typeCode); fd.setError("Maximum number of flow blocks exceeded"); throw new MaximumBlocksException(fd); } else { Logger.debug(userInfo.getUtilizador(), this, "buildFlow", "Number of blocks accepted. (" + fd.getFlow().size() + ")"); } Logger.debug(userInfo.getUtilizador(), this, "buildFlow", "FlowData object Constructed"); fd.setOnline(dbFlow.online); // now going for settings save FlowSettings settingsBean = BeanFactory.getFlowSettingsBean(); FlowSetting[] fsa = settingsBean.getFlowSettings(userInfo, flowId); settingsBean.saveFlowSettings(userInfo, fsa); Logger.debug(userInfo.getUtilizador(), this, "buildFlow", "Settings saved"); //saving max blockID and subflow mapping if they exist - useful for auditing subflows saveSubFlowExpansionResult(subFlowBlockMappings, subFlowDataExpander.findMaxblockId(), flowId, userInfo); resyncDeployedFlowWithSubFlow(userInfo, subFlowBlockMappings, flowId, fd); } setBuildDate(userInfo, flowId); } } else { // No data in flow... fd = new FlowData(flowId, dbFlow.name, dbFlow.file, dbFlow.online, dbFlow.organizationId, dbFlow.created, dbFlow.lastModified, dbFlow.seriesId, dbFlow.typeCode); } } catch (Exception e) { Logger.error(userInfo.getUtilizador(), this, "buildFlow", "exception caught: " + e.getMessage()); if (e instanceof FlowSecurityException) { throw (FlowSecurityException) e; } } return fd; } /** * Resync the state of this flow if necessary due to changes in it's subflows, must be done after saveSubFlowExpansionResult * * @param userInfo * @param procData * @param flowId * @param fd * @throws Exception */ private void resyncDeployedFlowWithSubFlow(UserInfoInterface userInfo, List<SubFlowMapping> subFlowBlockMappings, int flowId, FlowData fd) throws Exception { if (subFlowBlockMappings.size() == 0) return; Connection db = null; PreparedStatement pst = null; Flow flowBean = BeanFactory.getFlowBean(); List<Integer> oldOriginalBlockId = new ArrayList<Integer>(), oldMappedBlockId = new ArrayList<Integer>(); List<String> subFlowName = new ArrayList<String>(); try { db = Utils.getDataSource().getConnection(); pst = db.prepareStatement( "select original_blockid, sub_flowname, bm.mapped_blockid from iflow.subflow_block_mapping bm, iflow.flow_state fs " + "where bm.flowname=? and fs.flowid = ? and fs.state = bm.mapped_blockid " + "and bm.created=(select max(created) from iflow.subflow_block_mapping where flowname=? and created<(select max(created) from iflow.subflow_block_mapping where flowname=?))"); pst.setString(1, subFlowBlockMappings.get(0).getMainFlowName()); pst.setInt(2, flowId); pst.setString(3, subFlowBlockMappings.get(0).getMainFlowName()); pst.setString(4, subFlowBlockMappings.get(0).getMainFlowName()); ResultSet rst = pst.executeQuery(); while (rst.next()) { oldOriginalBlockId.add(rst.getInt(1)); subFlowName.add(rst.getString(2)); oldMappedBlockId.add(rst.getInt(3)); } } catch (Exception e) { Logger.error(userInfo.getUtilizador(), this, "resyncDeployedFlowWithSubFlow", "exception caught", e); e.printStackTrace(); } finally { DatabaseInterface.closeResources(db, pst); } for (int i = 0; i < oldOriginalBlockId.size(); i++) { Integer newOriginalBlockId = null; for (SubFlowMapping mapping : subFlowBlockMappings) if (mapping.getMappedBlockId() == oldMappedBlockId.get(i)) { newOriginalBlockId = mapping.getOriginalBlockId(); break; } if (newOriginalBlockId != null && oldOriginalBlockId.get(i) != newOriginalBlockId) { Integer newMappedBlockIdState = null; for (SubFlowMapping mapping : subFlowBlockMappings) if (mapping.getOriginalBlockId() == oldOriginalBlockId.get(i) && mapping.getSubFlowName().equals(subFlowName.get(i))) { newMappedBlockIdState = mapping.getMappedBlockId(); break; } if (newMappedBlockIdState == null) { Logger.error(userInfo.getUtilizador(), this, "resyncDeployedFlowWithSubFlow", "invalid state to resync"); throw new Exception("resyncDeployedFlowWithSubFlow, invalid state to resync"); } flowBean.resyncFlow(userInfo, flowId, oldMappedBlockId.get(i), newMappedBlockIdState, true, fd); } } } private void saveSubFlowExpansionResult(List<SubFlowMapping> subFlowBlockMappings, Integer maxblockId, int flowId, UserInfoInterface userInfo) { if (subFlowBlockMappings.size() == 0) return; Connection db = null; PreparedStatement pst = null; try { db = Utils.getDataSource().getConnection(); pst = db.prepareStatement("UPDATE flow SET max_block_id = ? WHERE flowid=?"); pst.setInt(1, maxblockId); pst.setInt(2, flowId); pst.execute(); // check if mappings have changed before saving them Boolean mappingsChanged = false; pst = db.prepareStatement( "select flowname, sub_flowname, original_blockid, mapped_blockid from iflow.subflow_block_mapping " + "bm where bm.flowname=? and bm.created=(select max(created) from iflow.subflow_block_mapping where flowname=?) order by id"); pst.setString(1, subFlowBlockMappings.get(0).getMainFlowName()); pst.setString(2, subFlowBlockMappings.get(0).getMainFlowName()); ResultSet rs = pst.executeQuery(); for (SubFlowMapping subFlowMapping : subFlowBlockMappings) { if (!rs.next()) { mappingsChanged = true; break; } if (!rs.getString(2).equals(subFlowMapping.getSubFlowName()) || !rs.getString(3).equals("" + subFlowMapping.getOriginalBlockId()) || !rs.getString(4).equals("" + subFlowMapping.getMappedBlockId())) mappingsChanged = true; } if (rs.next()) mappingsChanged = true; if (mappingsChanged) { Timestamp d = new Timestamp(new Date().getTime()); for (SubFlowMapping subFlowMapping : subFlowBlockMappings) { pst = db.prepareStatement( "INSERT INTO subflow_block_mapping (created,flowname, sub_flowname, original_blockid, mapped_blockid) VALUES(?,?,?,?,?)"); pst.setTimestamp(1, d); pst.setString(2, subFlowMapping.getMainFlowName()); pst.setString(3, subFlowMapping.getSubFlowName()); pst.setInt(4, subFlowMapping.getOriginalBlockId()); pst.setInt(5, subFlowMapping.getMappedBlockId()); pst.execute(); } } } catch (Exception e) { Logger.error(userInfo.getUtilizador(), this, "readFlow", "exception caught", e); e.printStackTrace(); } finally { DatabaseInterface.closeResources(db, pst); } } private DBFlow readFlow(UserInfoInterface userInfo, int flowId) { Connection db = null; PreparedStatement pst = null; ResultSet rs = null; DBFlow flow = null; try { db = Utils.getDataSource().getConnection(); pst = db.prepareStatement("SELECT * FROM flow WHERE flowid=?"); // 1st read user flow pst.setInt(1, flowId); rs = pst.executeQuery(); if (rs.next()) { // flow exists if (userInfo.isSysAdmin() || rs.getString("organizationid").equals(userInfo.getOrganization()) || BeanFactory.getFlowSettingsBean().isGuestAccessible(userInfo, flowId)) { flow = new DBFlow(); flow.flowid = rs.getInt("flowid"); flow.organizationId = rs.getString("organizationid"); // use db orgid, since sysadmin can perform actions with flows flow.file = rs.getString("flowfile"); flow.name = rs.getString("flowname"); flow.online = rs.getBoolean("enabled"); InputStream is = rs.getBinaryStream("flowdata"); flow.data = getBytes(is); flow.created = rs.getTimestamp("created").getTime(); flow.lastModified = rs.getTimestamp("modified").getTime(); for (int i = 0; i < Const.INDEX_COLUMN_COUNT; i++) flow.indexFields[i] = rs.getString("name_idx" + i); flow.seriesId = rs.getInt("seriesid"); flow.typeCode = rs.getString("type_code"); is.close(); } } rs.close(); } catch (Exception e) { Logger.error(userInfo.getUtilizador(), this, "readFlow", "exception caught", e); e.printStackTrace(); } finally { DatabaseInterface.closeResources(db, pst, rs); } return flow; } /** * Reread flow data from DB * * @param userInfo * @param anFlowId * @return */ public synchronized FlowData refreshFlow(UserInfoInterface userInfo, int flowId) { clearCachedFlow(userInfo, flowId); return getFlow(userInfo, flowId); } /** * Instantiate a new Flow from FlowData. <br> * A new flow will be created from a template if necessary. * * @param userInfo * @param fileName * flow file name * @return null if OK, otherwise error occurred */ public synchronized String deployFlow(UserInfoInterface userInfo, String fileName) { String retObj = null; int flowId = -1; String sLogin = userInfo.getUtilizador(); Logger.trace(this, "deployFlow", sLogin + " call for file " + fileName); Connection db = null; Statement st = null; PreparedStatement pst = null; ResultSet rs = null; boolean found = false; try { db = Utils.getDataSource().getConnection(); db.setAutoCommit(false); pst = db.prepareStatement("select flowid from flow where flowfile=? and organizationid=?"); pst.setString(1, fileName); pst.setString(2, userInfo.getOrganization()); rs = pst.executeQuery(); if (rs.next()) { found = true; flowId = rs.getInt("flowid"); } rs.close(); pst.close(); if (!found) { Timestamp now = new Timestamp(System.currentTimeMillis()); pst = db.prepareStatement(DBQueryManager.getQuery("FlowHolder.COPY_FLOW_TEMPLATE"), new String[] { "flowid" }); pst.setTimestamp(1, now); pst.setString(2, userInfo.getOrganization()); pst.setTimestamp(3, now); pst.setString(4, fileName); int updated = pst.executeUpdate(); if (updated == 0) throw new Exception("Could not copy flow template"); rs = pst.getGeneratedKeys(); if (rs.next()) { flowId = rs.getInt(1); found = true; } else { throw new Exception("Could not get new flow id from template copy"); } rs.close(); pst.close(); } db.commit(); } catch (Exception e) { e.printStackTrace(); retObj = "O fluxo não foi encontrado: \"" + e.getMessage() + "\""; Logger.error(sLogin, this, "deployFlow", retObj); } finally { DatabaseInterface.closeResources(db, pst, rs); db = null; pst = null; rs = null; } if (null != retObj) return retObj; if (!found) return "O fluxo não existe ou não está disponível"; FlowData flow = refreshFlow(userInfo, flowId); // if(null == flow) return "Fluxo invalido."; boolean online = flow != null && flow.isDeployed(); flow.setOnline(online); notifyDeploy(userInfo, flowId, online); try { db = Utils.getDataSource().getConnection(); st = db.createStatement(); st.executeUpdate("update flow set enabled=" + (online ? 1 : 0) + " where flowid=" + flowId); } catch (Exception e) { e.printStackTrace(); retObj = "Não foi possível actualizar o estado do fluxo."; Logger.error(sLogin, this, "deployFlow", retObj); } finally { DatabaseInterface.closeResources(db, st, rs); db = null; st = null; rs = null; } if (flow == null) { retObj = "Invalid flow"; // fd can be null at this point } else if (flow.hasError()) { retObj = flow.getError(); } Logger.debug(sLogin, this, "deployFlow", fileName + " flow commited"); return retObj; } /** * Free flow resources and mark it as offline. * * @param userInfo * @param fileName * @return */ public synchronized String undeployFlow(UserInfoInterface userInfo, String fileName) { String retObj = null; int flowId = -1; String sLogin = userInfo.getUtilizador(); Logger.trace(this, "undeployFlow", sLogin + " call for file " + fileName); Connection db = null; PreparedStatement pst = null; ResultSet rs = null; try { db = Utils.getDataSource().getConnection(); db.setAutoCommit(false); pst = db.prepareStatement("select flowid from flow where flowfile=? and organizationid=?"); pst.setString(1, fileName); pst.setString(2, userInfo.getOrganization()); rs = pst.executeQuery(); if (rs.next()) { flowId = rs.getInt("flowid"); } rs.close(); pst.close(); clearCachedFlow(userInfo, flowId); pst = db.prepareStatement("update flow set enabled=0 where flowfile=? and organizationid=?"); pst.setString(1, fileName); pst.setString(2, userInfo.getOrganization()); pst.executeUpdate(); pst.close(); db.commit(); notifyDeploy(userInfo, flowId, false); } catch (Exception e) { e.printStackTrace(); retObj = "Não foi possível actualizar o estado do fluxo."; Logger.error(sLogin, this, "deployFlow", retObj); } finally { DatabaseInterface.closeResources(db, pst, rs); } return retObj; } /** * Remove a flow from database * * @param userInfo * @param asFile * @param abProcs * If true, remove processes * @return */ public boolean deleteFlow(UserInfoInterface userInfo, String asFile, boolean abProcs) { if (!userInfo.isOrgAdmin()) { Logger.debug(userInfo.getUtilizador(), this, "updateFlowData", "No Adm privilege!!"); // return "No Adm privilege!!"; return false; } boolean retObj = false; String userid = userInfo.getUtilizador(); Logger.trace(this, "deleteFlow", userid + " call with asFile=" + asFile + ",abProcs=" + abProcs); // se abProcs, apagar flow e estruturas e processos associados; // se !abProcs, mover processos abertos para historico e fazer disable // do flow // mover flow (xml file) do repositorio de offline para deleted // verificar se e preciso apagar o flow da cache do flowholder ou de // outra cache qualquer. DataSource ds = null; Connection db = null; PreparedStatement pst = null; ResultSet rs = null; int nFlowId = -1; try { ds = Utils.getDataSource(); db = ds.getConnection(); db.setAutoCommit(false); pst = db.prepareStatement("select flowid,enabled from flow where flowfile=? and organizationid=?"); pst.setString(1, asFile); pst.setString(2, userInfo.getOrganization()); rs = pst.executeQuery(); boolean exists = false; boolean online = false; if (rs.next()) { exists = true; // flow already exists nFlowId = rs.getInt("flowid"); online = rs.getBoolean("enabled"); } rs.close(); pst.close(); rs = null; pst = null; if (!exists) { throw new Exception("No Flow for FlowFile=" + asFile); } if (online) { throw new Exception("Flow " + asFile + "is online!"); } pst = db.prepareStatement("call deleteFlow(?,?,?)"); pst.setString(1, userid); pst.setInt(2, nFlowId); pst.setInt(3, abProcs ? 1 : 0); pst.executeUpdate(); pst.close(); // db handled.. now handle repository db.commit(); retObj = true; } catch (Exception e) { try { if (db != null) db.rollback(); } catch (Exception e1) { } Logger.error(userid, this, "deleteFlow", "exception caught: " + e.getMessage()); retObj = false; } finally { DatabaseInterface.closeResources(db, pst, rs); } return retObj; } // checks if flow is in cache (cached flow may contain errors.. use flow // data's hasError method) private synchronized boolean hasCachedFlow(UserInfoInterface userInfo, int anFlowId) { Integer iId = new Integer(anFlowId); String org = userInfo.getOrganization(); if (!_hmFlowData.containsKey(org)) return false; Map<Integer, FlowData> orgFlowData = _hmFlowData.get(org); return orgFlowData != null && orgFlowData.containsKey(iId) && orgFlowData.get(iId) != null; } private synchronized void clearCachedFlow(UserInfoInterface userInfo, int flowId) { Integer iId = new Integer(flowId); String org = userInfo.getOrganization(); if (_hmFlowData.containsKey(org)) { Map<Integer, FlowData> orgFlowData = _hmFlowData.get(org); if (null != orgFlowData) { FlowData fd = orgFlowData.remove(iId); if (fd != null) { fd.setOnline(false); } } } _hmFlowBuildDate.remove(iId); } private synchronized FlowData getCachedFlow(UserInfoInterface userInfo, int flowId) { FlowData fd = null; String org = userInfo.getOrganization(); if (_hmFlowData.containsKey(org)) { Map<Integer, FlowData> orgFlowData = _hmFlowData.get(org); if (null != orgFlowData) fd = (FlowData) orgFlowData.get(new Integer(flowId)); } return fd; } private synchronized void setCachedFlow(UserInfoInterface userInfo, FlowData flowData) { String org = userInfo.getOrganization(); if (!_hmFlowData.containsKey(org) || _hmFlowData.get(org) == null) { _hmFlowData.put(org, new HashMap<Integer, FlowData>()); } Map<Integer, FlowData> orgFlowData = _hmFlowData.get(org); orgFlowData.put(new Integer(flowData.getId()), flowData); } private synchronized Collection<FlowData> getCachedFlows(UserInfoInterface userInfo) { Collection<FlowData> coll = new ArrayList<FlowData>(); String org = userInfo.getOrganization(); if (_hmFlowData.containsKey(org)) { Map<Integer, FlowData> orgFlowData = _hmFlowData.get(org); if (null != orgFlowData) coll = orgFlowData.values(); } return coll; } private synchronized void setBuildDate(UserInfoInterface userInfo, int flowId) { _hmFlowBuildDate.put(new Integer(flowId), new Date()); } private synchronized boolean buildDateNotOk(UserInfoInterface userInfo, int flowId) { boolean notok = false; Integer iId = new Integer(flowId); if (_hmFlowBuildDate.containsKey(iId)) { Date dtOld = _hmFlowBuildDate.get(iId); Date dtNow = new Date(); long ltmp = dtOld.getTime() + BUILD_WAIT; notok = ltmp > dtNow.getTime(); } return notok; } public static class FlowSecurityException extends SecurityException { /** * */ private static final long serialVersionUID = -3027197719077289993L; FlowData flow; public FlowSecurityException(FlowData flow) { this.flow = flow; } public FlowSecurityException() { // TODO Auto-generated constructor stub } public FlowData getFlowData() { return flow; } } public static class MaximumFlowsException extends FlowSecurityException { /** * */ private static final long serialVersionUID = -8581734366970381600L; public MaximumFlowsException(FlowData flow) { super(flow); } public String getMessage() { return "Numero maximo de flows atingido."; } } public static class MaximumBlocksException extends FlowSecurityException { /** * */ private static final long serialVersionUID = -3826269373077991692L; public MaximumBlocksException(FlowData flow) { super(flow); } /** * */ public String getMessage() { return "Numero maximo de blocos atingido."; } } public IFlowData getFlow(UserInfoInterface userInfo, String fileName) { IFlowData retObj = null; DataSource ds = null; Connection db = null; PreparedStatement st = null; ResultSet rs = null; try { ds = Utils.getDataSource(); db = ds.getConnection(); String sQuery = "select flowid,flowname,flowfile,enabled,organizationid,created,modified,seriesId,type_code,max_block_id from flow where organizationid=? and flowfile=?"; st = db.prepareStatement(sQuery); st.setString(1, userInfo.getOrganization()); st.setString(2, fileName); rs = st.executeQuery(); if (rs.next()) { int flowId = rs.getInt("flowid"); if (hasCachedFlow(userInfo, flowId)) { retObj = getCachedFlow(userInfo, flowId); } else { retObj = new FlowData(flowId, rs.getString("flowname"), rs.getString("flowfile"), rs.getBoolean("enabled"), rs.getString("organizationid"), rs.getTimestamp("created").getTime(), rs.getTimestamp("modified").getTime(), rs.getInt("seriesId"), rs.getString("type_code"), rs.getInt("max_block_id")); } } // while } catch (Exception e) { Logger.error(userInfo.getUtilizador(), this, "listFlows", "exception (" + e.getClass().getName() + ") caught: " + e.getMessage()); } finally { DatabaseInterface.closeResources(db, st, rs); } return retObj; } public synchronized FlowTemplate[] listFlowTemplates(UserInfoInterface userInfo) { FlowTemplate[] retObj = null; DataSource ds = null; Connection db = null; Statement st = null; ResultSet rs = null; try { ds = Utils.getDataSource(); db = ds.getConnection(); st = db.createStatement(); rs = null; // return every disabled flowfile in orgnaizationid. The unioned // query will exclude all org flows so it will not list an online // flow as offline final String query = "select name,description from flow_template"; rs = st.executeQuery(query); ArrayList<FlowTemplate> altmp = new ArrayList<FlowTemplate>(); while (rs.next()) { altmp.add(new FlowTemplate(rs.getString("name"), rs.getString("description"))); } // while retObj = altmp.toArray(new FlowTemplate[altmp.size()]); } catch (Exception e) { Logger.error(userInfo.getUtilizador(), this, "listFlowNames", "exception (" + e.getClass().getName() + ") caught: " + e.getMessage()); } finally { DatabaseInterface.closeResources(db, st, rs); } return retObj; } public synchronized byte[] readTemplateData(UserInfoInterface userInfo, String name) { Connection db = null; PreparedStatement st = null; ResultSet rs = null; byte[] data = null; try { db = Utils.getDataSource().getConnection(); // copy from template st = db.prepareStatement("select data FROM flow_template where name=?"); st.setString(1, name); rs = st.executeQuery(); if (rs.next()) { InputStream is = rs.getBinaryStream("data"); data = getBytes(is); } } catch (Exception e) { try { db.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); } finally { DatabaseInterface.closeResources(db, st, rs); } return data; } /** * Remove a flow template from database * * @param userInfo * @param asFile * @return */ public boolean deleteFlowTemplate(UserInfoInterface userInfo, String name) { if (!userInfo.isSysAdmin()) { Logger.error(userInfo.getUtilizador(), this, "deleteFlowTemplate", "User is not System Admin."); return false; } Connection db = null; PreparedStatement st = null; boolean result = false; try { db = Utils.getDataSource().getConnection(); // copy from template st = db.prepareStatement("delete FROM flow_template where name=?"); st.setString(1, name); result = (st.executeUpdate() == 1); } catch (Exception e) { try { db.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); } finally { DatabaseInterface.closeResources(db, st); } return result; } /** * Upload a flow template to database * * @param userInfo * @param name * @param description * @param data * @return */ public boolean uploadFlowTemplate(UserInfoInterface userInfo, String name, String description, byte[] data) { if (!userInfo.isSysAdmin()) { Logger.error(userInfo.getUtilizador(), this, "uploadFlowTemplate", "User is not System Admin."); return false; } if (null == data) { Logger.error(userInfo.getUtilizador(), this, "uploadFlowTemplate", "Data is null"); return false; } Connection db = null; PreparedStatement st = null; ResultSet rs = null; boolean insert = true; boolean result = false; try { db = Utils.getDataSource().getConnection(); db.setAutoCommit(false); // copy from template st = db.prepareStatement("select count(*) FROM flow_template where name=?"); st.setString(1, name); rs = st.executeQuery(); if (rs.next()) { insert = (rs.getInt(1) == 0); } rs.close(); st.close(); if (insert) { st = db.prepareStatement("insert into flow_template (description,data,name) values (?,?,?)"); } else { st = db.prepareStatement("update flow_template set description = ?, data = ? where name = ?"); } st.setString(1, description); ByteArrayInputStream bin = new ByteArrayInputStream(data); st.setBinaryStream(2, bin, data.length); st.setString(3, name); result = (st.executeUpdate() == 1); db.commit(); } catch (Exception e) { try { db.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); result = false; } finally { DatabaseInterface.closeResources(db, st, rs); } return result; } /** * Get the XML contents of the named flow version. * * <br> * <em>This method will not create a new flow!</em> * * @param userInfo * @param name * file name * @return XML bytes */ public synchronized byte[] readFlowData(UserInfoInterface userInfo, String name, int version) { return readData(userInfo, name, true, version); } /** * Get the XML contents of the named sub flow version. * * <br> * <em>This method will not create a new sub flow!</em> * * @param userInfo * @param name * file name * @return XML bytes */ public synchronized byte[] readSubFlowData(UserInfoInterface userInfo, String name, int version) { return readData(userInfo, name, false, version); } private synchronized byte[] readData(UserInfoInterface userInfo, String name, boolean isFlow, int version) { String query = null; Connection db = null; PreparedStatement st = null; ResultSet rs = null; byte[] data = null; String sub = isFlow ? "" : "sub_"; try { db = Utils.getDataSource().getConnection(); if (version < 0) { query = "select flowdata from " + sub + "flow where flowfile=? and organizationid=?"; } else { query = "select h.data as flowdata from " + sub + "flow f, " + sub + "flow_history h where f.flowfile=? and f.organizationid=? and f.flowid=h.flowid and h.flowversion=?"; } Logger.debug(userInfo.getUtilizador(), this, "readData", "Executing query: " + query); Logger.debug(userInfo.getUtilizador(), this, "readData", "Query params: name=" + name + "; organizationid=" + userInfo.getOrganization() + "; version=" + version); st = db.prepareStatement(query); st.setString(1, name); st.setString(2, userInfo.getOrganization()); if (version >= 0) st.setInt(3, version); rs = st.executeQuery(); boolean flowFound = false; if (rs.next()) { flowFound = true; InputStream is = rs.getBinaryStream(1); data = getBytes(is); Logger.debug(userInfo.getUtilizador(), this, "readData", "Flow found. Bytes: " + data.length); } rs.close(); st.close(); if (!flowFound && version < 0) { Logger.debug(userInfo.getUtilizador(), this, "readData", "Flow not found. Searching templates."); // copy from template query = "select data FROM " + sub + "flow_template where name=?"; Logger.debug(userInfo.getUtilizador(), this, "readData", "Executing query: " + query); Logger.debug(userInfo.getUtilizador(), this, "readData", "Query params: name=" + name); st = db.prepareStatement(query); st.setString(1, name); rs = st.executeQuery(); if (rs.next()) { InputStream is = rs.getBinaryStream(1); data = getBytes(is); Logger.debug(userInfo.getUtilizador(), this, "readData", "Template found. Bytes: " + data.length); } } } catch (Exception e) { Logger.error(userInfo.getUtilizador(), this, "readData", "Exception occured reading flow data.", e); } finally { DatabaseInterface.closeResources(db, st, rs); } return data; } public String getFlowComment(UserInfoInterface userInfo, String name, int version) { return getFlowVersionComment(userInfo, name, version, true); } public String getSubFlowComment(UserInfoInterface userInfo, String name, int version) { return getFlowVersionComment(userInfo, name, version, false); } public String[] getFlowVersions(UserInfoInterface userInfo, String name) { return getFlowVersions(userInfo, name, true); } public String[] getSubFlowVersions(UserInfoInterface userInfo, String name) { return getFlowVersions(userInfo, name, false); } private String[] getFlowVersions(UserInfoInterface userInfo, String name, boolean isFlow) { Connection db = null; PreparedStatement st = null; ResultSet rs = null; final int strSize = 20; String sub = isFlow ? "" : "sub_"; ArrayList<String> versions = new ArrayList<String>(); try { db = Utils.getDataSource().getConnection(); String query = DBQueryManager.processQuery("FlowHolder.LIST_FLOW_VERSIONS", new Object[] { sub }); Logger.debug(userInfo.getUtilizador(), this, "getFlowVersions", "Executing query: " + query); Logger.debug(userInfo.getUtilizador(), this, "getFlowVersions", "Query params: name=" + name + "; organizationid=" + userInfo.getOrganization()); st = db.prepareStatement(query); st.setString(1, name); st.setString(2, userInfo.getOrganization()); rs = st.executeQuery(); while (rs.next()) { int version = rs.getInt(1); Timestamp ts = rs.getTimestamp(2); String comment = rs.getString(3); if (null == comment) comment = ""; else if (comment.length() > strSize) comment = comment.substring(0, strSize - 3) + "..."; String versionLine = version + ";" + DateUtility.formatTimestamp(userInfo, ts) + " - " + comment; versions.add(versionLine); Logger.debug(userInfo.getUtilizador(), this, "getFlowVersions", "Version line: " + versionLine); } Logger.debug(userInfo.getUtilizador(), this, "getFlowVersions", "Flow found. Bytes: " + versions.size()); rs.close(); st.close(); } catch (Exception e) { Logger.error(userInfo.getUtilizador(), this, "getFlowVersions", "Exception occured reading flow data.", e); } finally { DatabaseInterface.closeResources(db, st, rs); } return versions.toArray(new String[versions.size()]); } private String getFlowVersionComment(UserInfoInterface userInfo, String name, int version, boolean isFlow) { if (version < 0) { return ""; } Connection db = null; PreparedStatement st = null; ResultSet rs = null; String sub = isFlow ? "" : "sub_"; String comment = ""; try { db = Utils.getDataSource().getConnection(); String query = DBQueryManager.processQuery("FlowHolder.FLOW_COMMENT", new Object[] { sub }); Logger.debug(userInfo.getUtilizador(), this, "getFlowVersionComment", "Executing query: " + query); Logger.debug(userInfo.getUtilizador(), this, "getFlowVersionComment", "Query params: name=" + name + "; organizationid=" + userInfo.getOrganization() + "; version=" + version); st = db.prepareStatement(query); st.setString(1, name); st.setString(2, userInfo.getOrganization()); st.setInt(3, version); rs = st.executeQuery(); if (rs.next()) { comment = rs.getString(1); Logger.debug(userInfo.getUtilizador(), this, "getFlowVersionComment", "Comment found: " + comment); } rs.close(); st.close(); } catch (Exception e) { Logger.error(userInfo.getUtilizador(), this, "getFlowVersionComment", "Exception occured reading flow comment.", e); } finally { DatabaseInterface.closeResources(db, st, rs); } return comment; } private synchronized void reindexFlow(UserInfoInterface userInfo, IFlowData flow) { int flowid = flow.getId(); DataSource ds = null; Connection db = null; Statement st = null; ResultSet rs = null; Object[] queryInfo = new Object[3]; // 0: flowid; 1: index position; 2: // var name queryInfo[0] = String.valueOf(flowid); Map<String, Integer> indexVar = flow.getIndexVars(); // Map<String,String> varTypes = flow.getCatalogueVars(); ProcessCatalogue catalog = flow.getCatalogue(); try { ds = Utils.getDataSource(); db = ds.getConnection(); db.setAutoCommit(false); st = db.createStatement(); String query = null; int nProcs = 0; // reset index for (String var : indexVar.keySet()) { int pos = indexVar.get(var); String escapedVar = StringEscapeUtils.escapeSql(var); String oldIdx = null; // get previous index query = "select name_idx" + pos + " from flow where flowid=" + flowid; Logger.debug(userInfo.getUtilizador(), this, "reindexFlow", "Executing query: " + query); rs = st.executeQuery(query); if (rs.next()) oldIdx = rs.getString(1); Logger.debug(userInfo.getUtilizador(), this, "reindexFlow", "Old index var: " + oldIdx); // if new var is empty or is the same as oldIdx, there is no // need to reindex if (StringUtils.isEmpty(var) || StringUtils.equals(oldIdx, var)) continue; if (catalog.isList(var)) { Logger.warning(userInfo.getUtilizador(), this, "reindexFlow", "Unindexable variable: '" + var + "'. skipping..."); continue; } queryInfo[1] = pos; queryInfo[2] = escapedVar; // update with new index query = "update flow set name_idx" + pos + "='" + escapedVar + "' where flowid=" + flowid; Logger.debug(userInfo.getUtilizador(), this, "reindexFlow", "Executing query: " + query); nProcs = st.executeUpdate(query); Logger.debug(userInfo.getUtilizador(), this, "reindexFlow", "Set new index var: " + nProcs); // open processes query = "update process set idx" + pos + "=null where flowid=" + flowid; Logger.debug(userInfo.getUtilizador(), this, "reindexFlow", "Executing query: " + query); nProcs = st.executeUpdate(query); Logger.debug(userInfo.getUtilizador(), this, "reindexFlow", "Reset " + nProcs + " process index"); query = DBQueryManager.processQuery("FlowHolder.REINDEX", queryInfo); Logger.debug(userInfo.getUtilizador(), this, "reindexFlow", "Executing query: " + query); nProcs = st.executeUpdate(query); Logger.debug(userInfo.getUtilizador(), this, "reindexFlow", "Finished reindexing " + nProcs + " processes"); // closed processes query = "update process_history set idx" + pos + "=null where flowid=" + flowid + " and closed=1"; Logger.debug(userInfo.getUtilizador(), this, "reindexFlow", "Executing query: " + query); nProcs = st.executeUpdate(query); Logger.debug(userInfo.getUtilizador(), this, "reindexFlow", "Reset " + nProcs + " closed process index"); query = DBQueryManager.processQuery("FlowHolder.REINDEX_HISTORY", queryInfo); Logger.debug(userInfo.getUtilizador(), this, "reindexFlow", "Executing query: " + query); nProcs = st.executeUpdate(query); Logger.debug(userInfo.getUtilizador(), this, "reindexFlow", "Finished reindexing " + nProcs + " processes"); db.commit(); } } catch (SQLException e) { Logger.error(userInfo.getUtilizador(), this, "reindexFlow", "Error reindexing process data.", e); } finally { // free db connections DatabaseInterface.closeResources(db, st, rs); } } public boolean updateFlowSeries(UserInfoInterface userInfo, int flowId, int seriesId) { int[] flowIds = new int[] { flowId }; return updateFlowsSeries(userInfo, flowIds, seriesId); } public synchronized boolean updateFlowsSeries(UserInfoInterface userInfo, int[] flowIds, int seriesId) { DataSource ds = null; Connection db = null; PreparedStatement pst = null; try { ds = Utils.getDataSource(); db = ds.getConnection(); db.setAutoCommit(false); pst = db.prepareStatement("update flow set seriesid=? where flowid=?"); pst.setInt(1, seriesId); for (int flowId : flowIds) { pst.setInt(2, flowId); Logger.debug(userInfo.getUtilizador(), this, "updateFlowsSeries", "going to update flow " + flowId + " with seriesId " + seriesId); int rows = pst.executeUpdate(); if (rows != 1) { throw new Exception( "flow " + flowId + " seriesId update returned " + rows + "(should return only 1)"); } Logger.debug(userInfo.getUtilizador(), this, "updateFlowsSeries", "updated flow " + flowId + " with seriesId " + seriesId); } db.commit(); // refresh flows for (int flowId : flowIds) { refreshFlow(userInfo, flowId); } return true; } catch (Exception e) { try { if (db != null) db.rollback(); } catch (Exception ee) { } Logger.error(userInfo.getUtilizador(), this, "updateFlowSeries", "Error updating flows with series " + seriesId, e); return false; } finally { // free db connections DatabaseInterface.closeResources(db, pst); } } public Collection<Integer> listFlowIds(UserInfoInterface userInfo) { if (null == userInfo || !userInfo.isSysAdmin()) return null; // not authorized ArrayList<Integer> retObj = new ArrayList<Integer>(); DataSource ds = null; Connection db = null; Statement st = null; ResultSet rs = null; try { ds = Utils.getDataSource(); db = ds.getConnection(); st = db.createStatement(); rs = null; String sQuery = "select flowid from flow order by flowid"; rs = st.executeQuery(sQuery); while (rs.next()) { retObj.add(rs.getInt("flowid")); } // while } catch (Exception e) { Logger.error(userInfo.getUtilizador(), this, "listFlowIds", "exception (" + e.getClass().getName() + ") caught: " + e.getMessage()); } finally { DatabaseInterface.closeResources(db, st, rs); } return retObj; } private void notifyNewFlow(UserInfoInterface userInfo, int flowid) { for (NewFlowListener listener : newflowListeners.values()) { try { listener.flowAdded(flowid); } catch (Exception e) { Logger.error(userInfo.getUtilizador(), this, "notifyNewFlow", "error notifying listener " + listener + " for new flow " + flowid, e); } } Logger.info(userInfo.getUtilizador(), this, "notifyNewFlow", "notified listeners for new flow " + flowid); } public void addNewFlowListener(String id, NewFlowListener listener) { newflowListeners.put(id, listener); } public void removeNewFlowListener(String id) { if (newflowListeners.containsKey(id)) { newflowListeners.remove(id); } } private void notifyDeploy(UserInfoInterface userInfo, int flowid, boolean bOnline) { for (FlowDeployListener l : deploylisteners.values()) { try { if (bOnline) { l.goOnline(flowid); } else { l.goOffline(flowid); } } catch (Exception e) { Logger.error(userInfo.getUtilizador(), this, "notifyDeploy", "error notifying listener " + l + " for new flow " + flowid, e); } } Logger.info(userInfo.getUtilizador(), this, "notifyDeploy", "notified listeners for flow " + flowid); } public void addFlowDeployListener(String id, FlowDeployListener listener) { deploylisteners.put(id, listener); } public void removeFlowDeployListener(String id) { if (deploylisteners.containsKey(id)) { deploylisteners.remove(id); } } private void notifyVersion(UserInfoInterface userInfo, int flowid) { for (FlowVersionListener l : versionlisteners.values()) { try { l.newVersion(flowid); } catch (Exception e) { Logger.error(userInfo.getUtilizador(), this, "notifyVersion", "error notifying listener " + l + " for flow " + flowid, e); } } Logger.info(userInfo.getUtilizador(), this, "notifyVersion", "notified listeners for flow " + flowid); } public void addFlowVersionListener(String id, FlowVersionListener listener) { versionlisteners.put(id, listener); } public void removeFlowVersionListener(String id) { if (versionlisteners.containsKey(id)) { versionlisteners.remove(id); } } public String getFlowOrganizationid(int flowid) { DataSource ds = null; Connection db = null; PreparedStatement st = null; ResultSet rs = null; // default value String result = Const.SYSTEM_ORGANIZATION; try { ds = Utils.getDataSource(); db = ds.getConnection(); st = db.prepareStatement("SELECT organizationid FROM flow WHERE flowid=?"); st.setInt(1, flowid); rs = st.executeQuery(); if (rs.next()) { result = rs.getString("organizationid"); } } catch (SQLException e) { Logger.error(null, this, "getFlowOrganizationid", "Error retrieving organization associated with flow", e); } finally { DatabaseInterface.closeResources(db, st, rs); } return result; } public boolean updateFlowType(UserInfoInterface userInfo, int flowid) { if (null == userInfo || !userInfo.isOrgAdmin()) return false; // not authorized if (flowid <= 0) return false; ProcessManager pm = BeanFactory.getProcessManagerBean(); int procCount = pm.countFlowProcesses(userInfo, flowid, true, false); boolean result = false; synchronized (this) { DataSource ds = null; Connection db = null; PreparedStatement st = null; ResultSet rs = null; try { ds = Utils.getDataSource(); db = ds.getConnection(); db.setAutoCommit(false); st = db.prepareStatement("select type_code from flow where flowid=?"); st.setInt(1, flowid); rs = st.executeQuery(); FlowType currentType = null; if (rs.next()) currentType = FlowType.getFlowType(rs.getString("type_code")); rs.close(); rs = null; st.close(); st = null; if (currentType == null) return false; FlowType newType = currentType.getNextType(); // check if there are any processes if (FlowType.SUPPORT.equals(newType) && procCount != 0) { // existem processos (ou nao consegue saber o estado) nao pode mudar para suport return false; } st = db.prepareStatement("update flow set type_code=? where flowid=?"); st.setString(1, newType.getCode()); st.setInt(2, flowid); st.executeUpdate(); FlowData fd = getCachedFlow(userInfo, flowid); if (fd != null) { fd.setFlowType(newType); } db.commit(); result = true; } catch (SQLException e) { Logger.error(null, this, "getFlowOrganizationid", "Error retrieving organization associated with flow", e); } finally { DatabaseInterface.closeResources(db, st, rs); } } return result; } public boolean updateFlowShowInMenuRequirement(UserInfoInterface userInfo, int flowid) { if (null == userInfo || !userInfo.isOrgAdmin()) { return false; // not authorized } if (flowid <= 0) { return false; } boolean result = false; synchronized (this) { DataSource ds = null; Connection db = null; PreparedStatement st = null; ResultSet rs = null; try { ds = Utils.getDataSource(); db = ds.getConnection(); db.setAutoCommit(false); st = db.prepareStatement( "SELECT flowid, name, description, value FROM flow_settings where flowid = ? and name like ?"); st.setInt(1, flowid); st.setString(2, Const.sFLOW_MENU_ACCESSIBLE); rs = st.executeQuery(); String currentValue = null; boolean hadData = false; if (rs.next()) { hadData = true; currentValue = rs.getString("value"); } else { hadData = false; } rs.close(); rs = null; st.close(); st = null; if (hadData) { String newValue = null; if (currentValue == null || Const.sFLOW_MENU_ACCESSIBLE_YES.equals(currentValue)) { newValue = Const.sFLOW_MENU_ACCESSIBLE_NO; } else { newValue = Const.sFLOW_MENU_ACCESSIBLE_YES; } st = db.prepareStatement("update flow_settings set value=? where flowid=? and name like ?"); st.setString(1, newValue); st.setInt(2, flowid); st.setString(3, Const.sFLOW_MENU_ACCESSIBLE); st.executeUpdate(); db.commit(); result = true; } } catch (SQLException e) { Logger.error(null, this, "updateFlowShowInMenuRequirement", "Error while atempting to update show in menu requirement field of flow [" + flowid + "]", e); } finally { DatabaseInterface.closeResources(db, st, rs); } } return result; } }