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 */ 017package org.apache.isis.core.metamodel.services.devutils; 018 019import java.util.Arrays; 020import java.util.List; 021import java.util.SortedSet; 022 023import com.google.common.base.Joiner; 024import com.google.common.base.Strings; 025import com.google.common.collect.Sets; 026 027import org.apache.isis.applib.util.ObjectContracts; 028import org.apache.isis.core.commons.lang.StringExtensions; 029import org.apache.isis.core.metamodel.facetapi.Facet; 030import org.apache.isis.core.metamodel.facets.ImperativeFacet; 031import org.apache.isis.core.metamodel.facets.actions.choices.ActionChoicesFacet; 032import org.apache.isis.core.metamodel.facets.actions.defaults.ActionDefaultsFacet; 033import org.apache.isis.core.metamodel.facets.hide.HiddenFacet; 034import org.apache.isis.core.metamodel.facets.param.autocomplete.ActionParameterAutoCompleteFacet; 035import org.apache.isis.core.metamodel.facets.param.choices.ActionParameterChoicesFacet; 036import org.apache.isis.core.metamodel.facets.param.defaults.ActionParameterDefaultsFacet; 037import org.apache.isis.core.metamodel.facets.properties.autocomplete.PropertyAutoCompleteFacet; 038import org.apache.isis.core.metamodel.facets.properties.choices.PropertyChoicesFacet; 039import org.apache.isis.core.metamodel.facets.properties.defaults.PropertyDefaultFacet; 040import org.apache.isis.core.metamodel.spec.ObjectSpecification; 041import org.apache.isis.core.metamodel.spec.feature.ObjectAction; 042import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter; 043import org.apache.isis.core.metamodel.spec.feature.ObjectMember; 044import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation; 045import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation; 046import org.apache.isis.core.progmodel.facets.actions.validate.ActionValidationFacet; 047import org.apache.isis.core.progmodel.facets.collections.validate.CollectionValidateAddToFacet; 048import org.apache.isis.core.progmodel.facets.collections.validate.CollectionValidateRemoveFromFacet; 049import org.apache.isis.core.progmodel.facets.members.disabled.DisabledFacet; 050import org.apache.isis.core.progmodel.facets.properties.validate.PropertyValidateFacet; 051 052public class MetaModelRow implements Comparable<MetaModelRow>{ 053 054 enum MemberType { 055 PROPERTY, 056 COLLECTION, 057 ACTION; 058 } 059 060 private final ObjectSpecification spec; 061 private final MemberType memberType; 062 private final ObjectMember member; 063 private ObjectAction action; 064 065 MetaModelRow(ObjectSpecification spec, OneToOneAssociation property) { 066 this.spec = spec; 067 this.member = property; 068 this.memberType = MemberType.PROPERTY; 069 } 070 071 MetaModelRow(ObjectSpecification spec, OneToManyAssociation collection) { 072 this.spec = spec; 073 this.member = collection; 074 this.memberType = MemberType.COLLECTION; 075 } 076 077 MetaModelRow(ObjectSpecification spec, ObjectAction action) { 078 this.spec = spec; 079 this.member = this.action = action; 080 this.memberType = MemberType.ACTION; 081 } 082 083 public String getClassType() { 084 boolean service = false; 085 for(ObjectSpecification subspecs: spec.subclasses()) { 086 service = service || subspecs.isService(); 087 } 088 return service || spec.isService() ?"2 Service":spec.isValue()?"3 Value":spec.isParentedOrFreeCollection()?"4 Collection":"1 Object"; 089 } 090 public String getClassName() { 091 final String fullIdentifier = spec.getFullIdentifier(); 092 final int lastDot = fullIdentifier.lastIndexOf("."); 093 return lastDot>0 && lastDot < fullIdentifier.length()-1 094 ?fullIdentifier.substring(lastDot+1,fullIdentifier.length()) 095 :fullIdentifier; 096 } 097 public String getPackageName() { 098 final String fullIdentifier = spec.getFullIdentifier(); 099 final int lastDot = fullIdentifier.lastIndexOf("."); 100 return lastDot>0?fullIdentifier.substring(0,lastDot):fullIdentifier; 101 } 102 public String getType() { 103 return memberType.name().toLowerCase(); 104 } 105 public String getMemberName() { 106 return member.getId(); 107 } 108 public String getNumParams() { 109 return action!=null?""+action.getParameterCount():""; 110 } 111 String getHidden() { 112 return interpret(HiddenFacet.class); 113 } 114 String getDisabled() { 115 return interpret(DisabledFacet.class); 116 } 117 public String getChoices() { 118 if(memberType == MemberType.PROPERTY) { 119 return interpretRowAndFacet(PropertyChoicesFacet.class); 120 } else if(memberType == MemberType.COLLECTION) { 121 return ""; 122 } else { 123 final List<ObjectActionParameter> parameters = this.action.getParameters(); 124 final SortedSet<String> interpretations = Sets.newTreeSet(); 125 for (ObjectActionParameter param : parameters) { 126 final ActionParameterChoicesFacet facet = param.getFacet(ActionParameterChoicesFacet.class); 127 addIfNotEmpty(interpretFacet(facet), interpretations); 128 } 129 return !interpretations.isEmpty()? Joiner.on(";").join(interpretations) : interpretRowAndFacet(ActionChoicesFacet.class); 130 } 131 } 132 public String getAutoComplete() { 133 if(memberType == MemberType.PROPERTY) { 134 return interpretRowAndFacet(PropertyAutoCompleteFacet.class); 135 } else if(memberType == MemberType.COLLECTION) { 136 return ""; 137 } else { 138 final List<ObjectActionParameter> parameters = this.action.getParameters(); 139 final SortedSet<String> interpretations = Sets.newTreeSet(); 140 for (ObjectActionParameter param : parameters) { 141 final ActionParameterAutoCompleteFacet facet = param.getFacet(ActionParameterAutoCompleteFacet.class); 142 addIfNotEmpty(interpretFacet(facet), interpretations); 143 } 144 return !interpretations.isEmpty()? Joiner.on(";").join(interpretations) : ""; 145 } 146 } 147 String getDefault() { 148 if(memberType == MemberType.PROPERTY) { 149 return interpretRowAndFacet(PropertyDefaultFacet.class); 150 } else if(memberType == MemberType.COLLECTION) { 151 return ""; 152 } else { 153 final List<ObjectActionParameter> parameters = this.action.getParameters(); 154 final SortedSet<String> interpretations = Sets.newTreeSet(); 155 for (ObjectActionParameter param : parameters) { 156 final ActionParameterDefaultsFacet facet = param.getFacet(ActionParameterDefaultsFacet.class); 157 addIfNotEmpty(interpretFacet(facet), interpretations); 158 } 159 return !interpretations.isEmpty()? Joiner.on(";").join(interpretations) : interpretRowAndFacet(ActionDefaultsFacet.class); 160 } 161 } 162 String getValidate() { 163 if(memberType == MemberType.PROPERTY) { 164 return interpretRowAndFacet(PropertyValidateFacet.class); 165 } else if(memberType == MemberType.COLLECTION) { 166 final SortedSet<String> interpretations = Sets.newTreeSet(); 167 addIfNotEmpty(interpretRowAndFacet(CollectionValidateAddToFacet.class), interpretations); 168 addIfNotEmpty(interpretRowAndFacet(CollectionValidateRemoveFromFacet.class), interpretations); 169 return !interpretations.isEmpty()? Joiner.on(";").join(interpretations) : ""; 170 } else { 171 return interpretRowAndFacet(ActionValidationFacet.class); 172 } 173 } 174 175 static Object header() { 176 return "classType,packageName,className,memberType,memberName,numParams,hidden,disabled,choices,autoComplete,default,validate"; 177 } 178 179 String asTextCsv() { 180 return Joiner.on(",").join( 181 getClassType(), 182 getPackageName(), 183 getClassName(), 184 getType(), 185 getMemberName(), 186 getNumParams(), 187 getHidden(), 188 getDisabled(), 189 getChoices(), 190 getAutoComplete(), 191 getDefault(), 192 getValidate()); 193 } 194 195 private String interpretRowAndFacet(Class<? extends Facet> facetClass) { 196 final Facet facet = member.getFacet(facetClass); 197 return interpretFacet(facet); 198 } 199 200 private static void addIfNotEmpty(final String str, final SortedSet<String> set) { 201 if(!Strings.isNullOrEmpty(str)) { 202 set.add(str); 203 } 204 } 205 206 private String interpret(final Class<? extends Facet> cls) { 207 return interpretFacet(member.getFacet(cls)); 208 } 209 210 private static String interpretFacet(final Facet facet) { 211 if (facet == null || facet.isNoop()) { 212 return ""; 213 } 214 if (facet instanceof ImperativeFacet) { 215 ImperativeFacet imperativeFacet = (ImperativeFacet) facet; 216 return imperativeFacet.getMethods().get(0).getName(); 217 } 218 final String name = facet.getClass().getSimpleName(); 219 if (ignore(name)) { 220 return ""; 221 } 222 final String abbr = StringExtensions.toAbbreviation(name); 223 return abbr.length()>0 ? abbr : name; 224 } 225 226 protected static boolean ignore(final String name) { 227 return Arrays.asList("PropertyValidateFacetDefault","PropertyDefaultFacetDerivedFromDefaultedFacet").contains(name); 228 } 229 230 @Override 231 public int compareTo(MetaModelRow o) { 232 return ObjectContracts.compare(this, o, "classType,className,type desc,memberName"); 233 } 234}