/*
* 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
}