/*
* 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.applib;
import java.util.List;
import javax.inject.Inject;
import com.google.common.base.Predicate;
import org.apache.isis.applib.annotation.Programmatic;
import org.apache.isis.applib.filter.Filter;
import org.apache.isis.applib.query.Query;
import org.apache.isis.applib.security.UserMemento;
import org.apache.isis.applib.services.i18n.TranslatableString;
/**
* Convenience super class for all classes that wish to interact with the
* container.
*
* @see org.apache.isis.applib.DomainObjectContainer
*/
public abstract class AbstractContainedObject {
/**
* Create a new instance of the specified class, but do not persist it.
*
* <p>
* It is recommended that the object be initially instantiated using
* this method, though the framework will also handle the case when
* the object is simply <i>new()</i>ed up. The benefits of using
* {@link #newTransientInstance(Class)} are:
* </p>
*
* <ul>
* <li>any services will be injected into the object immediately
* (otherwise they will not be injected until the framework
* becomes aware of the object, typically when it is
* {@link #persist(Object) persist}ed</li>
* <li>the default value for any properties (usually as specified by
* <tt>default<i>Xxx</i>()</tt> supporting methods) will not be
* used</li>
* <li>the <tt>created()</tt> callback will not be called.
* </ul>
*
* <p>
* The corollary is: if your code never uses <tt>default<i>Xxx</i>()</tt>
* supporting methods or the <tt>created()</tt> callback, then you can
* alternatively just <i>new()</i> up the object rather than call this
* method.
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#newTransientInstance(Class)
*/
protected <T> T newTransientInstance(final Class<T> ofType) {
return getContainer().newTransientInstance(ofType);
}
/**
* Create a new {@link ViewModel} instance of the specified type, initializing with the specified memento.
*
* <p>
* Rather than use this constructor it is generally preferable to simply instantiate a
* class annotated with {@link org.apache.isis.applib.annotation.ViewModel annotation}.
* If services need injecting into it, use {@link DomainObjectContainer#injectServicesInto(Object)}.
* </p>
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#newViewModelInstance(Class, String)
*/
protected <T extends ViewModel> T newViewModelInstance(final Class<T> ofType, final String memento) {
return getContainer().newViewModelInstance(ofType, memento);
}
/**
* @deprecated - not supported, will throw a RuntimeException
*/
@Deprecated
protected <T> T newAggregatedInstance(final Class<T> ofType) {
return newAggregatedInstance(this, ofType);
}
/**
* @deprecated - not supported, will throw a RuntimeException
*/
@Deprecated
protected <T> T newAggregatedInstance(final Object parent, final Class<T> ofType) {
return getContainer().newAggregatedInstance(parent, ofType);
}
// //////////////////////////////////////
/**
* Returns all the instances of the specified type (including subtypes).
* If the optional range parameters are used, the dataset returned starts
* from (0 based) index, and consists of only up to count items.
*
* <p>
* If there are no instances the list will be empty. This method creates a
* new {@link List} object each time it is called so the caller is free to
* use or modify the returned {@link List}, but the changes will not be
* reflected back to the repository.
* </p>
*
* <p>
* This method should only be called where the number of instances is known
* to be relatively low, unless the optional range parameters (2 longs) are
* specified. The range parameters are "start" and "count".
* </p>
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#allInstances(Class, long...)
*
* @param range 2 longs, specifying 0-based start and count.
*/
protected <T> List<T> allInstances(final Class<T> ofType, long... range) {
return getContainer().allInstances(ofType, range);
}
// //////////////////////////////////////
/**
* Returns all the instances of the specified type (including subtypes) that
* the predicate object accepts. If the optional range parameters are used, the
* dataset returned starts from (0 based) index, and consists of only up to
* count items.
*
* <p>
* If there are no instances the list will be empty. This method creates a
* new {@link List} object each time it is called so the caller is free to
* use or modify the returned {@link List}, but the changes will not be
* reflected back to the repository.
* </p>
*
* <p>
* This method is useful during exploration/prototyping, but - because the filtering is performed client-side -
* this method is only really suitable for initial development/prototyping, or for classes with very few
* instances. Use {@link #allMatches(Query)} for production code.
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#allMatches(Class, Predicate, long...)
* @see #allMatches(Query)
*
* @param range 2 longs, specifying 0-based start and count.
*/
@Programmatic
protected <T> List<T> allMatches(final Class<T> ofType, final Predicate<? super T> predicate, long... range) {
return getContainer().allMatches(ofType, predicate, range);
}
/**
* @deprecated - use {@link #allMatches(Class, Predicate, long...)} or (better) {@link #allMatches(Query)} instead
*/
@Deprecated
protected <T> List<T> allMatches(final Class<T> ofType, final Filter<? super T> filter, long... range) {
return getContainer().allMatches(ofType, filter, range);
}
/**
* Returns all the instances of the specified type (including subtypes) that
* match the given object: where any property that is set will be tested and
* properties that are not set will be ignored.
* If the optional range parameters are used, the dataset returned starts
* from (0 based) index, and consists of only up to count items.
*
* <p>
* If there are no instances the list will be empty. This method creates a
* new {@link List} object each time it is called so the caller is free to
* use or modify the returned {@link List}, but the changes will not be
* reflected back to the repository.
* </p>
*
* <p>
* This method is useful during exploration/prototyping, but - because the filtering is performed client-side -
* this method is only really suitable for initial development/prototyping, or for classes with very few
* instances. Use {@link #allMatches(Query)} for production code.
* </p>
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#allMatches(Class, Object, long...)
*
* @param range 2 longs, specifying 0-based start and count.
*/
protected <T> List<T> allMatches(final Class<T> ofType, final T pattern, long... range) {
return getContainer().allMatches(ofType, pattern, range);
}
/**
* Returns all the instances of the specified type (including subtypes) that
* have the given title.
* If the optional range parameters are used, the dataset returned starts
* from (0 based) index, and consists of only up to count items.
*
* <p>
* If there are no instances the list will be empty. This method creates a
* new {@link List} object each time it is called so the caller is free to
* use or modify the returned {@link List}, but the changes will not be
* reflected back to the repository.
* </p>
*
* <p>
* This method is useful during exploration/prototyping, but - because the filtering is performed client-side -
* this method is only really suitable for initial development/prototyping, or for classes with very few
* instances. Use {@link #allMatches(Query)} for production code.
* </p>
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#allMatches(Class, String, long...)
*
* @param range 2 longs, specifying 0-based start and count.
*/
protected <T> List<T> allMatches(final Class<T> ofType, final String title, long... range) {
return getContainer().allMatches(ofType, title, range);
}
/**
* Returns all the instances that match the given {@link Query}.
*
* <p>
* If there are no instances the list will be empty. This method creates a
* new {@link List} object each time it is called so the caller is free to
* use or modify the returned {@link List}, but the changes will not be
* reflected back to the repository.
* </p>
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#allMatches(Query)
*/
protected <T> List<T> allMatches(final Query<T> query) {
return getContainer().allMatches(query);
}
// //////////////////////////////////////
/**
* Returns the first instance of the specified type (including subtypes)
* that matches the supplied {@link Predicate}, or <tt>null</tt> if none.
*
* <p>
* This method is useful during exploration/prototyping, but - because the filtering is performed client-side -
* this method is only really suitable for initial development/prototyping, or for classes with very few
* instances. Use {@link #firstMatch(Query)} for production code.
* </p>
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#firstMatch(Class, Predicate)
*/
protected <T> T firstMatch(final Class<T> ofType, final Predicate<T> predicate) {
return getContainer().firstMatch(ofType, predicate);
}
/**
* @deprecated - use {@link #firstMatch(Class, Predicate)}
*/
@Deprecated
protected <T> T firstMatch(final Class<T> ofType, final Filter<T> filter) {
return getContainer().firstMatch(ofType, filter);
}
/**
* Returns the first instance of the specified type (including subtypes)
* that matches the supplied object as a pattern, or <tt>null</tt> if none.
*
* <p>
* This method is useful during exploration/prototyping, but - because the filtering is performed client-side -
* this method is only really suitable for initial development/prototyping, or for classes with very few
* instances. Use {@link #firstMatch(Query)} for production code.
* </p>
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#firstMatch(Class, Object)
*/
protected <T> T firstMatch(final Class<T> ofType, final T pattern) {
return getContainer().firstMatch(ofType, pattern);
}
/**
* Returns the first instance of the specified type (including subtypes)
* that matches the supplied title, or <tt>null</tt> if none.
*
* <p>
* This method is useful during exploration/prototyping, but - because the filtering is performed client-side -
* this method is only really suitable for initial development/prototyping, or for classes with very few
* instances. Use {@link #firstMatch(Query)} for production code.
* </p>
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#firstMatch(Class, String)
*/
protected <T> T firstMatch(final Class<T> ofType, final String title) {
return getContainer().firstMatch(ofType, title);
}
/**
* Returns the first instance that matches the supplied query, or <tt>null</tt> if none.
*
* <p>
* This method is the recommended way of querying for an instance when one or more may match. See also
* {@link #uniqueMatch(Query)}.
* </p>
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#firstMatch(Query)
* @see #uniqueMatch(Query)
*/
protected <T> T firstMatch(final Query<T> query) {
return getContainer().firstMatch(query);
}
// //////////////////////////////////////
/**
* Find the only instance of the specified type (including subtypes) that
* has the specified title.
*
* <p>
* If no instance is found then <tt>null</tt> will be return, while if there
* is more that one instances a run-time exception will be thrown.
*
* <p>
* This method is useful during exploration/prototyping, but - because the filtering is performed client-side -
* this method is only really suitable for initial development/prototyping, or for classes with very few
* instances. Use {@link #uniqueMatch(Query)} for production code.
* </p>
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#uniqueMatch(Class, Predicate)
*/
protected <T> T uniqueMatch(final Class<T> ofType, final Predicate<T> predicate) {
return getContainer().uniqueMatch(ofType, predicate);
}
/**
* @deprecated - use {@link #uniqueMatch(Class, Predicate)}
*/
@Deprecated
protected <T> T uniqueMatch(final Class<T> ofType, final Filter<T> filter) {
return getContainer().uniqueMatch(ofType, filter);
}
/**
* Find the only instance of the specified type (including subtypes) that
* has the specified title.
*
* <p>
* If no instance is found then <tt>null</tt> will be returned, while if
* there is more that one instances a run-time exception will be thrown.
*
* <p>
* This method is useful during exploration/prototyping, but - because the filtering is performed client-side -
* this method is only really suitable for initial development/prototyping, or for classes with very few
* instances. Use {@link #uniqueMatch(Query)} for production code.
* </p>
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#uniqueMatch(Class, String)
*/
protected <T> T uniqueMatch(final Class<T> ofType, final String title) {
return getContainer().uniqueMatch(ofType, title);
}
/**
* Find the only instance of the patterned object type (including subtypes)
* that matches the set fields in the pattern object: where any property
* that is set will be tested and properties that are not set will be
* ignored.
*
* <p>
* If no instance is found then null will be return, while if there is more
* that one instances a run-time exception will be thrown.
* </p>
*
* <p>
* This method is useful during exploration/prototyping, but - because the filtering is performed client-side -
* this method is only really suitable for initial development/prototyping, or for classes with very few
* instances. Use {@link #uniqueMatch(Query)} for production code.
* </p>
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#uniqueMatch(Class, Object)
*/
protected <T> T uniqueMatch(final Class<T> ofType, final T pattern) {
return getContainer().uniqueMatch(ofType, pattern);
}
/**
* Find the only instance that matches the provided query.
*
* <p>
* If no instance is found then null will be return, while if there is more
* that one instances a run-time exception will be thrown.
* </p>
*
* <p>
* This method is the recommended way of querying for (precisely) one instance. See also {@link #firstMatch(Query)}
* for less strict querying.
* </p>
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see #firstMatch(Query)
* @see DomainObjectContainer#uniqueMatch(Query)
*/
protected <T> T uniqueMatch(final Query<T> query) {
return getContainer().uniqueMatch(query);
}
// //////////////////////////////////////
/**
* Whether the object is in a valid state, that is that none of the
* validation of properties, collections and object-level is vetoing.
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see #validate(Object)
* @see DomainObjectContainer#isValid(Object)
*/
protected boolean isValid(final Object domainObject) {
return getContainer().isValid(domainObject);
}
/**
* The reason, if any why the object is in a invalid state
*
* <p>
* Checks the validation of all of the properties, collections and
* object-level.
* </p>
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see #isValid(Object)
* @see DomainObjectContainer#validate(Object)
*/
protected String validate(final Object domainObject) {
return getContainer().validate(domainObject);
}
// //////////////////////////////////////
/**
* Determines if the specified object is persistent (that it is stored permanently outside of the virtual machine
* in the object store).
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#isPersistent(Object)
*/
protected boolean isPersistent(final Object domainObject) {
return getContainer().isPersistent(domainObject);
}
/**
* Queues up a request to persist this object to the object store. The object is persisted either
* when the transaction is committed, or when it is flushed. Flushing is performed either implicitly whenever a subsequent query is run,
* or can be performed explicitly using {@link DomainObjectContainer#flush()}.
*
* <p>
* It is recommended that the object be initially instantiated using
* {@link #newTransientInstance(Class)}. However, the framework will also
* handle the case when the object is simply <i>new()</i>ed up. See
* {@link #newTransientInstance(Class)} for more information.
* </p>
*
* <p>
* This method will throw an exception if the object {@link #isPersistent(Object) is persistent} already. For this reason
* {@link #persistIfNotAlready(Object)} is generally preferred.
* </p>
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see #newTransientInstance(Class)
* @see #isPersistent(Object)
* @see #persistIfNotAlready(Object)
* @see DomainObjectContainer#persist(Object)
*/
protected <T> T persist(final T transientDomainObject) {
getContainer().persist(transientDomainObject);
return transientDomainObject;
}
/**
* Queues up a request to persist this object to the object store (as per {@link #persist(Object)}) (or do
* nothing if the object is already {@link #isPersistent(Object) persistent}).
*
* <p>
* It is recommended that the object be initially instantiated using
* {@link #newTransientInstance(Class)}. However, the framework will also
* handle the case when the object is simply <i>new()</i>ed up. See
* {@link #newTransientInstance(Class)} for more information.
* </p>
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see #newTransientInstance(Class)
* @see #isPersistent(Object)
* @see #persist(Object)
* @see {@link DomainObjectContainer#persistIfNotAlready(Object)}
*/
protected <T> T persistIfNotAlready(final T domainObject) {
getContainer().persistIfNotAlready(domainObject);
return domainObject;
}
/**
* Delete the provided object from the persistent object store.
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#remove(Object)
*/
protected <T> T remove(final T persistentDomainObject) {
getContainer().remove(persistentDomainObject);
return persistentDomainObject;
}
/**
* Delete the provided object from the persistent object store.
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#removeIfNotAlready(Object)
*/
protected <T> T removeIfNotAlready(final T persistentDomainObject) {
getContainer().removeIfNotAlready(persistentDomainObject);
return persistentDomainObject;
}
// //////////////////////////////////////
/**
* Display the specified message to the user, in a non-intrusive fashion.
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#informUser(String)
*/
protected void informUser(final String message) {
getContainer().informUser(message);
}
/**
* Display the specified i18n message to the user, in a non-intrusive fashion.
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#informUser(TranslatableString, Class, String)
*/
protected void informUser(TranslatableString message, final Class<?> contextClass, final String contextMethod) {
getContainer().informUser(message, contextClass, contextMethod);
}
/**
* Display the specified message as a warning to the user, in a more visible
* fashion, but without requiring explicit acknowledgement.
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#warnUser(String)
*/
protected void warnUser(final String message) {
getContainer().warnUser(message);
}
/**
* Display the specified i18n message as a warning to the user, in a more visible
* fashion, but without requiring explicit acknowledgement.
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#warnUser(TranslatableString, Class, String)
*/
protected void warnUser(TranslatableString message, final Class<?> contextClass, final String contextMethod) {
getContainer().warnUser(message, contextClass, contextMethod);
}
/**
* Display the specified message as an error to the user, ensuring that it
* is acknowledged.
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#raiseError(String)
*/
protected void raiseError(final String message) {
getContainer().raiseError(message);
}
/**
* Display the specified i18n message as an error to the user, ensuring that it
* is acknowledged.
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#raiseError(TranslatableString, Class, String)
*/
protected String raiseError(TranslatableString message, final Class<?> contextClass, final String contextMethod) {
return getContainer().raiseError(message, contextClass, contextMethod);
}
// //////////////////////////////////////
/**
* Get the details about the current user.
*
* <p>
* The method simply delegates to the {@link DomainObjectContainer}.
* </p>
*
* @see DomainObjectContainer#getUser()
*/
protected UserMemento getUser() {
return getContainer().getUser();
}
// //////////////////////////////////////
@javax.inject.Inject
private DomainObjectContainer container;
/**
* This field is not persisted, nor displayed to the user.
*/
protected DomainObjectContainer getContainer() {
return this.container;
}
/**
* @deprecated - will use the field to inject instead.
*/
@Deprecated
@Programmatic
public void setContainer(final DomainObjectContainer container) {
this.container = container;
}
}