/* * 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 org.apache.isis.applib.annotation.Where; import org.apache.isis.core.commons.exceptions.IsisException; import org.apache.isis.core.commons.util.ToString; 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.consent.InteractionResult; import org.apache.isis.core.metamodel.facetapi.FeatureType; import org.apache.isis.core.metamodel.facets.FacetedMethod; import org.apache.isis.core.metamodel.facets.collections.modify.CollectionAddToFacet; import org.apache.isis.core.metamodel.facets.collections.modify.CollectionClearFacet; import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet; import org.apache.isis.core.metamodel.facets.collections.modify.CollectionRemoveFromFacet; import org.apache.isis.core.metamodel.facets.collparam.semantics.CollectionSemantics; import org.apache.isis.core.metamodel.facets.collparam.semantics.CollectionSemanticsFacet; import org.apache.isis.core.metamodel.facets.propcoll.accessor.PropertyOrCollectionAccessorFacet; import org.apache.isis.core.metamodel.interactions.CollectionAddToContext; import org.apache.isis.core.metamodel.interactions.CollectionRemoveFromContext; import org.apache.isis.core.metamodel.interactions.CollectionUsabilityContext; import org.apache.isis.core.metamodel.interactions.CollectionVisibilityContext; import org.apache.isis.core.metamodel.interactions.InteractionUtils; import org.apache.isis.core.metamodel.interactions.UsabilityContext; import org.apache.isis.core.metamodel.interactions.ValidityContext; import org.apache.isis.core.metamodel.interactions.VisibilityContext; import org.apache.isis.core.metamodel.services.ServicesInjector; import org.apache.isis.core.metamodel.spec.ObjectSpecification; import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation; public class OneToManyAssociationDefault extends ObjectAssociationAbstract implements OneToManyAssociation { public OneToManyAssociationDefault( final FacetedMethod facetedMethod, final ServicesInjector servicesInjector) { this(facetedMethod, getSpecification(servicesInjector.getSpecificationLoader(), facetedMethod.getType()), servicesInjector); } protected OneToManyAssociationDefault( final FacetedMethod facetedMethod, final ObjectSpecification objectSpec, final ServicesInjector servicesInjector) { super(facetedMethod, FeatureType.COLLECTION, objectSpec, servicesInjector); } @Override public CollectionSemantics getCollectionSemantics() { return getFacet(CollectionSemanticsFacet.class).value(); } //region > visible, usable @Override public VisibilityContext<?> createVisibleInteractionContext( final ObjectAdapter ownerAdapter, final InteractionInitiatedBy interactionInitiatedBy, Where where) { return new CollectionVisibilityContext(ownerAdapter, getIdentifier(), interactionInitiatedBy, where); } @Override public UsabilityContext<?> createUsableInteractionContext( final ObjectAdapter ownerAdapter, final InteractionInitiatedBy interactionInitiatedBy, Where where) { return new CollectionUsabilityContext(ownerAdapter, getIdentifier(), interactionInitiatedBy, where); } //endregion //region > Validate Add // Not API private ValidityContext<?> createValidateAddInteractionContext( final InteractionInitiatedBy interactionInitiatedBy, final ObjectAdapter ownerAdapter, final ObjectAdapter proposedToAddAdapter) { return new CollectionAddToContext(ownerAdapter, getIdentifier(), proposedToAddAdapter, interactionInitiatedBy); } @Override public Consent isValidToAdd( final ObjectAdapter ownerAdapter, final ObjectAdapter proposedToAddAdapter, final InteractionInitiatedBy interactionInitiatedBy) { return isValidToAddResult(ownerAdapter, proposedToAddAdapter, interactionInitiatedBy).createConsent(); } private InteractionResult isValidToAddResult( final ObjectAdapter ownerAdapter, final ObjectAdapter proposedToAddAdapter, final InteractionInitiatedBy interactionInitiatedBy) { final ValidityContext<?> validityContext = createValidateAddInteractionContext( interactionInitiatedBy, ownerAdapter, proposedToAddAdapter); return InteractionUtils.isValidResult(this, validityContext); } //endregion //region > Validate Remove private ValidityContext<?> createValidateRemoveInteractionContext( final ObjectAdapter ownerAdapter, final ObjectAdapter proposedToRemoveAdapter, final InteractionInitiatedBy interactionInitiatedBy) { return new CollectionRemoveFromContext( ownerAdapter, getIdentifier(), proposedToRemoveAdapter, interactionInitiatedBy ); } @Override public Consent isValidToRemove( final ObjectAdapter ownerAdapter, final ObjectAdapter proposedToRemoveAdapter, final InteractionInitiatedBy interactionInitiatedBy) { return isValidToRemoveResult( ownerAdapter, proposedToRemoveAdapter, interactionInitiatedBy).createConsent(); } private InteractionResult isValidToRemoveResult( final ObjectAdapter ownerAdapter, final ObjectAdapter proposedToRemoveAdapter, final InteractionInitiatedBy interactionInitiatedBy) { final ValidityContext<?> validityContext = createValidateRemoveInteractionContext( ownerAdapter, proposedToRemoveAdapter, interactionInitiatedBy); return InteractionUtils.isValidResult(this, validityContext); } private boolean readWrite() { return !isNotPersisted(); } //endregion //region > get, isEmpty, add, clear @Override public ObjectAdapter get( final ObjectAdapter ownerAdapter, final InteractionInitiatedBy interactionInitiatedBy) { final PropertyOrCollectionAccessorFacet accessor = getFacet(PropertyOrCollectionAccessorFacet.class); final Object collection = accessor.getProperty(ownerAdapter, interactionInitiatedBy); if (collection == null) { return null; } return getPersistenceSessionService().adapterFor(collection, ownerAdapter, this); } @Override public boolean isEmpty(final ObjectAdapter parentAdapter, final InteractionInitiatedBy interactionInitiatedBy) { // REVIEW should we be able to determine if a collection is empty // without loading it? final ObjectAdapter collection = get(parentAdapter, interactionInitiatedBy); final CollectionFacet facet = CollectionFacet.Utils.getCollectionFacetFromSpec(collection); return facet.size(collection) == 0; } //endregion //region > add, clear @Override public void addElement( final ObjectAdapter ownerAdapter, final ObjectAdapter referencedAdapter, final InteractionInitiatedBy interactionInitiatedBy) { if (referencedAdapter == null) { throw new IllegalArgumentException("Can't use null to add an item to a collection"); } if (readWrite()) { if (ownerAdapter.representsPersistent() && referencedAdapter.isTransient()) { throw new IsisException("can't set a reference to a transient object from a persistent one: " + ownerAdapter.titleString(null) + " (persistent) -> " + referencedAdapter.titleString() + " (transient)"); } final CollectionAddToFacet facet = getFacet(CollectionAddToFacet.class); facet.add(ownerAdapter, referencedAdapter, interactionInitiatedBy); } } @Override public void removeElement( final ObjectAdapter ownerAdapter, final ObjectAdapter referencedAdapter, final InteractionInitiatedBy interactionInitiatedBy) { if (referencedAdapter == null) { throw new IllegalArgumentException("element should not be null"); } if (readWrite()) { final CollectionRemoveFromFacet facet = getFacet(CollectionRemoveFromFacet.class); facet.remove(ownerAdapter, referencedAdapter, interactionInitiatedBy); } } public void removeAllAssociations(final ObjectAdapter ownerAdapter) { final CollectionClearFacet facet = getFacet(CollectionClearFacet.class); facet.clear(ownerAdapter); } @Override public void clearCollection(final ObjectAdapter ownerAdapter) { if (readWrite()) { final CollectionClearFacet facet = getFacet(CollectionClearFacet.class); facet.clear(ownerAdapter); } } //endregion //region > defaults @Override public ObjectAdapter getDefault(final ObjectAdapter ownerAdapter) { return null; } @Override public void toDefault(final ObjectAdapter ownerAdapter) { } //endregion //region > choices & autoComplete @Override public ObjectAdapter[] getChoices( final ObjectAdapter ownerAdapter, final InteractionInitiatedBy interactionInitiatedBy) { return new ObjectAdapter[0]; } @Override public boolean hasChoices() { return false; } @Override public boolean hasAutoComplete() { return false; } @Override public ObjectAdapter[] getAutoComplete( ObjectAdapter object, String searchArg, final InteractionInitiatedBy interactionInitiatedBy) { return new ObjectAdapter[0]; } @Override public int getAutoCompleteMinLength() { return 0; // n/a } //endregion //region > toString @Override public String toString() { final ToString str = new ToString(this); str.append(super.toString()); str.append(","); str.append("persisted", !isNotPersisted()); str.append("type", getSpecification() == null ? "unknown" : getSpecification().getShortIdentifier()); return str.toString(); } //endregion }