/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.isis.core.metamodel.facets.param.parameter;
import org.apache.isis.applib.annotation.*;
import org.apache.isis.core.commons.config.IsisConfiguration;
import org.apache.isis.core.metamodel.facetapi.Facet;
import org.apache.isis.core.metamodel.facetapi.FacetUtil;
import org.apache.isis.core.metamodel.facetapi.FeatureType;
import org.apache.isis.core.metamodel.facetapi.MetaModelValidatorRefiner;
import org.apache.isis.core.metamodel.facets.Annotations;
import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
import org.apache.isis.core.metamodel.facets.FacetedMethodParameter;
import org.apache.isis.core.metamodel.facets.objectvalue.mandatory.MandatoryFacet;
import org.apache.isis.core.metamodel.facets.objectvalue.regex.RegExFacet;
import org.apache.isis.core.metamodel.facets.objectvalue.regex.TitleFacetFormattedByRegex;
import org.apache.isis.core.metamodel.facets.param.parameter.fileaccept.FileAcceptFacetForParameterAnnotation;
import org.apache.isis.core.metamodel.facets.param.parameter.mandatory.MandatoryFacetForParameterAnnotation;
import org.apache.isis.core.metamodel.facets.param.parameter.mandatory.MandatoryFacetInvertedByNullableAnnotationOnParameter;
import org.apache.isis.core.metamodel.facets.param.parameter.mandatory.MandatoryFacetInvertedByOptionalAnnotationOnParameter;
import org.apache.isis.core.metamodel.facets.param.parameter.maxlen.MaxLengthFacetForMaxLengthAnnotationOnParameter;
import org.apache.isis.core.metamodel.facets.param.parameter.maxlen.MaxLengthFacetForParameterAnnotation;
import org.apache.isis.core.metamodel.facets.param.parameter.mustsatisfy.MustSatisfySpecificationFacetForMustSatisfyAnnotationOnParameter;
import org.apache.isis.core.metamodel.facets.param.parameter.mustsatisfy.MustSatisfySpecificationFacetForParameterAnnotation;
import org.apache.isis.core.metamodel.facets.param.parameter.regex.RegExFacetForParameterAnnotation;
import org.apache.isis.core.metamodel.facets.param.parameter.regex.RegExFacetFromRegExAnnotationOnParameter;
import org.apache.isis.core.metamodel.services.ServicesInjector;
import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorComposite;
import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorForConflictingOptionality;
import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorForDeprecatedAnnotation;
import javax.annotation.Nullable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
public class ParameterAnnotationFacetFactory extends FacetFactoryAbstract implements MetaModelValidatorRefiner {
private final MetaModelValidatorForDeprecatedAnnotation maxLengthValidator = new MetaModelValidatorForDeprecatedAnnotation(MaxLength.class);
private final MetaModelValidatorForDeprecatedAnnotation mustSatisfyValidator = new MetaModelValidatorForDeprecatedAnnotation(MustSatisfy.class);
private final MetaModelValidatorForDeprecatedAnnotation regexValidator = new MetaModelValidatorForDeprecatedAnnotation(RegEx.class);
private final MetaModelValidatorForDeprecatedAnnotation optionalValidator = new MetaModelValidatorForDeprecatedAnnotation(Optional.class);
private final MetaModelValidatorForConflictingOptionality conflictingOptionalityValidator = new MetaModelValidatorForConflictingOptionality();
public ParameterAnnotationFacetFactory() {
super(FeatureType.PARAMETERS_ONLY);
}
@Override
public void processParams(final ProcessParameterContext processParameterContext) {
final Method method = processParameterContext.getMethod();
final int paramNum = processParameterContext.getParamNum();
final Class<?>[] parameterTypes = method.getParameterTypes();
if (paramNum >= parameterTypes.length) {
return; // ignore
}
processParamsMaxLength(processParameterContext);
processParamsMustSatisfy(processParameterContext);
processParamsRegEx(processParameterContext);
processParamsOptional(processParameterContext);
processParamsFileAccept(processParameterContext);
}
void processParamsMaxLength(final ProcessParameterContext processParameterContext) {
final Method method = processParameterContext.getMethod();
final int paramNum = processParameterContext.getParamNum();
final FacetedMethodParameter holder = processParameterContext.getFacetHolder();
final Annotation[] parameterAnnotations = Annotations.getParameterAnnotations(method)[paramNum];
for (final Annotation parameterAnnotation : parameterAnnotations) {
if (parameterAnnotation instanceof MaxLength) {
final MaxLength annotation = (MaxLength) parameterAnnotation;
final org.apache.isis.core.metamodel.facets.objectvalue.maxlen.MaxLengthFacet facet = MaxLengthFacetForMaxLengthAnnotationOnParameter.create(annotation, processParameterContext.getFacetHolder());
FacetUtil.addFacet(maxLengthValidator.flagIfPresent(facet, processParameterContext));
return;
}
}
for (final Annotation parameterAnnotation : parameterAnnotations) {
if (parameterAnnotation instanceof Parameter) {
final Parameter parameter = (Parameter) parameterAnnotation;
FacetUtil.addFacet(
MaxLengthFacetForParameterAnnotation.create(parameter, holder));
return;
}
}
}
void processParamsMustSatisfy(final ProcessParameterContext processParameterContext) {
final Method method = processParameterContext.getMethod();
final int paramNum = processParameterContext.getParamNum();
final FacetedMethodParameter holder = processParameterContext.getFacetHolder();
final Annotation[] parameterAnnotations = Annotations.getParameterAnnotations(method)[paramNum];
for (final Annotation parameterAnnotation : parameterAnnotations) {
if (parameterAnnotation instanceof MustSatisfy) {
final MustSatisfy annotation = (MustSatisfy) parameterAnnotation;
final Facet facet = MustSatisfySpecificationFacetForMustSatisfyAnnotationOnParameter.create(annotation, processParameterContext.getFacetHolder(), servicesInjector);
FacetUtil.addFacet(mustSatisfyValidator.flagIfPresent(facet, processParameterContext));
return;
}
}
for (final Annotation parameterAnnotation : parameterAnnotations) {
if (parameterAnnotation instanceof Parameter) {
final Parameter parameter = (Parameter) parameterAnnotation;
FacetUtil.addFacet(
MustSatisfySpecificationFacetForParameterAnnotation.create(parameter, holder, servicesInjector));
return;
}
}
}
void processParamsRegEx(final ProcessParameterContext processParameterContext) {
final Method method = processParameterContext.getMethod();
final int paramNum = processParameterContext.getParamNum();
final FacetedMethodParameter holder = processParameterContext.getFacetHolder();
final Class<?>[] parameterTypes = method.getParameterTypes();
final Annotation[] parameterAnnotations = Annotations.getParameterAnnotations(method)[paramNum];
for (final Annotation parameterAnnotation : parameterAnnotations) {
final Class<?> parameterType = parameterTypes[paramNum];
if (parameterAnnotation instanceof RegEx) {
final RegEx annotation = (RegEx) parameterAnnotation;
final RegExFacet facet = RegExFacetFromRegExAnnotationOnParameter.create(annotation, parameterType, holder);
FacetUtil.addFacet(regexValidator.flagIfPresent(facet, processParameterContext));
final RegExFacet regExFacet = facet;
// regex also adds a title facet
if(regExFacet != null) {
FacetUtil.addFacet(new TitleFacetFormattedByRegex(regExFacet));
}
return;
}
}
for (final Annotation parameterAnnotation : parameterAnnotations) {
if (parameterAnnotation instanceof Parameter) {
final Parameter parameter = (Parameter) parameterAnnotation;
final Class<?> parameterType = parameterTypes[paramNum];
FacetUtil.addFacet(
RegExFacetForParameterAnnotation.create(parameter, parameterType, holder));
return;
}
}
}
void processParamsOptional(final ProcessParameterContext processParameterContext) {
final Method method = processParameterContext.getMethod();
final int paramNum = processParameterContext.getParamNum();
final FacetedMethodParameter holder = processParameterContext.getFacetHolder();
final Class<?>[] parameterTypes = method.getParameterTypes();
final Annotation[] parameterAnnotations = Annotations.getParameterAnnotations(method)[paramNum];
for (final Annotation parameterAnnotation : parameterAnnotations) {
final Class<?> parameterType = parameterTypes[paramNum];
if (parameterAnnotation instanceof Optional) {
final Optional annotation = (Optional) parameterAnnotation;
FacetUtil.addFacet(optionalValidator.flagIfPresent(
MandatoryFacetInvertedByOptionalAnnotationOnParameter.create(
annotation, parameterType, holder), processParameterContext));
}
}
for (final Annotation parameterAnnotation : parameterAnnotations) {
final Class<?> parameterType = parameterTypes[paramNum];
if (parameterAnnotation instanceof javax.annotation.Nullable) {
final Nullable annotation = (Nullable) parameterAnnotation;
final MandatoryFacet facet =
MandatoryFacetInvertedByNullableAnnotationOnParameter.create(annotation, parameterType, holder);
FacetUtil.addFacet(facet);
conflictingOptionalityValidator.flagIfConflict(
facet, "Conflicting @Nullable with other optionality annotation");
}
}
for (final Annotation parameterAnnotation : parameterAnnotations) {
if (parameterAnnotation instanceof Parameter) {
final Parameter parameter = (Parameter) parameterAnnotation;
final Class<?> parameterType = parameterTypes[paramNum];
final MandatoryFacet facet =
MandatoryFacetForParameterAnnotation.create(parameter, parameterType, holder);
FacetUtil.addFacet(facet);
conflictingOptionalityValidator.flagIfConflict(
facet, "Conflicting @Parameter#optionality with other optionality annotation");
}
}
}
void processParamsFileAccept(final ProcessParameterContext processParameterContext) {
final Method method = processParameterContext.getMethod();
final int paramNum = processParameterContext.getParamNum();
final FacetedMethodParameter holder = processParameterContext.getFacetHolder();
final Annotation[] parameterAnnotations = Annotations.getParameterAnnotations(method)[paramNum];
for (final Annotation parameterAnnotation : parameterAnnotations) {
if (parameterAnnotation instanceof Parameter) {
final Parameter parameter = (Parameter) parameterAnnotation;
FacetUtil.addFacet(
FileAcceptFacetForParameterAnnotation.create(parameter, holder));
return;
}
}
}
@Override
public void refineMetaModelValidator(final MetaModelValidatorComposite metaModelValidator, final IsisConfiguration configuration) {
metaModelValidator.add(maxLengthValidator);
metaModelValidator.add(mustSatisfyValidator);
metaModelValidator.add(regexValidator);
metaModelValidator.add(optionalValidator);
metaModelValidator.add(conflictingOptionalityValidator);
}
@Override
public void setServicesInjector(final ServicesInjector servicesInjector) {
super.setServicesInjector(servicesInjector);
IsisConfiguration configuration = servicesInjector.getConfigurationServiceInternal();
maxLengthValidator.setConfiguration(configuration);
mustSatisfyValidator.setConfiguration(configuration);
regexValidator.setConfiguration(configuration);
optionalValidator.setConfiguration(configuration);
}
}