001package org.biopax.paxtools.controller;
002
003import org.apache.commons.logging.Log;
004import org.apache.commons.logging.LogFactory;
005import org.biopax.paxtools.model.BioPAXElement;
006import org.biopax.paxtools.util.IllegalBioPAXArgumentException;
007
008import java.util.HashSet;
009import java.util.Set;
010
011/**
012 * This class is a transitive decorator for PropertyAccessors. BioPAX has transitive properties, 
013 * such as: memberEntityReference, memberEntityFeature, memberPhysicalEntity, component. 
014 * These all represent nested containment relationships.
015 *
016 * When decorating a suitable property accessor this accessor will traverse the whole nesting hierarchy and bring all
017 * children( or if inverse parents). For example when used on a {@link org.biopax.paxtools.model.level3.Complex#getComponent()}
018 * it will not only return the immediate components but also the components of the components.
019 */
020public class TransitivePropertyAccessor<R extends BioPAXElement, D extends R> extends DecoratingPropertyAccessor<D, R>
021{
022        private final static Log log = LogFactory.getLog(TransitivePropertyAccessor.class);
023        
024        private TransitivePropertyAccessor(PropertyAccessor<D, R> accessor)
025        {
026                super(accessor);
027        }
028
029        @Override public Set<? extends R> getValueFromBean(D bean) throws IllegalBioPAXArgumentException
030        {
031                Set<R> values = new HashSet<R>();
032
033                transitiveGet(bean, values);
034                return values;
035        }
036
037
038        private void transitiveGet(D bean, Set<R> values)
039        {
040                Set<? extends R> valuesFromBean = impl.getValueFromBean(bean);
041                for (R value : valuesFromBean)
042                {
043                        if(values.add(value))
044                        {
045                                //if(impl.getDomain().isInstance(value)) - unnecessary as the impl does that check
046                                transitiveGet((D) value, values);
047                        }
048                        else {
049                                //report loop
050                                log.debug("Escaped an inf. loop (" + impl+ ") at " + value.getRDFId());
051                        }
052                }
053        }
054
055        public static < R extends BioPAXElement, D extends R> TransitivePropertyAccessor<R, D> create(
056                        PropertyAccessor<D, R> pa)
057        {
058                return new TransitivePropertyAccessor<R,D>(pa);
059        }
060
061}