AbstractPollingEndpoint.java :  » J2EE » spring-integration-2.0.0.M2 » org » springframework » integration » endpoint » Java Open Source

Java Open Source » J2EE » spring integration 2.0.0.M2 
spring integration 2.0.0.M2 » org » springframework » integration » endpoint » AbstractPollingEndpoint.java
/*
 * Copyright 2002-2009 the original author or authors.
 *
 * Licensed 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 org.springframework.integration.endpoint;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ScheduledFuture;

import org.aopalliance.aop.Advice;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.task.TaskExecutor;
import org.springframework.integration.channel.BeanFactoryChannelResolver;
import org.springframework.integration.channel.MessagePublishingErrorHandler;
import org.springframework.integration.util.ErrorHandlingTaskExecutor;
import org.springframework.scheduling.Trigger;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ErrorHandler;

/**
 * @author Mark Fisher
 */
public abstract class AbstractPollingEndpoint extends AbstractEndpoint implements InitializingBean, BeanClassLoaderAware {

  public static final int MAX_MESSAGES_UNBOUNDED = -1;


  private volatile Trigger trigger;

  protected volatile long maxMessagesPerPoll = MAX_MESSAGES_UNBOUNDED; 

  private volatile TaskExecutor taskExecutor;

  private volatile ErrorHandler errorHandler;

  private volatile PlatformTransactionManager transactionManager;

  private volatile TransactionDefinition transactionDefinition;

  private volatile TransactionTemplate transactionTemplate;

  private final List<Advice> adviceChain = new CopyOnWriteArrayList<Advice>();

  private volatile ClassLoader classLoader = ClassUtils.getDefaultClassLoader();

  private volatile ScheduledFuture<?> runningTask;

  private volatile Runnable poller;

  private volatile boolean initialized;

  private final Object initializationMonitor = new Object();


  public AbstractPollingEndpoint() {
    this.setPhase(Integer.MAX_VALUE);
  }


  public void setTrigger(Trigger trigger) {
    this.trigger = trigger;
  }

  /**
   * Set the maximum number of messages to receive for each poll.
   * A non-positive value indicates that polling should repeat as long
   * as non-null messages are being received and successfully sent.
   * 
   * <p>The default is unbounded.
   * 
   * @see #MAX_MESSAGES_UNBOUNDED
   */
  public void setMaxMessagesPerPoll(int maxMessagesPerPoll) {
    this.maxMessagesPerPoll = maxMessagesPerPoll;
  }

  public void setTaskExecutor(TaskExecutor taskExecutor) {
    this.taskExecutor = taskExecutor;
  }

  public void setErrorHandler(ErrorHandler errorHandler){
    this.errorHandler = errorHandler;
  }

  /**
   * Specify a transaction manager to use for all polling operations.
   * If none is provided, then the operations will occur without any
   * transactional behavior (i.e. there is no default transaction manager).
   */
  public void setTransactionManager(PlatformTransactionManager transactionManager) {
    this.transactionManager = transactionManager;
  }

  public void setTransactionDefinition(TransactionDefinition transactionDefinition) {
    this.transactionDefinition = transactionDefinition;
  }

  public void setBeanClassLoader(ClassLoader classLoader) {
    Assert.notNull(classLoader, "ClassLoader must not be null");
    this.classLoader = classLoader;
  }

  public void setAdviceChain(List<Advice> adviceChain) {
    synchronized (this.adviceChain) {
      this.adviceChain.clear();
      if (adviceChain != null) {
        this.adviceChain.addAll(adviceChain);
      }
    }
  }

  private TransactionTemplate getTransactionTemplate() {
    if (!this.initialized) {
      this.onInit();
    }
    return this.transactionTemplate;
  }

  @Override
  protected void onInit() {
    synchronized (this.initializationMonitor) {
      if (this.initialized) {
        return;
      }
      Assert.notNull(this.trigger, "trigger is required");
      if (this.transactionManager != null) {
        if (this.transactionDefinition == null) {
          this.transactionDefinition = new DefaultTransactionDefinition();
        }
        this.transactionTemplate = new TransactionTemplate(
            this.transactionManager, this.transactionDefinition);
      }
      if (this.taskExecutor != null && !(this.taskExecutor instanceof ErrorHandlingTaskExecutor)) {
        if (this.errorHandler == null) {
          this.errorHandler = new MessagePublishingErrorHandler(new BeanFactoryChannelResolver(getBeanFactory()));
        }
        this.taskExecutor = new ErrorHandlingTaskExecutor(this.taskExecutor, this.errorHandler);
      }
      this.poller = this.createPoller();
      this.initialized = true;
    }
  }

  private Runnable createPoller() {
    if (this.adviceChain.isEmpty()) {
      return new Poller();
    }
    ProxyFactory proxyFactory = new ProxyFactory(new Poller());
    for (Advice advice : this.adviceChain) {
      proxyFactory.addAdvice(advice);
    }
    return (Runnable) proxyFactory.getProxy(this.classLoader);
  }


  // LifecycleSupport implementation

  @Override // guarded by super#lifecycleLock
  protected void doStart() {
    if (!this.initialized) {
      this.onInit();
    }
    Assert.state(this.getTaskScheduler() != null,
        "unable to start polling, no taskScheduler available");
    this.runningTask = this.getTaskScheduler().schedule(this.poller, this.trigger);
  }

  @Override // guarded by super#lifecycleLock
  protected void doStop() {
    if (this.runningTask != null) {
      this.runningTask.cancel(true);
    }
    this.runningTask = null;
  }


  protected abstract boolean doPoll();


  private class Poller implements Runnable {

    public void run() {
      if (taskExecutor != null) {
        taskExecutor.execute(new Runnable() {
          public void run() {
            poll();
          }
        });
      }
      else {
        poll();
      }
    }

    private void poll() {
      int count = 0;
      while (maxMessagesPerPoll <= 0 || count < maxMessagesPerPoll) {
        if (!innerPoll()) {
          break;
        }
        count++;
      }
    }

    private boolean innerPoll() {
      TransactionTemplate txTemplate = getTransactionTemplate();
      if (txTemplate != null) {
        return txTemplate.execute(new TransactionCallback<Boolean>() {
          public Boolean doInTransaction(TransactionStatus status) {
            return doPoll();
          }
        });
      }
      return doPoll();
    }
  }

}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.