001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.isis.core.progmodel.layout.ordermethod;
018
019 import java.lang.reflect.InvocationTargetException;
020 import java.lang.reflect.Method;
021 import java.util.Arrays;
022 import java.util.List;
023
024 import org.apache.log4j.Logger;
025
026 import org.apache.isis.core.commons.lang.JavaClassUtils;
027 import org.apache.isis.core.commons.lang.StringUtils;
028 import org.apache.isis.core.metamodel.facets.FacetedMethod;
029 import org.apache.isis.core.metamodel.facets.object.orderactions.ActionOrderFacet;
030 import org.apache.isis.core.metamodel.facets.object.orderfields.FieldOrderFacet;
031 import org.apache.isis.core.metamodel.layout.MemberLayoutArranger;
032 import org.apache.isis.core.metamodel.layout.OrderSet;
033 import org.apache.isis.core.metamodel.layout.ordermethod.SimpleOrderSet;
034 import org.apache.isis.core.metamodel.methodutils.MethodFinderUtils;
035 import org.apache.isis.core.metamodel.methodutils.MethodScope;
036 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
037
038 public class MemberLayoutArrangerUsingOrderMethod implements MemberLayoutArranger {
039
040
041 private static final Logger LOG = Logger.getLogger(MemberLayoutArrangerUsingOrderMethod.class);
042
043 private static final Object[] NO_PARAMETERS = new Object[0];
044 private static final Class<?>[] NO_PARAMETERS_TYPES = new Class[0];
045
046 private static final String FIELD_PREFIX = null;
047
048 private static final String ACTION_PREFIX = null;
049
050
051 // ////////////////////////////////////////////////////////////////////////////
052 // constructor
053 // ////////////////////////////////////////////////////////////////////////////
054
055 public MemberLayoutArrangerUsingOrderMethod() { }
056
057
058 // ////////////////////////////////////////////////////////////////////////////
059 // associations
060 // ////////////////////////////////////////////////////////////////////////////
061
062
063 @Override
064 public OrderSet createAssociationOrderSetFor(ObjectSpecification spec, final List<FacetedMethod> associationMethods) {
065 if (LOG.isDebugEnabled()) {
066 LOG.debug("MemberLayoutArrangerUsingOrderMethod: createAssociationOrderSetFor " + spec.getFullIdentifier());
067 }
068
069 // ... and the ordering of the properties and collections
070 final FieldOrderFacet fieldOrderFacet = spec.getFacet(FieldOrderFacet.class);
071 String fieldOrder = fieldOrderFacet == null ? null : fieldOrderFacet.value();
072
073 if (fieldOrder == null) {
074 fieldOrder = invokeSortOrderMethod(spec, FIELD_PREFIX);
075 }
076 return createOrderSet(fieldOrder, associationMethods);
077 }
078
079
080 // ////////////////////////////////////////////////////////////////////////////
081 // actions
082 // ////////////////////////////////////////////////////////////////////////////
083
084 @Override
085 public OrderSet createActionOrderSetFor(ObjectSpecification spec, List<FacetedMethod> actionFacetedMethodList) {
086 if (LOG.isDebugEnabled()) {
087 LOG.debug("MemberLayoutArrangerUsingOrderMethod: createAssociationOrderSetFor " + spec.getFullIdentifier());
088 }
089
090 final ActionOrderFacet actionOrderFacet = spec.getFacet(ActionOrderFacet.class);
091 String actionOrder = actionOrderFacet == null ? null : actionOrderFacet.value();
092 if (actionOrder == null) {
093 actionOrder = invokeSortOrderMethod(spec, ACTION_PREFIX);
094 }
095 return createOrderSet(actionOrder, actionFacetedMethodList);
096 }
097
098 // ////////////////////////////////////////////////////////////////////////////
099 // helpers
100 // ////////////////////////////////////////////////////////////////////////////
101
102 /**
103 * Invokes a method called <tt>xxxOrder()</tt>, returning a {@link String}.
104 * @param spec
105 */
106 private String invokeSortOrderMethod(ObjectSpecification spec, final String methodNamePrefix) {
107 final List<Method> methods = Arrays.asList(spec.getCorrespondingClass().getMethods());
108 final Method method = MethodFinderUtils.findMethod(methods, MethodScope.CLASS, (methodNamePrefix + "Order"), String.class, NO_PARAMETERS_TYPES);
109 if (method == null) {
110 return null;
111 }
112
113 if (!JavaClassUtils.isStatic(method)) {
114 LOG.warn("method " + spec.getFullIdentifier() + "." + methodNamePrefix + "Order() must be declared as static");
115 return null;
116 }
117
118 try {
119 String s = (String) method.invoke(null, NO_PARAMETERS);
120 if (StringUtils.isNullOrEmpty(s)) {
121 return null;
122 }
123 return s;
124 } catch (IllegalArgumentException e) {
125 LOG.warn("method " + spec.getFullIdentifier() + "#" + method.getName() + "() should accept no parameters");
126 return null;
127 } catch (IllegalAccessException e) {
128 LOG.warn("method " + spec.getFullIdentifier() + "#" + method.getName() + "() must be declared as public");
129 return null;
130 } catch (InvocationTargetException e) {
131 LOG.warn("method " + spec.getFullIdentifier() + "#" + method.getName() + "() has thrown an exception");
132 return null;
133 }
134 }
135
136 private OrderSet createOrderSet(final String order, final List<FacetedMethod> members) {
137 if (order == null) {
138 return null;
139 }
140 return SimpleOrderSet.createOrderSet(order, members);
141 }
142 }