Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  //
  // Copyright 2006, 2007, 2008, 2009, 2010 The Apache Software Foundation
  // 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.apache.tapestry5.internal.transform;
 
 import java.util.List;
 import java.util.Map;
 
 
 public class OnEventWorker implements ComponentClassTransformWorker
 {
 
     private final Request request;
 
     private final ValueEncoderSource valueEncoderSource;
 
     private final ComponentClassCache classCache;

    
Stores a couple of special parameter type mappings that are used when matching the entire event context (either as Object[] or EventContext).
 
     private final Map<StringEventHandlerMethodParameterSourceparameterTypeToSource = CollectionFactory.newMap();
 
     {
         // Object[] and List are out-dated and may be deprecated some day
 
         .put("java.lang.Object[]"new EventHandlerMethodParameterSource()
         {
 
             public Object valueForEventHandlerMethodParameter(ComponentEvent event)
             {
                 return event.getContext();
             }
         });
 
         {
 
             public Object valueForEventHandlerMethodParameter(ComponentEvent event)
             {
                 return Arrays.asList(event.getContext());
             }
         });
 
         // This is better, as the EventContext maintains the original objects (or strings)
         // and gives the event handler method access with coercion
         {
 
             public Object valueForEventHandlerMethodParameter(ComponentEvent event)
             {
                 return event.getEventContext();
             }
         });
     }
 
     public OnEventWorker(Request requestValueEncoderSource valueEncoderSourceComponentClassCache classCache)
     {
         this. = request;
         this. = valueEncoderSource;
         this. = classCache;
     }
    public void transform(ClassTransformation transformationMutableComponentModel model)
    {
        List<TransformMethodmethods = matchEventHandlerMethods(transformation);
        if (methods.isEmpty())
            return;
        List<EventHandlerMethodInvokerinvokers = toInvokers(transformation.getClassName(), methods);
        updateModelWithHandledEvents(modelinvokers);
        adviseDispatchComponentEventMethod(transformationinvokers);
    }
    private void adviseDispatchComponentEventMethod(ClassTransformation transformation,
            List<EventHandlerMethodInvokerinvokers)
    {
        ComponentMethodAdvice advice = createDispatchComponentEventAdvice(invokers);
    }
    {
        return new ComponentMethodAdvice()
        {
            public void advise(ComponentMethodInvocation invocation)
            {
                // Invoke the super-class implementation first. If no super-class,
                // this will do nothing and return false.
                invocation.proceed();
                ComponentEvent event = (ComponentEventinvocation.getParameter(0);
                if (invokeEventHandlers(eventinvocation.getInstance()))
                    invocation.overrideResult(true);
            }
            private boolean invokeEventHandlers(ComponentEvent eventObject instance)
            {
                // If the super-class aborted the event (some super-class method return non-null),
                // then it's all over, don't even check for handlers in this class.
                if (event.isAborted())
                    return false;
                boolean didInvokeSomeHandler = false;
                for (EventHandlerMethodInvoker invoker : invokers)
                {
                    if (event.matches(invoker.getEventType(), invoker.getComponentId(),
                            invoker.getMinContextValueCount()))
                    {
                        didInvokeSomeHandler = true;
                        invoker.invokeEventHandlerMethod(eventinstance);
                        if (event.isAborted())
                            break;
                    }
                }
                return didInvokeSomeHandler;
            }
        };
    }
            final List<EventHandlerMethodInvokerinvokers)
    {
        for (EventHandlerMethodInvoker invoker : invokers)
        {
            model.addEventHandler(invoker.getEventType());
        }
    }
    {
        return transformation.matchMethods(new Predicate<TransformMethod>()
        {
            public boolean accept(TransformMethod method)
            {
                return (hasCorrectPrefix(method) || hasAnnotation(method)) && !method.isOverride();
            }
            private boolean hasCorrectPrefix(TransformMethod method)
            {
                return method.getName().startsWith("on");
            }
            private boolean hasAnnotation(TransformMethod method)
            {
                return method.getAnnotation(OnEvent.class) != null;
            }
        });
    }
    private List<EventHandlerMethodInvokertoInvokers(String componentClassNameList<TransformMethodmethods)
    {
        List<EventHandlerMethodInvokerresult = CollectionFactory.newList();
        for (TransformMethod method : methods)
        {
            result.add(toInvoker(componentClassNamemethod));
        }
        return result;
    }
    private EventHandlerMethodInvoker toInvoker(final String componentClassNameTransformMethod method)
    {
        OnEvent annotation = method.getAnnotation(OnEvent.class);
        String methodName = method.getName();
        String eventType = extractEventType(methodNameannotation);
        String componentId = extractComponentId(methodNameannotation);
        final TransformMethodSignature signature = method.getSignature();
        String[] parameterTypes = signature.getParameterTypes();
        if (parameterTypes.length == 0)
            return new BaseEventHandlerMethodInvoker(methodeventTypecomponentId);
        final List<EventHandlerMethodParameterSourcesources = CollectionFactory.newList();
        // I'd refactor a bit more of this if Java had covariant return types.
        int contextIndex = 0;
        for (int i = 0; i < parameterTypes.lengthi++)
        {
            String type = parameterTypes[i];
            EventHandlerMethodParameterSource source = .get(type);
            if (source != null)
            {
                sources.add(source);
                continue;
            }
            RequestParameter parameterAnnotation = method.getParameterAnnotation(iRequestParameter.class);
            if (parameterAnnotation != null)
            {
                String parameterName = parameterAnnotation.value();
                sources.add(createQueryParameterSource(componentClassNamesignatureiparameterNametype,
                        parameterAnnotation.allowBlank()));
                continue;
            }
            // Note: probably safe to do the conversion to Class early (class load time)
            // as parameters are rarely (if ever) component classes.
            final int parameterIndex = contextIndex++;
            sources.add(createEventContextSource(typeparameterIndex));
        }
        return createInvoker(methodeventTypecomponentIdcontextIndexsources);
    }
    private EventHandlerMethodParameterSource createQueryParameterSource(final String componentClassName,
            final TransformMethodSignature signaturefinal int parameterIndexfinal String parameterName,
            final String parameterTypeNamefinal boolean allowBlank)
    {
        return new EventHandlerMethodParameterSource()
        {
            @SuppressWarnings("unchecked")
            public Object valueForEventHandlerMethodParameter(ComponentEvent event)
            {
                try
                {
                    String parameterValue = .getParameter(parameterName);
                    if (!allowBlank && InternalUtils.isBlank(parameterValue))
                        throw new RuntimeException(String.format(
                                "The value for query parameter '%s' was blank, but a non-blank value is needed.",
                                parameterName));
                    Class parameterType = .forName(parameterTypeName);
                    ValueEncoder valueEncoder = .getValueEncoder(parameterType);
                    Object value = valueEncoder.toValue(parameterValue);
                    if (parameterType.isPrimitive() && value == null)
                        throw new RuntimeException(
                                String.format(
                                        "Query parameter '%s' evaluates to null, but the event method parameter is type %s, a primitive.",
                                        parameterNameparameterType.getName()));
                    return value;
                }
                catch (Exception ex)
                {
                    throw new RuntimeException(
                            String.format(
                                    "Unable process query parameter '%s' as parameter #%d of event handler method %s (in class %s): %s",
                                    parameterNameparameterIndex + 1, signaturecomponentClassName,
                                    InternalUtils.toMessage(ex)), ex);
                }
            }
        };
    }
    private EventHandlerMethodInvoker createInvoker(TransformMethod methodString eventTypeString componentId,
            final int minContextCountfinal List<EventHandlerMethodParameterSourcesources)
    {
        return new BaseEventHandlerMethodInvoker(methodeventTypecomponentId)
        {
            final int count = sources.size();
            @Override
            public int getMinContextValueCount()
            {
                return minContextCount;
            }
            @Override
            protected Object[] constructParameters(ComponentEvent event)
            {
                Object[] parameters = new Object[];
                for (int i = 0; i < i++)
                {
                    parameters[i] = sources.get(i).valueForEventHandlerMethodParameter(event);
                }
                return parameters;
            }
        };
    }
    private EventHandlerMethodParameterSource createEventContextSource(final String typefinal int parameterIndex)
    {
        return new EventHandlerMethodParameterSource()
        {
            public Object valueForEventHandlerMethodParameter(ComponentEvent event)
            {
                return event.coerceContext(parameterIndextype);
            }
        };
    }

    
Returns the component id to match against, or the empty string if the component id is not specified. The component id is provided by the OnEvent annotation or (if that is not present) by the part of the method name following "From" ("onActionFromFoo").
    private String extractComponentId(String methodNameOnEvent annotation)
    {
        if (annotation != null)
            return annotation.component();
        // Method name started with "on". Extract the component id, if present.
        int fromx = methodName.indexOf("From");
        if (fromx < 0)
            return "";
        return methodName.substring(fromx + 4);
    }

    
Returns the event name to match against, as specified in the annotation or (if the annotation is not present) extracted from the name of the method. "onActionFromFoo" or just "onAction".
    private String extractEventType(String methodNameOnEvent annotation)
    {
        if (annotation != null)
            return annotation.value();
        int fromx = methodName.indexOf("From");
        // The first two characters are always "on" as in "onActionFromFoo".
        return fromx == -1 ? methodName.substring(2) : methodName.substring(2, fromx);
    }
New to GrepCode? Check out our FAQ X