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.actions.invoke;
021
022 import java.lang.reflect.InvocationTargetException;
023 import java.lang.reflect.Method;
024 import java.util.Collections;
025 import java.util.List;
026
027 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
028 import org.apache.isis.core.metamodel.adapter.map.AdapterMap;
029 import org.apache.isis.core.metamodel.adapter.util.InvokeUtils;
030 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
031 import org.apache.isis.core.metamodel.facets.ImperativeFacet;
032 import org.apache.isis.core.metamodel.facets.actions.invoke.ActionInvocationFacetAbstract;
033 import org.apache.isis.core.metamodel.facets.typeof.ElementSpecificationProviderFromTypeOfFacet;
034 import org.apache.isis.core.metamodel.facets.typeof.TypeOfFacet;
035 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
036 import org.apache.isis.core.metamodel.specloader.ReflectiveActionException;
037 import org.apache.log4j.Logger;
038
039 public class ActionInvocationFacetViaMethod extends ActionInvocationFacetAbstract implements ImperativeFacet {
040
041 private final static Logger LOG = Logger.getLogger(ActionInvocationFacetViaMethod.class);
042
043 private final Method method;
044 private final int paramCount;
045 private final ObjectSpecification onType;
046 private final ObjectSpecification returnType;
047
048 private final AdapterMap adapterMap;
049
050 public ActionInvocationFacetViaMethod(final Method method, final ObjectSpecification onType,
051 final ObjectSpecification returnType, final FacetHolder holder, final AdapterMap adapterManager) {
052 super(holder);
053 this.method = method;
054 this.paramCount = method.getParameterTypes().length;
055 this.onType = onType;
056 this.returnType = returnType;
057 this.adapterMap = adapterManager;
058 }
059
060 /**
061 * Returns a singleton list of the {@link Method} provided in the constructor.
062 */
063 @Override
064 public List<Method> getMethods() {
065 return Collections.singletonList(method);
066 }
067
068 @Override
069 public ObjectSpecification getReturnType() {
070 return returnType;
071 }
072
073 @Override
074 public ObjectSpecification getOnType() {
075 return onType;
076 }
077
078 @Override
079 public ObjectAdapter invoke(final ObjectAdapter inObject, final ObjectAdapter[] parameters) {
080 if (parameters.length != paramCount) {
081 LOG.error(method + " requires " + paramCount + " parameters, not " + parameters.length);
082 }
083
084 try {
085 final Object[] executionParameters = new Object[parameters.length];
086 for (int i = 0; i < parameters.length; i++) {
087 executionParameters[i] = unwrap(parameters[i]);
088 }
089
090 final Object object = unwrap(inObject);
091 final Object result = method.invoke(object, executionParameters);
092 if (LOG.isDebugEnabled()) {
093 LOG.debug(" action result " + result);
094 }
095 if (result == null) {
096 return null;
097 }
098
099 final ObjectAdapter resultAdapter = getAdapterMap().adapterFor(result);
100 final TypeOfFacet typeOfFacet = getFacetHolder().getFacet(TypeOfFacet.class);
101 resultAdapter.setElementSpecificationProvider(ElementSpecificationProviderFromTypeOfFacet
102 .createFrom(typeOfFacet));
103 return resultAdapter;
104
105 } catch (final IllegalArgumentException e) {
106 throw e;
107 } catch (final InvocationTargetException e) {
108 if (e.getTargetException() instanceof IllegalStateException) {
109 throw new ReflectiveActionException("IllegalStateException thrown while executing " + method + " "
110 + e.getTargetException().getMessage(), e.getTargetException());
111 } else {
112 InvokeUtils.invocationException("Exception executing " + method, e);
113 return null;
114 }
115 } catch (final IllegalAccessException e) {
116 throw new ReflectiveActionException("Illegal access of " + method, e);
117 }
118 }
119
120 private static Object unwrap(final ObjectAdapter adapter) {
121 return adapter == null ? null : adapter.getObject();
122 }
123
124 @Override
125 public boolean impliesResolve() {
126 return true;
127 }
128
129 @Override
130 public boolean impliesObjectChanged() {
131 return false;
132 }
133
134 @Override
135 protected String toStringValues() {
136 return "method=" + method;
137 }
138
139 // /////////////////////////////////////////////////////////
140 // Dependencies (from constructor)
141 // /////////////////////////////////////////////////////////
142
143 private AdapterMap getAdapterMap() {
144 return adapterMap;
145 }
146
147 }