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.facetapi;
021
022import java.beans.Introspector;
023import java.lang.reflect.Method;
024import java.util.List;
025
026import com.google.common.collect.ImmutableList;
027
028import org.apache.isis.applib.Identifier;
029import org.apache.isis.core.commons.lang.StringExtensions;
030import org.apache.isis.core.metamodel.facets.FacetFactory;
031import org.apache.isis.core.metamodel.spec.ObjectSpecification;
032
033/**
034 * Enumerates the features that a particular Facet can be applied to.
035 *
036 * <p>
037 * The class-level feature processing is typically performed by {@link FacetFactory}s 
038 * pertaining to {@link #OBJECT}, performed before the processing of class members.  
039 * However, {@link FacetFactory}s can also be associated with {@link #OBJECT_POST_PROCESSING},
040 * which is run after all members have been introspected. This is useful for facets
041 * (eg the JDO <tt>Version</tt> annotation) that references class members.
042 *  
043 * <p>
044 * TODO: should rationalize this and {@link ObjectSpecification#getResultType()}
045 * . Note though that we don't distinguish value properties and reference
046 * properties (and we probably shouldn't in {@link ObjectSpecification},
047 * either).
048 */
049public enum FeatureType {
050
051    OBJECT("Object") {
052        /**
053         * The supplied method can be null; at any rate it will be ignored.
054         */
055        @Override
056        public Identifier identifierFor(final Class<?> type, final Method method) {
057            return Identifier.classIdentifier(type);
058        }
059    },
060    PROPERTY("Property") {
061        @Override
062        public Identifier identifierFor(final Class<?> type, final Method method) {
063            return propertyOrCollectionIdentifierFor(type, method);
064        }
065    },
066    COLLECTION("Collection") {
067        @Override
068        public Identifier identifierFor(final Class<?> type, final Method method) {
069            return propertyOrCollectionIdentifierFor(type, method);
070        }
071    },
072    ACTION("Action") {
073        @Override
074        public Identifier identifierFor(final Class<?> type, final Method method) {
075            final String fullMethodName = method.getName();
076            final Class<?>[] parameterTypes = method.getParameterTypes();
077            return Identifier.actionIdentifier(type.getName(), fullMethodName, parameterTypes);
078        }
079    },
080    ACTION_PARAMETER("Parameter") {
081        /**
082         * Always returns <tt>null</tt>.
083         */
084        @Override
085        public Identifier identifierFor(final Class<?> type, final Method method) {
086            return null;
087        }
088    },
089    OBJECT_POST_PROCESSING("Object post processing") {
090        /**
091         * The supplied method can be null; at any rate it will be ignored.
092         */
093        @Override
094        public Identifier identifierFor(final Class<?> type, final Method method) {
095            return Identifier.classIdentifier(type);
096        }
097    };
098    
099    public final static List<FeatureType> COLLECTIONS_ONLY = ImmutableList.of(COLLECTION);
100    public final static List<FeatureType> ACTIONS_ONLY = ImmutableList.of(ACTION);
101    public final static List<FeatureType> PARAMETERS_ONLY = ImmutableList.of(ACTION_PARAMETER);
102    public final static List<FeatureType> PROPERTIES_ONLY = ImmutableList.of(PROPERTY);
103    public final static List<FeatureType> OBJECTS_ONLY = ImmutableList.of(OBJECT);
104    public final static List<FeatureType> MEMBERS = ImmutableList.of(PROPERTY, COLLECTION, ACTION);
105    public final static List<FeatureType> OBJECTS_AND_PROPERTIES = ImmutableList.of(OBJECT, PROPERTY);
106    public final static List<FeatureType> OBJECTS_AND_COLLECTIONS = ImmutableList.of(OBJECT, COLLECTION);
107    public final static List<FeatureType> OBJECTS_AND_ACTIONS = ImmutableList.of(OBJECT, ACTION);
108    public final static List<FeatureType> OBJECTS_PROPERTIES_AND_COLLECTIONS = ImmutableList.of(OBJECT, PROPERTY, COLLECTION);
109    public final static List<FeatureType> OBJECTS_POST_PROCESSING_ONLY = ImmutableList.of(OBJECT_POST_PROCESSING);
110
111    /**
112     * Use of this is discouraged; instead use multiple {@link FacetFactory}s
113     * for different features.
114     */
115    public final static List<FeatureType> EVERYTHING_BUT_PARAMETERS = ImmutableList.of(OBJECT, PROPERTY, COLLECTION, ACTION);
116    /**
117     * Use of this is discouraged; instead use multiple {@link FacetFactory}s
118     * for different features.
119     */
120    public final static List<FeatureType> EVERYTHING = ImmutableList.of(OBJECT, PROPERTY, COLLECTION, ACTION, ACTION_PARAMETER);
121
122    private final String name;
123
124    private FeatureType(final String name) {
125        this.name = name;
126    }
127
128    private static Identifier propertyOrCollectionIdentifierFor(final Class<?> type, final Method method) {
129        final String capitalizedName = StringExtensions.asJavaBaseName(method.getName());
130        final String beanName = Introspector.decapitalize(capitalizedName);
131        return Identifier.propertyOrCollectionIdentifier(type.getName(), beanName);
132    }
133
134    public boolean isProperty() {
135        return this == PROPERTY;
136    }
137
138    public boolean isCollection() {
139        return this == COLLECTION;
140    }
141
142    public boolean isAction() {
143        return this == ACTION;
144    }
145
146    public boolean isActionParameter() {
147        return this == ACTION_PARAMETER;
148    }
149
150    /**
151     * Convenience.
152     */
153    public boolean isPropertyOrCollection() {
154        return isProperty() || isCollection();
155    }
156
157    public abstract Identifier identifierFor(Class<?> type, Method method);
158
159    @Override
160    public String toString() {
161        return name;
162    }
163
164}