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.metamodel.facets; 021 022import java.lang.reflect.Method; 023import java.util.List; 024import java.util.Properties; 025 026import com.google.common.collect.Lists; 027 028import org.apache.isis.applib.Identifier; 029import org.apache.isis.core.commons.lang.PropertiesExtensions; 030import org.apache.isis.core.metamodel.facetapi.Facet; 031import org.apache.isis.core.metamodel.facetapi.FacetHolder; 032import org.apache.isis.core.metamodel.facetapi.FeatureType; 033import org.apache.isis.core.metamodel.facetapi.MethodRemover; 034import org.apache.isis.core.metamodel.methodutils.MethodScope; 035import org.apache.isis.core.metamodel.spec.feature.ObjectAction; 036import org.apache.isis.core.metamodel.spec.feature.ObjectMember; 037import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation; 038import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation; 039 040public interface FacetFactory { 041 042 static class AbstractProcessContext<T extends FacetHolder> { 043 private final T facetHolder; 044 045 public AbstractProcessContext(final T facetHolder) { 046 this.facetHolder = facetHolder; 047 } 048 049 public T getFacetHolder() { 050 return facetHolder; 051 } 052 } 053 054 public interface ProcessContextWithMetadataProperties<T extends FacetHolder> { 055 public Properties metadataProperties(String subKey); 056 public T getFacetHolder(); 057 } 058 059 /** 060 * The {@link FeatureType feature type}s that this facet factory can create 061 * {@link Facet}s for. 062 * 063 * <p> 064 * Used by the Java5 Reflector's <tt>ProgrammingModel</tt> to reduce the 065 * number of {@link FacetFactory factory}s that are queried when building up 066 * the meta-model. 067 */ 068 List<FeatureType> getFeatureTypes(); 069 070 071 // ////////////////////////////////////// 072 // process class 073 // ////////////////////////////////////// 074 075 public static class ProcessClassContext extends AbstractProcessContext<FacetHolder> implements MethodRemover, ProcessContextWithMetadataProperties<FacetHolder> { 076 private final Class<?> cls; 077 private final MethodRemover methodRemover; 078 private final Properties metadataProperties; 079 080 /** 081 * For testing only. 082 */ 083 public ProcessClassContext(final Class<?> cls, final MethodRemover methodRemover, final FacetHolder facetHolder) { 084 this(cls, null, methodRemover, facetHolder); 085 } 086 087 public ProcessClassContext( 088 final Class<?> cls, 089 final Properties metadataProperties, 090 final MethodRemover methodRemover, 091 final FacetHolder facetHolder) { 092 super(facetHolder); 093 this.cls = cls; 094 this.methodRemover = methodRemover; 095 this.metadataProperties = metadataProperties; 096 } 097 098 /** 099 * The class being processed. 100 */ 101 public Class<?> getCls() { 102 return cls; 103 } 104 105 @Override 106 public void removeMethod(final Method method) { 107 methodRemover.removeMethod(method); 108 } 109 110 @Override 111 public List<Method> removeMethods(final MethodScope methodScope, final String prefix, final Class<?> returnType, final boolean canBeVoid, final int paramCount) { 112 return methodRemover.removeMethods(methodScope, prefix, returnType, canBeVoid, paramCount); 113 } 114 115 @Override 116 public void removeMethod(final MethodScope methodScope, final String methodName, final Class<?> returnType, final Class<?>[] parameterTypes) { 117 methodRemover.removeMethod(methodScope, methodName, returnType, parameterTypes); 118 } 119 120 @Override 121 public void removeMethods(final List<Method> methods) { 122 methodRemover.removeMethods(methods); 123 } 124 125 public Properties metadataProperties(String subKey) { 126 if(metadataProperties == null) { 127 return null; 128 } 129 final Properties subsetProperties = PropertiesExtensions.subset(this.metadataProperties, "class." + subKey); 130 return !subsetProperties.isEmpty() ? subsetProperties : null; 131 } 132 } 133 134 /** 135 * Process the class, and return the correctly setup annotation if present. 136 */ 137 void process(ProcessClassContext processClassContext); 138 139 // ////////////////////////////////////// 140 // process method 141 // ////////////////////////////////////// 142 143 144 public static class ProcessMethodContext extends AbstractProcessContext<FacetedMethod> implements MethodRemover, ProcessContextWithMetadataProperties<FacetedMethod> { 145 private final Class<?> cls; 146 private final FeatureType featureType; 147 private final Properties metadataProperties; 148 private final Method method; 149 private final MethodRemover methodRemover; 150 151 public ProcessMethodContext( 152 final Class<?> cls, 153 final FeatureType featureType, 154 final Properties metadataProperties, 155 final Method method, 156 final MethodRemover methodRemover, 157 final FacetedMethod facetedMethod) { 158 super(facetedMethod); 159 this.cls = cls; 160 this.featureType = featureType; 161 this.metadataProperties = metadataProperties; 162 this.method = method; 163 this.methodRemover = methodRemover; 164 } 165 166 public Class<?> getCls() { 167 return cls; 168 } 169 170 public Method getMethod() { 171 return method; 172 } 173 174 @Override 175 public List<Method> removeMethods(final MethodScope methodScope, final String prefix, final Class<?> returnType, final boolean canBeVoid, final int paramCount) { 176 return methodRemover.removeMethods(methodScope, prefix, returnType, canBeVoid, paramCount); 177 } 178 179 @Override 180 public void removeMethod(final MethodScope methodScope, final String methodName, final Class<?> returnType, final Class<?>[] parameterTypes) { 181 methodRemover.removeMethod(methodScope, methodName, returnType, parameterTypes); 182 } 183 184 @Override 185 public void removeMethod(final Method method) { 186 methodRemover.removeMethod(method); 187 } 188 189 @Override 190 public void removeMethods(final List<Method> methods) { 191 methodRemover.removeMethods(methods); 192 } 193 194 public Properties metadataProperties(String subKey) { 195 196 if(metadataProperties == null) { 197 return null; 198 } 199 Identifier identifier = featureType.identifierFor(getCls(), getMethod()); 200 final String id = identifier.getMemberName(); 201 202 // build list of keys to search for... 203 final List<String> keys = Lists.newArrayList(); 204 if(featureType == FeatureType.ACTION) { 205 // ... either "action.actionId" or "member.actionId()" 206 keys.add("action." + id+"."+subKey); 207 keys.add("member." + id+"()"+"."+subKey); 208 } else if(featureType == FeatureType.PROPERTY) { 209 // ... either "property.propertyId" or "member.propertyId" 210 keys.add("property." + id+"."+subKey); 211 keys.add("member." + id+"."+subKey); 212 } else if(featureType == FeatureType.COLLECTION) { 213 // ... either "collection.collectionId" or "member.collectionId" 214 keys.add("collection." + id+"."+subKey); 215 keys.add("member." + id+"."+subKey); 216 } 217 218 for (final String key : keys) { 219 final Properties subsetProperties = PropertiesExtensions.subset(this.metadataProperties, key); 220 if (!subsetProperties.isEmpty()) { 221 return subsetProperties; 222 } 223 } 224 225 return null; 226 } 227 } 228 229 /** 230 * Process the method, and return the correctly setup annotation if present. 231 */ 232 void process(ProcessMethodContext processMethodContext); 233 234 235 236 237 // ////////////////////////////////////// 238 // process param 239 // ////////////////////////////////////// 240 241 public static class ProcessParameterContext extends AbstractProcessContext<FacetedMethodParameter> { 242 private final Method method; 243 private final int paramNum; 244 245 public ProcessParameterContext( 246 final Method method, 247 final int paramNum, 248 final FacetedMethodParameter facetedMethodParameter) { 249 super(facetedMethodParameter); 250 this.method = method; 251 this.paramNum = paramNum; 252 } 253 254 public Method getMethod() { 255 return method; 256 } 257 258 public int getParamNum() { 259 return paramNum; 260 } 261 } 262 263 /** 264 * Process the parameters of the method, and return the correctly setup 265 * annotation if present. 266 */ 267 void processParams(ProcessParameterContext processParameterContext); 268}