001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019
020 package org.apache.isis.core.progmodel.facets.param.choices.method;
021
022 import java.lang.reflect.Method;
023 import java.util.List;
024
025 import org.apache.isis.core.commons.lang.NameUtils;
026 import org.apache.isis.core.metamodel.adapter.map.AdapterMap;
027 import org.apache.isis.core.metamodel.adapter.map.AdapterMapAware;
028 import org.apache.isis.core.metamodel.facetapi.Facet;
029 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
030 import org.apache.isis.core.metamodel.facetapi.FacetUtil;
031 import org.apache.isis.core.metamodel.facetapi.FeatureType;
032 import org.apache.isis.core.metamodel.methodutils.MethodScope;
033 import org.apache.isis.core.progmodel.facets.MethodFinderUtils;
034 import org.apache.isis.core.progmodel.facets.MethodPrefixBasedFacetFactoryAbstract;
035 import org.apache.isis.core.progmodel.facets.MethodPrefixConstants;
036
037 public class ActionChoicesFacetFactory extends MethodPrefixBasedFacetFactoryAbstract implements AdapterMapAware {
038
039 private static final String[] PREFIXES = { MethodPrefixConstants.CHOICES_PREFIX };
040
041 private AdapterMap adapterMap;
042
043 /**
044 * Note that the {@link Facet}s registered are the generic ones from noa-architecture (where they exist)
045 */
046 public ActionChoicesFacetFactory() {
047 super(FeatureType.ACTIONS_ONLY, PREFIXES);
048 }
049
050 // ///////////////////////////////////////////////////////
051 // Actions
052 // ///////////////////////////////////////////////////////
053
054 @Override
055 public void process(final ProcessMethodContext processMethodContext) {
056 attachActionChoicesFacetIfParameterChoicesMethodIsFound(processMethodContext);
057 }
058
059 private void attachActionChoicesFacetIfParameterChoicesMethodIsFound(final ProcessMethodContext processMethodContext) {
060
061 final Method actionMethod = processMethodContext.getMethod();
062 final Class<?>[] actionParamTypes = actionMethod.getParameterTypes();
063
064 if (actionParamTypes.length <= 0) {
065 return;
066 }
067
068 Method choicesMethod = null;
069 if (choicesMethod == null) {
070 choicesMethod = findChoicesMethodReturning(processMethodContext, Object[][].class);
071 }
072 if (choicesMethod == null) {
073 choicesMethod = findChoicesMethodReturning(processMethodContext, Object[].class);
074 }
075 if (choicesMethod == null) {
076 choicesMethod = findChoicesMethodReturning(processMethodContext, List.class);
077 }
078 if (choicesMethod == null) {
079 return;
080 }
081 processMethodContext.removeMethod(choicesMethod);
082
083 final Class<?> returnType = actionMethod.getReturnType();
084 final FacetHolder action = processMethodContext.getFacetHolder();
085 final ActionChoicesFacetViaMethod facet =
086 new ActionChoicesFacetViaMethod(choicesMethod, returnType, action, getSpecificationLookup(),
087 getAdapterMap());
088 FacetUtil.addFacet(facet);
089 }
090
091 protected Method findChoicesMethodReturning(final ProcessMethodContext processMethodContext,
092 final Class<?> returnType2) {
093 Method choicesMethod;
094 final Class<?> cls = processMethodContext.getCls();
095
096 final Method actionMethod = processMethodContext.getMethod();
097 final MethodScope methodScope = MethodScope.scopeFor(actionMethod);
098 final String capitalizedName = NameUtils.capitalizeName(actionMethod.getName());
099
100 final String name = MethodPrefixConstants.CHOICES_PREFIX + capitalizedName;
101 choicesMethod = MethodFinderUtils.findMethod(cls, methodScope, name, returnType2, new Class[0]);
102 return choicesMethod;
103 }
104
105 // ///////////////////////////////////////////////////////////////
106 // Dependencies
107 // ///////////////////////////////////////////////////////////////
108
109 @Override
110 public void setAdapterMap(final AdapterMap adapterMap) {
111 this.adapterMap = adapterMap;
112 }
113
114 protected AdapterMap getAdapterMap() {
115 return adapterMap;
116 }
117 }