org.openmdx.state2.cci.DateStateViews Maven / Gradle / Ivy
/*
* ====================================================================
* Project: openMDX/Core, http://www.openmdx.org/
* Description: Date State Views
* Owner: OMEX AG, Switzerland, http://www.omex.ch
* ====================================================================
*
* This software is published under the BSD license as listed below.
*
* Copyright (c) 2007-2011, OMEX AG, Switzerland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of the openMDX team nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* ------------------
*
* This product includes software developed by other organizations as
* listed in the NOTICE file.
*/
package org.openmdx.state2.cci;
import static org.oasisopen.cci2.QualifierType.REASSIGNABLE;
import java.util.AbstractSequentialList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.logging.Level;
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jmi.reflect.RefBaseObject;
import javax.jmi.reflect.RefObject;
import javax.jmi.reflect.RefPackage;
import javax.resource.cci.InteractionSpec;
import javax.xml.datatype.DatatypeConstants;
import javax.xml.datatype.XMLGregorianCalendar;
import org.oasisopen.cci2.QualifierType;
import org.oasisopen.jmi1.RefContainer;
import org.openmdx.base.accessor.cci.Container_1_0;
import org.openmdx.base.accessor.cci.DataObject_1_0;
import org.openmdx.base.accessor.cci.SystemAttributes;
import org.openmdx.base.accessor.jmi.cci.RefPackage_1_0;
import org.openmdx.base.accessor.jmi.cci.RefQuery_1_0;
import org.openmdx.base.accessor.jmi.spi.DelegatingRefObject_1_0;
import org.openmdx.base.accessor.rest.DataObjects;
import org.openmdx.base.accessor.spi.ExceptionHelper;
import org.openmdx.base.exception.RuntimeServiceException;
import org.openmdx.base.exception.ServiceException;
import org.openmdx.base.jmi1.AspectCapable;
import org.openmdx.base.mof.cci.Model_1_0;
import org.openmdx.base.mof.spi.Model_1Factory;
import org.openmdx.base.naming.Path;
import org.openmdx.base.persistence.cci.PersistenceHelper;
import org.openmdx.base.persistence.spi.TransientContainerId;
import org.openmdx.base.query.Condition;
import org.openmdx.base.query.Filter;
import org.openmdx.base.query.IsGreaterCondition;
import org.openmdx.base.query.IsGreaterOrEqualCondition;
import org.openmdx.base.query.IsInCondition;
import org.openmdx.base.query.IsInstanceOfCondition;
import org.openmdx.base.query.Quantifier;
import org.openmdx.base.rest.cci.ConditionRecord;
import org.openmdx.base.rest.cci.QueryFilterRecord;
import org.openmdx.kernel.exception.BasicException;
import org.openmdx.kernel.log.SysLog;
import org.openmdx.state2.jmi1.BasicState;
import org.openmdx.state2.jmi1.DateState;
import org.openmdx.state2.jmi1.Legacy;
import org.openmdx.state2.jmi1.StateCapable;
import org.openmdx.state2.spi.DateStateViewContext;
import org.openmdx.state2.spi.Order;
import org.openmdx.state2.spi.Parameters;
import org.openmdx.state2.spi.StateViewContext;
import org.openmdx.state2.spi.TechnicalAttributes;
import org.w3c.cci2.AnyTypePredicate;
import org.w3c.cci2.Container;
import org.w3c.cci2.ImmutableDatatype;
import org.w3c.spi.DatatypeFactories;
import org.w3c.spi.ImmutableDatatypeFactory;
/**
* Date State Views
*/
public class DateStateViews {
/**
* Constructor
*/
protected DateStateViews() {
// Avoid instantiation
}
/**
* Used in views for invalidated states open at both sides
*/
private static XMLGregorianCalendar DEFAULT_VALID_FOR = DatatypeFactories.xmlDatatypeFactory().newXMLGregorianCalendarDate(
2000,
1, // January
1, // 1st
DatatypeConstants.FIELD_UNDEFINED
);
private static final String[] EXCLUDE_FROM_STATE_CLONING = {
SystemAttributes.OBJECT_IDENTITY, SystemAttributes.CORE, TechnicalAttributes.STATE_VALID_FROM, TechnicalAttributes.STATE_VALID_TO, SystemAttributes.REMOVED_AT,
SystemAttributes.REMOVED_BY, SystemAttributes.CREATED_AT, SystemAttributes.CREATED_BY
};
private static final String[] EXCLUDE_FROM_CORE_CLONING = {
SystemAttributes.OBJECT_IDENTITY, TechnicalAttributes.STATE_VERSION, SystemAttributes.MODIFIED_AT, SystemAttributes.MODIFIED_BY
};
/**
* Retrieve the PersistenceManager for a given state view context
*
* @param persistenceManager
* the JDO context
* @param viewContext,
* may be null
*
* @return the PersistenceManager
for the requested state view context
*/
public static PersistenceManager getPersistenceManager(
PersistenceManager persistenceManager,
StateViewContext viewContext
) {
RefPackage_1_0 refPackageFactory = (RefPackage_1_0) persistenceManager.getUserObject(RefPackage.class);
return refPackageFactory.refPackage(viewContext).refPersistenceManager();
}
/**
* Retrieve the PersistenceManager for a given time range view
*
* @param persistenceManager
* the JDO context
* @param validFrom
* the begin of the time range, or null
for an unconstrained lower bound
* @param validTo
* the end of the time range, or null
for an unconstrained upper bound
*
* @return the PersistenceManager
for the given state view context
*
* @throws IllegalArgumentException
* if validTo is less than validFrom
*/
public static PersistenceManager getPersistenceManager(
PersistenceManager persistenceManager,
XMLGregorianCalendar validFrom,
XMLGregorianCalendar validTo
) {
return DateStateViews.getPersistenceManager(
persistenceManager,
DateStateViewContext.newTimeRangeViewContext(validFrom, validTo)
);
}
/**
* Retrieve the PersistenceManager for a given time point view
*
* @param persistenceManager
* the JDO context
* @param validFor
* the view's valid time point, or null
for today
* @param validAt
* the view's transaction time point, or null
for an up-to-date view
*
* @return the PersistenceManager
for the given state view context
*/
public static PersistenceManager getPersistenceManager(
PersistenceManager persistenceManager,
XMLGregorianCalendar validFor,
Date validAt
) {
return DateStateViews.getPersistenceManager(
persistenceManager,
DateStateViewContext.newTimePointViewContext(
validFor == null ? DateStateViews.today() : validFor,
validAt
)
);
}
/**
* Validates a container
*
* @param container
* the container to be validated
*
* @return the RefContainer
*
* @throws IllegalArgumentException
* if the container is not an instance of RefContainer>
*/
@SuppressWarnings("unchecked")
private static RefContainer asRefContainer(
Container> container
) {
if (container instanceof RefContainer>) {
return (RefContainer) container;
} else if (container == null) {
throw new IllegalArgumentException("The container must not be null");
} else {
throw BasicException.initHolder(
new IllegalArgumentException(
"The container should be an instance of " + RefBaseObject.class.getName(),
BasicException.newEmbeddedExceptionStack(
BasicException.Code.DEFAULT_DOMAIN,
BasicException.Code.BAD_PARAMETER,
new BasicException.Parameter("class", container.getClass().getName())
)
)
);
}
}
/**
* Retrieve the outermost package for given contexts
*
* @param refContext
* @param viewContext
*
* @return the outermost package for the given contexts
*/
private static RefPackage_1_0 getPackageForContext(
RefBaseObject refContext,
StateViewContext viewContext
) {
RefPackage_1_0 refPackageFactory = (RefPackage_1_0) refContext.refOutermostPackage();
return refPackageFactory.refPackage(viewContext);
}
/**
* Retrieve the PersistenceManager for a given state view context
*
* @param refContext
* @param viewContext,
* may be null
*
* @return the PersistenceManager
for the given state view context
*/
public static PersistenceManager getPersistenceManager(
RefBaseObject refContext,
StateViewContext viewContext
) {
return DateStateViews.getPackageForContext(refContext, viewContext).refPersistenceManager();
}
/**
* Retrieve the PersistenceManager for a given time range view
*
* @param refContext
* the JMI context
* @param validFrom
* the begin of the time range, or null
for an unconstrained lower bound
* @param validTo
* the end of the time range, or null
for an unconstrained upper bound
*
* @return the PersistenceManager
for the given state view context
*
* @throws IllegalArgumentException
* if validTo is less than validFrom
*/
public static PersistenceManager getPersistenceManager(
RefBaseObject refContext,
XMLGregorianCalendar validFrom,
XMLGregorianCalendar validTo
) {
return DateStateViews.getPersistenceManager(
refContext,
DateStateViewContext.newTimeRangeViewContext(validFrom, validTo)
);
}
/**
* Retrieve the PersistenceManager for a given time point view
*
* @param refContext
* the JMI context
* @param validFor
* the view's valid time point, or null
for today
* @param validAt
* the view's transaction time point, or null
for an up-to-date view
*
* @return the PersistenceManager
for the given state view context
*/
public static PersistenceManager getPersistenceManager(
RefBaseObject refContext,
XMLGregorianCalendar validFor,
Date validAt
) {
return DateStateViews.getPersistenceManager(
refContext,
DateStateViewContext.newTimePointViewContext(
validFor == null ? DateStateViews.today() : validFor,
validAt
)
);
}
/**
* Create a core object in the given context
*
* @param refContext
* @param coreClass
*
* @return a new core object
*/
public static T createCore(
RefBaseObject refContext,
Class coreClass
) {
return DateStateViews.getPackageForContext(
refContext,
null
).refPersistenceManager().newInstance(
coreClass
);
}
/**
* Add a core object to the date state context free view of the given container
*
* @param container
* @param qualifier
* @param core
*
* @throws IllegalArgumentException
* if one of the arguments is null or if the
* core object is not context free
*/
@SuppressWarnings("unchecked")
public static void addCoreToContainer(
Container super T> container,
String qualifier,
T core
) {
if (core == null) {
throw new IllegalArgumentException("The core object must not be null");
}
DateStateContext context = DateStateViews.getContext(core);
if (context != null) {
throw BasicException.initHolder(
new IllegalArgumentException(
"The core object must be context free",
BasicException.newEmbeddedExceptionStack(
BasicException.Code.DEFAULT_DOMAIN,
BasicException.Code.BAD_PARAMETER,
new BasicException.Parameter("context", context)
)
)
);
}
RefContainer super T> refContainer = asRefContainer(container);
if (DateStateViews.getContext(refContainer) != null) {
refContainer = (RefContainer super T>) DateStateViews.getPersistenceManager(refContainer, null).getObjectById(
JDOHelper.getTransactionalObjectId(refContainer)
);
}
refContainer.refAdd(
REASSIGNABLE,
qualifier,
core
);
}
/**
* Link core and state
*
* @param state
* @param core
*/
public static void linkStateAndCore(
DateState state,
StateCapable core
) {
state.setCore(core);
}
/**
* Create an additional state
*
* @param core
* @param stateValidFrom
* @param stateValidTo
* @param stateClass
*
* @return a new state
*
* @throws InvalidArgumentException
* if validTo is less than validFrom or
* coreClass.getClass().isAssignableFrom(stateClass) is false
*/
public static T createState(
StateCapable core,
XMLGregorianCalendar stateValidFrom,
XMLGregorianCalendar stateValidTo,
Class stateClass
) {
T state = DateStateViews.getPersistenceManager(
core,
stateValidFrom,
stateValidTo
).newInstance(
stateClass
);
linkStateAndCore(state, core);
return state;
}
/**
* Create a stated object
*
* @param container
* @param qualifier
* @param coreClass
* @param stateValidFrom
* @param stateValidTo
* @param stateClass
*
* @return a stated object with a single state
*
* @throws InvalidArgumentException
* if validTo is less than validFrom or
* coreClass.getClass().isAssignableFrom(stateClass) is false
*/
public static S createStatedObject(
Container super C> container,
String qualifier,
Class coreClass,
XMLGregorianCalendar stateValidFrom,
XMLGregorianCalendar stateValidTo,
Class stateClass
) {
C core = DateStateViews.createCore((RefContainer>) container, coreClass);
DateStateViews.addCoreToContainer(container, qualifier, core);
return DateStateViews.createState(core, stateValidFrom, stateValidTo, stateClass);
}
/**
* Retrieve the state context aware predicate
*
* @param refContainer
* @param predicate
*
* @return the state context aware predicate
*/
private static AnyTypePredicate getStatePredicate(
RefContainer> refContainer,
AnyTypePredicate predicate
) {
if (predicate == null)
return null;
QueryFilterRecord original = ((RefQuery_1_0) predicate).refGetFilter();
for (ConditionRecord condition : original.getCondition()) {
String feature = condition.getFeature();
if (SystemAttributes.CREATED_AT.equals(feature) ||
SystemAttributes.REMOVED_AT.equals(feature) ||
TechnicalAttributes.STATE_VALID_FROM.equals(feature) ||
TechnicalAttributes.STATE_VALID_TO.equals(feature)) {
return predicate;
}
}
List amendment = DateStateViews.getAmendment(
getContext(refContainer)
);
if (amendment == null)
return predicate;
Filter newFilter = new Filter(
original.getCondition(),
original.getOrderSpecifier(),
null // extension
);
newFilter.getCondition().addAll(amendment);
return newFilter;
}
/**
* Retrieve the valid state predicate
*
* @param refContainer
* @param predicate
*
* @return the valid state predicate
*/
private static AnyTypePredicate getValidStatePredicate(
AnyTypePredicate predicate
) {
Filter newFilter;
if (predicate == null) {
newFilter = new Filter(
new IsInstanceOfCondition("org:openmdx:state2:DateState")
);
} else {
QueryFilterRecord original = ((RefQuery_1_0) predicate).refGetFilter();
newFilter = new Filter(
original.getCondition(),
original.getOrderSpecifier(),
null // extension
);
}
newFilter.getCondition().add(
new IsInCondition(
Quantifier.FOR_ALL,
SystemAttributes.REMOVED_AT,
true
)
);
return newFilter;
}
@SuppressWarnings("unchecked")
private static Container getTimeIndependentContainer(
RefContainer super T> refContainer
) {
return (Container) DateStateViews.getPersistenceManager(
refContainer,
null
).getObjectById(
JDOHelper.getTransactionalObjectId(refContainer)
);
}
/**
* Retrieve the states selected by the given predicate
*
* @param container
* @param predicate
*
* @return the states selected by the given predicate
*/
public static List getStates(
Container super T> container,
AnyTypePredicate predicate
) {
RefContainer super T> refContainer = (RefContainer super T>) container;
Container coreContainer = getTimeIndependentContainer(refContainer);
return new StateList(
coreContainer.getAll(
getStatePredicate(refContainer, predicate)
)
);
}
/**
* Retrieve the valid states selected by the given predicate
*
* @param container
* @param predicate
*
* @return the states selected by the given predicate
*/
public static List getValidStates(
Container super T> container,
AnyTypePredicate predicate
) {
RefContainer super T> refContainer = (RefContainer super T>) container;
Container coreContainer = getTimeIndependentContainer(refContainer);
return new StateList(
coreContainer.getAll(
getValidStatePredicate(predicate)
)
);
}
/**
* Retrieve a view appropriate to represent the given state, i.e.
*
* - a time-range view for a valid state
*
- a time-point view for an invalidated state
*
*
* @param state
*
* @return a view representing the given state
*/
static T getViewForState(
T state
) {
if (state == null) {
return null;
} else if (JDOHelper.isDeleted(state)) {
return state;
} else if (state.getRemovedAt() == null) {
getCore(state); // heal if necessary
return DateStateViews.getViewForTimeRange(
state,
state.getStateValidFrom(),
state.getStateValidTo()
);
} else {
XMLGregorianCalendar validFor = state.getStateValidFrom();
if (validFor == null)
validFor = state.getStateValidTo();
if (validFor == null)
validFor = DateStateViews.DEFAULT_VALID_FOR;
return DateStateViews.getViewForTimePoint(
state,
validFor,
state.getCreatedAt()
);
}
}
//------------------------------------------------------------------------
// Core View
//------------------------------------------------------------------------
/**
* Retrieve a context-free view onto the given object
*
* @param refObject
* the object for which a context free view is requested
*
* @return a context-free view onto the given object
*
* @exception NullPointerException
* if refObject is null
*/
@SuppressWarnings("unchecked")
public static C getViewForCore(
S refObject
) {
if (getContext(refObject) == null) {
if (refObject instanceof BasicState) {
return (C) ((BasicState) refObject).getCore();
} else {
return refObject;
}
} else {
return (C) DateStateViews.getPersistenceManager(
refObject,
null
).getObjectById(
JDOHelper.getTransactionalObjectId(refObject)
);
}
}
/**
* Retrieve a context-free view onto the given object or container
*
* @param refBaseObject
* the object or container for which a context free view is requested
*
* @return a context-free view onto the given object or container
*/
@SuppressWarnings("unchecked")
public static C getTimeIndependentView(
RefBaseObject refBaseObject
) {
return (C) (getContext(refBaseObject) == null ? refBaseObject : DateStateViews.getPersistenceManager(
refBaseObject,
null
).getObjectById(
JDOHelper.getTransactionalObjectId(refBaseObject)
));
}
private static boolean equals(
XMLGregorianCalendar left,
XMLGregorianCalendar right
) {
if (left == right) {
return true;
}
if (left == null || right == null) {
return false;
}
if (left instanceof ImmutableDatatype> != right instanceof ImmutableDatatype>) {
ImmutableDatatypeFactory datatypeFactory = DatatypeFactories.immutableDatatypeFactory();
return datatypeFactory.toDate(left).equals(datatypeFactory.toDate(right));
}
return left.equals(right);
}
private static boolean equals(
Date left,
Date right
) {
if (left == right) {
return true;
}
if (left == null || right == null) {
return false;
}
if (left instanceof ImmutableDatatype> != right instanceof ImmutableDatatype>) {
ImmutableDatatypeFactory datatypeFactory = DatatypeFactories.immutableDatatypeFactory();
return datatypeFactory.toDateTime(left).equals(datatypeFactory.toDateTime(right));
}
return left.equals(right);
}
/**
* Retrieve a state's core
*
* @param state
*
* @return a state's core
*/
private static RefObject getCore(
BasicState state
) {
RefObject core = state.getCore();
if (core == null) {
if (state instanceof Legacy && ((Legacy) state).isValidTimeUnique()) {
return state;
}
if (JDOHelper.isDirty(state) && !JDOHelper.isTransactional(state)) {
SysLog.log(
Level.FINE,
"The object {0} with XRI {1} is in state {2}. " +
"Going to make it transactional and to retry",
new Object[] {
JDOHelper.getTransactionalObjectId(state),
state.refMofId(),
JDOHelper.getObjectState(state)
}
);
JDOHelper.getPersistenceManager(state).makeTransactional(state);
core = state.getCore();
if (core == null) {
SysLog.log(
Level.FINE,
"The object {0} with XRI {1} is now in state {2}. " +
"Its core is still unavailable. " +
"Last resort is going to return null.",
new Object[] {
JDOHelper.getTransactionalObjectId(state),
state.refMofId(),
JDOHelper.getObjectState(state)
}
);
} else {
SysLog.log(
Level.FINE,
"The object {0} with XRI {1} is now in state {2}. Its core is {3} with XRI {4}.",
new Object[] {
JDOHelper.getTransactionalObjectId(state),
state.refMofId(),
JDOHelper.getObjectState(state),
JDOHelper.getTransactionalObjectId(core),
core.refMofId()
}
);
}
} else {
SysLog.log(
Level.FINE,
"The object {0} with XRI {1} is in state {2}. " +
"Its core is unavailable. " +
"Last resort is going to return null.",
new Object[] {
JDOHelper.getTransactionalObjectId(state),
state.refMofId(),
JDOHelper.getObjectState(state)
}
);
}
}
return core;
}
/**
* Retrieve a view for a given validity, which is propagated
* through navigation and applied to DateState
instances.
*
* Views to DateState instances are read-only, views to other objects
* are readable and writable.
*
* @param object
* a plain JMI object or a date view
* @param validFor
* exclude all states not valid at the given date,
* use today()
in case of null
* @param validAt
* exclude all states created after the given time point
*
* @return a view to the given object
*
* @exception IllegalArgumentException
* if the object
does not support views
*/
@SuppressWarnings("unchecked")
public static V getViewForTimePoint(
T object,
XMLGregorianCalendar validFor,
Date validAt
) {
if (object == null)
return null;
DateStateContext context = DateStateViews.getContext(object);
RefObject refObject = object;
if (context == null) {
if (object instanceof BasicState) {
refObject = getCore((BasicState) object);
}
} else if (context.getViewKind() == ViewKind.TIME_POINT_VIEW &&
DateStateViews.equals(validAt, context.getExistsAt()) &&
DateStateViews.equals(validFor, context.getValidAt())) {
return (V) object;
}
return (V) DateStateViews.getPersistenceManager(
object,
validFor,
validAt
).getObjectById(
JDOHelper.getTransactionalObjectId(refObject)
);
}
/**
* Retrieve a view for a given validity, which is propagated
* through navigation and applied to DateState
instances.
*
* Views to DateState instances are read-only, views to other objects
* are readable and writable.
*
* @param container
* a plain JMI container or a date view of a container
* @param validFor
* exclude all states not valid at the given date,
* use today()
in case of null
* @param validAt
* exclude all states created after the given time point
*
* @return a view to the given container
*
* @exception IllegalArgumentException
* if the container
is neither null
* nor an instance of RefBaseObject
*/
@SuppressWarnings("unchecked")
public static > T getViewForTimePoint(
T container,
XMLGregorianCalendar validFor,
Date validAt
) {
RefContainer> source = asRefContainer(container);
DateStateContext context = DateStateViews.getContext(source);
if (context != null &&
context.getViewKind() == ViewKind.TIME_POINT_VIEW &&
DateStateViews.equals(validAt, context.getExistsAt()) &&
DateStateViews.equals(validFor, context.getValidAt())) {
return (T) source;
} else {
return (T) DateStateViews.getPersistenceManager(
source,
validFor,
validAt
).getObjectById(
JDOHelper.getTransactionalObjectId(source)
);
}
}
/**
*
* @param
* @param refContext
* @param refPackageClass
* @param validFrom
* @param validTo
* @return
*
* @throws IllegalArgumentException
* if validTo is less than validFrom
*/
@SuppressWarnings("unchecked")
public static T getPackageForTimeRange(
RefBaseObject refContext,
Class refPackageClass,
XMLGregorianCalendar validFrom,
XMLGregorianCalendar validTo
) {
return refContext == null ? null : (T) DateStateViews.getPackageForContext(
refContext,
DateStateViewContext.newTimeRangeViewContext(validFrom, validTo)
).refPackage(
refPackageClass.getName()
);
}
/**
* Retrieve a view for a given period.
*
* @param dateState
* @param packageClass
*
* @return a package for the time range given by dateState
*/
@SuppressWarnings("unchecked")
public static T getPackageForTimeRange(
DateState dateState,
Class packageClass
) {
return DateStateViews.getViewKind(dateState) == ViewKind.TIME_RANGE_VIEW ? (T) dateState.refImmediatePackage()
: DateStateViews.getPackageForTimeRange(
dateState,
packageClass,
dateState.getStateValidFrom(),
dateState.getStateValidTo()
);
}
/**
* Retrieve a view for a given period.
*
* Views to DateState instances are write-only except for stateValidFrom
* and stateValidTo. Attribute modification operations are propagated to
* all included states. Holes remain untouched.
*
* @param refObject
* a plain JMI object or a date state view
* @param validFrom
* exclude all states not valid at or after the given
* date unless validFrom is null
* @param validTo
* exclude all states not valid at or before the given
* date unless validTo is null
*
* @return a view to the given object
*
* @exception IllegalArgumentException
* if the object
does not support views
* or validTo is less than validFrom
*/
@SuppressWarnings("unchecked")
public static V getViewForTimeRange(
T object,
XMLGregorianCalendar validFrom,
XMLGregorianCalendar validTo
) {
DateStateContext context = DateStateViews.getContext(object);
Object objectId;
if (context == null) {
objectId = JDOHelper.getTransactionalObjectId(
object instanceof BasicState ? getCore((BasicState) object) : object
);
} else if (context.getViewKind() == ViewKind.TIME_RANGE_VIEW &&
DateStateViews.equals(validFrom, context.getValidFrom()) &&
DateStateViews.equals(validTo, context.getValidTo())) {
return (V) object;
} else {
objectId = JDOHelper.getTransactionalObjectId(object);
}
DelegatingRefObject_1_0 refView = (DelegatingRefObject_1_0) DateStateViews.getPersistenceManager(
object,
validFrom,
validTo
).getObjectById(
objectId
);
return (V) refView;
}
/**
* Retrieve a view for a given period.
*
* Views to DateState instances are write-only except for stateValidFrom
* and stateValidTo. Attribute modification operations are propagated to
* all included states. Holes remain untouched.
*
* @param refObject
* a plain JMI object or a date state view
* @param validFrom
* exclude all states not valid at or after the given
* date unless validFrom is null
* @param validTo
* exclude all states not valid at or before the given
* date unless validTo is null
*
* @return a view to the given object
*
* @exception IllegalArgumentException
* if the container
is neither null
* nor an instance of RefBaseObject
or if validTo is less than validFrom.
*/
@SuppressWarnings("unchecked")
public static > T getViewForTimeRange(
T container,
XMLGregorianCalendar validFrom,
XMLGregorianCalendar validTo
) {
RefBaseObject refContainer = (RefBaseObject) container;
DateStateContext context = DateStateViews.getContext(refContainer);
if (context != null &&
context.getViewKind() == ViewKind.TIME_RANGE_VIEW &&
DateStateViews.equals(validFrom, context.getValidFrom()) &&
DateStateViews.equals(validTo, context.getValidTo())) {
return container;
} else {
return (T) DateStateViews.getPersistenceManager(
refContainer,
validFrom,
validTo
).getObjectById(
JDOHelper.getTransactionalObjectId(refContainer)
);
}
}
/**
* Retrieve time-range views for the states in a given range
*
*
* Note:
* The border states are represented by views for propagated states if necessary.
*
*
* @param stateCapable
* a plain JMI object or a date state view
* @param validFrom
* exclude all states not valid at or after the given
* date unless validFrom is null
* @param validTo
* exclude all states not valid at or before the given
* date unless validTo is null
*
* @return a view to the given object
*
* @exception IllegalArgumentException
* if the object
does not support views
*/
public static List getCroppedStates(
StateCapable stateCapable,
XMLGregorianCalendar validFrom,
XMLGregorianCalendar validTo
) {
return stateCapable == null ? null : DateStateViews.getStates(
stateCapable,
validFrom,
validTo,
Boolean.FALSE, // invalidated
null, // existsAt
AccessMode.FOR_UPDATE
);
}
/**
* Retrieve a view for the period beginning with the earliest application-time point of any non-removed
* state and ending with the latest application-time point of any non-removed state of this object.
*
* Views to DateState instances are write-only except for stateValidFrom
* and stateValidTo. Attribute modification operations are propagated to
* all included states. Holes inside the given range remain untouched.
*
* @param stateCapable
* a plain JMI object or a date state view
*
* @return a view covering the whole period
*
* @exception IllegalArgumentException
* if the dateState
does not support views
*/
@SuppressWarnings("unchecked")
public static T getViewForLifeTime(
StateCapable stateCapable
) {
if (stateCapable == null)
return null;
List extends DateState> states = DateStateViews.getValidStates(stateCapable);
if (states.isEmpty())
return null;
return (T) DateStateViews.getViewForTimeRange(
stateCapable,
states.get(0).getStateValidFrom(),
states.get(states.size() - 1).getStateValidTo()
);
}
//------------------------------------------------------------------------
// State Propagation Views (readable and writable)
//------------------------------------------------------------------------
/**
* Retrieve a view for a given period.
*
* The attributes are readable and writable.
*
* @param stateClass
* the class of the new state
* @param core
* the underlying date state view
* @param validFrom
* begin of the overridden period
* @param validTo
* end of the overridden period
* @param override
* tells whether it is allowed to override valid states
*
* @return a view to the given object
*
* @throws IllegalArgumentException
* if override is false and the given range is not empty
*/
public static T getViewForInitializedState(
Class stateClass,
StateCapable core,
XMLGregorianCalendar validFrom,
XMLGregorianCalendar validTo,
boolean override
) {
if (core == null)
return null;
PersistenceManager targetManager = DateStateViews.getPersistenceManager(
core,
validFrom,
validTo
);
Object object = targetManager.getObjectById(
JDOHelper.getTransactionalObjectId(core)
);
if (object != null && !JDOHelper.isDeleted(object)) {
if (override) {
targetManager.deletePersistent(object);
} else {
throw BasicException.initHolder(
new IllegalArgumentException(
"The given range is not empty",
BasicException.newEmbeddedExceptionStack(
BasicException.Code.DEFAULT_DOMAIN,
BasicException.Code.DUPLICATE,
ExceptionHelper.newObjectIdParameter(BasicException.Parameter.XRI, core),
new BasicException.Parameter("validFrom", validFrom),
new BasicException.Parameter("validTo", validTo),
new BasicException.Parameter("override", override)
)
)
);
}
}
T range = targetManager.newInstance(stateClass);
linkStateAndCore(range, core);
return range;
}
/**
* Retrieve a view for a given period.
*
* The attributes are readable and writable.
*
* @param source
* the underlying date state view
* @param validFrom
* begin of the overridden period
* @param validTo
* end of the overridden period
* @param override
* tells whether it is allowed to override valid states
*
* @return a view to the given object
*
* @throws IllegalArgumentException
* if override is false and the given range is not empty
*/
@SuppressWarnings("unchecked")
public static T getViewForInitializedState(
T source,
XMLGregorianCalendar validFrom,
XMLGregorianCalendar validTo,
boolean override
) {
if (source == null)
return null;
PersistenceManager persistenceManager = DateStateViews.getPersistenceManager(
source,
validFrom,
validTo
);
T range = (T) persistenceManager.getObjectById(
JDOHelper.getTransactionalObjectId(source)
);
if (range != null && !JDOHelper.isDeleted(range)) {
if (override) {
range.refDelete();
} else {
throw BasicException.initHolder(
new IllegalArgumentException(
"The given range is not empty",
BasicException.newEmbeddedExceptionStack(
BasicException.Code.DEFAULT_DOMAIN,
BasicException.Code.DUPLICATE,
ExceptionHelper.newObjectIdParameter(BasicException.Parameter.XRI, source),
new BasicException.Parameter("validFrom", validFrom),
new BasicException.Parameter("validTo", validTo),
new BasicException.Parameter("override", override)
)
)
);
}
}
range = (T) persistenceManager.newInstance(
source.getClass().getInterfaces()[0]
);
linkStateAndCore(range, (StateCapable) source);
return range;
}
/**
* This method fills the holes in the given time-range but leaves existing
* states before returning a view for the given time-range.
*
* @param stateClass
* @param core
* @param validFrom
* @param validTo
*
* @return a view for the requested time range.
*/
public static T getViewForTimeRangeWithoutHoles(
Class stateClass,
StateCapable core,
XMLGregorianCalendar validFrom,
XMLGregorianCalendar validTo
) {
XMLGregorianCalendar nextFrom = validFrom;
States: for (DateState state : DateStateViews.getValidStates(core, validFrom, validTo)) {
XMLGregorianCalendar nextTo = state.getStateValidFrom();
if (Order.compareValidFrom(nextFrom, nextTo) < 0) {
DateStateViews.createState(core, nextFrom, Order.predecessor(nextTo), stateClass);
}
nextFrom = state.getStateValidTo();
if (nextFrom == null)
break States;
nextFrom = Order.successor(nextFrom);
}
if (nextFrom != null && Order.compareValidTo(nextFrom, validTo) <= 0) {
DateStateViews.createState(core, nextFrom, validTo, stateClass);
}
return stateClass.cast(
DateStateViews.getViewForTimeRange(core, validFrom, validTo)
);
}
/**
* Determine whether the propagation is idempotent or not
*
* @param source
* @param validFrom
* @param validTo
*
* @return true
if the propagation is idempotent
*/
private static boolean isPropagationIdempotent(
DateState source,
XMLGregorianCalendar validFrom,
XMLGregorianCalendar validTo
) {
DateStateContext viewContext = DateStateViews.getContext(source);
if (viewContext.getViewKind() == ViewKind.TIME_POINT_VIEW && viewContext.getExistsAt() != null) {
return false;
} else {
int lowerFlag = Order.compareValidFrom(
source.getStateValidFrom(),
validFrom
);
int upperFlag = Order.compareValidTo(
source.getStateValidTo(),
validTo
);
return lowerFlag <= 0 && upperFlag >= 0;
}
}
/**
* Retrieve a view for a given period.
*
* The attributes are readable and writable.
*
* @param source
* the underlying date state view
* @param validFrom
* begin of the overridden period
* @param validTo
* end of the overridden period
* @param override
* tells whether it is allowed to override valid states
*
* @return a view to the given object
*
* @throws IllegalArgumentException
* if source is deleted or if override is
* false and the given range is occupied by another state
*/
@SuppressWarnings("unchecked")
public static T getViewForPropagatedState(
T source,
XMLGregorianCalendar validFrom,
XMLGregorianCalendar validTo,
boolean override
) {
if (source == null)
return null;
if (JDOHelper.isDeleted(source)) {
throw new IllegalArgumentException(
"The source must not be deleted"
);
}
//
// Compare source and view validity
//
PersistenceManager targetManager = getPersistenceManager(
source,
validFrom,
validTo
);
T target = (T) targetManager.getObjectById(
JDOHelper.getTransactionalObjectId(source)
);
if (!isPropagationIdempotent(source, validFrom, validTo)) {
if (override || target == null) {
T state = (T) targetManager.getObjectById(
DateStateViews.getResourceIdentifierOfClone(source, DateStateViews.EXCLUDE_FROM_STATE_CLONING)
);
state.setStateValidFrom(validFrom);
state.setStateValidTo(validTo);
if (target == null) {
target = state;
} else {
target.refDelete();
}
linkStateAndCore(state, (StateCapable) source);
} else {
signalInterference(source, target);
}
}
return target;
}
/**
* Validate that the requested space is not blocked by another state
*
* @param source
* @param target
*
* @throws IllegalArgumentException
* if the given range is occupied by another state
*/
private static void signalInterference(
DateState source,
DateState target
) {
DateStateContext sourceContext = DateStateViews.getContext(source);
DateState compatibleState = null;
switch (sourceContext.getViewKind()) {
case TIME_RANGE_VIEW:
compatibleState = source;
break;
case TIME_POINT_VIEW:
if (sourceContext.getExistsAt() == null) {
compatibleState = DateStateViews.getViewForTimeRange(
source,
source.getStateValidFrom(),
source.getStateValidTo()
);
}
break;
}
DateStateContext targetContext = DateStateViews.getContext(target);
for (DateState state : DateStateViews.getValidStates(
(StateCapable) source, targetContext.getValidFrom(), targetContext.getValidTo()
)) {
if (state != compatibleState) {
throw BasicException.initHolder(
new IllegalArgumentException(
"There is another valid state in the given period",
BasicException.newEmbeddedExceptionStack(
BasicException.Code.DEFAULT_DOMAIN,
BasicException.Code.DUPLICATE,
ExceptionHelper.newObjectIdParameter(BasicException.Parameter.XRI, source),
new BasicException.Parameter("override", Boolean.FALSE),
new BasicException.Parameter("viewContext", targetContext),
new BasicException.Parameter("stateContext", DateStateViews.getContext(state))
)
)
);
}
}
}
/**
* Retrieve a view for a given period, which is propagated
* through navigation and applied to DateState
instances.
*
* The attributes are readable and writable.
*
* @param dateStateView
* the underlying date state view
* @param validFrom
* begin of the overridden period
* @param validTo
* end of the overridden period
*
* @return a view to the given object
*/
public static T getViewForPropagatedState(
T dateStateView,
XMLGregorianCalendar validFrom,
XMLGregorianCalendar validTo
) {
return DateStateViews.getViewForPropagatedState(
dateStateView,
validFrom,
validTo,
true
);
}
/**
* Clones a state
*
* The attributes are readable and writable.
*
* @param source
* the underlying date state view
* @param validFrom
* begin of the overridden period
* @param validTo
* end of the overridden period
*
* @return a view for the clone
*/
@SuppressWarnings("unchecked")
public static T getViewForClonedState(
T source,
XMLGregorianCalendar validFrom,
XMLGregorianCalendar validTo
) {
T state = (T) DateStateViews.getPersistenceManager(
source,
validFrom,
validTo
).getObjectById(
DateStateViews.getResourceIdentifierOfClone(source, DateStateViews.EXCLUDE_FROM_STATE_CLONING)
);
state.setStateValidFrom(validFrom);
state.setStateValidTo(validTo);
return state;
}
/**
* Clones a state
*
* The attributes are readable and writable.
*
* @param source
* the underlying date state view
*
* @return a view for the clone
*/
public static T getViewForClonedState(
T source
) {
return getViewForClonedState(
source,
source.getStateValidFrom(),
source.getStateValidTo()
);
}
/**
* Clones a core object
*
* The attributes are readable and writable.
*
* @param source
* the underlying
*
* @return a view for the clone
*/
public static T getViewForClonedCore(
T source
) {
return PersistenceHelper.clone(
DateStateViews.getViewForCore(source),
DateStateViews.EXCLUDE_FROM_CORE_CLONING
);
}
/**
* Retrieve states by their core reference
*
* @param refContainer
* @param resourceIdentifier
*
* @return the states belonging to a core object
*/
private static List getRawStates(
RefContainer refContainer,
Object... resourceIdentifier
) {
return refContainer.refGetAll(
new Filter(
new IsInstanceOfCondition(
"org:openmdx:state2:DateState"
),
new IsInCondition(
Quantifier.THERE_EXISTS,
SystemAttributes.CORE,
true,
resourceIdentifier
)
)
);
}
/**
* Retrieve states
*
* @param referenceCollection
* the result of the parent view's getXXX() method
* @param validFrom
* include all states ending at validFrom or later
* @param validTo
* include all states beginning at validTo or earlier
* @param invalidated
* tells whether valid or invalid states excluded
*
* null
: Neither valid nor invalid states are excluded
* TRUE
: Valid states are excluded
* FALSE
: Invalid states are excluded
*
* @param qualifiers
* the objects' qualifiers
* @return a collection of DateState instances
*
* @throws IllegalArgumentException
* if validTo is less than validFrom
*/
@SuppressWarnings("unchecked")
private static List getStates(
Container super T> referenceCollection,
XMLGregorianCalendar validFrom,
XMLGregorianCalendar validTo,
Boolean invalidated,
String... qualifiers
) {
Order.assertTimeRange(validFrom, validTo);
Path containerId = (Path) JDOHelper.getObjectId(referenceCollection);
RefContainer contextFreeContainer = (RefContainer) DateStateViews.getPersistenceManager(
((RefContainer) referenceCollection),
null
).getObjectById(
JDOHelper.getTransactionalObjectId(referenceCollection)
);
Object[] resourceIdentifiers = new Object[qualifiers.length];
int i = 0;
for (String qualifier : qualifiers) {
resourceIdentifiers[i++] = containerId == null ? JDOHelper.getTransactionalObjectId(
qualifier.startsWith("!") ? contextFreeContainer.refGet(
QualifierType.PERSISTENT,
qualifier.substring(1)
) : contextFreeContainer.refGet(
QualifierType.REASSIGNABLE,
qualifier
)
) : containerId.getChild(
qualifier
);
}
return new FilteredStates(
DateStateViews.getRawStates(
contextFreeContainer,
resourceIdentifiers
),
validFrom,
validTo,
invalidated,
null,
AccessMode.FOR_QUERY
);
}
/**
* Retrieve states
*
* @param referenceCollection
* the result of the parent view's getXXX() method
* @param invalidated
* tells whether valid or invalid states excluded
*
* null
: Neither valid nor invalid states are excluded
* TRUE
: Valid states are excluded
* FALSE
: Invalid states are excluded
*
* @param qualifiers
* the objects' qualifiers
* @return a collection of DateState instances
*/
public static List getStates(
Container super T> referenceCollection,
Boolean invalidated,
String... qualifiers
) {
return DateStateViews.getStates(
referenceCollection,
null, // validFrom
null, // validTo
invalidated,
qualifiers
);
}
/**
* Retrieve states
*
* @param referenceCollection
* the result of the parents getXXX() method
* @param qualifier
* the object's qualifier
* @param includeValidStates
* tells whether the invalidatedAt attribute may be non-null
* @param includeInvalidStates
* tells whether the invalidatedAt attribute may be null
* @return a collection of DateState instances
*/
public static List getStates(
Container super T> referenceCollection,
String qualifier,
boolean includeValidStates,
boolean includeInvalidStates
) {
return includeValidStates || includeInvalidStates ? DateStateViews.getStates(
referenceCollection,
includeInvalidStates && includeValidStates ? null : Boolean.valueOf(includeInvalidStates),
qualifier
) : Collections.emptyList();
}
/**
* Retrieve valid states
*
* @param referenceCollection
* the result of the parents getXXX() method
* @param validFrom
* include all states ending at validFrom or later
* @param validTo
* include all states beginning at validTo or earlier
* @param qualifiers
* the objects' qualifiers
*
* @return a list of DateState instances
*/
public static List getValidStates(
Container super T> referenceCollection,
XMLGregorianCalendar validFrom,
XMLGregorianCalendar validTo,
String... qualifiers
) {
return DateStateViews.getStates(
referenceCollection,
validFrom,
validTo,
Boolean.FALSE,
qualifiers
);
}
/**
* Retrieve all valid states
*
* @param referenceCollection
* the result of the parents getXXX() method
* @param qualifiers
* the objects' qualifiers
*
* @return a list of DateState instances
*/
public static List getValidStates(
Container super T> referenceCollection,
String... qualifiers
) {
return DateStateViews.getStates(
referenceCollection,
null, // validFrom
null, // validTo
Boolean.FALSE, // invalidated
qualifiers
);
}
/**
* Retrieve states
*
* @param stateCapable
* a plain JMI object or a date state view
* @param validFrom
* include all states ending at validFrom or later
* @param validTo
* include all states beginning at validTo or earlier
* @param invalidated
* tells whether valid or invalid states excluded
*
* null
: Neither valid nor invalid states are excluded
* TRUE
: Valid states are excluded
* FALSE
: Invalid states are excluded
*
* @param existsAt
* @param mode
* @return a collection of DateState instance
*
* @throws IllegalArgumentException
* if validTo is less than validFrom
*/
@SuppressWarnings("unchecked")
private static List getStates(
StateCapable stateCapable,
XMLGregorianCalendar validFrom,
XMLGregorianCalendar validTo,
Boolean invalidated,
Date existsAt,
AccessMode mode
) {
Order.assertTimeRange(validFrom, validTo);
DataObject_1_0 dataObject = DataObjects.getDataObject(stateCapable);
UUID objectId = (UUID) JDOHelper.getTransactionalObjectId(dataObject);
TransientContainerId containerId = (TransientContainerId) JDOHelper.getTransactionalObjectId(dataObject.getContainer(false));
RefContainer refContainer = (RefContainer) DateStateViews.getPersistenceManager(stateCapable, null).getObjectById(
containerId
);
return new FilteredStates(
DateStateViews.getRawStates(refContainer, objectId),
validFrom,
validTo,
invalidated,
existsAt,
mode
);
}
/**
* Retrieve states
*
* @param stateCapable
* a plain JMI object or a date state view
* @param invalidated
* tells whether valid or invalid states excluded
*
* null
: Neither valid nor invalid states are excluded
* TRUE
: Valid states are excluded
* FALSE
: Invalid states are excluded
*
* @return a collection of DateState instances matching the given criteria
*/
public static List getStates(
StateCapable stateCapable,
Boolean invalidated
) {
return stateCapable == null ? null : DateStateViews.getStates(
stateCapable,
null, // validFrom
null, // validTo
invalidated,
null,
AccessMode.FOR_QUERY
);
}
/**
* Retrieve states
*
* @param stateCapable
* a plain JMI object or a date state view
* @param includeValidStates
* tells whether the invalidatedAt attribute may
* be non-null
* @param includeInvalidStates
* tells whether the invalidatedAt attribute
* may be null
*
* @return a collection of DateState instances
*/
public static Collection getStates(
StateCapable stateCapable,
boolean includeValidStates,
boolean includeInvalidStates
) {
return includeValidStates || includeInvalidStates ? DateStateViews.getStates(
stateCapable,
includeInvalidStates && includeValidStates ? null : Boolean.valueOf(includeInvalidStates)
) : Collections.emptySet();
}
/**
* Retrieve valid states
*
* @param dateState
* a plain JMI object or a date state view
* @param validFrom
* include all states ending at validFrom or later
* @param validTo
* include all states beginning at validTo or earlier
*
* @return a list of DateState instances
*
* @throws IllegalArgumentException
* if validTo is less than validFrom
*/
public static List getValidStates(
StateCapable dateState,
XMLGregorianCalendar validFrom,
XMLGregorianCalendar validTo
) {
return dateState == null ? null : DateStateViews.getStates(
dateState,
validFrom,
validTo,
Boolean.FALSE, // invalidated
null, // existsAt
AccessMode.FOR_QUERY
);
}
/**
* Retrieve valid states
*
* @param dateState
* a plain JMI object or a date state view
*
* @return a list of DateState instances
*/
public static List getValidStates(
StateCapable dateState
) {
return dateState == null ? null : DateStateViews.getValidStates(
dateState,
(XMLGregorianCalendar) null,
(XMLGregorianCalendar) null
);
}
/**
* Retrieve states involved in the current view
*
* @param dateState
* a plain JMI object or a date state view
*
* @return a list of DateState instances
*/
@SuppressWarnings("unchecked")
public static List getStatesInvolvedInView(
StateCapable dateState
) {
DateStateContext context = DateStateViews.getContext(dateState);
return context == null ? DateStateViews.getValidStates(dateState)
: context.getViewKind() == ViewKind.TIME_POINT_VIEW ? Collections.singletonList((T) dateState)
: DateStateViews.getValidStates(dateState, context.getValidFrom(), context.getValidTo());
}
@SuppressWarnings("unchecked")
public static T getViewForContext(
RefBaseObject context,
T value
) {
if (context == null || value == null) {
return value;
} else {
PersistenceManager actual = JDOHelper.getPersistenceManager(value);
PersistenceManager expected = JDOHelper.getPersistenceManager(context);
return actual == expected ? value : (T) expected.getObjectById(JDOHelper.getTransactionalObjectId(value));
}
}
//------------------------------------------------------------------------
// Date State Context
//------------------------------------------------------------------------
/**
* Retrieve the context for date state views.
*
* @param jmiContext
* a plain JMI object or a date state view
*
* @return the DateStateContext
in case of a
* Date State View, null
otherwise.
*/
public static DateStateContext getContext(
RefBaseObject jmiContext
) {
if (jmiContext != null) {
RefPackage refPackage = jmiContext.refOutermostPackage();
if (refPackage instanceof RefPackage_1_0) {
InteractionSpec interactionSpec = ((RefPackage_1_0) refPackage).refInteractionSpec();
if (interactionSpec instanceof DateStateContext) {
return (DateStateContext) interactionSpec;
}
}
}
return null;
}
/**
* Retrieve a JMI context's view kind
*
* @param jmiContext
* a JMI context
*
* @return the view kind, or null
if the view context is null
*/
public static ViewKind getViewKind(
RefBaseObject jmiContext
) {
DateStateContext viewContext = DateStateViews.getContext(jmiContext);
return viewContext == null ? null : viewContext.getViewKind();
}
/**
* Tests whether a given object is readable
*
* @param refObject
* a plain JMI object or a date state view
*
* @return true
unless one of the following conditions is met
*
* refObject
is null
* refObject
is deleted
* - all if the following conditions are
true
*
* refObject instanceof DateState
* - getViewKind(refObject) == ViewKind.TIME_RANGE_VIEW
*
-
*
newInstance()
orcreate…()
*getStates()
*getValidStates()
*getViewForInitializedState()
*getViewForPropagatedState()
*
true
if the view refers to a single state
*
* @throws IllegalArgumentException
* if there is no date-state context
*/
public static boolean representsSingleState(
DateState state
) {
ViewKind viewKind = DateStateViews.getViewKind(state);
if (viewKind == null) {
throw new IllegalArgumentException("DateState context lacking");
}
switch (viewKind) {
case TIME_POINT_VIEW:
return true;
case TIME_RANGE_VIEW:
List periodFactory
) {
Map periods = getPeriods(jmiManager, result, core);
if (dataObject.objGetValue(SystemAttributes.REMOVED_AT) == null) {
final XMLGregorianCalendar stateValidFrom = (XMLGregorianCalendar) dataObject.objGetValue(TechnicalAttributes.STATE_VALID_FROM);
final XMLGregorianCalendar stateValidTo = (XMLGregorianCalendar) dataObject.objGetValue(TechnicalAttributes.STATE_VALID_TO);
periods.add(periodFactory.newPeriod(stateValidFrom, stateValidTo));
}
} else {
getPeriods(jmiManager, result, dataObject);
}
}
} catch (ServiceException exception) {
throw new RuntimeServiceException(exception);
}
return result;
}
/**
* Populates the cache
*
* @param container
* the container
*/
public static getPeriods(
PersistenceManager manager, Map periods = result.get(key);
if (periods == null) {
result.put(key, periods = new HashSet ());
}
return periods;
}
/**
* Retrieve the states selected by the given predicate
*
* @param container the container
* @param predicate the predicate
* @param consumer the state consumer
*
* @return the states selected by the given predicate
*/
public static DateState
comparator
*/
private final static Comparator