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.describedas.staticmethod;
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.adapter.util.InvokeUtils;
029 import org.apache.isis.core.metamodel.exceptions.MetaModelException;
030 import org.apache.isis.core.metamodel.facetapi.Facet;
031 import org.apache.isis.core.metamodel.facetapi.FacetUtil;
032 import org.apache.isis.core.metamodel.facetapi.FeatureType;
033 import org.apache.isis.core.metamodel.facets.FacetedMethod;
034 import org.apache.isis.core.metamodel.facets.FacetedMethodParameter;
035 import org.apache.isis.core.metamodel.methodutils.MethodScope;
036 import org.apache.isis.core.progmodel.facets.MethodFinderUtils;
037 import org.apache.isis.core.progmodel.facets.MethodPrefixBasedFacetFactoryAbstract;
038 import org.apache.isis.core.progmodel.facets.MethodPrefixConstants;
039 import org.apache.isis.core.progmodel.facets.members.describedas.staticmethod.DescribedAsFacetViaMethod;
040
041 public class ActionParameterDescriptionsMethodFacetFactory extends MethodPrefixBasedFacetFactoryAbstract implements
042 AdapterMapAware {
043
044 private static final String[] PREFIXES = { MethodPrefixConstants.DESCRIPTION_PREFIX };
045
046 private AdapterMap adapterMap;
047
048 /**
049 * Note that the {@link Facet}s registered are the generic ones from noa-architecture (where they exist)
050 */
051 public ActionParameterDescriptionsMethodFacetFactory() {
052 super(FeatureType.ACTIONS_ONLY, PREFIXES);
053 }
054
055 // ///////////////////////////////////////////////////////
056 // Actions
057 // ///////////////////////////////////////////////////////
058
059 @Override
060 public void process(final ProcessMethodContext processMethodContext) {
061
062 final FacetedMethod facetedMethod = processMethodContext.getFacetHolder();
063 final List<FacetedMethodParameter> holderList = facetedMethod.getParameters();
064
065 attachDescribedAsFacetForParametersIfParameterDescriptionsMethodIsFound(processMethodContext, holderList);
066 }
067
068 private static void attachDescribedAsFacetForParametersIfParameterDescriptionsMethodIsFound(
069 final ProcessMethodContext processMethodContext, final List<FacetedMethodParameter> parameters) {
070
071 if (parameters.isEmpty()) {
072 return;
073 }
074
075 final Method actionMethod = processMethodContext.getMethod();
076
077 final String capitalizedName = NameUtils.capitalizeName(actionMethod.getName());
078
079 final Class<?> cls = processMethodContext.getCls();
080 final Method descriptionMethod =
081 MethodFinderUtils.findMethod(cls, MethodScope.CLASS, MethodPrefixConstants.DESCRIPTION_PREFIX
082 + capitalizedName, String[].class, new Class[0]);
083 if (descriptionMethod == null) {
084 return;
085 }
086 processMethodContext.removeMethod(descriptionMethod);
087
088 final String[] descriptions = invokeDescriptionsMethod(descriptionMethod, parameters.size());
089 for (int i = 0; i < descriptions.length; i++) {
090 // add facets directly to parameters, not to actions
091 FacetUtil.addFacet(new DescribedAsFacetViaMethod(descriptions[i], descriptionMethod, parameters.get(i)));
092 }
093 }
094
095 private static String[] invokeDescriptionsMethod(final Method descriptionMethod, final int numElementsRequired) {
096 String[] descriptions = null;
097 try {
098 descriptions = (String[]) InvokeUtils.invokeStatic(descriptionMethod, new Object[0]);
099 } catch (final ClassCastException ex) {
100 // ignore
101 }
102 if (descriptions == null || descriptions.length != numElementsRequired) {
103 throw new MetaModelException(descriptionMethod
104 + " must return an String[] array of same size as number of parameters of action");
105 }
106 return descriptions;
107 }
108
109 // ///////////////////////////////////////////////////////////////
110 // Dependencies
111 // ///////////////////////////////////////////////////////////////
112
113 @Override
114 public void setAdapterMap(final AdapterMap adapterMap) {
115 this.adapterMap = adapterMap;
116 }
117
118 private AdapterMap getAdapterMap() {
119 return adapterMap;
120 }
121
122 }