| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package flex.messaging.util.concurrent; |
| |
| import javax.naming.InitialContext; |
| import javax.naming.NamingException; |
| |
| import com.ibm.websphere.asynchbeans.Work; |
| import com.ibm.websphere.asynchbeans.WorkEvent; |
| import com.ibm.websphere.asynchbeans.WorkException; |
| import com.ibm.websphere.asynchbeans.WorkListener; |
| import com.ibm.websphere.asynchbeans.WorkManager; |
| |
| import flex.messaging.config.ConfigurationException; |
| import flex.messaging.log.Log; |
| import flex.messaging.log.LogCategories; |
| |
| /** |
| * Implements {@link Executor} by delegating command execution to a WAS asynchbeans <code>WorkManager</code>. |
| * For more information on the asynchbeans API, refer to the WAS Javadoc for |
| * <a href="http://publib.boulder.ibm.com/infocenter/wasinfo/v5r0/index.jsp?topic=/com.ibm.wasee.doc/info/ee/javadoc/ee/com/ibm/websphere/asynchbeans/WorkManager.html">WorkManager</a>. |
| */ |
| public class AsynchBeansWorkManagerExecutor implements Executor { |
| //-------------------------------------------------------------------------- |
| // |
| // Constructor |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Constructs an <code>AsynchBeansWorkManagerExecutor</code> that will delegate command execution |
| * to the specified <code>WorkManager</code> instance that is registered in JNDI. |
| * |
| * @param workManagerJNDIName The JNDI resource ref name for the <code>WorkManager</code>. |
| * @see com.ibm.websphere.asynchbeans.WorkManager |
| */ |
| public AsynchBeansWorkManagerExecutor(String workManagerJNDIName) { |
| try { |
| InitialContext ic = new InitialContext(); |
| workManager = (WorkManager) ic.lookup(workManagerJNDIName); |
| } catch (NamingException ne) { |
| ConfigurationException ce = new ConfigurationException(); |
| ce.setMessage(13600, new Object[]{workManagerJNDIName}); |
| ce.setRootCause(ne); |
| throw ce; |
| } |
| |
| workListener = new WorkListener() { |
| public void workAccepted(WorkEvent event) { |
| /* No-op */ |
| } |
| |
| public void workCompleted(WorkEvent event) { |
| // This only needs to be handled if execution of the Runnable failed. |
| WorkException e = event.getException(); |
| if (e != null) { |
| if (Log.isDebug()) |
| Log.getLogger(LogCategories.EXECUTOR).error("AsynchBeansWorkManager's WorkListener.workCompleted() callback invoked for failed execution.", e); |
| |
| handleFailedExecution(((WorkCommandWrapper) event.getWork()).command, e); |
| } |
| } |
| |
| public void workRejected(WorkEvent event) { |
| WorkException e = event.getException(); |
| if (Log.isDebug()) |
| Log.getLogger(LogCategories.EXECUTOR).error("AsynchBeansWorkManager's WorkListener.workRejected() callback invoked. WorkException? " + e); |
| |
| handleFailedExecution(((WorkCommandWrapper) event.getWork()).command, e); |
| } |
| |
| public void workStarted(WorkEvent event) { |
| /* No-op */ |
| } |
| }; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Variables |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Instance level lock for thread-safe state changes. |
| */ |
| private final Object lock = new Object(); |
| |
| /** |
| * Reference to the WorkManager instance configured in WAS that this executor instance delegates to. |
| */ |
| private final WorkManager workManager; |
| |
| /** |
| * Listener that monitors scheduled work for errors and notifies the FailedExecutionHandler if one has been set. |
| */ |
| private final WorkListener workListener; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // failedExecutionHandler |
| //---------------------------------- |
| |
| private FailedExecutionHandler failedExecutionHandler; |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public FailedExecutionHandler getFailedExecutionHandler() { |
| synchronized (lock) { |
| return failedExecutionHandler; |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void setFailedExecutionHandler(FailedExecutionHandler value) { |
| synchronized (lock) { |
| failedExecutionHandler = value; |
| } |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Public Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void execute(Runnable command) { |
| try { |
| // Register our listener to monitor each scheduled work, and set the start timeout for the work to indefinite (no queue timeout). |
| workManager.startWork(new WorkCommandWrapper(command), WorkManager.INDEFINITE, workListener); |
| } catch (WorkException e) { |
| handleFailedExecution(command, e); |
| } |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Private Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Handles command execution problems by notifying the FailedExecutionHandler if one has been set |
| * and otherwise logging the failure. |
| * |
| * @param command The command that failed to execute successfully. |
| * @param e The exception generated by the failed command. |
| */ |
| private void handleFailedExecution(Runnable command, Exception e) { |
| FailedExecutionHandler handler = getFailedExecutionHandler(); |
| if (handler != null) { |
| handler.failedExecution(command, this, e); |
| } else if (Log.isError()) { |
| Log.getLogger(LogCategories.EXECUTOR).error("AsynchBeansWorkManager hit an Exception but no FailedExecutionHandler is registered to handle the error.", e); |
| } |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Inner Classes |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Helper class that wraps Runnable commands in the WAS Work interface. |
| */ |
| class WorkCommandWrapper implements Work { |
| public WorkCommandWrapper(Runnable command) { |
| this.command = command; |
| } |
| |
| private final Runnable command; |
| |
| public void run() { |
| command.run(); |
| } |
| |
| /** |
| * This is invoked by WAS when the server is shutting down to signal long-running daemon threads spawned by the WorkManager |
| * to exit from their run() method. Our works are all short lived so this is a no-op; in this case WAS will force any |
| * works that are executing at server shutdown to terminate. |
| */ |
| public void release() { |
| // No-op. |
| } |
| } |
| } |