Package org.springframework.batch.admin.jmx

Source Code of org.springframework.batch.admin.jmx.BatchMBeanExporter$ExecutionMetricsFactory

/*
* Copyright 2009-2010 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.batch.admin.jmx;

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.admin.service.JobService;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.launch.NoSuchJobException;
import org.springframework.context.SmartLifecycle;
import org.springframework.jmx.export.MBeanExporter;
import org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedMetric;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler;
import org.springframework.jmx.export.naming.MetadataNamingStrategy;
import org.springframework.jmx.support.MetricType;
import org.springframework.util.Assert;

@ManagedResource
public class BatchMBeanExporter extends MBeanExporter implements SmartLifecycle {

  private static final Log logger = LogFactory.getLog(BatchMBeanExporter.class);

  public static final String DEFAULT_DOMAIN = "org.springframework.batch";

  private volatile boolean autoStartup = true;

  private volatile int phase = 0;

  private volatile boolean running;

  private final Map<String, String> objectNameStaticProperties = new LinkedHashMap<String, String>();

  private final ReentrantLock lifecycleLock = new ReentrantLock();

  private Set<String> stepKeys = new HashSet<String>();

  private Set<String> jobKeys = new HashSet<String>();

  private final AnnotationJmxAttributeSource attributeSource = new AnnotationJmxAttributeSource();

  private JobService jobService;

  private String domain = DEFAULT_DOMAIN;

  private boolean registerSteps = true;

  private JobExecutionMetricsFactory jobExecutionMetricsFactory = new ExecutionMetricsFactory();

  private StepExecutionMetricsFactory stepExecutionMetricsFactory = new ExecutionMetricsFactory();

  public BatchMBeanExporter() {
    super();
    setAutodetect(false);
    setNamingStrategy(new MetadataNamingStrategy(attributeSource));
    setAssembler(new MetadataMBeanInfoAssembler(attributeSource));
  }

  /**
   * Flag to determine if any metrics at all should be exposed for step
   * executions (default true). Set to fals eto only expose job-level metrics.
   *
   * @param registerSteps the flag to set
   */
  public void setRegisterSteps(boolean registerSteps) {
    this.registerSteps = registerSteps;
  }

  /**
   * The JMX domain to use for MBeans registered. Defaults to
   * <code>org.springframework.batch</code> (which is useful in SpringSource
   * HQ).
   *
   * @param domain the domain name to set
   */
  public void setDefaultDomain(String domain) {
    this.domain = domain;
  }

  /**
   * Help method for extensions which need access to the default domain.
   *
   * @return the default domain used to construct object names
   */
  protected String getDefaultDomain() {
    return this.domain;
  }

  public void setJobService(JobService jobService) {
    this.jobService = jobService;
  }

  /**
   * Static properties that will be added to all object names.
   *
   * @param objectNameStaticProperties the objectNameStaticProperties to set
   */
  public void setObjectNameStaticProperties(Map<String, String> objectNameStaticProperties) {
    this.objectNameStaticProperties.putAll(objectNameStaticProperties);
  }

  /**
   * Factory for {@link JobExecutionMetrics}. Can be used to customize and
   * extend the metrics exposed.
   *
   * @param stepExecutionMetricsFactory the {@link StepExecutionMetricsFactory} to set
   */
  public void setStepExecutionMetricsFactory(StepExecutionMetricsFactory stepExecutionMetricsFactory) {
    this.stepExecutionMetricsFactory = stepExecutionMetricsFactory;
  }

  /**
   * Factory for {@link StepExecutionMetrics}. Can be used to customize and
   * extend the metrics exposed.
   *
   * @param jobExecutionMetricsFactory the {@link JobExecutionMetricsFactory} to set
   */
  public void setJobExecutionMetricsFactory(JobExecutionMetricsFactory jobExecutionMetricsFactory) {
    this.jobExecutionMetricsFactory = jobExecutionMetricsFactory;
  }

  @Override
  public void afterPropertiesSet() {
    Assert.state(jobService != null, "A JobService must be provided");
    super.afterPropertiesSet();
  }

  protected void registerBeans() {
    // Completely disable super class registration to avoid duplicates
  }

  private void registerSteps() {
    if (!registerSteps) {
      return;
    }
    for (String jobName : jobService.listJobs(0, Integer.MAX_VALUE)) {
      Collection<JobExecution> jobExecutions = Collections.emptySet();
      try {
        jobExecutions = jobService.listJobExecutionsForJob(jobName, 0, 1);
      }
      catch (NoSuchJobException e) {
        // do-nothing
        logger.error("Job listed but does not exist", e);
      }
      for (JobExecution jobExecution : jobExecutions) {
        for (StepExecution stepExecution : jobExecution.getStepExecutions()) {
          String stepName = stepExecution.getStepName();
          String stepKey = String.format("%s/%s", jobName, stepName);
          String beanKey = getBeanKeyForStepExecution(jobName, stepName);
          if (!stepKeys.contains(stepKey)) {
            stepKeys.add(stepKey);
            logger.info("Registering step execution " + stepKey);
            registerBeanNameOrInstance(stepExecutionMetricsFactory.createMetricsForStep(jobName, stepName),
                beanKey);
          }
        }
      }
    }
  }

  private void registerJobs() {
    for (String jobName : jobService.listJobs(0, Integer.MAX_VALUE)) {
      if (!jobKeys.contains(jobName)) {
        jobKeys.add(jobName);
        logger.info("Registering job execution " + jobName);
        registerBeanNameOrInstance(jobExecutionMetricsFactory.createMetricsForJob(jobName),
            getBeanKeyForJobExecution(jobName));
      }
    }
  }

  /**
   * Encode the job name into an ObjectName in the form
   * <code>[domain]:type=JobExecution,name=[jobName]</code>.
   *
   * @param jobName the name of the job
   * @return a String representation of an ObjectName
   */
  protected String getBeanKeyForJobExecution(String jobName) {
    jobName = escapeForObjectName(jobName);
    return String.format("%s:type=JobExecution,name=%s", domain, jobName) + getStaticNames();
  }

  /**
   * Encode the job and step name into an ObjectName in the form
   * <code>[domain]:type=JobExecution,name=[jobName],step=[stepName]</code>.
   *
   * @param jobName the name of the job
   * @param stepName the name of the step
   * @return a String representation of an ObjectName
   */
  protected String getBeanKeyForStepExecution(String jobName, String stepName) {
    jobName = escapeForObjectName(jobName);
    stepName = escapeForObjectName(stepName);
    return String.format("%s:type=JobExecution,name=%s,step=%s", domain, jobName, stepName) + getStaticNames();
  }

  private String getStaticNames() {
    if (objectNameStaticProperties.isEmpty()) {
      return "";
    }
    StringBuilder builder = new StringBuilder();
    for (String key : objectNameStaticProperties.keySet()) {
      builder.append("," + key + "=" + objectNameStaticProperties.get(key));
    }
    return builder.toString();
  }

  private String escapeForObjectName(String value) {
    value = value.replaceAll(":", "@");
    value = value.replaceAll(",", ";");
    value = value.replaceAll("=", "~");
    return value;
  }

  @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Step Count")
  public int getStepCount() {
    registerSteps();
    return stepKeys.size();
  }

  @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Job Count")
  public int getJobCount() {
    registerJobs();
    return jobKeys.size();
  }

  @ManagedAttribute
  public String[] getJobNames() {
    return jobKeys.toArray(new String[0]);
  }

  @ManagedAttribute
  public String[] getStepNames() {
    return stepKeys.toArray(new String[0]);
  }

  @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Job Execution Failure Count")
  public int getJobExecutionFailureCount() {
    int count = 0;
    int start = 0;
    int pageSize = 100;
    Collection<JobExecution> jobExecutions;
    do {
      jobExecutions = jobService.listJobExecutions(start, pageSize);
      start += pageSize;
      for (JobExecution jobExecution : jobExecutions) {
        if (jobExecution.getStatus().isUnsuccessful()) {
          count++;
        }
      }
    } while (!jobExecutions.isEmpty());
    return count;
  }

  @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Job Execution Count")
  public int getJobExecutionCount() {
    return jobService.countJobExecutions();
  }

  public final boolean isAutoStartup() {
    return this.autoStartup;
  }

  public final int getPhase() {
    return this.phase;
  }

  public final boolean isRunning() {
    this.lifecycleLock.lock();
    try {
      return this.running;
    }
    finally {
      this.lifecycleLock.unlock();
    }
  }

  public final void start() {
    this.lifecycleLock.lock();
    try {
      if (!this.running) {
        this.doStart();
        this.running = true;
        if (logger.isInfoEnabled()) {
          logger.info("started " + this);
        }
      }
    }
    finally {
      this.lifecycleLock.unlock();
    }
  }

  public final void stop() {
    this.lifecycleLock.lock();
    try {
      if (this.running) {
        this.doStop();
        this.running = false;
        if (logger.isInfoEnabled()) {
          logger.info("stopped " + this);
        }
      }
    }
    finally {
      this.lifecycleLock.unlock();
    }
  }

  public final void stop(Runnable callback) {
    this.lifecycleLock.lock();
    try {
      this.stop();
      callback.run();
    }
    finally {
      this.lifecycleLock.unlock();
    }
  }

  protected void doStop() {
    unregisterBeans();
    jobKeys.clear();
    stepKeys.clear();
  }

  protected void doStart() {
    registerJobs();
    registerSteps();
  }

  private class ExecutionMetricsFactory implements JobExecutionMetricsFactory, StepExecutionMetricsFactory {

    public StepExecutionMetrics createMetricsForStep(String jobName, String stepName) {
      return new SimpleStepExecutionMetrics(jobService, jobName, stepName);
    }

    public JobExecutionMetrics createMetricsForJob(String jobName) {
      return new SimpleJobExecutionMetrics(jobService, jobName);
    }

  }

}
TOP

Related Classes of org.springframework.batch.admin.jmx.BatchMBeanExporter$ExecutionMetricsFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.