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 020package org.apache.isis.core.progmodel.facets.actions.invoke; 021 022import java.lang.reflect.Method; 023 024import org.apache.isis.core.commons.lang.StringExtensions; 025import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager; 026import org.apache.isis.core.metamodel.adapter.mgr.AdapterManagerAware; 027import org.apache.isis.core.metamodel.facetapi.Facet; 028import org.apache.isis.core.metamodel.facetapi.FacetHolder; 029import org.apache.isis.core.metamodel.facetapi.FacetUtil; 030import org.apache.isis.core.metamodel.facetapi.FeatureType; 031import org.apache.isis.core.metamodel.facets.actions.debug.DebugFacet; 032import org.apache.isis.core.metamodel.facets.actions.exploration.ExplorationFacet; 033import org.apache.isis.core.metamodel.facets.actions.invoke.ActionInvocationFacet; 034import org.apache.isis.core.metamodel.facets.named.NamedFacet; 035import org.apache.isis.core.metamodel.facets.named.NamedFacetInferred; 036import org.apache.isis.core.metamodel.runtimecontext.RuntimeContext; 037import org.apache.isis.core.metamodel.runtimecontext.RuntimeContextAware; 038import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector; 039import org.apache.isis.core.metamodel.runtimecontext.ServicesInjectorAware; 040import org.apache.isis.core.metamodel.spec.ObjectSpecification; 041import org.apache.isis.core.progmodel.facets.MethodPrefixBasedFacetFactoryAbstract; 042 043/** 044 * Sets up {@link ActionInvocationFacet}, along with a number of supporting 045 * facets that are based on the action's name. 046 * 047 * <p> 048 * The supporting methods are: {@link ExecutedFacet}, {@link ExplorationFacet} 049 * and {@link DebugFacet}. In addition a {@link NamedFacet} is inferred from the 050 * name (taking into account the above well-known prefixes). 051 */ 052public class ActionInvocationFacetFactory extends MethodPrefixBasedFacetFactoryAbstract implements AdapterManagerAware, ServicesInjectorAware, RuntimeContextAware { 053 054 private static final String EXPLORATION_PREFIX = "Exploration"; 055 private static final String DEBUG_PREFIX = "Debug"; 056 057 private static final String[] PREFIXES = { EXPLORATION_PREFIX, DEBUG_PREFIX }; 058 059 private AdapterManager adapterManager; 060 private ServicesInjector servicesInjector; 061 private RuntimeContext runtimeContext; 062 063 /** 064 * Note that the {@link Facet}s registered are the generic ones from 065 * noa-architecture (where they exist) 066 */ 067 public ActionInvocationFacetFactory() { 068 super(FeatureType.ACTIONS_ONLY, OrphanValidation.VALIDATE, PREFIXES); 069 } 070 071 // /////////////////////////////////////////////////////// 072 // Actions 073 // /////////////////////////////////////////////////////// 074 075 @Override 076 public void process(final ProcessMethodContext processMethodContext) { 077 078 // InvocationFacet 079 attachInvocationFacet(processMethodContext); 080 081 // DebugFacet, ExplorationFacet 082 attachDebugFacetIfActionMethodNamePrefixed(processMethodContext); 083 attachExplorationFacetIfActionMethodNamePrefixed(processMethodContext); 084 085 // inferred name 086 // (must be called after the attachinvocationFacet methods) 087 attachNamedFacetInferredFromMethodName(processMethodContext); 088 } 089 090 private void attachInvocationFacet(final ProcessMethodContext processMethodContext) { 091 092 final Method actionMethod = processMethodContext.getMethod(); 093 094 try { 095 final Class<?> returnType = actionMethod.getReturnType(); 096 final ObjectSpecification returnSpec = getSpecificationLoader().loadSpecification(returnType); 097 if (returnSpec == null) { 098 return; 099 } 100 101 final Class<?> cls = processMethodContext.getCls(); 102 final ObjectSpecification typeSpec = getSpecificationLoader().loadSpecification(cls); 103 final FacetHolder holder = processMethodContext.getFacetHolder(); 104 105 FacetUtil.addFacet(new ActionInvocationFacetViaMethod(actionMethod, typeSpec, returnSpec, holder, getRuntimeContext(), getAdapterManager(), getServicesInjector())); 106 } finally { 107 processMethodContext.removeMethod(actionMethod); 108 } 109 } 110 111 private void attachDebugFacetIfActionMethodNamePrefixed(final ProcessMethodContext processMethodContext) { 112 113 final Method actionMethod = processMethodContext.getMethod(); 114 final String capitalizedName = StringExtensions.asCapitalizedName(actionMethod.getName()); 115 if (!capitalizedName.startsWith(DEBUG_PREFIX)) { 116 return; 117 } 118 final FacetHolder facetedMethod = processMethodContext.getFacetHolder(); 119 FacetUtil.addFacet(new DebugFacetViaNamingConvention(facetedMethod)); 120 } 121 122 private void attachExplorationFacetIfActionMethodNamePrefixed(final ProcessMethodContext processMethodContext) { 123 124 final Method actionMethod = processMethodContext.getMethod(); 125 final String capitalizedName = StringExtensions.asCapitalizedName(actionMethod.getName()); 126 if (!capitalizedName.startsWith(EXPLORATION_PREFIX)) { 127 return; 128 } 129 final FacetHolder facetedMethod = processMethodContext.getFacetHolder(); 130 FacetUtil.addFacet(new ExplorationFacetViaNamingConvention(facetedMethod)); 131 } 132 133 /** 134 * Must be called after added the debug, exploration etc facets. 135 * 136 * <p> 137 * TODO: remove this hack 138 */ 139 private void attachNamedFacetInferredFromMethodName(final ProcessMethodContext processMethodContext) { 140 141 final Method method = processMethodContext.getMethod(); 142 final String capitalizedName = StringExtensions.asCapitalizedName(method.getName()); 143 144 // this is nasty... 145 String name = capitalizedName; 146 name = StringExtensions.removePrefix(name, DEBUG_PREFIX); 147 name = StringExtensions.removePrefix(name, EXPLORATION_PREFIX); 148 name = StringExtensions.asNaturalName2(name); 149 150 final FacetHolder facetedMethod = processMethodContext.getFacetHolder(); 151 FacetUtil.addFacet(new NamedFacetInferred(name, facetedMethod)); 152 } 153 154 // /////////////////////////////////////////////////////////////// 155 // Dependencies 156 // /////////////////////////////////////////////////////////////// 157 158 @Override 159 public void setAdapterManager(final AdapterManager adapterManager) { 160 this.adapterManager = adapterManager; 161 } 162 163 private AdapterManager getAdapterManager() { 164 return adapterManager; 165 } 166 167 @Override 168 public void setServicesInjector(final ServicesInjector servicesInjector) { 169 this.servicesInjector = servicesInjector; 170 } 171 172 private ServicesInjector getServicesInjector() { 173 return servicesInjector; 174 } 175 176 private RuntimeContext getRuntimeContext() { 177 return runtimeContext; 178 } 179 180 @Override 181 public void setRuntimeContext(RuntimeContext runtimeContext) { 182 this.runtimeContext = runtimeContext; 183 } 184}