/* * Copyright 2011 <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a> * * 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.ocpsoft.rewrite.annotation.handler; import java.lang.reflect.Field; import java.util.Iterator; import org.ocpsoft.common.services.ServiceLoader; import org.ocpsoft.common.util.Assert; import org.ocpsoft.logging.Logger; import org.ocpsoft.rewrite.annotation.Validate; import org.ocpsoft.rewrite.annotation.api.FieldContext; import org.ocpsoft.rewrite.annotation.api.HandlerChain; import org.ocpsoft.rewrite.annotation.spi.FieldAnnotationHandler; import org.ocpsoft.rewrite.context.EvaluationContext; import org.ocpsoft.rewrite.event.Rewrite; import org.ocpsoft.rewrite.exception.RewriteException; import org.ocpsoft.rewrite.param.Parameter; import org.ocpsoft.rewrite.param.ParameterConfiguration; import org.ocpsoft.rewrite.param.Validator; import org.ocpsoft.rewrite.spi.ValidatorProvider; /** * Handler for {@link Validate}. * * @author Christian Kaltepoth */ public class ValidateHandler extends FieldAnnotationHandler<Validate> { private final Logger log = Logger.getLogger(ValidateHandler.class); @Override public Class<Validate> handles() { return Validate.class; } @Override public int priority() { return HandlerWeights.WEIGHT_TYPE_ENRICHING; } @Override public void process(FieldContext context, Validate annotation, HandlerChain chain) { Field field = context.getJavaField(); Parameter<?> parameter = (Parameter<?>) context.get(Parameter.class); if (parameter != null) { Validator<?> validator = null; // identify validator by the type of the validator if (annotation.with() != Object.class) { validator = LazyValidatorAdapter.forValidatorType(annotation.with()); } // identify validator by some kind of unique id else if (annotation.id().length() > 0) { validator = LazyValidatorAdapter.forValidatorId(annotation.id()); } // default: identify validator by the target type else { validator = LazyValidatorAdapter.forTargetType(field.getType()); } if (parameter instanceof ParameterConfiguration) ((ParameterConfiguration<?>) parameter).validatedBy(validator); else throw new RewriteException("Cannot add @" + Validate.class.getSimpleName() + " to [" + field + "] of class [" + field.getDeclaringClass() + "] because the parameter [" + parameter.getName() + "] is not writable."); if (log.isTraceEnabled()) { log.trace("Attached validator to field [{}] of class [{}]: ", new Object[] { field.getName(), field.getDeclaringClass().getName(), validator }); } } // continue with the chain chain.proceed(); } /** * This class uses the {@link ValidatorProvider} SPI to lazily obtain the {@link Validator} for a given {@link Class} * instance. */ private static class LazyValidatorAdapter implements Validator<Object> { private final Class<?> targetType; private final String validatorId; private final Class<?> validatorType; private LazyValidatorAdapter(Class<?> targetType, String validatorId, Class<?> validatorType) { this.targetType = targetType; this.validatorId = validatorId; this.validatorType = validatorType; } public static LazyValidatorAdapter forValidatorType(Class<?> validatorType) { return new LazyValidatorAdapter(null, null, validatorType); } public static LazyValidatorAdapter forValidatorId(String id) { return new LazyValidatorAdapter(null, id, null); } public static LazyValidatorAdapter forTargetType(Class<?> targetType) { return new LazyValidatorAdapter(targetType, null, null); } @Override @SuppressWarnings({ "rawtypes", "unchecked" }) public boolean isValid(Rewrite event, EvaluationContext context, Object value) { Validator validator = null; // let one of the SPI implementations build the validator Iterator<ValidatorProvider> providers = ServiceLoader.load(ValidatorProvider.class).iterator(); while (providers.hasNext()) { ValidatorProvider provider = providers.next(); if (targetType != null) { validator = provider.getByTargetType(targetType); } else if (validatorType != null) { validator = provider.getByValidatorType(validatorType); } else { validator = provider.getByValidatorId(validatorId); } if (validator != null) { break; } } Assert.notNull(validator, "Got no validator from any ValidatorProvider for: " + this.toString()); return validator.isValid(event, context, value); } @Override public String toString() { StringBuilder b = new StringBuilder(); b.append(this.getClass().getSimpleName()); b.append(" for "); if (targetType != null) { b.append(" target type "); b.append(targetType.getName()); } else if (validatorType != null) { b.append(" validator type "); b.append(validatorType.getName()); } else { b.append(" id "); b.append(validatorId); } return b.toString(); } } }