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 */
019package org.apache.isis.viewer.restfulobjects.rendering.domainobjects;
020
021import java.util.Map;
022
023import org.apache.isis.applib.util.Enums;
024import org.apache.isis.core.commons.internal.collections._Maps;
025import org.apache.isis.core.metamodel.facets.actions.action.invocation.ActionInvocationFacet;
026import org.apache.isis.core.metamodel.facets.actions.validate.ActionValidationFacet;
027import org.apache.isis.core.metamodel.facets.collections.modify.CollectionAddToFacet;
028import org.apache.isis.core.metamodel.facets.collections.modify.CollectionRemoveFromFacet;
029import org.apache.isis.core.metamodel.facets.collections.validate.CollectionValidateAddToFacet;
030import org.apache.isis.core.metamodel.facets.collections.validate.CollectionValidateRemoveFromFacet;
031import org.apache.isis.core.metamodel.facets.properties.update.clear.PropertyClearFacet;
032import org.apache.isis.core.metamodel.facets.properties.update.modify.PropertySetterFacet;
033import org.apache.isis.core.metamodel.facets.properties.validating.PropertyValidateFacet;
034import org.apache.isis.core.metamodel.spec.ObjectSpecification;
035import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
036import org.apache.isis.core.metamodel.spec.feature.ObjectFeature;
037import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
038import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
039import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
040import org.apache.isis.viewer.restfulobjects.applib.Rel;
041import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
042import org.apache.isis.viewer.restfulobjects.applib.RestfulHttpMethod;
043
044public enum MemberType {
045
046    PROPERTY("properties/", RepresentationType.OBJECT_PROPERTY,
047            _Maps.unmodifiable(
048                    "modify", MutatorSpec.of(Rel.MODIFY, PropertyValidateFacet.class, PropertySetterFacet.class, RestfulHttpMethod.PUT, BodyArgs.ONE),
049                    "clear", MutatorSpec.of(Rel.CLEAR, PropertyValidateFacet.class, PropertyClearFacet.class, RestfulHttpMethod.DELETE, BodyArgs.NONE))) {
050        @Override
051        public ObjectSpecification specFor(final ObjectMember objectMember) {
052            return objectMember.getSpecification();
053        }
054    },
055    /**
056     * {@link #getMutators()} are keyed by
057     * {@link CollectionSemantics#getAddToKey()}
058     */
059    COLLECTION("collections/", RepresentationType.OBJECT_COLLECTION,
060            _Maps.unmodifiable(
061                    "addToSet", MutatorSpec.of(Rel.ADD_TO, CollectionValidateAddToFacet.class, CollectionAddToFacet.class, RestfulHttpMethod.PUT, BodyArgs.ONE),
062                    "addToList", MutatorSpec.of(Rel.ADD_TO, CollectionValidateAddToFacet.class, CollectionAddToFacet.class, RestfulHttpMethod.POST, BodyArgs.ONE), "removeFrom", MutatorSpec.of(Rel.REMOVE_FROM, CollectionValidateRemoveFromFacet.class, CollectionRemoveFromFacet.class, RestfulHttpMethod.DELETE, BodyArgs.ONE))) {
063        @Override
064        public ObjectSpecification specFor(final ObjectMember objectMember) {
065            return objectMember.getSpecification();
066        }
067    },
068    /**
069     * {@link #getMutators()} are keyed by
070     * {@link ActionSemantics#getInvokeKey()}
071     */
072    ACTION("actions/", RepresentationType.OBJECT_ACTION,
073            _Maps.unmodifiable(
074                    "invokeQueryOnly", MutatorSpec.of(Rel.INVOKE, ActionValidationFacet.class, ActionInvocationFacet.class, RestfulHttpMethod.GET, BodyArgs.MANY, "invoke"),
075                    "invokeIdempotent", MutatorSpec.of(Rel.INVOKE, ActionValidationFacet.class, ActionInvocationFacet.class, RestfulHttpMethod.PUT, BodyArgs.MANY, "invoke"),
076                    "invoke", MutatorSpec.of(Rel.INVOKE, ActionValidationFacet.class, ActionInvocationFacet.class, RestfulHttpMethod.POST, BodyArgs.MANY, "invoke"))) {
077        @Override
078        public ObjectSpecification specFor(final ObjectMember objectMember) {
079            final ObjectAction objectAction = (ObjectAction) objectMember;
080            return objectAction.getReturnType();
081        }
082    };
083
084    private final String urlPart;
085    private final String name;
086    private final RepresentationType representationType;
087
088    private final Map<String, MutatorSpec> mutators;
089
090    private MemberType(final String urlPart, final RepresentationType representationType, final Map<String, MutatorSpec> mutators) {
091        this.urlPart = urlPart;
092        this.representationType = representationType;
093        this.mutators = mutators;
094        name = Enums.enumToCamelCase(this);
095    }
096
097    public String getUrlPart() {
098        return urlPart;
099    }
100
101    public Map<String, MutatorSpec> getMutators() {
102        return mutators;
103    }
104
105    public abstract ObjectSpecification specFor(ObjectMember objectMember);
106
107    public boolean isProperty() {
108        return this == MemberType.PROPERTY;
109    }
110
111    public boolean isCollection() {
112        return this == MemberType.COLLECTION;
113    }
114
115    public boolean isAction() {
116        return this == MemberType.ACTION;
117    }
118
119    public static MemberType lookup(final String memberTypeName) {
120        for (final MemberType memberType : values()) {
121            if (memberType.getName().equals(memberTypeName)) {
122                return memberType;
123            }
124        }
125        return null;
126    }
127
128    public static MemberType of(final ObjectMember objectMember) {
129        return objectMember.isAction() ? ACTION : objectMember.isOneToOneAssociation() ? PROPERTY : COLLECTION;
130    }
131
132    public RepresentationType getRepresentationType() {
133        return representationType;
134    }
135
136    public String getName() {
137        return name;
138    }
139
140    public static MemberType determineFrom(final ObjectFeature objectFeature) {
141        if (objectFeature instanceof ObjectAction) {
142            return MemberType.ACTION;
143        }
144        if (objectFeature instanceof OneToOneAssociation) {
145            return MemberType.PROPERTY;
146        }
147        if (objectFeature instanceof OneToManyAssociation) {
148            return MemberType.COLLECTION;
149        }
150        return null;
151    }
152
153}