You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2015/10/14 02:28:57 UTC
[12/12] isis git commit: ISIS-1213: mix-ins for associations.
ISIS-1213: mix-ins for associations.
Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/3a299c20
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/3a299c20
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/3a299c20
Branch: refs/heads/ISIS-1213
Commit: 3a299c2000812dc039709895d37bbe6b2e23028d
Parents: 6c88813
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Wed Oct 14 01:28:04 2015 +0100
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Wed Oct 14 01:28:04 2015 +0100
----------------------------------------------------------------------
.../layout/ActionLayoutFacetFactory.java | 17 +-
...otContributedFacetDerivedFromMixinFacet.java | 32 +++
...ibutedFacetDerivedFromMixinFacetFactory.java | 52 +++++
.../MixinFacetForDomainObjectAnnotation.java | 9 +
.../mixin/MixinFacetForMixinAnnotation.java | 5 +
.../specloader/ObjectReflectorDefault.java | 8 +
.../specloader/specimpl/ContributeeMember.java | 13 +-
.../specimpl/ObjectActionContributee.java | 3 -
.../specimpl/ObjectActionMixedIn.java | 115 +++--------
.../specimpl/ObjectMemberAbstract.java | 55 +++++-
.../specimpl/ObjectSpecificationAbstract.java | 152 +++++++++++++--
.../specimpl/OneToManyAssociationMixedIn.java | 193 +++++++++++++++++++
.../specimpl/OneToOneAssociationMixedIn.java | 174 +++++++++++++++++
.../dflt/ProgrammingModelFacetsJava5.java | 4 +
.../specimpl/ObjectActionMixedInTest.java | 12 +-
15 files changed, 711 insertions(+), 133 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/isis/blob/3a299c20/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetFactory.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetFactory.java
index 7e3becf..6219faa 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetFactory.java
@@ -18,9 +18,9 @@
*/
package org.apache.isis.core.metamodel.facets.actions.layout;
-
import java.lang.reflect.Method;
import java.util.Properties;
+
import org.apache.isis.applib.annotation.ActionLayout;
import org.apache.isis.applib.annotation.NatureOfService;
import org.apache.isis.core.metamodel.facetapi.FacetHolder;
@@ -39,6 +39,7 @@ import org.apache.isis.core.metamodel.facets.members.cssclass.CssClassFacet;
import org.apache.isis.core.metamodel.facets.members.cssclassfa.CssClassFaFacet;
import org.apache.isis.core.metamodel.facets.object.bookmarkpolicy.BookmarkPolicyFacet;
import org.apache.isis.core.metamodel.facets.object.domainservice.DomainServiceFacet;
+import org.apache.isis.core.metamodel.facets.object.mixin.MixinFacet;
import org.apache.isis.core.metamodel.spec.ObjectSpecification;
@@ -122,7 +123,7 @@ public class ActionLayoutFacetFactory extends FacetFactoryAbstract implements Co
// contributing
- if (isContributingService(processMethodContext)) {
+ if (isContributingServiceOrMixinObject(processMethodContext)) {
NotContributedFacet notContributedFacet = NotContributedFacetForLayoutProperties.create(properties, holder);
if(notContributedFacet == null) {
notContributedFacet = NotContributedFacetForActionLayoutAnnotation.create(actionLayout, holder);
@@ -131,18 +132,28 @@ public class ActionLayoutFacetFactory extends FacetFactoryAbstract implements Co
}
}
- protected boolean isContributingService(final ProcessMethodContext processMethodContext) {
+ protected boolean isContributingServiceOrMixinObject(final ProcessMethodContext processMethodContext) {
final Method method = processMethodContext.getMethod();
final Class<?> declaringClass = method.getDeclaringClass();
final ObjectSpecification spec = getSpecificationLoader().loadSpecification(declaringClass);
+ return isContributingService(spec) || isMixinObject(spec);
+ }
+
+ private static boolean isContributingService(final ObjectSpecification spec) {
final DomainServiceFacet domainServiceFacet = spec.getFacet(DomainServiceFacet.class);
return domainServiceFacet != null && !domainServiceFacet.isNoop() &&
domainServiceFacet.getNatureOfService() != NatureOfService.VIEW_MENU_ONLY &&
domainServiceFacet.getNatureOfService() != NatureOfService.DOMAIN;
}
+ private static boolean isMixinObject(final ObjectSpecification spec) {
+ final MixinFacet mixinFacet = spec.getFacet(MixinFacet.class);
+ final boolean b = mixinFacet != null && !mixinFacet.isNoop();
+ return b;
+ }
+ // UNUSED
protected boolean skipContributing(final DomainServiceFacet domainServiceFacet) {
return domainServiceFacet == null || domainServiceFacet.isNoop() || domainServiceFacet.getNatureOfService() == NatureOfService.VIEW_MENU_ONLY || domainServiceFacet.getNatureOfService() == NatureOfService.DOMAIN;
}
http://git-wip-us.apache.org/repos/asf/isis/blob/3a299c20/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/notcontributed/derived/NotContributedFacetDerivedFromMixinFacet.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/notcontributed/derived/NotContributedFacetDerivedFromMixinFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/notcontributed/derived/NotContributedFacetDerivedFromMixinFacet.java
new file mode 100644
index 0000000..ba6f38f
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/notcontributed/derived/NotContributedFacetDerivedFromMixinFacet.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.isis.core.metamodel.facets.actions.notcontributed.derived;
+
+import org.apache.isis.applib.annotation.NotContributed;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.actions.notcontributed.NotContributedFacetAbstract;
+
+public class NotContributedFacetDerivedFromMixinFacet extends NotContributedFacetAbstract {
+
+ public NotContributedFacetDerivedFromMixinFacet(
+ final FacetHolder holder) {
+ super(NotContributed.As.EITHER, holder, Derivation.DERIVED);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/3a299c20/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/notcontributed/derived/NotContributedFacetDerivedFromMixinFacetFactory.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/notcontributed/derived/NotContributedFacetDerivedFromMixinFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/notcontributed/derived/NotContributedFacetDerivedFromMixinFacetFactory.java
new file mode 100644
index 0000000..1e7a052
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/notcontributed/derived/NotContributedFacetDerivedFromMixinFacetFactory.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.core.metamodel.facets.actions.notcontributed.derived;
+
+import java.lang.reflect.Method;
+
+import org.apache.isis.core.metamodel.facetapi.FacetUtil;
+import org.apache.isis.core.metamodel.facetapi.FeatureType;
+import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
+import org.apache.isis.core.metamodel.facets.FacetedMethod;
+import org.apache.isis.core.metamodel.facets.object.mixin.MixinFacet;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+
+public class NotContributedFacetDerivedFromMixinFacetFactory extends FacetFactoryAbstract {
+
+ public NotContributedFacetDerivedFromMixinFacetFactory() {
+ super(FeatureType.ACTIONS_ONLY);
+ }
+
+ @Override
+ public void process(final ProcessMethodContext processMethodContext) {
+ final Method method = processMethodContext.getMethod();
+ final Class<?> declaringClass = method.getDeclaringClass();
+ final ObjectSpecification spec = getSpecificationLoader().loadSpecification(declaringClass);
+
+ final MixinFacet mixinFacet = spec.getFacet(MixinFacet.class);
+ if(mixinFacet == null || mixinFacet.isNoop()) {
+ return;
+ }
+
+ final FacetedMethod facetHolder = processMethodContext.getFacetHolder();
+ FacetUtil.addFacet(new NotContributedFacetDerivedFromMixinFacet(facetHolder));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/3a299c20/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForDomainObjectAnnotation.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForDomainObjectAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForDomainObjectAnnotation.java
index 3493fcc..cdd0c2a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForDomainObjectAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForDomainObjectAnnotation.java
@@ -21,6 +21,8 @@ package org.apache.isis.core.metamodel.facets.object.mixin;
import java.lang.reflect.Constructor;
+import org.apache.isis.applib.annotation.DomainObject;
+import org.apache.isis.applib.annotation.Nature;
import org.apache.isis.core.metamodel.facetapi.Facet;
import org.apache.isis.core.metamodel.facetapi.FacetHolder;
import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
@@ -42,6 +44,13 @@ public class MixinFacetForDomainObjectAnnotation extends MixinFacetAbstract {
public static MixinFacet create(
final Class<?> candidateMixinType, final FacetHolder facetHolder,
final ServicesInjector servicesInjector) {
+ final DomainObject domainObject = candidateMixinType.getAnnotation(DomainObject.class);
+ if(domainObject == null) {
+ return null;
+ }
+ if(domainObject.nature() != Nature.MIXIN) {
+ return null;
+ }
final Constructor<?>[] constructors = candidateMixinType.getConstructors();
for (Constructor<?> constructor : constructors) {
final Class<?>[] constructorTypes = constructor.getParameterTypes();
http://git-wip-us.apache.org/repos/asf/isis/blob/3a299c20/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForMixinAnnotation.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForMixinAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForMixinAnnotation.java
index ed369c5..7aedf55 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForMixinAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForMixinAnnotation.java
@@ -21,6 +21,7 @@ package org.apache.isis.core.metamodel.facets.object.mixin;
import java.lang.reflect.Constructor;
+import org.apache.isis.applib.annotation.Mixin;
import org.apache.isis.core.metamodel.facetapi.Facet;
import org.apache.isis.core.metamodel.facetapi.FacetHolder;
import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
@@ -42,6 +43,10 @@ public class MixinFacetForMixinAnnotation extends MixinFacetAbstract {
public static MixinFacet create(
final Class<?> candidateMixinType, final FacetHolder facetHolder,
final ServicesInjector servicesInjector) {
+ final Mixin mixin = candidateMixinType.getAnnotation(Mixin.class);
+ if(mixin == null) {
+ return null;
+ }
final Constructor<?>[] constructors = candidateMixinType.getConstructors();
for (Constructor<?> constructor : constructors) {
final Class<?>[] constructorTypes = constructor.getParameterTypes();
http://git-wip-us.apache.org/repos/asf/isis/blob/3a299c20/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/ObjectReflectorDefault.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/ObjectReflectorDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/ObjectReflectorDefault.java
index cdea01b..4bb6a47 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/ObjectReflectorDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/ObjectReflectorDefault.java
@@ -32,6 +32,7 @@ import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.apache.isis.applib.AppManifest;
import org.apache.isis.core.commons.components.ApplicationScopedComponent;
import org.apache.isis.core.commons.config.IsisConfiguration;
import org.apache.isis.core.commons.debug.DebugBuilder;
@@ -250,6 +251,7 @@ public final class ObjectReflectorDefault
metaModelValidator.init();
loadSpecificationsForServices();
+ loadSpecificationsForMixins();
}
private void loadSpecificationsForServices() {
@@ -258,6 +260,12 @@ public final class ObjectReflectorDefault
}
}
+ private void loadSpecificationsForMixins() {
+ for (final Class<?> mixinType : AppManifest.Registry.instance().getMixinTypes()) {
+ internalLoadSpecification(mixinType);
+ }
+ }
+
private void cacheBySpecId() {
final Map<ObjectSpecId, ObjectSpecification> specById = Maps.newHashMap();
for (final ObjectSpecification objSpec : allSpecifications()) {
http://git-wip-us.apache.org/repos/asf/isis/blob/3a299c20/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ContributeeMember.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ContributeeMember.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ContributeeMember.java
index 97dd48d..9aca015 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ContributeeMember.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ContributeeMember.java
@@ -26,15 +26,14 @@ import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
* Interface indicating an a contributed association or action.
*/
public interface ContributeeMember extends ObjectMember {
-
+
+
public static class Predicates {
private Predicates(){}
-
+
/**
- * Evaluates the supplied {@link ObjectMember} and includes either if it is not a {@link ContributeeMember}
- * (ie is a regular member) or is a {@link ContributeeMember} and contributed are to be
- * {@link Contributed#isIncluded() included}.
+ * Now generalized to handle {@link MixedInMember}s as well as {@link ContributeeMember}s.
*/
public static <T extends ObjectMember> Predicate<T> regularElse(final Contributed contributed) {
return com.google.common.base.Predicates.or(regular(), is(contributed));
@@ -44,7 +43,7 @@ public interface ContributeeMember extends ObjectMember {
return new Predicate<T>() {
@Override
public boolean apply(ObjectMember input) {
- return !(input instanceof ContributeeMember);
+ return !(input instanceof ContributeeMember) && !(input instanceof MixedInMember);
}
};
}
@@ -53,7 +52,7 @@ public interface ContributeeMember extends ObjectMember {
return new Predicate<T>() {
@Override
public boolean apply(ObjectMember input) {
- return input instanceof ContributeeMember && contributed.isIncluded();
+ return contributed.isIncluded();
}
};
}
http://git-wip-us.apache.org/repos/asf/isis/blob/3a299c20/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionContributee.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionContributee.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionContributee.java
index 117d2e4..5aa6444 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionContributee.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionContributee.java
@@ -72,9 +72,6 @@ public class ObjectActionContributee extends ObjectActionDefault implements Cont
private final Identifier identifier;
- /**
- * @param contributeeParam - the parameter number which corresponds to the contributee, and so should be suppressed.
- */
public ObjectActionContributee(
final Object servicePojo,
final ObjectActionDefault serviceAction,
http://git-wip-us.apache.org/repos/asf/isis/blob/3a299c20/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
index 3f68d8e..067be24 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
@@ -25,27 +25,25 @@ import com.google.common.collect.Lists;
import org.apache.isis.applib.Identifier;
import org.apache.isis.applib.annotation.Bulk;
import org.apache.isis.applib.annotation.InvokedOn;
+import org.apache.isis.applib.annotation.NotContributed;
import org.apache.isis.applib.annotation.Where;
-import org.apache.isis.applib.filter.Filter;
import org.apache.isis.applib.services.actinvoc.ActionInvocationContext;
import org.apache.isis.applib.services.bookmark.Bookmark;
import org.apache.isis.applib.services.command.Command;
import org.apache.isis.applib.services.command.Command.Executor;
import org.apache.isis.applib.services.command.CommandContext;
import org.apache.isis.core.commons.lang.ObjectExtensions;
-import org.apache.isis.core.commons.lang.StringExtensions;
import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
import org.apache.isis.core.metamodel.consent.Consent;
import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
-import org.apache.isis.core.metamodel.facetapi.Facet;
import org.apache.isis.core.metamodel.facetapi.FacetHolder;
import org.apache.isis.core.metamodel.facetapi.FacetHolderImpl;
import org.apache.isis.core.metamodel.facetapi.FacetUtil;
-import org.apache.isis.core.metamodel.facetapi.MultiTypedFacet;
import org.apache.isis.core.metamodel.facets.actions.action.invocation.CommandUtil;
import org.apache.isis.core.metamodel.facets.actions.bulk.BulkFacet;
+import org.apache.isis.core.metamodel.facets.actions.notcontributed.NotContributedFacet;
+import org.apache.isis.core.metamodel.facets.actions.notcontributed.NotContributedFacetAbstract;
import org.apache.isis.core.metamodel.facets.all.named.NamedFacetInferred;
-import org.apache.isis.core.metamodel.facets.object.mixin.MixinFacet;
import org.apache.isis.core.metamodel.interactions.InteractionUtils;
import org.apache.isis.core.metamodel.interactions.UsabilityContext;
import org.apache.isis.core.metamodel.interactions.VisibilityContext;
@@ -99,39 +97,20 @@ public class ObjectActionMixedIn extends ObjectActionDefault implements MixedInM
// adjust name if necessary
final String name = getName();
- String memberName = null;
if(Objects.equal(name, "_")) {
- memberName = determineNameFrom(mixinAction);
+ String memberName = determineNameFrom(mixinAction);
FacetUtil.addFacet(new NamedFacetInferred(memberName, facetHolder));
}
// calculate the identifier
final Identifier mixinIdentifier = mixinAction.getFacetedMethod().getIdentifier();
- memberName = memberName != null? memberName : mixinIdentifier.getMemberName();
List<String> memberParameterNames = mixinIdentifier.getMemberParameterNames();
- identifier = Identifier.actionIdentifier(getOnType().getCorrespondingClass().getName(), memberName, memberParameterNames);
+ identifier = Identifier.actionIdentifier(getOnType().getCorrespondingClass().getName(), getId(), memberParameterNames);
}
- private static String determineNameFrom(final ObjectActionDefault mixinAction) {
- return suffixAfterUnderscore(mixinAction.getOnType().getSingularName());
- }
-
- static String suffixAfterUnderscore(final String singularName) {
- return StringExtensions.asCapitalizedName(suffix(singularName));
- }
-
- private static String suffix(final String singularName) {
- if (singularName.endsWith("_")) {
- if (Objects.equal(singularName, "_")) {
- return singularName;
- }
- return singularName;
- }
- final int indexOfUnderscore = singularName.lastIndexOf('_');
- if (indexOfUnderscore == -1) {
- return singularName;
- }
- return singularName.substring(indexOfUnderscore + 1);
+ @Override
+ public String getId() {
+ return determineIdFrom(this.mixinAction);
}
@Override
@@ -166,9 +145,10 @@ public class ObjectActionMixedIn extends ObjectActionDefault implements MixedInM
public Consent isVisible(
final ObjectAdapter mixedInAdapter,
final InteractionInitiatedBy interactionInitiatedBy,
- Where where) {
- final VisibilityContext<?> ic = mixinAction.createVisibleInteractionContext(mixinAdapterFor(mixedInAdapter),
- interactionInitiatedBy, where);
+ final Where where) {
+ final VisibilityContext<?> ic =
+ mixinAction.createVisibleInteractionContext(
+ mixinAdapterFor(mixinType, mixedInAdapter), interactionInitiatedBy, where);
return InteractionUtils.isVisibleResult(this, ic).createConsent();
}
@@ -176,28 +156,29 @@ public class ObjectActionMixedIn extends ObjectActionDefault implements MixedInM
public Consent isUsable(
final ObjectAdapter mixedInAdapter,
final InteractionInitiatedBy interactionInitiatedBy, final Where where) {
- final UsabilityContext<?> ic = mixinAction.createUsableInteractionContext(mixinAdapterFor(mixedInAdapter),
- interactionInitiatedBy, where);
+ final UsabilityContext<?> ic =
+ mixinAction.createUsableInteractionContext(
+ mixinAdapterFor(mixinType, mixedInAdapter), interactionInitiatedBy, where);
return InteractionUtils.isUsableResult(this, ic).createConsent();
}
@Override
public ObjectAdapter[] getDefaults(final ObjectAdapter mixedInAdapter) {
- return mixinAction.getDefaults(mixinAdapterFor(mixedInAdapter));
+ return mixinAction.getDefaults(mixinAdapterFor(mixinType, mixedInAdapter));
}
@Override
public ObjectAdapter[][] getChoices(
final ObjectAdapter mixedInAdapter,
final InteractionInitiatedBy interactionInitiatedBy) {
- return mixinAction.getChoices(mixinAdapterFor(mixedInAdapter), interactionInitiatedBy);
+ return mixinAction.getChoices(mixinAdapterFor(mixinType, mixedInAdapter), interactionInitiatedBy);
}
public Consent isProposedArgumentSetValid(
final ObjectAdapter mixedInAdapter,
final ObjectAdapter[] proposedArguments,
final InteractionInitiatedBy interactionInitiatedBy) {
- return mixinAction.isProposedArgumentSetValid(mixinAdapterFor(mixedInAdapter), proposedArguments, interactionInitiatedBy);
+ return mixinAction.isProposedArgumentSetValid(mixinAdapterFor(mixinType, mixedInAdapter), proposedArguments, interactionInitiatedBy);
}
@Override
@@ -248,61 +229,22 @@ public class ObjectActionMixedIn extends ObjectActionDefault implements MixedInM
}
}
- return mixinAction.execute(mixinAdapterFor(mixedInAdapter), arguments, interactionInitiatedBy);
- }
-
- // //////////////////////////////////////
- // FacetHolder
- // //////////////////////////////////////
-
- @Override
- public Class<? extends Facet>[] getFacetTypes() {
- return facetHolder.getFacetTypes();
- }
-
- @Override
- public <T extends Facet> T getFacet(Class<T> cls) {
- return facetHolder.getFacet(cls);
- }
-
- @Override
- public boolean containsFacet(Class<? extends Facet> facetType) {
- return facetHolder.containsFacet(facetType);
+ return mixinAction.execute(mixinAdapterFor(mixinType, mixedInAdapter), arguments, interactionInitiatedBy);
}
- @Override
- public boolean containsDoOpFacet(Class<? extends Facet> facetType) {
- return facetHolder.containsDoOpFacet(facetType);
- }
+ //region > facetHolder
@Override
- public List<Facet> getFacets(Filter<Facet> filter) {
- return facetHolder.getFacets(filter);
+ protected FacetHolder getFacetHolder() {
+ return facetHolder;
}
+ //endregion
- @Override
- public void addFacet(Facet facet) {
- facetHolder.addFacet(facet);
- }
- @Override
- public void addFacet(MultiTypedFacet facet) {
- facetHolder.addFacet(facet);
- }
-
- @Override
- public void removeFacet(Facet facet) {
- facetHolder.removeFacet(facet);
- }
-
- @Override
- public void removeFacet(Class<? extends Facet> facetType) {
- facetHolder.removeFacet(facetType);
+ ObjectAdapter mixinAdapterFor(final ObjectAdapter mixedInAdapter) {
+ return mixinAdapterFor(mixinType, mixedInAdapter);
}
-
- // //////////////////////////////////////
-
/* (non-Javadoc)
* @see org.apache.isis.core.metamodel.specloader.specimpl.ObjectMemberAbstract#getIdentifier()
*/
@@ -311,12 +253,5 @@ public class ObjectActionMixedIn extends ObjectActionDefault implements MixedInM
return identifier;
}
- // //////////////////////////////////////
- ObjectAdapter mixinAdapterFor(final ObjectAdapter mixedInAdapter) {
- final ObjectSpecification objectSpecification = getSpecificationLoader().loadSpecification(mixinType);
- final MixinFacet mixinFacet = objectSpecification.getFacet(MixinFacet.class);
- final Object mixinPojo = mixinFacet.instantiate(mixedInAdapter.getObject());
- return getPersistenceSessionService().adapterFor(mixinPojo);
- }
}
http://git-wip-us.apache.org/repos/asf/isis/blob/3a299c20/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java
index 85ba2f3..2fc4fc3 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java
@@ -21,6 +21,8 @@ package org.apache.isis.core.metamodel.specloader.specimpl;
import java.util.List;
+import com.google.common.base.Objects;
+
import org.apache.isis.applib.Identifier;
import org.apache.isis.applib.annotation.When;
import org.apache.isis.applib.annotation.Where;
@@ -39,6 +41,7 @@ import org.apache.isis.core.metamodel.facets.all.describedas.DescribedAsFacet;
import org.apache.isis.core.metamodel.facets.all.help.HelpFacet;
import org.apache.isis.core.metamodel.facets.all.hide.HiddenFacet;
import org.apache.isis.core.metamodel.facets.all.named.NamedFacet;
+import org.apache.isis.core.metamodel.facets.object.mixin.MixinFacet;
import org.apache.isis.core.metamodel.interactions.AccessContext;
import org.apache.isis.core.metamodel.interactions.DisablingInteractionAdvisor;
import org.apache.isis.core.metamodel.interactions.HidingInteractionAdvisor;
@@ -63,7 +66,6 @@ public abstract class ObjectMemberAbstract implements ObjectMember {
//region > fields
private final CollectionTypeRegistry collectionTypeRegistry = new CollectionTypeRegistry();
- protected final String defaultName;
private final String id;
private final FacetedMethod facetedMethod;
private final FeatureType featureType;
@@ -78,12 +80,11 @@ public abstract class ObjectMemberAbstract implements ObjectMember {
final ObjectMemberDependencies objectMemberDependencies) {
final String id = facetedMethod.getIdentifier().getMemberName();
if (id == null) {
- throw new IllegalArgumentException("Name must always be set");
+ throw new IllegalArgumentException("Id must always be set");
}
this.facetedMethod = facetedMethod;
this.featureType = featureType;
this.id = id;
- this.defaultName = StringExtensions.asNaturalName2(this.id);
this.specificationLookup = objectMemberDependencies.getSpecificationLoader();
this.servicesInjector = objectMemberDependencies.getServicesInjector();
@@ -182,7 +183,7 @@ public abstract class ObjectMemberAbstract implements ObjectMember {
}
else {
// this should now be redundant, see NamedFacetDefault
- return defaultName;
+ return StringExtensions.asNaturalName2(getId());
}
}
@@ -310,6 +311,52 @@ public abstract class ObjectMemberAbstract implements ObjectMember {
}
//endregion
+ //region > mixinAdapterFor
+ /**
+ * For mixins
+ */
+ protected ObjectAdapter mixinAdapterFor(
+ final Class<?> mixinType,
+ final ObjectAdapter mixedInAdapter) {
+ final ObjectSpecification objectSpecification = getSpecificationLoader().loadSpecification(mixinType);
+ final MixinFacet mixinFacet = objectSpecification.getFacet(MixinFacet.class);
+ final Object mixinPojo = mixinFacet.instantiate(mixedInAdapter.getObject());
+ return getPersistenceSessionService().adapterFor(mixinPojo);
+ }
+
+ static String determineNameFrom(final ObjectActionDefault mixinAction) {
+ return StringExtensions.asCapitalizedName(suffix(mixinAction));
+ }
+
+ static String determineIdFrom(final ObjectActionDefault mixinAction) {
+ final String id = compress(suffix(mixinAction));
+ return id;
+ }
+
+ private static String compress(final String suffix) {
+ return suffix.replaceAll(" ","");
+ }
+
+ static String suffix(final ObjectActionDefault mixinAction) {
+ return suffix(mixinAction.getOnType().getSingularName());
+ }
+
+ static String suffix(final String singularName) {
+ if (singularName.endsWith("_")) {
+ if (Objects.equal(singularName, "_")) {
+ return singularName;
+ }
+ return singularName;
+ }
+ final int indexOfUnderscore = singularName.lastIndexOf('_');
+ if (indexOfUnderscore == -1) {
+ return singularName;
+ }
+ return singularName.substring(indexOfUnderscore + 1);
+ }
+
+ //endregion
+
//region > toString
@Override
http://git-wip-us.apache.org/repos/asf/isis/blob/3a299c20/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java
index f7968a3..fd6bf5c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java
@@ -27,6 +27,7 @@ import java.util.Properties;
import java.util.Set;
import com.google.common.base.Function;
+import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
@@ -148,8 +149,8 @@ public abstract class ObjectSpecificationAbstract extends FacetHolderImpl implem
return map;
}
- private boolean contributeeAssociationsAdded;
- private boolean contributeeActionsAdded;
+ private boolean contributeeAndMixedInAssociationsAdded;
+ private boolean contributeeAndMixedInActionsAdded;
private final List<ObjectSpecification> interfaces = Lists.newArrayList();
@@ -623,12 +624,13 @@ public abstract class ObjectSpecificationAbstract extends FacetHolderImpl implem
public List<ObjectAssociation> getAssociations(final Contributed contributed) {
// the "contributed.isIncluded()" guard is required because we cannot do this too early;
// there must be a session available
- if(contributed.isIncluded() && !contributeeAssociationsAdded) {
+ if(contributed.isIncluded() && !contributeeAndMixedInAssociationsAdded) {
synchronized (this.associations) {
List<ObjectAssociation> associations = Lists.newArrayList(this.associations);
associations.addAll(createContributeeAssociations());
+ associations.addAll(createMixedInAssociations());
sortAndUpdateAssociations(associations);
- contributeeAssociationsAdded = true;
+ contributeeAndMixedInAssociationsAdded = true;
}
}
final List<ObjectAssociation> associations = Lists.newArrayList(this.associations);
@@ -736,13 +738,13 @@ public abstract class ObjectSpecificationAbstract extends FacetHolderImpl implem
// and they have not yet been added
// the "contributed.isIncluded()" guard is required because we cannot do this too early;
// there must be a session available
- if(contributed.isIncluded() && !contributeeActionsAdded) {
+ if(contributed.isIncluded() && !contributeeAndMixedInActionsAdded) {
synchronized (this.objectActions) {
final List<ObjectAction> actions = Lists.newArrayList(this.objectActions);
actions.addAll(createContributeeActions());
- actions.addAll(createMixinActions());
+ actions.addAll(createMixedInActions());
sortCacheAndUpdateActions(actions);
- contributeeActionsAdded = true;
+ contributeeAndMixedInActionsAdded = true;
}
}
@@ -894,8 +896,11 @@ public abstract class ObjectSpecificationAbstract extends FacetHolderImpl implem
contributedActions.add((ObjectActionDefault) serviceAction);
}
- return Lists.newArrayList(Iterables.transform(contributedActions, createContributeeAssociationFunctor(
- servicePojo, this)));
+ return Lists.newArrayList(
+ Iterables.transform(
+ contributedActions,
+ createContributeeAssociationFunctor(servicePojo, this)
+ ));
}
private Function<ObjectActionDefault, ObjectAssociation> createContributeeAssociationFunctor(
@@ -905,14 +910,114 @@ public abstract class ObjectSpecificationAbstract extends FacetHolderImpl implem
@Override
public ObjectAssociation apply(ObjectActionDefault input) {
final ObjectSpecification returnType = input.getReturnType();
- final ObjectAssociationAbstract association = returnType.isNotCollection()
- ? new OneToOneAssociationContributee(servicePojo, input, contributeeType,
- objectMemberDependencies)
- : new OneToManyAssociationContributee(servicePojo, input, contributeeType,
- objectMemberDependencies);
+ final ObjectAssociationAbstract association = createObjectAssociation(input, returnType);
facetProcessor.processMemberOrder(metadataProperties, association);
return association;
}
+
+ ObjectAssociationAbstract createObjectAssociation(
+ final ObjectActionDefault input,
+ final ObjectSpecification returnType) {
+ if (returnType.isNotCollection()) {
+ return new OneToOneAssociationContributee(servicePojo, input, contributeeType,
+ objectMemberDependencies);
+ } else {
+ return new OneToManyAssociationContributee(servicePojo, input, contributeeType,
+ objectMemberDependencies);
+ }
+ }
+ };
+ }
+
+ //endregion
+
+ //region > mixin associations (properties and collections)
+
+ private List<ObjectAssociation> createMixedInAssociations() {
+ if (isService() || isValue()) {
+ return Collections.emptyList();
+ }
+
+ final Set<Class<?>> mixinTypes = AppManifest.Registry.instance().getMixinTypes();
+ if(mixinTypes == null) {
+ return Collections.emptyList();
+ }
+
+ final List<ObjectAssociation> mixedInAssociations = Lists.newArrayList();
+
+ for (final Class<?> mixinType : mixinTypes) {
+ addMixedInAssociationsIfAny(mixinType, mixedInAssociations);
+ }
+ return mixedInAssociations;
+ }
+
+ private void addMixedInAssociationsIfAny(
+ final Class<?> mixinType, final List<ObjectAssociation> toAppendTo) {
+
+ final ObjectSpecification specification = getSpecificationLoader().loadSpecification(mixinType);
+ if (specification == this) {
+ return;
+ }
+ final MixinFacet mixinFacet = specification.getFacet(MixinFacet.class);
+ if(mixinFacet == null) {
+ // this shouldn't happen; perhaps it would be more correct to throw an exception?
+ return;
+ }
+ if(!mixinFacet.isMixinFor(getCorrespondingClass())) {
+ return;
+ }
+
+ final List<ObjectActionDefault> mixinActions = getObjectActions(specification);
+
+ final List<ObjectAssociation> mixedInAssociations = Lists.newArrayList(
+ Iterables.transform(
+ Iterables.filter(mixinActions, new Predicate<ObjectActionDefault>() {
+ @Override public boolean apply(final ObjectActionDefault input) {
+ final NotContributedFacet notContributedFacet = input.getFacet(NotContributedFacet.class);
+ if (notContributedFacet == null || !notContributedFacet.toActions()) {
+ return false;
+ }
+ if(input.getParameterCount() != 0) {
+ return false;
+ }
+ if(!input.getSemantics().isSafeInNature()) {
+ return false;
+ }
+ return true;
+ }
+ }),
+ createMixedInAssociationFunctor(this, mixinType)
+ ));
+
+ toAppendTo.addAll(mixedInAssociations);
+ }
+
+ private List getObjectActions(final ObjectSpecification specification) {
+ return specification.getObjectActions(ActionType.ALL, Contributed.INCLUDED, Filters.<ObjectAction>any());
+ }
+
+ private Function<ObjectActionDefault, ObjectAssociation> createMixedInAssociationFunctor(
+ final ObjectSpecification mixedInType,
+ final Class<?> mixinType) {
+ return new Function<ObjectActionDefault, ObjectAssociation>(){
+ @Override
+ public ObjectAssociation apply(final ObjectActionDefault mixinAction) {
+ final ObjectAssociationAbstract association = createObjectAssociation(mixinAction);
+ facetProcessor.processMemberOrder(metadataProperties, association);
+ return association;
+ }
+
+ ObjectAssociationAbstract createObjectAssociation(
+ final ObjectActionDefault mixinAction) {
+ final ObjectSpecification returnType = mixinAction.getReturnType();
+ if (returnType.isNotCollection()) {
+ return new OneToOneAssociationMixedIn(
+ mixinAction, mixedInType, mixinType, objectMemberDependencies);
+ } else {
+ return new OneToManyAssociationMixedIn(
+ mixinAction, mixedInType, mixinType, objectMemberDependencies);
+ }
+ }
};
}
@@ -1004,7 +1109,7 @@ public abstract class ObjectSpecificationAbstract extends FacetHolderImpl implem
* If this specification {@link #isService() is actually for} a service,
* then returns an empty list.
*/
- protected List<ObjectAction> createMixinActions() {
+ protected List<ObjectAction> createMixedInActions() {
if (isService() || isValue()) {
return Collections.emptyList();
}
@@ -1013,17 +1118,17 @@ public abstract class ObjectSpecificationAbstract extends FacetHolderImpl implem
return Collections.emptyList();
}
- final List<ObjectAction> mixinActions = Lists.newArrayList();
+ final List<ObjectAction> mixedInActions = Lists.newArrayList();
for (final Class<?> mixinType : mixinTypes) {
- addMixinActionsIfAny(mixinType, mixinActions);
+ addMixedInActionsIfAny(mixinType, mixedInActions);
}
- return mixinActions;
+ return mixedInActions;
}
- private void addMixinActionsIfAny(
+ private void addMixedInActionsIfAny(
final Class<?> mixinType,
- final List<ObjectAction> mixinActionsToAppendTo) {
+ final List<ObjectAction> mixedInActionsToAppendTo) {
final ObjectSpecification specification = getSpecificationLoader().loadSpecification(mixinType);
if (specification == this) {
return;
@@ -1048,16 +1153,21 @@ public abstract class ObjectSpecificationAbstract extends FacetHolderImpl implem
continue;
}
final ObjectActionDefault mixinAction = (ObjectActionDefault) mixinTypeAction;
+ final NotContributedFacet notContributedFacet = mixinAction.getFacet(NotContributedFacet.class);
+ if(notContributedFacet.toActions()) {
+ continue;
+ }
ObjectActionMixedIn mixedInAction =
new ObjectActionMixedIn(mixinType, mixinAction, this, objectMemberDependencies);
facetProcessor.processMemberOrder(metadataProperties, mixedInAction);
actions.add(mixedInAction);
}
- mixinActionsToAppendTo.addAll(actions);
+ mixedInActionsToAppendTo.addAll(actions);
}
//endregion
+
//region > validity
@Override
public Consent isValid(final ObjectAdapter targetAdapter, final InteractionInitiatedBy interactionInitiatedBy) {
http://git-wip-us.apache.org/repos/asf/isis/blob/3a299c20/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java
new file mode 100644
index 0000000..1890b3d
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java
@@ -0,0 +1,193 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.isis.core.metamodel.specloader.specimpl;
+
+import java.util.List;
+
+import com.google.common.base.Objects;
+
+import org.apache.isis.applib.Identifier;
+import org.apache.isis.applib.annotation.When;
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facetapi.FacetHolderImpl;
+import org.apache.isis.core.metamodel.facetapi.FacetUtil;
+import org.apache.isis.core.metamodel.facets.actcoll.typeof.TypeOfFacet;
+import org.apache.isis.core.metamodel.facets.actcoll.typeof.TypeOfFacetAbstract;
+import org.apache.isis.core.metamodel.facets.all.named.NamedFacetInferred;
+import org.apache.isis.core.metamodel.facets.members.disabled.DisabledFacet;
+import org.apache.isis.core.metamodel.facets.members.disabled.DisabledFacetForContributee;
+import org.apache.isis.core.metamodel.facets.propcoll.notpersisted.NotPersistedFacet;
+import org.apache.isis.core.metamodel.facets.propcoll.notpersisted.NotPersistedFacetAbstract;
+import org.apache.isis.core.metamodel.interactions.InteractionUtils;
+import org.apache.isis.core.metamodel.interactions.UsabilityContext;
+import org.apache.isis.core.metamodel.interactions.VisibilityContext;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.SpecificationLoader;
+import org.apache.isis.core.metamodel.spec.feature.ObjectMemberDependencies;
+
+public class OneToManyAssociationMixedIn extends OneToManyAssociationDefault implements MixedInMember {
+
+ /**
+ * The type of the mixin (providing the action), eg annotated with {@link org.apache.isis.applib.annotation.Mixin}.
+ */
+ private final Class<?> mixinType;
+
+ /**
+ * The {@link ObjectActionDefault} for the action being mixed in (ie on the {@link #mixinType}.
+ */
+ private final ObjectActionDefault mixinAction;
+
+ /**
+ * The domain object type being mixed in to (being supplemented).
+ */
+ private final ObjectSpecification mixedInType;
+
+
+ /**
+ * Hold facets rather than delegate to the mixin action (different types might use layout metadata to position
+ * the mixin in different ways)
+ */
+ private final FacetHolder facetHolder = new FacetHolderImpl();
+
+ private final Identifier identifier;
+
+ private static ObjectSpecification typeOfSpec(
+ final ObjectActionDefault objectAction,
+ final ObjectMemberDependencies objectMemberDependencies) {
+
+ final TypeOfFacet actionTypeOfFacet = objectAction.getFacet(TypeOfFacet.class);
+ final SpecificationLoader specificationLookup = objectMemberDependencies.getSpecificationLoader();
+ // TODO: a bit of a hack; ought really to set up a fallback TypeOfFacetDefault which ensures that there is always
+ // a TypeOfFacet for any mixedIn associations created from mixin actions.
+ Class<? extends Object> cls = actionTypeOfFacet != null? actionTypeOfFacet.value(): Object.class;
+ return specificationLookup.loadSpecification(cls);
+ }
+
+ public OneToManyAssociationMixedIn(
+ final ObjectActionDefault mixinAction,
+ final ObjectSpecification mixedInType,
+ final Class<?> mixinType,
+ final ObjectMemberDependencies objectMemberDependencies) {
+ super(mixinAction.getFacetedMethod(),
+ typeOfSpec(mixinAction, objectMemberDependencies),
+ objectMemberDependencies);
+
+ this.mixinType = mixinType;
+ this.mixinAction = mixinAction;
+ this.mixedInType = mixedInType;
+
+ //
+ // ensure the mixedIn collection cannot be modified, and derive its TypeOfFaccet
+ //
+ final NotPersistedFacet notPersistedFacet = new NotPersistedFacetAbstract(this) {};
+ final DisabledFacet disabledFacet = disabledFacet();
+ final TypeOfFacet typeOfFacet = new TypeOfFacetAbstract(getSpecification().getCorrespondingClass(), this, objectMemberDependencies
+ .getSpecificationLoader()) {};
+
+ FacetUtil.addFacet(notPersistedFacet);
+ FacetUtil.addFacet(disabledFacet);
+ FacetUtil.addFacet(typeOfFacet);
+
+
+ //
+ // in addition, copy over facets from contributed to own.
+ //
+ // These could include everything under @Collection(...) because the
+ // CollectionAnnotationFacetFactory is also run against actions.
+ //
+ FacetUtil.copyFacets(mixinAction.getFacetedMethod(), facetHolder);
+
+ // adjust name if necessary
+ final String name = getName();
+
+ if(Objects.equal(name, "_")) {
+ String memberName = ObjectActionMixedIn.determineNameFrom(mixinAction);
+ FacetUtil.addFacet(new NamedFacetInferred(memberName, facetHolder));
+ }
+
+ // calculate the identifier
+ final Identifier mixinIdentifier = mixinAction.getFacetedMethod().getIdentifier();
+ List<String> memberParameterNames = mixinIdentifier.getMemberParameterNames();
+
+ identifier = Identifier.actionIdentifier(mixedInType.getCorrespondingClass().getName(), getId(), memberParameterNames);
+ }
+
+ private DisabledFacet disabledFacet() {
+ final DisabledFacet originalFacet = facetHolder.getFacet(DisabledFacet.class);
+ if( originalFacet != null &&
+ originalFacet.when() == When.ALWAYS &&
+ originalFacet.where() == Where.ANYWHERE) {
+ return originalFacet;
+ }
+ // ensure that the contributed association is always disabled
+ return new DisabledFacetForContributee("Contributed collection", this);
+ }
+
+ @Override
+ public ObjectAdapter get(final ObjectAdapter mixedInAdapter, final InteractionInitiatedBy interactionInitiatedBy) {
+ final ObjectAdapter mixinAdapter = mixinAdapterFor(mixinType, mixedInAdapter);
+ return mixinAction.execute(mixinAdapter, new ObjectAdapter[0], interactionInitiatedBy);
+ }
+
+ @Override
+ public Identifier getIdentifier() {
+ return identifier;
+ }
+
+ @Override
+ public String getId() {
+ return determineIdFrom(this.mixinAction);
+ }
+
+ @Override
+ public Consent isVisible(
+ final ObjectAdapter mixedInAdapter,
+ final InteractionInitiatedBy interactionInitiatedBy,
+ final Where where) {
+ final VisibilityContext<?> ic =
+ mixinAction.createVisibleInteractionContext(
+ mixinAdapterFor(mixinType, mixedInAdapter), interactionInitiatedBy, where);
+ return InteractionUtils.isVisibleResult(this, ic).createConsent();
+ }
+
+ @Override
+ public Consent isUsable(
+ final ObjectAdapter mixedInAdapter,
+ final InteractionInitiatedBy interactionInitiatedBy,
+ final Where where) {
+ final UsabilityContext<?> ic =
+ mixinAction.createUsableInteractionContext(
+ mixinAdapterFor(mixinType, mixedInAdapter), interactionInitiatedBy, where);
+ return InteractionUtils.isUsableResult(this, ic).createConsent();
+ }
+
+ //region > FacetHolder
+
+ @Override
+ protected FacetHolder getFacetHolder() {
+ return facetHolder;
+ }
+
+ //endregion
+
+
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/3a299c20/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java
new file mode 100644
index 0000000..71daf26
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java
@@ -0,0 +1,174 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.isis.core.metamodel.specloader.specimpl;
+
+import java.util.List;
+
+import com.google.common.base.Objects;
+
+import org.apache.isis.applib.Identifier;
+import org.apache.isis.applib.annotation.NotContributed;
+import org.apache.isis.applib.annotation.When;
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facetapi.FacetHolderImpl;
+import org.apache.isis.core.metamodel.facetapi.FacetUtil;
+import org.apache.isis.core.metamodel.facets.actions.notcontributed.NotContributedFacet;
+import org.apache.isis.core.metamodel.facets.actions.notcontributed.NotContributedFacetAbstract;
+import org.apache.isis.core.metamodel.facets.all.named.NamedFacetInferred;
+import org.apache.isis.core.metamodel.facets.members.disabled.DisabledFacet;
+import org.apache.isis.core.metamodel.facets.members.disabled.DisabledFacetForContributee;
+import org.apache.isis.core.metamodel.facets.propcoll.notpersisted.NotPersistedFacet;
+import org.apache.isis.core.metamodel.facets.propcoll.notpersisted.NotPersistedFacetAbstract;
+import org.apache.isis.core.metamodel.interactions.InteractionUtils;
+import org.apache.isis.core.metamodel.interactions.UsabilityContext;
+import org.apache.isis.core.metamodel.interactions.VisibilityContext;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectMemberDependencies;
+
+public class OneToOneAssociationMixedIn extends OneToOneAssociationDefault implements MixedInMember {
+
+ /**
+ * The type of the mixin (providing the action), eg annotated with {@link org.apache.isis.applib.annotation.Mixin}.
+ */
+ private final Class<?> mixinType;
+
+ /**
+ * The {@link ObjectActionDefault} for the action being mixed in (ie on the {@link #mixinType}.
+ */
+ private final ObjectActionDefault mixinAction;
+
+ /**
+ * The domain object type being mixed in to (being supplemented).
+ */
+ private final ObjectSpecification mixedInType;
+
+
+ /**
+ * Hold facets rather than delegate to the contributed action (different types might
+ * use layout metadata to position the contributee in different ways)
+ */
+ private final FacetHolder facetHolder = new FacetHolderImpl();
+
+ private final Identifier identifier;
+
+ public OneToOneAssociationMixedIn(
+ final ObjectActionDefault mixinAction,
+ final ObjectSpecification mixedInType,
+ final Class<?> mixinType,
+ final ObjectMemberDependencies objectMemberDependencies) {
+ super(mixinAction.getFacetedMethod(), mixinAction.getReturnType(), objectMemberDependencies);
+
+ this.mixinType = mixinType;
+ this.mixinAction = mixinAction;
+ this.mixedInType = mixedInType;
+
+ //
+ // ensure the contributed property cannot be modified
+ //
+ final NotPersistedFacet notPersistedFacet = new NotPersistedFacetAbstract(this) {};
+ final DisabledFacet disabledFacet = disabledFacet();
+
+ FacetUtil.addFacet(notPersistedFacet);
+ FacetUtil.addFacet(disabledFacet);
+
+ //
+ // in addition, copy over facets from contributed to own.
+ //
+ // These could include everything under @Property(...) because the
+ // PropertyAnnotationFacetFactory is also run against actions.
+ //
+ FacetUtil.copyFacets(mixinAction.getFacetedMethod(), facetHolder);
+
+
+
+ // adjust name if necessary
+ final String name = getName();
+
+ if(Objects.equal(name, "_")) {
+ String memberName = ObjectActionMixedIn.determineNameFrom(mixinAction);
+ FacetUtil.addFacet(new NamedFacetInferred(memberName, facetHolder));
+ }
+
+
+ // calculate the identifier
+ final Identifier mixinIdentifier = mixinAction.getFacetedMethod().getIdentifier();
+ List<String> memberParameterNames = mixinIdentifier.getMemberParameterNames();
+
+ identifier = Identifier.actionIdentifier(mixedInType.getCorrespondingClass().getName(), getId(), memberParameterNames);
+ }
+
+ private DisabledFacet disabledFacet() {
+ final DisabledFacet originalFacet = facetHolder.getFacet(DisabledFacet.class);
+ if( originalFacet != null &&
+ originalFacet.when() == When.ALWAYS &&
+ originalFacet.where() == Where.ANYWHERE) {
+ return originalFacet;
+ }
+ // ensure that the contributed association is always disabled
+ return new DisabledFacetForContributee("Contributed property", this);
+ }
+
+ @Override
+ public ObjectAdapter get(
+ final ObjectAdapter mixedInAdapter,
+ final InteractionInitiatedBy interactionInitiatedBy) {
+
+ final ObjectAdapter mixinAdapter = mixinAdapterFor(mixinType, mixedInAdapter);
+ return mixinAction.execute(mixinAdapter, new ObjectAdapter[0], interactionInitiatedBy);
+ }
+
+ @Override
+ public Identifier getIdentifier() {
+ return identifier;
+ }
+
+ @Override
+ public String getId() {
+ return determineIdFrom(this.mixinAction);
+ }
+
+ @Override
+ public Consent isVisible(
+ final ObjectAdapter mixedInAdapter,
+ final InteractionInitiatedBy interactionInitiatedBy,
+ Where where) {
+ final VisibilityContext<?> ic =
+ mixinAction.createVisibleInteractionContext(
+ mixinAdapterFor(mixinType, mixedInAdapter), interactionInitiatedBy, where);
+ return InteractionUtils.isVisibleResult(this, ic).createConsent();
+ }
+
+ @Override
+ public Consent isUsable(
+ final ObjectAdapter mixedInAdapter,
+ final InteractionInitiatedBy interactionInitiatedBy, final Where where) {
+ final UsabilityContext<?> ic =
+ mixinAction.createUsableInteractionContext(
+ mixinAdapterFor(mixinType, mixedInAdapter), interactionInitiatedBy, where);
+ return InteractionUtils.isUsableResult(this, ic).createConsent();
+ }
+
+ @Override
+ protected FacetHolder getFacetHolder() {
+ return facetHolder;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/3a299c20/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java b/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
index f21e958..4b9c4b7 100644
--- a/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
+++ b/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
@@ -28,6 +28,7 @@ import org.apache.isis.core.metamodel.facets.actions.interaction.ActionNamedDebu
import org.apache.isis.core.metamodel.facets.actions.layout.ActionLayoutFacetFactory;
import org.apache.isis.core.metamodel.facets.actions.notcontributed.annotation.NotContributedFacetAnnotationFactory;
import org.apache.isis.core.metamodel.facets.actions.notcontributed.derived.NotContributedFacetDerivedFromDomainServiceFacetFactory;
+import org.apache.isis.core.metamodel.facets.actions.notcontributed.derived.NotContributedFacetDerivedFromMixinFacetFactory;
import org.apache.isis.core.metamodel.facets.actions.notinservicemenu.annotation.NotInServiceMenuFacetAnnotationFactory;
import org.apache.isis.core.metamodel.facets.actions.notinservicemenu.derived.NotInServiceMenuFacetDerivedFromDomainServiceFacetFactory;
import org.apache.isis.core.metamodel.facets.actions.notinservicemenu.method.NotInServiceMenuFacetViaMethodFactory;
@@ -365,6 +366,7 @@ public final class ProgrammingModelFacetsJava5 extends ProgrammingModelAbstract
addFactory(RecreatableObjectFacetFactory.class);
addFactory(MixinFacetForMixinAnnotationFactory.class);
+
addFactory(MaxLengthFacetOnTypeAnnotationFactory.class);
addFactory(MaxLengthFacetOnActionAnnotationFactory.class);
@@ -389,6 +391,8 @@ public final class ProgrammingModelFacetsJava5 extends ProgrammingModelAbstract
// must come after DomainObjectAnnotationFacetFactory
addFactory(DisabledFacetOnPropertyDerivedFromRecreatableObjectFacetFactory.class);
addFactory(DisabledFacetOnCollectionDerivedFromViewModelFacetFactory.class);
+ // must come after DomainObjectAnnotationFacetFactory & MixinFacetFactory
+ addFactory(NotContributedFacetDerivedFromMixinFacetFactory.class);
addFactory(DomainServiceLayoutFactory.class);
addFactory(DomainObjectLayoutFacetFactory.class);
http://git-wip-us.apache.org/repos/asf/isis/blob/3a299c20/core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedInTest.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedInTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedInTest.java
index fdb3eaf..9707af6 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedInTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedInTest.java
@@ -2,6 +2,8 @@ package org.apache.isis.core.metamodel.specloader.specimpl;
import org.junit.Test;
+import org.apache.isis.core.commons.lang.StringExtensions;
+
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
@@ -12,31 +14,31 @@ public class ObjectActionMixedInTest {
@Test
public void exactly_underscore() throws Exception {
- final String s = ObjectActionMixedIn.suffixAfterUnderscore("_");
+ final String s = StringExtensions.asCapitalizedName(ObjectMemberAbstract.suffix("_"));
assertThat(s, is("_"));
}
@Test
public void ends_with_underscore() throws Exception {
- final String s = ObjectActionMixedIn.suffixAfterUnderscore("abc_");
+ final String s = StringExtensions.asCapitalizedName(ObjectMemberAbstract.suffix("abc_"));
assertThat(s, is("Abc_"));
}
@Test
public void has_no_underscore() throws Exception {
- final String s = ObjectActionMixedIn.suffixAfterUnderscore("defghij");
+ final String s = StringExtensions.asCapitalizedName(ObjectMemberAbstract.suffix("defghij"));
assertThat(s, is("Defghij"));
}
@Test
public void contains_one_underscore() throws Exception {
- final String s = ObjectActionMixedIn.suffixAfterUnderscore("abc_def");
+ final String s = StringExtensions.asCapitalizedName(ObjectMemberAbstract.suffix("abc_def"));
assertThat(s, is("Def"));
}
@Test
public void contains_more_than_one_underscore() throws Exception {
- final String s = ObjectActionMixedIn.suffixAfterUnderscore("abc_def_ghi");
+ final String s = StringExtensions.asCapitalizedName(ObjectMemberAbstract.suffix("abc_def_ghi"));
assertThat(s, is("Ghi"));
}
}