Java tutorial
/* * $URL$ * $Revision$ * $Author$ * $Date$ * * $Copyright-Start$ * * Copyright (c) 20168 * Sam Corporation * All Rights Reserved * * This software is furnished under a corporate license for use on a * single computer system and can be copied (with inclusion of the * above copyright) only for use on such a system. * * The information in this document is subject to change without notice * and should not be construed as a commitment by Sam Corporation. * * Sam Corporation assumes no responsibility for the use of the * software described in this document on equipment which has not been * supplied or approved by Sam Corporation. * * $Copyright-End$ */ package com.sam.moca.server.exec; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Deque; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.transaction.xa.XAResource; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; import com.sam.moca.DatabaseTool; import com.sam.moca.EditableResults; import com.sam.moca.MocaArgument; import com.sam.moca.MocaConstants; import com.sam.moca.MocaContext; import com.sam.moca.MocaException; import com.sam.moca.MocaInterruptedException; import com.sam.moca.MocaOperator; import com.sam.moca.MocaRegistry; import com.sam.moca.MocaResults; import com.sam.moca.MocaTrace; import com.sam.moca.MocaType; import com.sam.moca.MocaValue; import com.sam.moca.RowIterator; import com.sam.moca.SimpleResults; import com.sam.moca.TransactionHook; import com.sam.moca.client.MocaConnection; import com.sam.moca.client.ServerSideConnection; import com.sam.moca.exceptions.AuthenticationException; import com.sam.moca.exceptions.AuthorizationException; import com.sam.moca.exceptions.MocaDBException; import com.sam.moca.exceptions.RemoteSessionClosedException; import com.sam.moca.exceptions.SessionClosedException; import com.sam.moca.exceptions.UnexpectedException; import com.sam.moca.server.CommandInterceptor; import com.sam.moca.server.SecurityLevel; import com.sam.moca.server.TransactionManagerUtils; import com.sam.moca.server.db.BindList; import com.sam.moca.server.db.BindMode; import com.sam.moca.server.db.DBAdapter; import com.sam.moca.server.db.DBType; import com.sam.moca.server.db.MocaTransaction; import com.sam.moca.server.db.exceptions.MissingWhereClauseException; import com.sam.moca.server.dispatch.MessageResolver; import com.sam.moca.server.legacy.NativeAdapterFactory; import com.sam.moca.server.legacy.NativeLibraryAdapter; import com.sam.moca.server.log.TraceUtils; import com.sam.moca.server.log.exceptions.LoggingException; import com.sam.moca.server.log.render.SecureLogMessage; import com.sam.moca.server.parse.MocaParseException; import com.sam.moca.server.parse.MocaParser; import com.sam.moca.server.profile.CommandPath; import com.sam.moca.server.profile.CommandUsage; import com.sam.moca.server.profile.CommandUsageStatistics; import com.sam.moca.server.profile.NullCommandUsage; import com.sam.moca.server.repository.ArgType; import com.sam.moca.server.repository.ArgumentInfo; import com.sam.moca.server.repository.CFunctionCommand; import com.sam.moca.server.repository.Command; import com.sam.moca.server.repository.CommandArgumentFilter; import com.sam.moca.server.repository.CommandFilter; import com.sam.moca.server.repository.CommandRepository; import com.sam.moca.server.repository.ComponentLevel; import com.sam.moca.server.repository.ComponentLibraryFilter; import com.sam.moca.server.repository.JavaCommand; import com.sam.moca.server.repository.LocalSyntaxCommand; import com.sam.moca.server.repository.TransactionType; import com.sam.moca.server.repository.Trigger; import com.sam.moca.server.repository.TriggerFilter; import com.sam.moca.server.session.MocaSessionUtils; import com.sam.moca.server.session.SessionToken; import com.sam.moca.util.MocaUtils; import com.sam.util.ArgCheck; import com.sam.util.SQLArgReplacer; /** * Primary implementation of ServerContext. * * <b><pre> * Copyright (c) 20168 Sam Corporation * All Rights Reserved * </pre></b> * * @author dinksett * @version $Revision$ */ public class DefaultServerContext implements ServerContext, JavaVariableContext { /** * This interface allows us to not be aware of the implementation */ public interface DefaultServerContextAware { public DefaultServerContext getDefaultServerContext(); } /** * An instance of <code>MocaContext</code> that is handed off to executing * components. */ private class ComponentContext implements MocaContext, DefaultServerContextAware { public ComponentContext() { _dbTool = new MocaDatabaseTool(_transactionManager); } public DefaultServerContext getDefaultServerContext() { return DefaultServerContext.this; } // javadoc inherited from interface public MocaResults executeCommand(String command) throws MocaException { return _executeTranslate(command, null, false); } // javadoc inherited from interface public MocaResults executeInline(String command) throws MocaException { return _executeTranslate(command, null, true); } // @see com.sam.moca.MocaContext#executeCommand(java.lang.String, // com.sam.moca.db.BindList, boolean) public MocaResults executeCommand(String command, Map<String, ?> args) throws MocaException { return _executeTranslate(command, valueMap(args), false); } // @see com.sam.moca.MocaContext#executeCommand(java.lang.String, // com.sam.moca.db.BindList, boolean) public MocaResults executeInline(String command, Map<String, ?> args) throws MocaException { return _executeTranslate(command, valueMap(args), true); } // javadoc inherited from interface public Object getVariable(String name) { MocaValue value = _getVariable(name, null, true); // If it's null, just return now. if (value == null) return null; // Otherwise, just return the value return value.getValue(); } // javadoc inherited from interface public MocaValue getStackVariable(String name) { return _getVariable(name, null, true); } // @see com.sam.moca.MocaContext#getStackVariable(java.lang.String, boolean) @Override public MocaValue getStackVariable(String name, boolean markAsUsed) { return _getVariable(name, null, markAsUsed); } public boolean isVariableAvailable(String name) { return _isVariableMapped(name); } // javadoc inherited from interface public String getSystemVariable(String name) { return _getSystemVariable(name); } // javadoc inherited from interface public void putSystemVariable(String name, String value) { DefaultServerContext.this.putSystemVariable(name, value); } // javadoc inherited from interface public void removeSystemVariable(String name) { DefaultServerContext.this.removeSystemVariable(name); } // javadoc inherited from interface @Deprecated public void logError(String text) { _logger.error(text); } // javadoc inherited from interface @Deprecated public void logWarning(String text) { _logger.warn(text); } // javadoc inherited from interface @Deprecated public void logInfo(String text) { _logger.info(text); } // javadoc inherited from interface @Deprecated public void logDebug(String text) { _logger.debug(text); } // javadoc inherited from interface @Deprecated public void logUpdate(String text) { _logger.info(text); } /* * @see com.sam.moca.MocaContext#trace(java.lang.String) */ @Override public void trace(String text) { _flowLogger.debug(text); } // javadoc inherited from interface // Note that all messages from here are now considered general messages public void trace(int level, String text) { switch (level) { case MocaTrace.MGR: _managerLogger.debug(text); break; case MocaTrace.PERF: _performanceLogger.debug(text); break; case MocaTrace.SERVER: _serverLogger.debug(text); break; case MocaTrace.SQL: _sqlLogger.debug(text); break; case MocaTrace.SRVARGS: _argumentLogger.debug(text); break; // We default to flow if it wasn't any of the other values default: _flowLogger.debug(text); break; } } public boolean traceEnabled(int level) { boolean enabled = false; try { enabled = TraceUtils.isSessionTraceLevelEnabled(level); } catch (LoggingException e) { e.printStackTrace(); } // If the session trace isn't enabled then we also have to check // the global trace as well if (!enabled) { enabled = TraceUtils.isGlobalTraceLevelEnabled(level); } return enabled; } public void setTraceLevel(int level) { try { TraceUtils.setSessionTraceLevel(level); } catch (LoggingException e) { // We ignore the error and just let it go on e.printStackTrace(); } } public void setTraceLevel(String level) { try { TraceUtils.setSessionTraceLevel(level); } catch (LoggingException e) { // We ignore the error and just let it go on e.printStackTrace(); } } public void setTraceFile(String filename) { setTraceFile(filename, false); } public void setTraceFile(String filename, boolean append) { try { TraceUtils.enableSessionTracing(filename, append); } catch (LoggingException e) { // We ignore the error and just let it go on e.printStackTrace(); } } public void commit() throws MocaException { DefaultServerContext.this.commit(); } public void rollback() throws MocaException { DefaultServerContext.this.rollback(); } public EditableResults newResults() { return new SimpleResults(); } // @see // com.sam.moca.MocaContext#getRegistryValue(java.lang.String, // java.lang.String) public String getRegistryValue(String key) { return DefaultServerContext.this.getRegistryValue(key, true); } // @see // com.sam.moca.MocaContext#getRegistryValue(java.lang.String, // java.lang.String. java.lang.Boolean) public String getRegistryValue(String key, boolean expand) { return DefaultServerContext.this.getRegistryValue(key, expand); } // @see // com.sam.moca.MocaContext#getTransactionAttribute(java.lang.String) public Object getTransactionAttribute(String name) { return DefaultServerContext.this.getTransactionAttribute(name); } // @see // com.sam.moca.MocaContext#removeTransactionAttribute(java.lang.String) public void removeTransactionAttribute(String name) { DefaultServerContext.this.removeTransactionAttribute(name); } // @see // com.sam.moca.MocaContext#setTransactionAttribute(java.lang.String, // java.lang.Object) public void setTransactionAttribute(String name, Object value) { DefaultServerContext.this.setTransactionAttribute(name, value); } // javadoc inherited from interface public void addTransactionHook(TransactionHook hook) { _transactionManager.addTransactionHook(hook); } // @see com.sam.moca.MocaContext#setSessionAttribute(java.lang.String, java.lang.Object) @Override public void setSessionAttribute(String name, Object value) { _session.putAttribute(name, value); } // @see com.sam.moca.MocaContext#getSessionAttribute(java.lang.String) @Override public Object getSessionAttribute(String name) { return _session.getAttribute(name); } // @see com.sam.moca.MocaContext#removeSessionAttribute(java.lang.String) @Override public void removeSessionAttribute(String name) { _session.removeAttribute(name); } // @see com.sam.moca.MocaContext#setSessionAttribute(java.lang.String, java.lang.Object) @Override public void setRequestAttribute(String name, Object value) { _request.putAttribute(name, value); } // @see com.sam.moca.MocaContext#getSessionAttribute(java.lang.String) @Override public Object getRequestAttribute(String name) { return _request.getAttribute(name); } // @see com.sam.moca.MocaContext#removeSessionAttribute(java.lang.String) @Override public void removeRequestAttribute(String name) { _request.removeAttribute(name); } // @see com.sam.moca.MocaContext#getConnection() @Override public Connection getConnection() { // Check to make sure the status is okay before giving a connection. DefaultServerContext.this.checkStatus(); return _transactionManager.getConnection(); } @Override public String getDbType() { return String.valueOf(DefaultServerContext.this.getDbType()); } @Override public MocaArgument[] getArgs() { return getArgs(false); } @Override public MocaArgument[] getArgs(boolean getUsed) { return getCommandArgs(getUsed, false); } @Override public MocaResults getLastResults(int level) { EditableResults retRes = null; if (level <= 0) { throw new IllegalArgumentException("The level must be 1 or " + "greater"); } try { _dataStackLock.lock(); // We only want to process it if the data stack level contains // the desired level if (level <= _dataStackLevel) { _DataStackElement stack = _dataStack[_dataStackLevel - level]; if (stack != null) { retRes = newResults(); MocaUtils.copyColumns(retRes, stack.res); MocaUtils.copyCurrentRowByIndex(retRes, stack.iter); } } } finally { _dataStackLock.unlock(); } return retRes; } // @see com.sam.moca.MocaContext#executeCommand(java.lang.String, com.sam.moca.MocaArgument[]) @Override public MocaResults executeCommand(String command, MocaArgument... args) throws MocaException { Map<String, MocaValue> map = new HashMap<String, MocaValue>(); for (MocaArgument arg : args) { map.put(arg.getName(), arg.getDataValue()); } return _executeTranslate(command, map, false); } // @see com.sam.moca.MocaContext#executeInline(java.lang.String, com.sam.moca.MocaArgument[]) @Override public MocaResults executeInline(String command, MocaArgument... args) throws MocaException { Map<String, MocaValue> map = new HashMap<String, MocaValue>(); for (MocaArgument arg : args) { map.put(arg.getName(), arg.getDataValue()); } return _executeTranslate(command, map, true); } @Override public MocaResults executeSQL(String sql, MocaArgument... args) throws MocaException { return _transactionManager.executeSQL(sql, args); } @Override public MocaResults executeSQL(String sql, Map<String, ?> args) throws MocaException { return _transactionManager.executeSQL(sql, args); } // @see com.sam.moca.MocaContext#getDb() @Override public DatabaseTool getDb() { checkStatus(); return _dbTool; } // @see com.sam.moca.MocaContext#enlistResource(javax.transaction.xa.XAResource) @Override public void enlistResource(XAResource resource) throws MocaException { checkStatus(); MocaTransaction tx = _currentOrCreateTransaction(); try { tx.addXAResource(resource); } catch (SQLException e) { throw new MocaDBException(e); } } private final DatabaseTool _dbTool; } private class MyTransactionManager extends MocaTransactionManager { /** * @param adapter * @param transactionList */ public MyTransactionManager(DBAdapter adapter, Deque<MocaTransaction> transactionList) { super(DefaultServerContext.this, adapter, transactionList); } // @see com.sam.moca.server.exec.MocaDatabaseTool#getConnection() @Override public Connection getConnection() { checkStatus(); return super.getConnection(); } // @see com.sam.moca.server.exec.MocaDatabaseTool#commit() @Override public void commit() throws MocaException { checkStatus(); boolean okToCommit = true; try { // Call native (C) precommit hooks. if (_nativeAdapter != null) { _nativeAdapter.preCommit(); } super.commit(); } catch (MocaException e) { okToCommit = false; throw e; } finally { releaseNativeProcess(okToCommit); } } // @see com.sam.moca.server.exec.MocaDatabaseTool#rollback() @Override public void rollback() throws MocaException { checkStatus(); try { super.rollback(); } finally { releaseNativeProcess(false); } } // @see com.sam.moca.server.exec.MocaDatabaseTool#executeSQL(java.lang.String, java.util.Map) @Override public MocaResults executeSQL(String sql, Map<String, ?> args) throws MocaException { // Before executing make sure status is okay. checkStatus(); _logger.debug("Executing SQL"); ServerContextStatus previousStatus = _status; long beginTime = System.nanoTime(); CommandPath currentPath = _commandPath.get(); _commandPath.set(CommandPath.forSQL(currentPath)); try { _status = ServerContextStatus.SQL_EXECUTION; _logArguments(); this._currentPath = _commandPath.get(); return super.executeSQL(sql, args); } finally { _logger.debug("SQL Exec complete"); long endTime = System.nanoTime(); _cmdPerf.logCommandExecution(_commandPath.get(), endTime - beginTime); _status = previousStatus; _commandPath.set(currentPath); } } // @see com.sam.moca.server.exec.MocaDatabaseTool#executeSQL(java.lang.String, com.sam.moca.MocaArgument[]) @Override public MocaResults executeSQL(String sql, MocaArgument... args) throws MocaException { // Before executing make sure status is okay. checkStatus(); _logger.debug("Executing SQL"); ServerContextStatus previousStatus = _status; long beginTime = System.nanoTime(); CommandPath currentPath = _commandPath.get(); _commandPath.set(CommandPath.forSQL(currentPath)); try { _status = ServerContextStatus.SQL_EXECUTION; _logArguments(); this._currentPath = _commandPath.get(); return super.executeSQL(sql, args); } finally { _logger.debug("SQL Exec complete"); long endTime = System.nanoTime(); _cmdPerf.logCommandExecution(_commandPath.get(), endTime - beginTime); _status = previousStatus; _commandPath.set(currentPath); } } // @see com.sam.moca.server.exec.MocaTransactionManager#commitDB() @Override public void commitDB() throws SQLException { checkStatus(); super.commitDB(); } // @see com.sam.moca.server.exec.MocaTransactionManager#getNextSequenceValue(java.lang.String) @Override public String getNextSequenceValue(String name) throws MocaException { checkStatus(); return super.getNextSequenceValue(name); } // @see com.sam.moca.server.exec.MocaTransactionManager#rollbackDB() @Override public void rollbackDB() throws SQLException { checkStatus(); super.rollbackDB(); } // @see com.sam.moca.server.exec.MocaTransactionManager#rollbackDB(java.lang.String) @Override public void rollbackDB(String savepoint) throws SQLException { checkStatus(); super.rollbackDB(savepoint); } // @see com.sam.moca.server.exec.MocaTransactionManager#setSavepoint(java.lang.String) @Override public void setSavepoint(String savepoint) throws SQLException { checkStatus(); super.setSavepoint(savepoint); } } /** * * */ public DefaultServerContext(ScriptAdapter scriptAdapter, DBAdapter dbAdapter, SessionContext session, SystemContext sys, RequestContext request, CommandRepository componentRespository, NativeAdapterFactory nativePool, CommandUsage cmdPerf, Collection<String> blacklistedArgs, MessageResolver messageResolver, RemoteConnectionFactory connectionFactory) { _scriptAdapter = scriptAdapter; _dbAdapter = dbAdapter; _session = session; _sys = sys; _request = request; _componentRepository = componentRespository; _nativePool = nativePool; _cmdPerf = (cmdPerf == null) ? new NullCommandUsage() : cmdPerf; _blacklistedArgs = blacklistedArgs; _messageResolver = messageResolver; _transactionManager = new MyTransactionManager(_dbAdapter, _transactionStack); _connectionFactory = connectionFactory; } // @see com.sam.moca.server.exec.ServerContext#newResults() public EditableResults newResults() { return new SimpleResults(); } public MocaContext getComponentContext() { // Before handing out make sure status is okay checkStatus(); return new ComponentContext(); } // @see com.sam.moca.server.exec.ServerContext#popStack() @Override public void popStack(boolean keepErrorState) { try { _dataStackLock.lock(); boolean errorStateSet = _dataStack[_dataStackLevel].errorStatePushed; MocaException errorState = _dataStack[_dataStackLevel].pushedError; // First we null out the reference so the garbage collector can // collect the data stack if needed _dataStack[_dataStackLevel] = null; _dataStackLevel--; _stackLevel.decrementLevel(); if (keepErrorState && _dataStackLevel >= 0 && errorStateSet) { _dataStack[_dataStackLevel].errorStatePushed = true; _dataStack[_dataStackLevel].pushedError = errorState; } } finally { _dataStackLock.unlock(); } } // @see com.sam.moca.server.exec.ServerContext#pushStack() @Override public void pushStack() { try { _dataStackLock.lock(); _dataStackLevel++; _stackLevel.incrementLevel(); _dataStack[_dataStackLevel] = new _DataStackElement(); } finally { _dataStackLock.unlock(); } } // @see com.sam.moca.server.exec.ServerContext#setCommand(java.lang.String) @Override public void setCommand(ExecutableComponent command) { try { _dataStackLock.lock(); _DataStackElement frame = _dataStack[_dataStackLevel]; frame.command = command; } finally { _dataStackLock.unlock(); } } // @see com.sam.moca.server.exec.ServerContext#setColumns(com.sam.moca.MocaResults) @Override public void setColumns(MocaResults res) { try { _dataStackLock.lock(); _DataStackElement frame = _dataStack[_dataStackLevel]; frame.res = res; } finally { _dataStackLock.unlock(); } } // @see com.sam.moca.server.exec.ServerContext#setRow(com.sam.moca.RowIterator) public void setRow(RowIterator row) { try { _dataStackLock.lock(); _DataStackElement frame = _dataStack[_dataStackLevel]; frame.iter = row; } finally { _dataStackLock.unlock(); } } // @see com.sam.moca.server.exec.ServerContext#clearArgs() public void clearArgs() { try { _dataStackLock.lock(); _DataStackElement frame = _dataStack[_dataStackLevel]; frame.args.clear(); frame.argList.clear(); } finally { _dataStackLock.unlock(); } } // @see com.sam.moca.server.exec.ServerContext#addArg(java.lang.String, com.sam.moca.MocaOperator, com.sam.moca.server.MocaValue) public void addArg(String name, MocaOperator oper, MocaValue value) { try { _dataStackLock.lock(); _DataStackElement frame = _dataStack[_dataStackLevel]; String lowerName = name.toLowerCase(); _StackArg arg = new _StackArg(name, oper, value); frame.args.put(lowerName, arg); frame.argList.add(arg); } finally { _dataStackLock.unlock(); } } @Override public MocaException getLastError() { try { _dataStackLock.lock(); for (int i = _dataStackLevel; i >= 0; i--) { _DataStackElement frame = _dataStack[i]; if (frame.errorStateSet) { return frame.error; } } } finally { _dataStackLock.unlock(); } return null; } // @see com.sam.moca.server.exec.ServerContext#setError(com.sam.moca.MocaException) public void setError(MocaException e) { try { _dataStackLock.lock(); _DataStackElement frame = _dataStack[_dataStackLevel]; frame.error = e; frame.errorStateSet = true; frame.pushedError = e; frame.errorStatePushed = true; } finally { _dataStackLock.unlock(); } } @Override public void fixErrorState() { try { _dataStackLock.lock(); _DataStackElement frame = _dataStack[_dataStackLevel]; if (!frame.errorStateSet) { frame.errorStateSet = true; frame.error = frame.pushedError; } } finally { _dataStackLock.unlock(); } } public void clearError() { try { _dataStackLock.lock(); if (_dataStackLevel >= 0) { _DataStackElement frame = _dataStack[_dataStackLevel]; frame.error = null; frame.errorStateSet = false; frame.errorStatePushed = false; } } finally { _dataStackLock.unlock(); } } // @see com.sam.moca.server.exec.ServerContext#getStackLevel() public StackLevel getStackLevel() { // This can be used in a separate thread, but the data stack lock must // be acquired before retrieval and released after you are done using it. return _stackLevel; } // @see com.sam.moca.server.exec.ServerContext#getVariable(java.lang.String, boolean) public MocaValue getVariable(String name, boolean markUsed) { return getVariable(name, null, markUsed); } // @see com.sam.moca.server.exec.ServerContext#getVariable(java.lang.String, boolean) public MocaValue getVariable(String name, String alias, boolean markUsed) { return _getVariable(name, alias, markUsed); } // @see com.sam.moca.server.exec.ServerContext#isVariableAvailable(java.lang.String) public boolean isVariableAvailable(String name) { return _isVariableMapped(name); } // javadoc inherited from interface // @see com.sam.moca.server.exec.ServerContext#getSystemVariable(java.lang.String) public String getSystemVariable(String name) { return _getSystemVariable(name); } // javadoc inherited from interface // @see com.sam.moca.server.exec.ServerContext#putSystemVariable(java.lang.String, java.lang.Sting) public void putSystemVariable(String name, String value) { String oldValue = _session.putVariable(name, value); _request.putVariable(name, value); // This will cover to make sure that if the old value was different // then the new one. // The first part of the if covers if oldvalue was null and value // was not // The second part of the if covers 2 parts: when oldvalue was not // null and value was null (since equals is not true in this) and // when they are both not null and are not equals if (_nativeAdapter != null && ((value != null && oldValue == null) || (oldValue != null && !oldValue.equals(value)))) { _nativeAdapter.setEnvironmentVariable(name, value); } } @Override public void putJavaSystemVariable(String name, String value) { _session.putVariable(name, value); _request.putVariable(name, value); } // javadoc inherited from interface // @see com.sam.moca.server.exec.ServerContext#removeSystemVariable(java.lang.String) public void removeSystemVariable(String name) { if (_session.isVariableMapped(name)) { _session.removeVariable(name); if (_nativeAdapter != null) { _nativeAdapter.setEnvironmentVariable(name, null); } } _request.removeVariable(name); } // @see com.sam.moca.server.exec.ServerContext#getVariableAsArgument(java.lang.String, boolean) public MocaArgument getVariableAsArgument(String name, boolean markUsed, boolean equalsOnly) { return _getVariableOrArg(name, null, markUsed, equalsOnly); } // @see com.sam.moca.server.exec.ServerContext#getVariableAsArgument(java.lang.String, boolean) public MocaArgument getVariableAsArgument(String name, String alias, boolean markUsed, boolean equalsOnly) { return _getVariableOrArg(name, alias, markUsed, equalsOnly); } // @see com.sam.moca.server.exec.ServerContext#getCommandArgs() public MocaArgument[] getCommandArgs(boolean getAll, boolean useLowLevel) { List<MocaArgument> argList = new ArrayList<MocaArgument>(); if (!_commandStack.isEmpty()) { _CommandStackElement top = _commandStack.getFirst(); if (top != null && top.args != null) { for (_StackArg arg : top.args) { if (getAll || !arg.used) { String argName = arg.name; MocaArgument outArg = new MocaArgument(argName, arg.oper, arg.value.getType(), arg.value.getValue()); argList.add(outArg); } } } } if (useLowLevel) { try { _dataStackLock.lock(); _DataStackElement frame = _dataStack[_dataStackLevel]; for (_StackArg arg : frame.argList) { if (getAll || !arg.used) { String argName = arg.name; MocaArgument outArg = new MocaArgument(argName, arg.oper, arg.value.getType(), arg.value.getValue()); argList.add(outArg); } } } finally { _dataStackLock.unlock(); } } return argList.toArray(new MocaArgument[argList.size()]); } // @see com.sam.moca.server.exec.ServerContext#getRegistryValue(java.lang.String, java.lang.String, java.lang.Boolean) public String getRegistryValue(String key, boolean expand) { return _getRegistryValue(key, expand); } // @see com.sam.moca.server.exec.ServerContext#removeTransactionAttribute(java.lang.String) public void removeTransactionAttribute(String name) { _transactionManager.removeTransactionAttribute(name); } // @see com.sam.moca.server.exec.ServerContext#getTransactionAttribute(java.lang.String) public Object getTransactionAttribute(String name) { return _transactionManager.getTransactionAttribute(name); } // @see com.sam.moca.server.exec.ServerContext#setTransactionAttribute(java.lang.String, java.lang.Object) public void setTransactionAttribute(String name, Object value) { _transactionManager.setTransactionAttribute(name, value); } public CompiledScript compileScript(String script, String language) throws MocaException { _checkAuthorization(SecurityLevel.SCRIPT, "SCRIPT"); _CommandStackElement currentCommand = _commandStack.isEmpty() ? null : _commandStack.getFirst(); Command runningCommand = currentCommand != null ? currentCommand.command : null; ScriptAdapter adapter = _scriptAdapter; if (language != null) { adapter = _scriptAdapters.get(language); if (adapter == null) { throw new MocaException(3929); // TODO real exception } } return adapter.compile(script, runningCommand); } // @see com.sam.moca.server.exec.ServerContext#executeScript(java.lang.String) public MocaResults executeScript(CompiledScript compiled) throws MocaException { _checkAuthorization(SecurityLevel.SCRIPT, "SCRIPT"); CommandPath currentPath = _commandPath.get(); _commandPath.set(CommandPath.forScript(currentPath)); ServerContextStatus previousStatus = _status; try { _status = ServerContextStatus.SCRIPT_EXECUTION; _logArguments(); return compiled.execute(new ComponentContext()); } finally { _status = previousStatus; _commandPath.set(currentPath); } } // @see com.sam.moca.server.exec.ServerContext#executeScript(java.lang.String) public Object evaluateScript(CompiledScript compiled) throws MocaException { _checkAuthorization(SecurityLevel.SCRIPT, "SCRIPT"); CommandPath currentPath = _commandPath.get(); _commandPath.set(CommandPath.forScript(currentPath)); ServerContextStatus previousStatus = _status; try { _status = ServerContextStatus.SCRIPT_EXECUTION; _logArguments(); return compiled.evaluate(new ComponentContext()); } finally { _status = previousStatus; _commandPath.set(currentPath); } } // @see com.sam.moca.server.exec.ServerContext#executeSQLWithVars(java.lang.String, java.lang.String) @Override public MocaResults executeSQLWithVars(String sql) throws MocaException { return executeSQLWithVars(sql, null); } // @see com.sam.moca.server.exec.ServerContext#executeSQL(java.lang.String) @Override public MocaResults executeSQLWithVars(String sql, String profileHint) throws MocaException { _checkAuthorization(SecurityLevel.SQL, "SQL"); ServerContextStatus previousStatus = _status; long beginTime = System.nanoTime(); CommandPath currentPath = _commandPath.get(); if (profileHint == null) { _commandPath.set(CommandPath.forSQL(currentPath)); } else { _commandPath.set(CommandPath.forSQL(currentPath, profileHint)); } try { _status = ServerContextStatus.SQL_EXECUTION; _logArguments(); SQLArgReplacer sqlScanner = new SQLArgReplacer(sql, this); String resultSQL = sqlScanner.getSQLString(); BindList resultArgs = sqlScanner.getBindList(); BindMode mode = resultArgs.isEmpty() ? BindMode.AUTO : BindMode.VAR; // We don't want to try if we don't even have enough characters // for the word update or delete. if (resultSQL.length() > 6) { String beginSql = resultSQL.substring(0, 6); // If it is an update or delete then we have to make sure we // have a where clause as well. if (beginSql.equalsIgnoreCase("update") || beginSql.equalsIgnoreCase("delete")) { // We use the regex with the case not mattering Matcher whereMatcher = _whereClauseMatcher.matcher(resultSQL); if (!whereMatcher.find()) { throw new MissingWhereClauseException(); } } } EditableResults res = _dbAdapter.executeSQL(this, _currentOrCreateTransaction(), resultSQL, resultArgs, mode, false, _commandPath.get()); if (res != null) { res.reset(); } return res; } catch (SQLException e) { throw new MocaDBException(e); } finally { long endTime = System.nanoTime(); _cmdPerf.logCommandExecution(_commandPath.get(), endTime - beginTime); _status = previousStatus; _commandPath.set(currentPath); } } @Override public ExecutableComponent lookupNamedCommand(String verbNounClause, boolean override) throws CommandNotFoundException { // First, try to execute known commands. _logger.debug(MocaUtils.concat("Looking up command: ", verbNounClause)); final CommandInterceptor interceptor = _overriddenCommands.get(verbNounClause); if (interceptor != null) { _logger.debug(MocaUtils.concat("Found command interceptor [", interceptor, "] for Command: ", verbNounClause)); return new ExecutableComponent() { @Override public MocaResults execute(ServerContext ctx) throws MocaException { return interceptor.intercept(ctx.getComponentContext()); } }; } Command current = _commandStack.isEmpty() ? null : _commandStack.getFirst().command; return _componentRepository.resolveCommand(verbNounClause, override, current); } @Override public MocaResults executeDefinedCommand(Command commandDef, List<Trigger> triggers) throws MocaException { _logArguments(); _logger.debug(MocaUtils.concat("Executing Command: ", commandDef)); _checkAuthorization(commandDef.getSecurityLevel(), commandDef); // While executing, we need to keep track of the current command's // argument list. This is so a more complex command can capture the // arguments and use them for SQL variable replacement, e.g. // We don't need to lock here since this is just a read only operation _commandStack.addFirst(new _CommandStackElement(commandDef, _dataStack[_dataStackLevel].argList)); // We need to keep the current command path, for profiling purposes. CommandPath currentPath = _commandPath.get(); _commandPath.set(CommandPath.forCommand(currentPath, commandDef)); // From now on, we're authorized, due to the fact that we're running a command. _authStack++; MocaException excp = null; boolean needToRollback = true; long beginTime = System.nanoTime(); try { if (commandDef.getTransactionType() == TransactionType.REQUIRES_NEW) { _logger.debug("Creating sub transaction"); _pushTransaction(); _nativeAdapterStack.addFirst(_nativeAdapter); _nativeAdapter = null; } MocaResults results = commandDef.execute(this); // Only look at triggers if executing a top-level command. if (triggers != null && triggers.size() != 0) { // Create a new stack frame in the current execution engine. pushStack(); CommandPath beforeTriggerPath = _commandPath.get(); try { // Within this stack level, set the result columns. setColumns(results); _logger.debug(MocaUtils.concat("Firing triggers... (", commandDef.getName(), ")")); if (_logger.isDebugEnabled()) { StringBuilder builder = new StringBuilder(); for (Trigger trigger : triggers) { if (!trigger.isDisabled()) { if (builder.length() > 0) { builder.append("\n;\n"); } else { // We move it to next line to make it a little easier to read builder.append("\n"); } builder.append(trigger.getSyntax().trim()); } } _logger.debug(builder); } // If there are no rows, we should still execute // triggers once. if (results.getRowCount() == 0) { for (Trigger trigger : triggers) { if (!trigger.isDisabled()) { _commandPath.set(CommandPath.forTrigger(beforeTriggerPath, trigger)); long triggerBegin = System.nanoTime(); try { trigger.execute(this); } finally { _cmdPerf.logCommandExecution(_commandPath.get(), System.nanoTime() - triggerBegin); _commandPath.set(beforeTriggerPath); } } } } else { // Execute once per row. RowIterator rows = results.getRows(); while (rows.hasNext()) { rows.next(); // To push the row's data onto the stack, tell // the context about the current row's data. setRow(rows); for (Trigger trigger : triggers) { if (!trigger.isDisabled()) { _commandPath.set(CommandPath.forTrigger(beforeTriggerPath, trigger)); long triggerBegin = System.nanoTime(); try { trigger.execute(this); } finally { _cmdPerf.logCommandExecution(_commandPath.get(), System.nanoTime() - triggerBegin); _commandPath.set(beforeTriggerPath); } } } } } _logger.debug(MocaUtils.concat("Done Firing triggers... (", commandDef.getName(), ")")); } finally { popStack(false); _commandPath.set(beforeTriggerPath); } } needToRollback = false; return results; } catch (MocaException e) { excp = e; throw e; } finally { try { if (commandDef.getTransactionType() == TransactionType.REQUIRES_NEW) { if (needToRollback) { _logger.debug("Rolling back sub transaction"); } else { _logger.debug("Committing sub transaction"); } _popTransaction(needToRollback); // This means that keepalive was set. It can't be still // executing as that makes no sense here since we // defined the scope of the native adapter to start // at this stack level. if (_nativeAdapter != null) { _logger.debug("Native adapter used in nested " + "transaction with keepalive -- releasing"); _nativeAdapter.release(); _nativeAdapter = null; } _nativeAdapter = _nativeAdapterStack.removeFirst(); } } catch (MocaException e) { _logger.error("Exception closing sub-transaction: " + e, e); throw e; } finally { _authStack--; _commandStack.removeFirst(); if (_logger.isDebugEnabled()) { _logger.debug(MocaUtils.concat("Executed Command: ", commandDef)); if (excp != null) { _logger.debug(MocaUtils.concat("*** RAISING ERROR ", excp.getErrorCode())); } if (!_commandStack.isEmpty()) { Command formerCommand = _commandStack.getFirst().command; if (formerCommand != null) { _logger.debug(MocaUtils.concat("Resuming execution of ", formerCommand)); } } } long endTime = System.nanoTime(); _cmdPerf.logCommandExecution(_commandPath.get(), endTime - beginTime); _commandPath.set(currentPath); } } } // @see com.sam.moca.server.exec.ServerContext#executeNamedCommand(java.lang.String, boolean) public MocaResults executeNamedCommand(String verbNounClause, boolean override) throws MocaException { ExecutableComponent exec = this.lookupNamedCommand(verbNounClause, override); return exec.execute(this); } // @see com.sam.moca.server.exec.ServerContext#executeRemote(java.lang.String, java.lang.String) @Override public MocaResults executeRemote(String remoteHost, String commandText) throws MocaException { _checkAuthorization(SecurityLevel.REMOTE, "REMOTE"); CommandPath beforePath = _commandPath.get(); CommandPath remotePath = CommandPath.forRemote(beforePath, remoteHost); _commandPath.set(remotePath); long remoteBegin = System.nanoTime(); ServerContextStatus previousStatus = _status; try { _status = ServerContextStatus.REMOTE_EXECUTION; _logger.debug(MocaUtils.concat("Executing command on remote host (", remoteHost, "): ", commandText)); MocaConnection conn = _getRemoteConnection(remoteHost, true, false); MocaArgument[] context; if (conn instanceof LocalConnection) { _logger.debug("Redirecting remote command to local server " + "with different transaction..."); context = null; } else { // Set up a stack context to be used for remote calls, but only // if it is real remote call. context = prepareNormalContext(); } // We always need the command args for @* support MocaArgument[] commandArgs = getCommandArgs(false, false); try { return conn.executeCommandWithContext(commandText, context, commandArgs); } catch (MocaException e) { int errorCode = e.getErrorCode(); if (errorCode == AuthenticationException.CODE) { throw new RemoteAuthenticationException(e.getMessage()); } else if (errorCode == SessionClosedException.CODE) { throw new RemoteSessionClosedException(); } else { throw e; } } } finally { _logger.debug("Remote execution complete"); _status = previousStatus; _cmdPerf.logCommandExecution(remotePath, System.nanoTime() - remoteBegin); _commandPath.set(beforePath); } } // @see com.sam.moca.server.exec.ServerContext#executeParallel(java.lang.String, java.lang.String, boolean) @Override public MocaResults executeParallel(String hosts, String commandText, boolean inTransaction) throws MocaException { _checkAuthorization(SecurityLevel.REMOTE, "PARALLEL"); _logger.debug(MocaUtils.concat("Executing ", inTransaction ? "in" : "", "parallel command on hosts (", hosts, "): ", commandText)); MocaArgument[] context = prepareNormalContext(); MocaArgument[] commandArgs = getCommandArgs(false, false); String[] hostList = hosts.split(","); ExecutorService pool = Executors.newFixedThreadPool(hostList.length); List<RemoteCall> tasks = new ArrayList<RemoteCall>(); for (String host : hostList) { MocaConnection conn = _getRemoteConnection(host, inTransaction, true); tasks.add(new RemoteCall(conn, commandText, context, commandArgs)); } EditableResults out = newResults(); out.addColumn("system", MocaType.STRING); out.addColumn("status", MocaType.INTEGER); out.addColumn("resultset", MocaType.RESULTS); CommandPath beforePath = _commandPath.get(); CommandPath remotePath = CommandPath.forRemote(beforePath, hosts); _commandPath.set(remotePath); ServerContextStatus previousStatus = _status; try { _status = ServerContextStatus.REMOTE_EXECUTION; // Keep track of ther overall status of the execution. int overallStatus = 0; List<Future<MocaResults>> allResults = pool.invokeAll(tasks); int i = 0; for (Future<MocaResults> runResult : allResults) { out.addRow(); out.setStringValue("system", hostList[i]); try { MocaResults res = runResult.get(); out.setIntValue("status", 0); out.setResultsValue("resultset", res); } catch (ExecutionException e) { Throwable t = e.getCause(); if (t instanceof MocaException) { // Keep track of the error state if we're checking for errors int errorCode = ((MocaException) t).getErrorCode(); // We only allow the execution status to kill the current transaction if // using inparallel. if (inTransaction) { overallStatus = errorCode; } MocaResults res = ((MocaException) t).getResults(); if (res == null) { res = new SimpleResults(); } out.setIntValue("status", errorCode); out.setResultsValue("resultset", res); } else { // This is done as an info, since there is no easy way // to propagate the error to the client _logger.info("Unexpected Exception received while " + "processing parallel execution for host: " + hostList[i], t); out.setIntValue("status", UnexpectedException.CODE); out.setResultsValue("resultset", new SimpleResults()); } } i++; } // If there was a failure, throw an exception. if (overallStatus != 0) { throw new ParallelExecutionException(overallStatus, out); } } catch (InterruptedException e) { throw new MocaInterruptedException(e); } finally { _logger.debug("Parallel execution complete"); _status = previousStatus; _commandPath.set(beforePath); pool.shutdownNow(); } return out; } @SuppressWarnings("unchecked") private MocaConnection _getRemoteConnection(String remoteHost, boolean inTransaction, boolean parallel) throws MocaException { MocaTransaction tx = _currentOrCreateTransaction(); long timeout = 0L; // Get list of current remote transactions. Map<String, RemoteTransaction> remoteTransactions = (Map<String, RemoteTransaction>) tx .getAttribute(REMOTE_TX_ATTR); if (remoteTransactions == null) { remoteTransactions = new LinkedHashMap<String, RemoteTransaction>(); tx.setAttribute(REMOTE_TX_ATTR, remoteTransactions); } // Break up the host into host#timeout String[] hostTimeout = remoteHost.split("#", 2); if (hostTimeout.length == 2) { remoteHost = hostTimeout[0]; try { timeout = Long.parseLong(hostTimeout[1]) * 1000L; } catch (NumberFormatException e) { _logger.warn("Invalid timeout specified (" + hostTimeout[1] + ")"); timeout = 0L; } } // If we don't have one for the named server, create a new one. RemoteTransaction remote = remoteTransactions.get(remoteHost); MocaConnection conn; if (remote == null) { Map<String, String> env = new LinkedHashMap<String, String>(_request.getAllVariables()); // Push a session key into the request, corresponding to the ID of the user. env.put(MocaSessionUtils.AUTH_ENV_KEY, MocaSessionUtils.newRemoteKey(_session.getUserId())); String remoteServerMapping = MocaRegistry.REGSEC_SERVER_MAPPING + "." + remoteHost; // We have to check the registry to see if there are any mappings // that we have to transform the remote into something else String serverMapping = _sys.getConfigurationElement(remoteServerMapping, false); // If the registry value wasn't present default back to remote host if (serverMapping == null) { serverMapping = remoteHost; } String url = _sys.getConfigurationElement(MocaRegistry.REGKEY_SERVER_URL, false); // If the resultant mapping matches the url in the registry, then // we bypass the remote call and instead use a local connection to // avoid the performance hit of the connection protocol. // We don't support this for parallel. if (serverMapping.equals(url) && !parallel) { conn = new LocalConnection(); } else { try { conn = _connectionFactory.getConnection(serverMapping, env); } catch (MocaException e) { throw new RemoteConnectionFailedException(serverMapping, e); } } conn.setAutoCommit(false); conn.setRemote(true); remoteTransactions.put(remoteHost, new RemoteTransaction(conn, inTransaction)); } else { conn = remote.getConn(); } conn.setTimeout(timeout); return conn; } private MocaArgument[] prepareNormalContext() { // Go through the data stack and grab a "normalized" context. Basically, that means to make a list of current // stack values and push those into a single "row" of data. Map<String, MocaArgument> contextMap = new LinkedHashMap<String, MocaArgument>(); Set<String> hiddenArguments = new HashSet<String>(); // Loop through the data stack elements for (int i = _dataStackLevel; i >= 0; i--) { _DataStackElement stack = _dataStack[i]; // If there are results, push those values into the map. if (stack.iter != null && stack.res != null) { for (int c = 0; c < stack.res.getColumnCount(); c++) { String columnName = stack.res.getColumnName(c).toLowerCase(); if (!contextMap.containsKey(columnName) && !hiddenArguments.contains(columnName)) { // If the result set is hidden then we want to // make sure it gets hidden Object value = stack.iter.getValue(c); if (value == MocaConstants.HIDDEN) { hiddenArguments.add(columnName); } MocaType type = stack.res.getColumnType(c); contextMap.put(columnName, new MocaArgument(columnName, type, stack.iter.getValue(c))); } } } // If there are arguments at this level, push those values (and operators) // into the map. if (stack.args != null) { for (Map.Entry<String, _StackArg> entry : stack.args.entries()) { String name = entry.getKey(); // already lower case if (!contextMap.containsKey(name) && !hiddenArguments.contains(name.toLowerCase())) { _StackArg arg = entry.getValue(); contextMap.put(name, new MocaArgument(arg.name, arg.oper, arg.value.getType(), arg.value.getValue())); } } } } _logArguments(); // Squeeze the context list into an array. MocaArgument[] context = contextMap.values().toArray(new MocaArgument[contextMap.size()]); return context; } // @see com.sam.moca.server.exec.ServerContext#executeCommand(java.lang.String, java.util.Map, boolean) @Override public MocaResults executeCommand(String command, Map<String, ?> args, boolean keepContext) throws MocaException { return _executeTranslate(command, valueMap(args), keepContext); } private static Map<String, MocaValue> valueMap(Map<String, ?> input) { if (input == null) return null; Map<String, MocaValue> values = new LinkedHashMap<String, MocaValue>(input.size()); for (Map.Entry<String, ?> entry : input.entrySet()) { Object value = entry.getValue(); values.put(entry.getKey(), new MocaValue(MocaType.forValue(value), value)); } return values; } @Override public MocaResults executeCommandWithRemoteContext(String command, Collection<MocaArgument> context, Collection<MocaArgument> args) throws MocaException { // Keep track of incoming command args -- they're part of our remote // protocol List<_StackArg> incomingArgs = new ArrayList<_StackArg>(); if (args != null) { for (MocaArgument arg : args) { String name = arg.getName(); MocaValue value = new MocaValue(arg.getType(), arg.getValue()); incomingArgs.add(new _StackArg(name, arg.getOper(), value)); } } _CommandStackElement tmpStack = new _CommandStackElement(null, incomingArgs); _commandStack.addFirst(tmpStack); ServerContextStatus previousStatus = _status; try { _status = ServerContextStatus.IN_ENGINE; // Now, deal with the "normal" context. We treat the incoming // context as args, even though they're not, // and the data stack args differ greatly from the command args (set // up above). if (context != null) { Map<String, _StackArg> execArgs = new HashMap<String, _StackArg>(); for (MocaArgument arg : context) { String name = arg.getName(); String lowerName = name.toLowerCase(); MocaValue value = new MocaValue(arg.getType(), arg.getValue()); execArgs.put(lowerName, new _StackArg(name, arg.getOper(), value)); } MocaResults res = _executeQuery(command, execArgs, false); return res; } else { MocaResults res = _executeQuery(command, null, false); return res; } } finally { _status = previousStatus; _commandStack.removeFirst(); } } // @see com.sam.moca.server.exec.ServerContext#commit() @Override public void commit() throws MocaException { _transactionManager.commit(); } // @see com.sam.moca.server.exec.ServerContext#rollback() @Override public void rollback() throws MocaException { _transactionManager.rollback(); } // @see com.sam.moca.server.exec.ServerContext#getDbType() @Override public DBType getDbType() { return _dbAdapter.getDBType(); } // @see com.sam.moca.server.exec.ServerContext#getNextSequenceValue(java.lang.String) @Override public String getNextSequenceValue(String name) throws MocaException { ServerContextStatus previousStatus = _status; try { _status = ServerContextStatus.SQL_EXECUTION; return _transactionManager.getNextSequenceValue(name); } finally { _status = previousStatus; } } // @see com.sam.moca.server.exec.ServerContext#getNativeLibraryAdapter() @Override synchronized public NativeLibraryAdapter getNativeLibraryAdapter() throws MocaException { if (_nativeAdapter == null) { _nativeAdapter = _nativePool.getNativeAdapter(this); } return _nativeAdapter; } @Override public void commitDB() throws SQLException { _transactionManager.commitDB(); } @Override public MocaResults executeSQL(String sql, BindList args, boolean autoBind, boolean ignoreResults) throws SQLException, MocaException { // Before executing make sure status is okay. checkStatus(); _logger.debug("Executing SQL"); MocaTransaction tx = _currentOrCreateTransaction(); ServerContextStatus previousStatus = _status; long beginTime = System.nanoTime(); CommandPath currentPath = _commandPath.get(); _commandPath.set(CommandPath.forSQL(currentPath)); try { _status = ServerContextStatus.SQL_EXECUTION; _logArguments(); BindMode bindMode = autoBind ? BindMode.AUTO : BindMode.NONE; EditableResults res = _dbAdapter.executeSQL(this, tx, sql, args, bindMode, ignoreResults, _commandPath.get()); if (res != null) { res.reset(); } return res; } finally { _logger.debug("SQL Exec complete"); long endTime = System.nanoTime(); _cmdPerf.logCommandExecution(_commandPath.get(), endTime - beginTime); _status = previousStatus; _commandPath.set(currentPath); } } @Override public void rollbackDB() throws SQLException { _transactionManager.rollbackDB(); } @Override public void setSavepoint(String savepoint) throws SQLException { _transactionManager.setSavepoint(savepoint); } @Override public void rollbackDB(String savepoint) throws SQLException { _transactionManager.rollbackDB(savepoint); } @Override public void close() { if (!_closed) { _logger.debug("Server Context Closed"); // Now we have to rollback each transaction one by one. while (_transactionStack.size() > 0) { try { rollback(); } catch (MocaException e) { _logger.error("Error closing transaction (should already be closed)"); } _transactionStack.remove(); } // Release the native process when we're done with our // transaction. try { if (_nativeAdapter != null) { _nativeAdapter.release(); _nativeAdapter = null; } } catch (MocaException e) { _logger.error("Error releasing native process"); } // After we are finished closing make sure to mark it as so. _closed = true; } } /* (non-Javadoc) * @see com.sam.moca.server.exec.ServerContext#hasKeepalive() */ @Override public boolean hasKeepalive() { return _nativeAdapter != null; } @Override public boolean hasTransaction() { if (_transactionStack.isEmpty()) { return false; } if (_transactionStack.size() == 1 && !_transactionStack.getFirst().isOpen()) { return false; } return true; } @Override public void logDebug(Object msg) { _logger.debug(msg); } // // Implementation // // Execute a query request and translate the arguments into well-known value objects. private MocaResults _executeTranslate(String query, Map<String, MocaValue> args, boolean keepContext) throws MocaException { ServerContextStatus previousStatus = _status; try { _status = ServerContextStatus.IN_ENGINE; MocaResults res; _logger.debug(MocaUtils.concat("Command initiated: [", query, "], Inline: ", keepContext)); if (args != null) { Map<String, _StackArg> execArgs = new HashMap<String, _StackArg>(); for (Entry<String, MocaValue> e : args.entrySet()) { String name = e.getKey(); String lowerName = name.toLowerCase(); MocaValue value = e.getValue(); execArgs.put(lowerName, new _StackArg(name, MocaOperator.EQ, value)); } res = _executeQuery(query, execArgs, keepContext); } else { res = _executeQuery(query, null, keepContext); } return res; } finally { _status = previousStatus; } } // Execute a client query private MocaResults _executeQuery(String query, Map<String, _StackArg> args, boolean keepContext) throws MocaException { // Make sure status is okay before executing the command. checkStatus(); _logger.debug("Parsing command... "); CommandSequence compiled; try { MocaParser parser = new MocaParser(query); compiled = parser.parse(); _logger.debug("Parsed command"); } catch (MocaParseException e) { _logger.debug(MocaUtils.concat("Parse Error: ", e)); throw e; } _previousStatement.push(query); _DataStackElement[] tempStack = null; int tempStackLevel = 0; if (!keepContext) { try { _dataStackLock.lock(); // We copy the stack level tempStackLevel = _dataStackLevel; _dataStackLevel = -1; // We copy the actual stack up to the stack level tempStack = Arrays.copyOf(_dataStack, tempStackLevel + 1); // We then have to fill the datastack with nulls, so that our // context is cleared Arrays.fill(_dataStack, 0, tempStackLevel + 1, null); } finally { _dataStackLock.unlock(); } } pushStack(); setCommand(compiled); try { if (args != null) { try { _dataStackLock.lock(); _DataStackElement frame = _dataStack[_dataStackLevel]; frame.args.putAll(Multimaps.forMap(args)); frame.argList.addAll(args.values()); } finally { _dataStackLock.unlock(); } } _logger.debug("Executing..."); return compiled.execute(this); } finally { popStack(false); _previousStatement.pop(); if (!keepContext) { try { _dataStackLock.lock(); // We copy the stack level back in _dataStackLevel = tempStackLevel; // We copy the actual stack up to the stack level back in System.arraycopy(tempStack, 0, _dataStack, 0, _dataStackLevel + 1); } finally { _dataStackLock.unlock(); } } } } /** * This will log a server argument given the values. Any value that is a * Java object will default to what toString would provide as if it wasn't * overwritten by the class * @param type The type, or the first part appended to the trace ie. Argument * or Published * @param name The name of the value * @param value The value itself */ private void _logServerArguments(String type, String name, MocaValue value) { switch (value.getType()) { case OBJECT: Object javaObj = value.getValue(); if (javaObj == null) { _argumentLogger .debug(MocaUtils.concat(type, " ", name, "=null (", value.getType().toString(), ")")); } else if (javaObj == MocaConstants.HIDDEN) { _argumentLogger.debug(MocaUtils.concat(type, " ", name, "=", javaObj)); } else { _argumentLogger.debug(MocaUtils.concat(type, " ", name, "=", javaObj.getClass(), "@", System.identityHashCode(javaObj), " (", value.getType().toString(), ")")); } break; default: if (_blacklistedArgs != null && _blacklistedArgs.contains(name)) { _argumentLogger.debug(new SecureLogMessage(true, type + " " + name + "=%1$s (" + value.getType().toString() + ")", value.asString())); } else { _argumentLogger.debug(MocaUtils.concat(type, " ", name, "=", value.asString(), " (", value.getType().toString(), ")")); } break; } } /** * This will log all the current arguments or results on the stack to the * argument logger if it is enabled. */ private void _logArguments() { // We only want to go through the arguments if the logger // has trace enabled if (_argumentLogger.isDebugEnabled()) { // We loop through the stack, and we include the 0th level since // a user can pass in what people refer to as bind variables, but // really are just lvl 0 stack variables. for (int i = _dataStackLevel; i >= 0; i--) { _DataStackElement traceFrame = _dataStack[i]; List<_StackArg> traceArgs = traceFrame.argList; RowIterator traceIter = traceFrame.iter; MocaResults traceMetadata = traceFrame.res; // We print out the results first if (traceMetadata != null && traceIter != null) { // Now loop through all the columns of the metadata for (int j = 0; j < traceMetadata.getColumnCount(); ++j) { MocaType traceType = traceMetadata.getColumnType(j); _logServerArguments("Published", traceMetadata.getColumnName(j), new MocaValue(traceType, traceIter.getValue(j))); } } // We print out the arguments last if (traceArgs != null) { for (_StackArg arg : traceArgs) { MocaValue value = arg.value; _logServerArguments("Argument", arg.name, value); } } _logger.debug("--------------------------------------"); } } } private void releaseNativeProcess(boolean okToCommit) throws MocaException { // Release the native process when we're done with our // transaction. if (_nativeAdapter != null) { // Call native (C) postcommit hooks. _nativeAdapter.postTransaction(okToCommit); // release the adapter, unless something is executingon the C side. if (!_nativeAdapter.isKeepaliveSet() && !_nativeAdapter.currentlyActive()) { _nativeAdapter.release(); _nativeAdapter = null; } } } private MocaValue _getVariable(String name, String alias, boolean markUsed) { // Shortcut if null is passed in if (name == null && alias == null) { return null; } String lowerName = (name == null || name.isEmpty()) ? null : name.toLowerCase(); String lowerAlias = (alias == null || alias.isEmpty()) ? null : alias.toLowerCase(); // We shouldn't have to synchronize this since we are just doing a read for (int i = _dataStackLevel; i >= 0; --i) { _DataStackElement stack = _dataStack[i]; if (stack.iter != null && stack.res != null) { int column = -1; if (lowerName != null) { column = stack.res.getColumnNumber(lowerName); } if (lowerAlias != null) { int tmpCol = stack.res.getColumnNumber(lowerAlias); // If the alias column exists in the current stack level, // use it, but only if the actual column name is not found, // or was found in this stack level but earlier in the result // set. if (tmpCol != -1 && (column == -1 || tmpCol < column)) { column = tmpCol; } } if (column != -1) { if (stack.iter.getValue(column) == MocaConstants.HIDDEN) { return null; } return new MocaValue(stack.res.getColumnType(column), stack.iter.getValue(column)); } } // Check arguments. MocaArgument argValue = null; if (lowerName != null) { argValue = stack.getArg(lowerName, markUsed, true); } if (lowerAlias != null) { MocaArgument tmp = stack.getArg(lowerAlias, markUsed, true); if (argValue == null) { argValue = tmp; } else { if (tmp != null && stack.useAlias(lowerName, lowerAlias)) { argValue = tmp; } } } if (argValue != null) { return new MocaValue(argValue.getType(), argValue.getValue()); } } return null; } private MocaArgument _getVariableOrArg(String name, String alias, boolean markUsed, boolean equalsOnly) { // Shortcut if null is passed in if (name == null && alias == null) { return null; } String lowerName = (name == null || name.isEmpty()) ? null : name.toLowerCase(); String lowerAlias = (alias == null || alias.isEmpty()) ? null : alias.toLowerCase(); // We shouldn't have to synchronize this since we are just doing a read for (int i = _dataStackLevel; i >= 0; --i) { _DataStackElement stack = _dataStack[i]; if (stack.iter != null && stack.res != null) { int column = -1; if (lowerName != null) { column = stack.res.getColumnNumber(lowerName); } if (lowerAlias != null) { int tmpCol = stack.res.getColumnNumber(lowerAlias); if (tmpCol != -1 && tmpCol < column) { column = tmpCol; } } if (column != -1) { if (stack.iter.getValue(column) == MocaConstants.HIDDEN) { return null; } Object valueData = stack.iter.getValue(column); MocaType valueType = stack.res.getColumnType(column); return new MocaArgument(name, MocaOperator.EQ, valueType, valueData); } } MocaArgument argValue = stack.getArg(lowerName, markUsed, equalsOnly); if (lowerAlias != null) { MocaArgument tmp = stack.getArg(lowerAlias, markUsed, true); if (argValue == null) { argValue = tmp; } else { if (tmp != null && stack.useAlias(lowerName, lowerAlias)) { argValue = tmp; } } } if (argValue == null && lowerAlias != null) { argValue = stack.getArg(lowerAlias, markUsed, true); } if (argValue != null) { return argValue; } } return null; } private boolean _isVariableMapped(String name) { String lowerName = name.toLowerCase(); // We shouldn't have to synchronize this since we are just doing a read for (int i = _dataStackLevel; i >= 0; --i) { _DataStackElement stack = _dataStack[i]; if (stack.res != null && stack.res.containsColumn(lowerName) && stack.iter != null) { if (stack.iter.getValue(lowerName) == MocaConstants.HIDDEN) { return false; } return true; } if (stack.args.containsKey(lowerName)) { return true; } } return false; } private String _getSystemVariable(String name) { if (_request != null && _request.isVariableMapped(name)) { return _request.getVariable(name); } else if (_session != null && _session.isVariableMapped(name)) { return _session.getVariable(name); } else { return _sys.getVariable(name); } } private String _getRegistryValue(String key, boolean expand) { return _sys.getConfigurationElement(key, expand); } private static class _StackArg { private _StackArg(String name, MocaOperator oper, MocaValue value) { ArgCheck.notNull(name); ArgCheck.notNull(oper); ArgCheck.notNull(value); this.name = name; this.oper = oper; this.value = value; this.used = false; } private String name; private MocaOperator oper; private MocaValue value; private boolean used; } private static class _CommandStackElement { private _CommandStackElement(Command command, Collection<_StackArg> args) { this.command = command; this.args = args; } private Command command; private Collection<_StackArg> args; } private static class _DataStackElement { private _DataStackElement() { args = ArrayListMultimap.create(); argList = new ArrayList<_StackArg>(); } private MocaArgument getArg(String name, boolean markUsed, boolean equalsOnly) { Collection<_StackArg> argsForName = null; // Check if the key exists before getting it, this way we // can reduce some overhead of initializing the collection behind // the multimap if (args.containsKey(name)) { argsForName = args.get(name); } if (argsForName == null || argsForName.size() == 0) { return null; } _StackArg arg = null; for (_StackArg tmp : argsForName) { // Operator mismatch -- don't return other operators if (!equalsOnly || tmp.oper == MocaOperator.EQ) { arg = tmp; if (markUsed) tmp.used = true; } } if (arg == null) { return null; } return new MocaArgument(arg.name, arg.oper, arg.value.getType(), arg.value.getValue()); } private boolean useAlias(String name, String alias) { // This method is called to determine which argument to use, the // one with the primary name, or the one with the alias. The // last one on the stack should take precedence. The only time // this method should be called is when both name and alias are // not null, and are known to be on the current stack level as // arguments. boolean useAlias = false; // last one wins. for (_StackArg arg : argList) { if (arg.name.equalsIgnoreCase(name)) { useAlias = false; } else if (arg.name.equalsIgnoreCase(alias)) { useAlias = true; } } return useAlias; } private MocaException error; private boolean errorStateSet = false; private MocaException pushedError; private boolean errorStatePushed = false; private final Multimap<String, _StackArg> args; private final List<_StackArg> argList; // No one should ever call .next() on the MocaResults. This is only // here for column metadata private MocaResults res; // No one should ever call .next() on the RowIterator, it is a single // row pointing into the result set private RowIterator iter; // This is the command that is being executed at this stack level. Useful // for reporting and management purposes private ExecutableComponent command; } private MocaTransaction _currentOrCreateTransaction() throws MocaException { MocaTransaction current = _transactionStack.peekFirst(); if (current == null) { // If there is no current tx and we have a global tx then we need // start a new moca tx to tie to it if (TransactionManagerUtils.getCurrentTransaction() != null) { current = _dbAdapter.newTransaction(); _transactionStack.addFirst(current); } else { _pushTransaction(); } } MocaTransaction tx = _transactionStack.getFirst(); return tx; } private void _pushTransaction() throws MocaException { // We have to suspend the top tx MocaTransaction current = _transactionStack.peekFirst(); if (current != null) { try { current.suspend(); } catch (SQLException e) { throw new MocaDBException(e); } } MocaTransaction tx = _dbAdapter.newTransaction(); _transactionStack.addFirst(tx); } private void _popTransaction(boolean rollback) throws MocaException { if (rollback) { rollback(); } else { commit(); } _transactionStack.removeFirst(); // We have to resume the now top tx if there was one MocaTransaction current = _transactionStack.peekFirst(); if (current != null) { try { current.resume(); } catch (SQLException e) { throw new MocaDBException(e); } } } /** * This method will return the stack contents for the given MocaContext * * The result set is created by going level by level of the stack first * putting the result values of the stack first in the result. Then it * will append the arguments for that stack level. * * If there is any collision between columns in results or arguments the * first occurance of that column will be display in the result set. * Multiple columns with the same name will not exist in the result set * * If the stack is not flattened it will create a new result set for each * level of the stack and insert it into the returned result set in the * column <code>results</code>. Each row of the returned result will also * state what command was executed at the level <code>stack_command</code> * as well as the stack level itself <code>stack_level</code> * @param ctx The moca context to get the stack dump from * @param flatten Whether or not to flatten the data stack into a single * row of results * @return The results containing the stack dump */ public static MocaResults dumpStack(MocaContext ctx, boolean flatten) { EditableResults retRes = ctx.newResults(); if (ctx instanceof DefaultServerContextAware) { DefaultServerContext me = ((DefaultServerContextAware) ctx).getDefaultServerContext(); if (flatten) { retRes.addRow(); } else { retRes.addColumn("results", MocaType.RESULTS); retRes.addColumn("stack_command", MocaType.STRING); retRes.addColumn("stack_level", MocaType.INTEGER); } try { me._dataStackLock.lock(); int stackLevel = me._dataStackLevel; int actualLevel = me.getStackLevel().getLevel(); // Now loop through all the stack for (; actualLevel >= 0; --actualLevel, --stackLevel) { _DataStackElement element; if (stackLevel >= 0) { element = me._dataStack[stackLevel]; } else { element = null; } EditableResults result; // If we are flattening we want to keep using the same // result if (flatten) { result = retRes; } // Else we use a new result set else { retRes.addRow(); if (element != null) { retRes.setStringValue("stack_command", String.valueOf(element.command)); retRes.setIntValue("stack_level", actualLevel); } else { retRes.setStringValue("stack_command", ""); retRes.setIntValue("stack_level", actualLevel); } result = ctx.newResults(); result.addRow(); retRes.setResultsValue("results", result); } // Only add to the result set if we're on the known stack if (element != null) { RowIterator rowIter = element.iter; MocaResults results = element.res; // If the last result doesn't have a row we just ignore it if (rowIter != null && results != null) { // Now go through all the columns of the next result set for (int j = 0; j < results.getColumnCount(); ++j) { String columnName = results.getColumnName(j); // If our result set doesn't already contain this column // that we write stuff into it setting the value if (!result.containsColumn(columnName)) { Object value = rowIter.getValue(j); // If it is hidden we want to do the toString if (value == MocaConstants.HIDDEN) { result.addColumn(columnName, MocaType.STRING); result.setValue(columnName, value.toString()); } else { result.addColumn(columnName, results.getColumnType(j)); result.setValue(columnName, value); } } } } for (_StackArg arg : element.argList) { String columnName = arg.name; // If our result set doesn't already contain this column // that we write stuff into it setting the value if (!result.containsColumn(columnName)) { result.addColumn(columnName, arg.value.getType()); result.setValue(columnName, arg.value.getValue()); } } } } } finally { me._dataStackLock.unlock(); } } return retRes; } /** * This will list the given commands for the given MocaContext. By default * it will return all commands that are found. An optional CommandFilter * can be specified which will allow a user to pick a command by name and/or * sequence level. * @param ctx The moca context to check for commands * @return A MocaResults that contains all the information pertinent to * the commands that passed the filter. * <br> <b>Returned Columns:</b> * <br> cmplvl - The component level name as a {@link java.lang.String} * <br> cmplvlseq - The sort sequence of the component level as an * {@link int} * <br> command - The actual name of the command as a * {@link java.lang.String} * <br> cmptyp - The command type of the command as a * {@link java.lang.String} * <br> type - The command type of the command abbreviated as a * {@link java.lang.String} * <br> syntax - The syntax of the command if it is local syntax as * a {@link java.lang.String} * <br> class - The class name of the command if it is a java method * as a {@link java.lang.String} * <br> functn - The function of the command if it is a C function or * the method if is a java method as a {@link java.lang.String} * <br> insecure - Whether or not this command is insecure as a * {@link boolean} * <br> trnstyp - The transaction type of the command as a * {@link java.lang.String} */ public static MocaResults listCommands(MocaContext ctx, CommandFilter filter) { EditableResults retRes = ctx.newResults(); retRes.addColumn("cmplvl", MocaType.STRING); retRes.addColumn("cmplvlseq", MocaType.INTEGER); retRes.addColumn("command", MocaType.STRING); retRes.addColumn("cmdtyp", MocaType.STRING); retRes.addColumn("type", MocaType.STRING); retRes.addColumn("syntax", MocaType.STRING); retRes.addColumn("class", MocaType.STRING); retRes.addColumn("functn", MocaType.STRING); retRes.addColumn("security", MocaType.STRING); retRes.addColumn("trnstyp", MocaType.STRING); retRes.addColumn("filename", MocaType.STRING); retRes.addColumn("desc", MocaType.STRING); // If the ctx isn't our context object then don't allow it if (ctx instanceof DefaultServerContextAware) { DefaultServerContext me = ((DefaultServerContextAware) ctx).getDefaultServerContext(); // Now we actually get all the commands from the repository List<Command> commands = me._componentRepository.getAllCommands(); // Loop through each of them and check if it passes the filter // and then set the information on the result set for (Command command : commands) { if (filter == null || filter.accept(command.getName(), command.getLevel().getName())) { retRes.addRow(); // These values are common to all commands retRes.setStringValue("cmplvl", command.getLevel().getName()); retRes.setIntValue("cmplvlseq", command.getLevel().getSortseq()); retRes.setStringValue("command", command.getName()); retRes.setStringValue("security", command.getSecurityLevel().toString()); retRes.setStringValue("trnstyp", command.getTransactionType().toString()); retRes.setStringValue("filename", command.getFileName()); retRes.setStringValue("desc", command.getDescription()); switch (command.getType()) { case LOCAL_SYNTAX: retRes.setStringValue("cmdtyp", "L"); retRes.setStringValue("type", "Local Syntax"); // If it is local syntax then we need to add the syntax if (command instanceof LocalSyntaxCommand) { retRes.setStringValue("syntax", ((LocalSyntaxCommand) command).getSyntax().trim()); } break; case C_FUNCTION: retRes.setStringValue("cmdtyp", "C"); retRes.setStringValue("type", "C Function"); // If it is a CFunctionCommand that we need to append // the function to it if (command instanceof CFunctionCommand) { retRes.setStringValue("functn", ((CFunctionCommand) command).getFunction()); } break; case SIMPLE_C_FUNCTION: retRes.setStringValue("cmdtyp", "C"); retRes.setStringValue("type", "Simple C Function"); // If it is a CFunctionCommand that we need to append // the function to it if (command instanceof CFunctionCommand) { retRes.setStringValue("functn", ((CFunctionCommand) command).getFunction()); } break; case COM_METHOD: retRes.setStringValue("cmdtyp", "O"); retRes.setStringValue("type", "COM Method"); break; case JAVA_METHOD: retRes.setStringValue("cmdtyp", "J"); retRes.setStringValue("type", "Java Method"); // If it is a JavaMethod that we need to append the // class and function/method to it if (command instanceof JavaCommand) { retRes.setStringValue("class", ((JavaCommand) command).getClassName()); retRes.setStringValue("functn", ((JavaCommand) command).getMethod()); } break; default: // This means it is unknown retRes.setStringValue("cmdtyp", "U"); retRes.setStringValue("type", "Unknown"); break; } } } } return retRes; } public static Collection<CommandUsageStatistics> listCommandUsage(MocaContext ctx) { // If the ctx isn't our context object then don't allow it if (ctx instanceof DefaultServerContextAware) { DefaultServerContext me = ((DefaultServerContextAware) ctx).getDefaultServerContext(); return me._cmdPerf.getStats(); } else { return null; } } public static void clearCommandUsage(MocaContext ctx) { // If the ctx isn't our context object then don't allow it if (ctx instanceof DefaultServerContextAware) { DefaultServerContext me = ((DefaultServerContextAware) ctx).getDefaultServerContext(); me._cmdPerf.reset(); } } /** * This will list the given command arguments for the given MocaContext. By * default it will return all command arguments available. An optional * CommandArgumentFilter can be specified which will allow a user to pick * a command argument by name, component level and/or argument name. * @param ctx The Moca Context * @param filter The optional filter that can narrow the command arguments * returned * @return A MocaResults that contains all the information pertinent to * the command arguments that passed the filter. * <br> <b>Returned Columns:</b> * <br> cmplvl - The component level name as a {@link java.lang.String} * <br> command - The actual name of the command as a * {@link java.lang.String} * <br> argname - The argument name as a {@link java.lang.String} * <br> altnam - The alternate name for the argument as a * {@link java.lang.String} * <br> argtyp - The argument data type as a {@link java.lang.String} * <br> fixval - The default value of the argument if a value was * not provided as a {@link java.lang.String} * <br> argidx - The index of the argument for the command as a * {@link int} * <br> argreq - Whether or not this argument is required as a * {@link boolean} */ public static MocaResults listCommandArguments(MocaContext ctx, CommandArgumentFilter filter) { EditableResults retRes = ctx.newResults(); retRes.addColumn("cmplvl", MocaType.STRING); retRes.addColumn("command", MocaType.STRING); retRes.addColumn("argnam", MocaType.STRING); retRes.addColumn("altnam", MocaType.STRING); retRes.addColumn("argtyp", MocaType.STRING); retRes.addColumn("fixval", MocaType.STRING); retRes.addColumn("argidx", MocaType.INTEGER); retRes.addColumn("argreq", MocaType.BOOLEAN); // If the ctx isn't our context object then don't allow it if (ctx instanceof DefaultServerContextAware) { DefaultServerContext me = ((DefaultServerContextAware) ctx).getDefaultServerContext(); // Now we actually get all the commands from the repository List<Command> commands = me._componentRepository.getAllCommands(); for (Command command : commands) { List<ArgumentInfo> arguments = command.getArguments(); int index = 0; for (ArgumentInfo argument : arguments) { if (filter == null || filter.accept(command.getLevel().getName(), command.getName(), argument.getName())) { retRes.addRow(); retRes.setStringValue("cmplvl", command.getLevel().getName()); retRes.setStringValue("command", command.getName()); retRes.setStringValue("argnam", argument.getName()); retRes.setStringValue("altnam", argument.getAlias()); // If the data type is null then set it to UNKNOWN if (argument.getDatatype() == null) { retRes.setStringValue("argtyp", ArgType.UNKNOWN.toString()); } else { retRes.setStringValue("argtyp", argument.getDatatype().toString()); } retRes.setStringValue("fixval", argument.getDefaultValue()); retRes.setIntValue("argidx", index); retRes.setBooleanValue("argreq", argument.isRequired()); } index++; } } } return retRes; } /** * This will list the given library versions for the given MocaContext. By * default it will return all library versions available. An optional * ComponentLibraryFilter can be specified which will allow a user to pick * a library by category. * @param ctx The Moca Context * @param filter The optional filter that can narrow the libraries returned * @return A MocaResults that contains all the information pertinent to * the command arguments that passed the filter. * <br> <b>Returned Columns:</b> * <br> category - The component level name as a {@link java.lang.String} * <br> library_name - The C library name associated with this * library as a {@link java.lang.String} * <br> library_type - The type of library this is as a * {@link java.lang.String} This can be Java, C, COM * <br> package_name - The java package if provided for this library * as a {@link java.lang.String} * <br> version - The compile date or version as a * {@link java.lang.String} * <br> product - The product license this library falls under as a * {@link java.lang.String} * <br> licensed - Whether this library is licensed or not as a * {@link boolean} */ public static MocaResults listLibraryVersions(MocaContext ctx, ComponentLibraryFilter filter) { EditableResults retRes = ctx.newResults(); retRes.addColumn("category", MocaType.STRING); retRes.addColumn("library_type", MocaType.STRING); retRes.addColumn("library_name", MocaType.STRING); retRes.addColumn("package_name", MocaType.STRING); retRes.addColumn("progid", MocaType.STRING); retRes.addColumn("sort_seq", MocaType.INTEGER); retRes.addColumn("version", MocaType.STRING); retRes.addColumn("product", MocaType.STRING); // If the ctx isn't our context object then don't allow it if (ctx instanceof DefaultServerContextAware) { DefaultServerContext me = ((DefaultServerContextAware) ctx).getDefaultServerContext(); List<ComponentLevel> components = me._componentRepository.getLevels(); for (ComponentLevel component : components) { if (filter != null) { // If the filter is provided and the component didn't pass // then go to the next one if (!filter.accept(component)) { continue; } } retRes.addRow(); retRes.setStringValue("category", component.getName()); retRes.setStringValue("library_name", component.getLibrary()); retRes.setStringValue("package_name", component.getPackage()); retRes.setStringValue("progid", component.getProgid()); retRes.setIntValue("sort_seq", component.getSortseq()); retRes.setStringValue("version", component.getVersion()); retRes.setStringValue("product", component.getProduct()); String type = "????"; if (component.getPackage() != null && !component.getPackage().trim().isEmpty()) { type = "Java"; } else if (component.getLibrary() != null && !component.getLibrary().trim().isEmpty()) { type = "C"; } else if (component.getProgid() != null && !component.getProgid().trim().isEmpty()) { type = "COM"; } retRes.setStringValue("library_type", type); } } return retRes; } /** * This will list the given levels for the given MocaContext. By default * it will return all levels that are found. An optional level name * can be specified which will allow a user to pick a level by name. * @param ctx The moca context to check for commands * @param levelName The level to return if specified * @return A MocaResults that contains all the information pertinent to * the commands that passed the filter. * <br> <b>Returned Columns:</b> * <br> name - The component level name as a {@link java.lang.String} * <br> desc - The component level description as a * {@link int} * <br> srt_seq - The sort sequence of the component level as an * {@link int} * <br> editable - Whether or not this component level is editable * as a {@link boolean} * <br> cmd_dir - The directory which contains commands for this * component level as a {@link java.lang.String} */ public static MocaResults listLevels(MocaContext ctx, String levelName) { EditableResults retRes = ctx.newResults(); retRes.addColumn("name", MocaType.STRING); retRes.addColumn("desc", MocaType.STRING); retRes.addColumn("srt_seq", MocaType.INTEGER); retRes.addColumn("editable", MocaType.BOOLEAN); retRes.addColumn("cmd_dir", MocaType.STRING); // If the ctx isn't our context object then don't allow it if (ctx instanceof DefaultServerContextAware) { DefaultServerContext me = ((DefaultServerContextAware) ctx).getDefaultServerContext(); // Now we actually get all the commands from the repository List<ComponentLevel> levels = me._componentRepository.getLevels(); // Loop through each of them and check if it passes the filter // and then set the information on the result set for (ComponentLevel level : levels) { if (levelName == null || levelName.equals(level.getName())) { retRes.addRow(); retRes.setStringValue("name", level.getName()); retRes.setStringValue("desc", level.getDescription()); retRes.setIntValue("srt_seq", level.getSortseq()); retRes.setBooleanValue("editable", level.isEditable()); retRes.setStringValue("cmd_dir", level.getCmdDir()); } } } return retRes; } // @see com.sam.moca.server.exec.ServerContext#getStatus() @Override public ServerContextStatus getCurrentStatus() { return _status; } // @see com.sam.moca.server.exec.ServerContext#setCurrentStatus(com.sam.moca.server.exec.ServerContextStatus) @Override public void setCurrentStatus(ServerContextStatus status) { _status = status; } // @see com.sam.moca.server.exec.ServerContext#getLastStatementInitiated() @Override public String getLastStatementInitiated() { return _previousStatement.peek(); } /** * This will list the given triggers for the given MocaContext. By default * it will return all triggers available. An optional TriggerFilter can be * specified which will allow a user to pick a trigger by the name of the * command it is triggering off of * @param ctx The Moca Context * @param filter The optional filter that can narrow the triggers returned * @return A MocaResults that contains all the information pertinent to * the triggers that passed the filter. * <br> <b>Returned Columns:</b> * <br> command - The actual name of the command the trigger will * fire off of as a {@link java.lang.String} * <br> trgseq - The sequence the triggers will fire in as an * {@link int} * <br> syntax - The syntax of the trigger as a * {@link java.lang.String} */ public static MocaResults listTriggers(MocaContext ctx, TriggerFilter filter) { EditableResults retRes = ctx.newResults(); retRes.addColumn("name", MocaType.STRING); retRes.addColumn("command", MocaType.STRING); retRes.addColumn("trgseq", MocaType.INTEGER); retRes.addColumn("syntax", MocaType.STRING); retRes.addColumn("enabled", MocaType.BOOLEAN); retRes.addColumn("filename", MocaType.STRING); // If the ctx isn't our context object then don't allow it if (ctx instanceof DefaultServerContextAware) { DefaultServerContext me = ((DefaultServerContextAware) ctx).getDefaultServerContext(); // Now we actually get all the triggers from the repository List<Trigger> triggers = me._componentRepository.getAllTriggers(); for (Trigger trigger : triggers) { if (filter == null || filter.accept(trigger.getCommand())) { retRes.addRow(); retRes.setStringValue("name", trigger.getName()); retRes.setStringValue("command", trigger.getCommand()); retRes.setIntValue("trgseq", trigger.getFireSequence()); retRes.setStringValue("syntax", trigger.getSyntax()); retRes.setBooleanValue("enabled", !trigger.isDisabled()); retRes.setStringValue("filename", trigger.getFileName()); } } } return retRes; } /** * This will the component repository for the server * @param ctx The Moca Context * @return The component repository */ public static CommandRepository getRepository(MocaContext ctx) { if (ctx instanceof DefaultServerContextAware) { DefaultServerContext me = ((DefaultServerContextAware) ctx).getDefaultServerContext(); return me._componentRepository; } return null; } private void _checkAuthorization(SecurityLevel required, Object command) throws MocaException { // Once we're executing a command that's defined in the system, we can // execute anything. if (_authStack > 0) { return; } // If no security is required, no need to check their session. if (required == SecurityLevel.OPEN) { return; } SecurityLevel authLevel = null; // If the session is authenticated, grab the security level from // that session token. SessionToken authToken = _session.getSessionToken(); if (authToken != null) { authLevel = authToken.getSecurityLevel(); } // Default to "open" security -- an unauthenticated session can // execute only unsecured commands. if (authLevel == null) authLevel = SecurityLevel.PUBLIC; // Three possibilities. First, if security is OK, just return. If // there is no security token, the user needs to log in. If there is // a security token, and it doesn't allow execution at the proper // level, throw an authorization exception. if (authLevel.compareTo(required) >= 0) { return; } else if (authLevel == SecurityLevel.OPEN) { throw new AuthenticationException(String.valueOf(command)); } else { throw new AuthorizationException(String.valueOf(command)); } } // @see com.sam.moca.server.exec.ServerContext#getSession() @Override public SessionContext getSession() { return _session; } // @see com.sam.moca.server.exec.ServerContext#getRequest() @Override public RequestContext getRequest() { return _request; } // @see java.lang.Object#finalize() @Override protected void finalize() throws Throwable { super.finalize(); close(); } private void checkStatus() { // First check if execution was interrupted, if so then throw our error if (Thread.interrupted()) { throw new MocaInterruptedException(); } if (_closed) { throw new IllegalStateException("Context is closed."); } } // @see com.sam.moca.server.exec.ServerContext#getMessageResolver() @Override public MessageResolver getMessageResolver() { return _messageResolver; } // @see com.sam.moca.server.exec.ServerContext#getDatabaseTool() @Override public TransactionManager getTransactionManager() { return _transactionManager; } // @see com.sam.moca.server.exec.ServerContext#currentCommandPath() @Override public CommandPath currentCommandPath() { return _commandPath.get(); } // @see com.sam.moca.server.exec.ServerContext#overrideCommand(java.lang.String, com.sam.moca.server.CommandInterceptor) @Override public void overrideCommand(String commandName, CommandInterceptor interceptor) { _overriddenCommands.put(commandName, interceptor); } // @see com.sam.moca.server.exec.ServerContext#clearOverriddenCommands() @Override public void clearOverriddenCommands() { _overriddenCommands.clear(); } private class LocalConnection extends ServerSideConnection { // @see com.sam.moca.client.ServerSideConnection#executeCommandWithContext(java.lang.String, com.sam.moca.MocaArgument[], com.sam.moca.MocaArgument[]) @Override public MocaResults executeCommandWithContext(String command, MocaArgument[] args, MocaArgument[] commandArgs) throws MocaException { MocaTransaction oldTransaction = _transactionStack.peekFirst(); try { if (oldTransaction != null) { oldTransaction.suspend(); } if (_tx == null) { _tx = _dbAdapter.newTransaction(); } _tx.resume(); } catch (SQLException e) { throw new MocaDBException(e); } _transactionStack.addFirst(_tx); Map<String, MocaValue> map = new HashMap<String, MocaValue>(); if (commandArgs != null) { for (MocaArgument arg : commandArgs) { map.put(arg.getName(), arg.getDataValue()); } } try { // The Local Connection doesn't take any args directly. To // maintain this this class must only be accessible through in // the DefaultServerContext. return DefaultServerContext.this._executeTranslate(command, map, true); } finally { // We remove the transaction directly, however our transaction // will be present in the remote _transactionStack.remove(_tx); try { _tx.suspend(); if (oldTransaction != null) { oldTransaction.resume(); } } catch (SQLException e) { throw new MocaDBException(e); } } } private MocaTransaction _tx = null; } private static final String REMOTE_TX_ATTR = MocaTransactionManager.REMOTE_TX_ATTR; private static final Map<String, ScriptAdapter> _scriptAdapters = new HashMap<String, ScriptAdapter>(); static { // _scriptAdapters.put("groovy", new GroovyScriptAdapter()); } private static final Logger _logger = LogManager.getLogger(DefaultServerContext.class); private static final Logger _serverLogger = LogManager.getLogger("com.sam.moca.server"); private static final Logger _argumentLogger = LogManager.getLogger("com.sam.moca.server.Argument"); private static final Logger _sqlLogger = LogManager.getLogger("com.sam.moca.server.db.Sql"); private static final Logger _performanceLogger = LogManager.getLogger("com.sam.moca.server.Performance"); private static final Logger _managerLogger = LogManager.getLogger("com.sam.moca.server.Manager"); private static final Logger _flowLogger = LogManager.getLogger("com.sam.moca.server.Flow"); private ServerContextStatus _status = ServerContextStatus.INACTIVE; private static final int _dataStackMaxSize = 500; private final RemoteConnectionFactory _connectionFactory; private final TransactionManager _transactionManager; private final ScriptAdapter _scriptAdapter; private final DBAdapter _dbAdapter; private final NativeAdapterFactory _nativePool; private final CommandRepository _componentRepository; private final SystemContext _sys; private final SessionContext _session; private final RequestContext _request; private final Collection<String> _blacklistedArgs; private final MessageResolver _messageResolver; /** * dataStackLevel holds the level of the stack as it is currently executing. * entireStackLevel holds the level of the stack, but is not reset for * srvInitiateCommand or MocaContext.executeCommand calls. * A -1 means that there is no command currently being executed, this state * will be shown as 0 in tracing. * A 0 means that we have received a command to parse and executed * Anything higher than 0 means that we are actively executing some kind of * command */ private int _dataStackLevel = -1; /** * This is the locking mechanism for concurrent access to the data stack. * If any state of the data stack is to change you must lock on this object. * Also if any read operation requires ability to be called by another * thread it must also lock on this. */ private final Lock _dataStackLock = new ReentrantLock(); /** * No one should directly iterate over this without using the * {@link #_dataStackLevel} to tell what stack values are available for use */ private final _DataStackElement[] _dataStack = new _DataStackElement[_dataStackMaxSize]; private final LinkedList<_CommandStackElement> _commandStack = new LinkedList<_CommandStackElement>(); private AtomicReference<CommandPath> _commandPath = new AtomicReference<CommandPath>(); private final LinkedList<MocaTransaction> _transactionStack = new LinkedList<MocaTransaction>(); private final LinkedList<NativeLibraryAdapter> _nativeAdapterStack = new LinkedList<NativeLibraryAdapter>(); private final LinkedList<String> _previousStatement = new LinkedList<String>(); private final MocaStackLevel _stackLevel = new MocaStackLevel(); private final CommandUsage _cmdPerf; private int _authStack = 0; private NativeLibraryAdapter _nativeAdapter; private volatile boolean _closed = false; private final Map<String, CommandInterceptor> _overriddenCommands = new HashMap<String, CommandInterceptor>(); static final Pattern _whereClauseMatcher = Pattern.compile("where", Pattern.CASE_INSENSITIVE); }