/* * 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; import java.lang.reflect.Method; import java.util.List; import com.google.common.collect.Lists; import org.apache.isis.applib.filter.Filter; import org.apache.isis.applib.filter.Filters; import org.apache.isis.applib.services.wrapper.WrapperFactory; import org.apache.isis.core.commons.lang.ObjectExtensions; import org.apache.isis.core.metamodel.facetapi.DecoratingFacet; import org.apache.isis.core.metamodel.facetapi.Facet; import org.apache.isis.core.metamodel.spec.ObjectSpecification; import org.apache.isis.core.metamodel.spec.feature.ObjectMember; /** * A {@link Facet} implementation that ultimately wraps a {@link Method} or * possibly several equivalent methods, for a Java implementation of a * {@link ObjectMember}. * * <p> * Used by <tt>ObjectSpecificationDefault#getMember(Method)</tt> in order to * reverse lookup {@link ObjectMember}s from underlying {@link Method}s. So, for * example, the facets that represents an action xxx, or an <tt>validateXxx</tt> * method, or an <tt>addToXxx</tt> collection, can all be used to lookup the * member. * * <p> * Note that {@link Facet}s relating to the class itself (ie for * {@link ObjectSpecification}) should not implement this interface. */ public interface ImperativeFacet extends Facet { /** * The {@link Method}s invoked by this {@link Facet}. * * <p> * In the vast majority of cases there is only a single {@link Method} (eg * wrapping a property's getter). However, some {@link Facet}s, such as * those for callbacks, could map to multiple {@link Method}s. * Implementations that will return multiple {@link Method}s should * implement the {@link ImperativeFacetMulti} sub-interface that provides * the ability to {@link ImperativeFacetMulti#addMethod(Method) add} * {@link Method}s as part of the interface API. For example: * * <pre> * if (someFacet instanceof ImperativeFacetMulti) { * ImperativeFacetMulti ifm = (ImperativeFacetMulti)someFacet; * ifm.addMethod(...); * } * </pre> */ public List<Method> getMethods(); public static enum Intent { CHECK_IF_HIDDEN, CHECK_IF_DISABLED, CHECK_IF_VALID, ACCESSOR, EXECUTE, MODIFY_PROPERTY, /** * Modify property using modify/clear rather than simply using set. */ MODIFY_PROPERTY_SUPPORTING, MODIFY_COLLECTION_ADD, MODIFY_COLLECTION_REMOVE, CHOICES_OR_AUTOCOMPLETE, DEFAULTS, INITIALIZATION, LIFECYCLE, UI_HINT } /** * The intent of this method, so that the {@link WrapperFactory} knows whether to delegate on or to reject. * @param method - one of the methods returned from {@link #getMethods()} */ public Intent getIntent(Method method); public static Filter<Facet> FILTER = new Filter<Facet>() { @Override public boolean accept(final Facet facet) { return ImperativeFacet.Util.isImperativeFacet(facet); } }; // ////////////////////////////////////// public static class Util { private Util(){} /** * Returns the provided {@link Facet facet} as an {@link ImperativeFacet} if * it either is one or if it is a {@link DecoratingFacet} that in turn wraps * an {@link ImperativeFacet}. * * <p> * Otherwise, returns <tt>null</tt>. */ public static ImperativeFacet getImperativeFacet(final Facet facet) { if (facet instanceof ImperativeFacet) { return (ImperativeFacet) facet; } if (facet.getUnderlyingFacet() instanceof ImperativeFacet) { return (ImperativeFacet) facet.getUnderlyingFacet(); } if (facet instanceof DecoratingFacet) { final DecoratingFacet<?> decoratingFacet = ObjectExtensions.asT(facet); return getImperativeFacet(decoratingFacet.getDecoratedFacet()); } return null; } public static boolean isImperativeFacet(final Facet facet) { return getImperativeFacet(facet) != null; } public static Intent getIntent(final ObjectMember member, final Method method) { final List<Facet> allFacets = member.getFacets(Filters.anyOfType(Facet.class)); final List<ImperativeFacet> imperativeFacets = Lists.newArrayList(); for (final Facet facet : allFacets) { final ImperativeFacet imperativeFacet = ImperativeFacet.Util.getImperativeFacet(facet); if (imperativeFacet == null) { continue; } final List<Method> methods = imperativeFacet.getMethods(); if (!methods.contains(method)) { continue; } imperativeFacets.add(imperativeFacet); } switch(imperativeFacets.size()) { case 0: break; case 1: return imperativeFacets.get(0).getIntent(method); default: Intent intentToReturn = null; for (ImperativeFacet imperativeFacet : imperativeFacets) { Intent intent = imperativeFacet.getIntent(method); if(intentToReturn == null) { intentToReturn = intent; } else if(intentToReturn != intent) { throw new IllegalArgumentException(member.getIdentifier().toClassAndNameIdentityString() + ": more than one ImperativeFacet for method " + method.getName() + " , with inconsistent intents: " + imperativeFacets.toString()); } } return intentToReturn; } throw new IllegalArgumentException(member.getIdentifier().toClassAndNameIdentityString() + ": unable to determine intent of " + method.getName()); } } }