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.properties.modify;
021    
022    import java.lang.reflect.Method;
023    
024    import org.apache.isis.core.commons.lang.NameUtils;
025    import org.apache.isis.core.metamodel.facetapi.FacetHolder;
026    import org.apache.isis.core.metamodel.facetapi.FacetUtil;
027    import org.apache.isis.core.metamodel.facetapi.FeatureType;
028    import org.apache.isis.core.metamodel.methodutils.MethodScope;
029    import org.apache.isis.core.progmodel.facets.MethodFinderUtils;
030    import org.apache.isis.core.progmodel.facets.MethodPrefixBasedFacetFactoryAbstract;
031    import org.apache.isis.core.progmodel.facets.MethodPrefixConstants;
032    import org.apache.isis.core.progmodel.facets.members.disable.DisabledFacet;
033    import org.apache.isis.core.progmodel.facets.members.disable.staticmethod.DisabledFacetAlways;
034    import org.apache.isis.core.progmodel.facets.properties.derived.inferred.DerivedFacetInferred;
035    
036    public class PropertySetAndClearFacetFactory extends MethodPrefixBasedFacetFactoryAbstract {
037    
038        private static final String[] PREFIXES = { MethodPrefixConstants.SET_PREFIX, MethodPrefixConstants.CLEAR_PREFIX };
039    
040        public PropertySetAndClearFacetFactory() {
041            super(FeatureType.PROPERTIES_ONLY, PREFIXES);
042        }
043    
044        @Override
045        public void process(final ProcessMethodContext processMethodContext) {
046    
047            final Method setMethod = attachPropertyModifyFacetIfSetterIsFound(processMethodContext);
048            final Method clearMethod = attachPropertyClearFacetIfClearMethodIsFound(processMethodContext);
049    
050            attachPropertyClearFacetUsingSetterIfRequired(processMethodContext, setMethod, clearMethod);
051        }
052    
053        /**
054         * Sets up the {@link PropertySetterFacetViaSetterMethod} to invoke the property's setter if available, but if none
055         * then marks the property as {@link DerivedFacet derived} and {@link DisabledFacet disabled} otherwise.
056         */
057        private static Method attachPropertyModifyFacetIfSetterIsFound(final ProcessMethodContext processMethodContext) {
058    
059            final Method getMethod = processMethodContext.getMethod();
060            final String capitalizedName = NameUtils.javaBaseName(getMethod.getName());
061    
062            final Class<?> cls = processMethodContext.getCls();
063            final Class<?> returnType = getMethod.getReturnType();
064            final Class<?>[] paramTypes = new Class[] { returnType };
065            final Method setMethod =
066                MethodFinderUtils.findMethod(cls, MethodScope.OBJECT, MethodPrefixConstants.SET_PREFIX + capitalizedName,
067                    void.class, paramTypes);
068            processMethodContext.removeMethod(setMethod);
069    
070            final FacetHolder property = processMethodContext.getFacetHolder();
071            if (setMethod != null) {
072                FacetUtil.addFacet(new PropertySetterFacetViaSetterMethod(setMethod, property));
073                FacetUtil.addFacet(new PropertyInitializationFacetViaSetterMethod(setMethod, property));
074            } else {
075                FacetUtil.addFacet(new DerivedFacetInferred(property));
076                FacetUtil.addFacet(new DisabledFacetAlways(property));
077            }
078    
079            return setMethod;
080        }
081    
082        private Method attachPropertyClearFacetIfClearMethodIsFound(final ProcessMethodContext processMethodContext) {
083            final Class<?> cls = processMethodContext.getCls();
084            final Method getMethod = processMethodContext.getMethod();
085            final FacetHolder property = processMethodContext.getFacetHolder();
086    
087            final String capitalizedName = NameUtils.javaBaseName(getMethod.getName());
088            final Method clearMethod =
089                MethodFinderUtils.findMethod(cls, MethodScope.OBJECT, MethodPrefixConstants.CLEAR_PREFIX + capitalizedName,
090                    void.class, NO_PARAMETERS_TYPES);
091    
092            if (clearMethod == null) {
093                return null;
094            }
095            processMethodContext.removeMethod(clearMethod);
096    
097            FacetUtil.addFacet(new PropertyClearFacetViaClearMethod(clearMethod, property));
098    
099            return clearMethod;
100        }
101    
102        private static void attachPropertyClearFacetUsingSetterIfRequired(final ProcessMethodContext processMethodContext,
103            final Method setMethod, final Method clearMethod) {
104    
105            if (clearMethod != null) {
106                return;
107            }
108            if (setMethod == null) {
109                return;
110            }
111            final FacetHolder property = processMethodContext.getFacetHolder();
112            FacetUtil.addFacet(new PropertyClearFacetViaSetterMethod(setMethod, property));
113        }
114    
115    }