/* * JBoss, Home of Professional Open Source * Copyright 2010, Red Hat Inc., and individual contributors as indicated * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.as.ejb3.deployment.processors.merging; import java.lang.reflect.Method; import java.util.List; import java.util.Map; import java.util.Set; import javax.ejb.Schedule; import javax.ejb.ScheduleExpression; import javax.ejb.TimedObject; import javax.ejb.Timeout; import org.jboss.as.ee.component.EEApplicationClasses; import org.jboss.as.ee.metadata.MethodAnnotationAggregator; import org.jboss.as.ee.metadata.RuntimeAnnotationInformation; import org.jboss.as.ejb3.logging.EjbLogger; import org.jboss.as.ejb3.component.EJBComponentDescription; import org.jboss.as.ejb3.deployment.processors.dd.MethodResolutionUtils; import org.jboss.as.ejb3.timerservice.AutoTimer; import org.jboss.as.server.deployment.DeploymentUnit; import org.jboss.as.server.deployment.DeploymentUnitProcessingException; import org.jboss.as.server.deployment.reflect.ClassReflectionIndex; import org.jboss.as.server.deployment.reflect.DeploymentReflectionIndex; import org.jboss.metadata.common.ejb.IScheduleTarget; import org.jboss.metadata.common.ejb.ITimeoutTarget; import org.jboss.metadata.ejb.spec.EnterpriseBeanMetaData; import org.jboss.metadata.ejb.spec.NamedMethodMetaData; import org.jboss.metadata.ejb.spec.ScheduleMetaData; import org.jboss.metadata.ejb.spec.TimerMetaData; /** * Deployment unit processor that merges the annotation information with the information in the deployment descriptor * * @author Stuart Douglas */ public class TimerMethodMergingProcessor extends AbstractMergingProcessor<EJBComponentDescription> { public TimerMethodMergingProcessor() { super(EJBComponentDescription.class); } @Override protected void handleAnnotations(final DeploymentUnit deploymentUnit, final EEApplicationClasses applicationClasses, final DeploymentReflectionIndex deploymentReflectionIndex, final Class<?> componentClass, final EJBComponentDescription description) throws DeploymentUnitProcessingException { final RuntimeAnnotationInformation<AutoTimer> scheduleAnnotationData = MethodAnnotationAggregator.runtimeAnnotationInformation(componentClass, applicationClasses, deploymentReflectionIndex, Schedule.class); final Set<Method> timerAnnotationData = MethodAnnotationAggregator.runtimeAnnotationPresent(componentClass, applicationClasses, deploymentReflectionIndex, Timeout.class); final Method timeoutMethod; if (timerAnnotationData.size() > 1) { throw EjbLogger.ROOT_LOGGER.componentClassHasMultipleTimeoutAnnotations(componentClass); } else if (timerAnnotationData.size() == 1) { timeoutMethod = timerAnnotationData.iterator().next(); } else { timeoutMethod = null; } description.setTimeoutMethod(timeoutMethod); //now for the schedule methods for (Map.Entry<Method, List<AutoTimer>> entry : scheduleAnnotationData.getMethodAnnotations().entrySet()) { for (AutoTimer timer : entry.getValue()) { description.addScheduleMethod(entry.getKey(), timer); } } } @Override protected void handleDeploymentDescriptor(final DeploymentUnit deploymentUnit, final DeploymentReflectionIndex deploymentReflectionIndex, final Class<?> componentClass, final EJBComponentDescription description) throws DeploymentUnitProcessingException { final EnterpriseBeanMetaData descriptorData = description.getDescriptorData(); if (descriptorData != null) { if (description.isSession() || description.isMessageDriven()) { assert descriptorData instanceof ITimeoutTarget : descriptorData + " is not an ITimeoutTarget"; ITimeoutTarget target = (ITimeoutTarget) descriptorData; if (target.getTimeoutMethod() != null) { parseTimeoutMethod(target, description, componentClass, deploymentReflectionIndex); } parseScheduleMethods(descriptorData, description, componentClass, deploymentReflectionIndex); } } //now check to see if the class implemented TimedObject //if so, this will take precedence over annotations //or the method specified in the deployment descriptor if (TimedObject.class.isAssignableFrom(componentClass)) { Class<?> c = componentClass; while (c != null && c != Object.class) { final ClassReflectionIndex index = deploymentReflectionIndex.getClassIndex(c); //TimedObject takes precedence Method method = index.getMethod(Void.TYPE, "ejbTimeout", javax.ejb.Timer.class); if (method != null) { final Method otherMethod = description.getTimeoutMethod(); if (otherMethod != null) { if (!otherMethod.equals(method)) { throw EjbLogger.ROOT_LOGGER.invalidEjbEntityTimeout("3.1 18.2.5.3", componentClass); } } description.setTimeoutMethod(method); break; } c = c.getSuperclass(); } } } private void parseScheduleMethods(final EnterpriseBeanMetaData beanMetaData, final EJBComponentDescription sessionBean, final Class<?> componentClass, final DeploymentReflectionIndex deploymentReflectionIndex) throws DeploymentUnitProcessingException { if (beanMetaData instanceof IScheduleTarget) { IScheduleTarget md = (IScheduleTarget) beanMetaData; if (md.getTimers() != null) { for (final TimerMetaData timer : md.getTimers()) { AutoTimer autoTimer = new AutoTimer(); autoTimer.getTimerConfig().setInfo(timer.getInfo()); autoTimer.getTimerConfig().setPersistent(timer.isPersistent()); final ScheduleExpression scheduleExpression = autoTimer.getScheduleExpression(); final ScheduleMetaData schedule = timer.getSchedule(); if (schedule != null) { scheduleExpression.dayOfMonth(schedule.getDayOfMonth()); scheduleExpression.dayOfWeek(schedule.getDayOfWeek()); scheduleExpression.hour(schedule.getHour()); scheduleExpression.minute(schedule.getMinute()); scheduleExpression.month(schedule.getMonth()); scheduleExpression.second(schedule.getSecond()); scheduleExpression.year(schedule.getYear()); } if (timer.getEnd() != null) { scheduleExpression.end(timer.getEnd().getTime()); } if (timer.getStart() != null) { scheduleExpression.start(timer.getStart().getTime()); } scheduleExpression.timezone(timer.getTimezone()); sessionBean.addScheduleMethod(MethodResolutionUtils.resolveMethod(timer.getTimeoutMethod(), componentClass, deploymentReflectionIndex), autoTimer); } } } } private void parseTimeoutMethod(final ITimeoutTarget beanMetaData, final EJBComponentDescription sessionBean, final Class<?> componentClass, final DeploymentReflectionIndex deploymentReflectionIndex) throws DeploymentUnitProcessingException { //resolve timeout methods final NamedMethodMetaData methodData = beanMetaData.getTimeoutMethod(); sessionBean.setTimeoutMethod(MethodResolutionUtils.resolveMethod(methodData, componentClass, deploymentReflectionIndex)); } }