Content of file PriorityAsSupport.java.html

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../../jacoco-resources/report.gif" type="image/gif"/><title>PriorityAsSupport.java</title><link rel="stylesheet" href="../../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../../index.html" class="el_report">blueMarine II :: Media Scanner</a> &gt; <a href="../index.html" class="el_bundle">it-tidalwave-bluemarine2-commons</a> &gt; <a href="index.source.html" class="el_package">it.tidalwave.util.spi</a> &gt; <span class="el_source">PriorityAsSupport.java</span></div><h1>PriorityAsSupport.java</h1><pre class="source lang-java linenums">/*
 * *********************************************************************************************************************
 *
 * blueMarine II: Semantic Media Centre
 * http://tidalwave.it/projects/bluemarine2
 *
 * Copyright (C) 2015 - 2021 by Tidalwave s.a.s. (http://tidalwave.it)
 *
 * *********************************************************************************************************************
 *
 * Licensed under the Apache License, Version 2.0 (the &quot;License&quot;); 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 &quot;AS IS&quot; 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.
 *
 * *********************************************************************************************************************
 *
 * git clone https://bitbucket.org/tidalwave/bluemarine2-src
 * git clone https://github.com/tidalwave-it/bluemarine2-src
 *
 * *********************************************************************************************************************
 */
package it.tidalwave.util.spi;

import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import it.tidalwave.util.As;
import it.tidalwave.util.AsException;
import it.tidalwave.dci.annotation.DciRole;
import lombok.extern.slf4j.Slf4j;

/***********************************************************************************************************************
 *
 * A specialisation of {@link AsSupport} that deals with multiple roles of the same type by prioritising them; they
 * are ordered from most relevant to least relevant (where relevance is associated to specialisation, that is most
 * specialised roles, or roles associated via {@code @DciRole} to most specialised datum classes, are most relevant).
 *
 * FIXME: could be seen as a replacement to {@code AsSupport}?
could be seen as a replacement to {@code AsSupport}?
* * @author Fabrizio Giudici * **********************************************************************************************************************/ <span class="fc" id="L51">@Slf4j</span> public class PriorityAsSupport extends AsSupport implements As { @FunctionalInterface public static interface RoleProvider { @Nonnull public &lt;T&gt; Collection&lt;T&gt; findRoles (@Nonnull final Class&lt;T&gt; type); } @Nonnull private final Object owner; // for logging only @Nonnull private final Optional&lt;RoleProvider&gt; additionalRoleProvider; public PriorityAsSupport (final Object owner) { <span class="fc" id="L69"> this(owner, Collections.emptyList());</span> <span class="fc" id="L70"> }</span> public PriorityAsSupport (@Nonnull final Object owner, @Nonnull final Collection&lt;Object&gt; rolesOrFactories) { <span class="fc" id="L74"> super(owner, rolesOrFactories);</span> <span class="fc" id="L75"> this.owner = owner;</span> <span class="fc" id="L76"> this.additionalRoleProvider = Optional.empty();</span> <span class="fc" id="L77"> }</span> public PriorityAsSupport (@Nonnull final Object owner, @Nonnull final RoleProvider additionalRoleProvider, @Nonnull final Collection&lt;Object&gt; rolesOrFactories) { <span class="nc" id="L83"> super(owner, rolesOrFactories);</span> <span class="nc" id="L84"> this.owner = owner;</span> <span class="nc" id="L85"> this.additionalRoleProvider = Optional.of(additionalRoleProvider);</span> <span class="nc" id="L86"> }</span> /******************************************************************************************************************* * * {@inheritDoc} * * Returned roles can be associated both to this type and to the delegate; the one with the higher priority is * returned. See {@link #asMany(java.lang.Class)} for further details. * * @see #asMany(java.lang.Class) * ******************************************************************************************************************/ @Override @Nonnull public &lt;T&gt; T as (@Nonnull final Class&lt;T&gt; type) { <span class="fc" id="L101"> return as(type, As.Defaults.throwAsException(type));</span> } /******************************************************************************************************************* * * {@inheritDoc} * * Returned roles can be associated both to this type and to the delegate; the one with the higher priority is * returned. See {@link #asMany(java.lang.Class)} for further details. * * @see #asMany(java.lang.Class) * ******************************************************************************************************************/ @Override @Nonnull public &lt;T&gt; T as (@Nonnull final Class&lt;T&gt; type, @Nonnull final NotFoundBehaviour&lt;T&gt; notFoundBehaviour) { <span class="pc" id="L117"> return maybeAs(type).orElseGet(() -&gt; notFoundBehaviour.run(new AsException(type)));</span> } /******************************************************************************************************************* * * {@inheritDoc} * * Returned roles can be associated both to this type and to the delegate; the one with the higher priority is * returned. See {@link #asMany(java.lang.Class)} for further details. * * @see #asMany(java.lang.Class) * ******************************************************************************************************************/ @Override @Nonnull public &lt;T&gt; Optional&lt;T&gt; maybeAs (@Nonnull final Class&lt;T&gt; type) { <span class="fc" id="L133"> return asMany(type).stream().findFirst();</span> } /******************************************************************************************************************* * * {@inheritDoc} * * Returned roles can be associated both to this type and to the delegate; the one with the higher priority is * returned. The ones associated to this type come with higher priority (this makes sense, being this class a * decorator, specific roles could be associated to it). But given that the default implementation of asMany() * doesn't guarantee ant order (see TFT-192) there's something to take care of. Currently this method contains * some hardwired priority logics. * ******************************************************************************************************************/ @Override @Nonnull public &lt;T&gt; Collection&lt;T&gt; asMany (@Nonnull final Class&lt;T&gt; type) { <span class="fc" id="L150"> log.trace(&quot;asMany({}) - {}&quot;, type, owner);</span> <span class="fc" id="L151"> final List&lt;T&gt; unordered = new ArrayList&lt;&gt;(super.asMany(type));</span> <span class="pc" id="L152"> additionalRoleProvider.ifPresent(r -&gt; unordered.addAll(r.findRoles(type)));</span> // // Need a kind of bubble sort, because: // a) the original sequence might have a meaning; for instance, additional roles added by // additionalRoleProvider are appended and, generally, they should stay low in priority. // b) there is not always a well-defined way to define a relation order between the elements. // <span class="fc" id="L159"> final List&lt;T&gt; result = new ArrayList&lt;&gt;();</span> <span class="fc" id="L160"> unordered.forEach(item -&gt; addInOrder(result, item));</span> <span class="fc" id="L161"> log.trace(&quot;&gt;&gt;&gt;&gt; returning {}&quot;, result);</span> <span class="fc" id="L163"> return result;</span> } /******************************************************************************************************************* * * Adds an item to the list, just before the first existing item which whose datum class is an instance of a * subclass of its datum class. * ******************************************************************************************************************/ private static &lt;T&gt; void addInOrder (@Nonnull final List&lt;T&gt; list, @Nonnull final T item) { <span class="fc" id="L174"> log.trace(&quot;&gt;&gt;&gt;&gt; add in order {} into {}&quot;, item, list);</span> <span class="pc" id="L175"> final Optional&lt;T&gt; firstAncestor = list.stream().filter(i -&gt; isDatumAncestor(i, item)).findFirst();</span> <span class="fc" id="L176"> final int index = firstAncestor.map(list::indexOf).orElse(list.size());</span> <span class="fc" id="L177"> list.add(index, item);</span> <span class="fc" id="L178"> log.trace(&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; add in order {} &quot;, list);</span> <span class="fc" id="L179"> }</span> /******************************************************************************************************************* * ******************************************************************************************************************/ private static &lt;T&gt; boolean isDatumAncestor (@Nonnull final T a, @Nonnull final T b) { <span class="nc" id="L186"> final DciRole aBoundDatumClass = a.getClass().getAnnotation(DciRole.class);</span> <span class="nc" id="L187"> final DciRole bBoundDatumClass = b.getClass().getAnnotation(DciRole.class);</span> <span class="nc bnc" id="L189" title="All 4 branches missed."> if ((aBoundDatumClass != null) &amp;&amp; (bBoundDatumClass != null))</span> { <span class="nc" id="L191"> return aBoundDatumClass.datumType()[0].isAssignableFrom(bBoundDatumClass.datumType()[0]); // FIXME: multiple classes?</span> } <span class="nc" id="L194"> return a.getClass().isAssignableFrom(b.getClass());</span> } } </pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.7.202105040129</span></div></body></html>