• Views
  • Iteration Report
  • My Iteration Report
  •  
OMERO.server
  • Login
  • Help/Guide
  • About Trac
  • Preferences
  • Wiki
  • Timeline
  • Roadmap
  • Browse Source
  • View Tickets
  • Search

Context Navigation

  • ← Previous Changeset
  • Next Changeset →

Changeset 1024

Show
Ignore:
Timestamp:
10/09/06 15:25:26 (2 years ago)
Author:
jmoore
Message:

#334 Merged RenderingEngineImpl? into RenderingBean? (also for #212 and #326)

Location:
trunk/components
Files:
1 removed
4 modified

  • common/src/omeis/providers/re/RenderingEngine.java (modified) (2 diffs)
  • rendering/src/omeis/providers/re/RenderingEngineImpl.java (deleted)
  • server/resources/ome/services/service-ome.api.IThumb.xml (modified) (1 diff)
  • server/resources/ome/services/service-omeis.providers.re.RenderingEngine.xml (modified) (2 diffs)
  • server/src/ome/services/RenderingBean.java (modified) (8 diffs)

Legend:

Unmodified
Added
Removed
  • trunk/components/common/src/omeis/providers/re/RenderingEngine.java

    r862 r1024  
    4343import ome.model.enums.Family; 
    4444import ome.model.enums.RenderingModel; 
     45import ome.model.meta.Event; 
     46import ome.system.EventContext; 
    4547import ome.system.SelfConfigurableService; 
    4648import omeis.providers.re.codomain.CodomainMapContext; 
    … …  
    115117        public void load(); 
    116118     
     119        /** Returns the current {@link EventContext} for this instance. This is 
     120         * useful for later identifying changes made by this {@link Event}. 
     121         */ 
     122        public EventContext getCurrentEventContext(); 
     123         
    117124        /** 
    118125     * Specifies the model that dictates how transformed raw data has to be  
  • trunk/components/server/resources/ome/services/service-ome.api.IThumb.xml

    r966 r1024  
    3838  <bean parent="level2" id="internal:ome.api.IThumb" class="ome.logic.ThumbImpl"> 
    3939    <property name="ioService" ref="/OME/OMEIS/Thumbs"/> 
    40     <property name="renderingEngine" ref="internal:ome.services.RenderingWrapper"/> 
     40    <property name="renderingEngine" ref="internal:omeis.providers.re.RenderingEngine"/> 
    4141    <property name="scaleService" ref="internal:ome.api.IScale"/> 
    4242  </bean> 
  • trunk/components/server/resources/ome/services/service-omeis.providers.re.RenderingEngine.xml

    r903 r1024  
    3636<beans>  
    3737 
    38   <bean singleton="false" parent="binary" 
     38  <bean singleton="false" parent="level2" 
    3939        id="internal:omeis.providers.re.RenderingEngine"  
    40      class="omeis.providers.re.RenderingEngineImpl"> 
     40     class="ome.services.RenderingBean"> 
     41        <!-- following copied from parent="binary" --> 
     42    <property name="pixelsMetadata" ref="internal:ome.api.IPixels"/> 
     43    <property name="pixelsData"     ref="/OME/OMEIS/Pixels"/> 
    4144  </bean> 
    4245 
    … …  
    4649  </bean> 
    4750 
    48   <bean singleton="false" parent="level2" 
    49         id="internal:ome.services.RenderingWrapper"  
    50      class="ome.services.RenderingBean"> 
    51      <property name="delegate" ref="internal:omeis.providers.re.RenderingEngine"/> 
    52   </bean> 
    53    
    54   <bean id="managed:ome.services.RenderingWrapper" parent="managedService"> 
    55     <property name="proxyInterfaces" value="ome.services.RenderingWrapper"/> 
    56     <property name="target" ref="internal:omeis.providers.re.RenderingEngine"/> 
    57   </bean> 
    5851</beans> 
  • trunk/components/server/src/ome/services/RenderingBean.java

    r922 r1024  
    3131 
    3232// Java imports 
     33import java.io.IOException; 
    3334import java.io.Serializable; 
    3435import java.util.ArrayList; 
    3536import java.util.List; 
     37import java.util.concurrent.locks.ReentrantReadWriteLock; 
    3638 
    3739import javax.annotation.PostConstruct; 
    … …  
    4850 
    4951// Third-party libraries 
     52import org.apache.commons.logging.Log; 
     53import org.apache.commons.logging.LogFactory; 
    5054import org.jboss.annotation.ejb.LocalBinding; 
    5155import org.jboss.annotation.ejb.RemoteBinding; 
    … …  
    5357import org.jboss.annotation.security.SecurityDomain; 
    5458import org.jboss.ejb3.cache.NoPassivationCache; 
     59import org.springframework.transaction.annotation.Transactional; 
    5560 
    5661// Application-internal dependencies 
    5762import ome.annotations.RevisionDate; 
    5863import ome.annotations.RevisionNumber; 
     64import ome.api.IPixels; 
    5965import ome.api.ServiceInterface; 
     66import ome.conditions.ApiUsageException; 
     67import ome.conditions.InternalException; 
     68import ome.conditions.ResourceError; 
     69import ome.conditions.ValidationException; 
     70import ome.io.nio.PixelBuffer; 
     71import ome.io.nio.PixelsService; 
    6072import ome.logic.AbstractLevel2Service; 
    6173import ome.model.IObject; 
    6274import ome.model.core.Channel; 
    6375import ome.model.core.Pixels; 
     76import ome.model.display.ChannelBinding; 
    6477import ome.model.display.QuantumDef; 
     78import ome.model.display.RenderingDef; 
    6579import ome.model.enums.Family; 
    6680import ome.model.enums.RenderingModel; 
     81import ome.system.EventContext; 
     82import ome.system.SimpleEventContext; 
    6783import ome.util.ShallowCopy; 
    6884 
    6985import omeis.providers.re.RGBBuffer; 
     86import omeis.providers.re.Renderer; 
    7087import omeis.providers.re.RenderingEngine; 
    71 import omeis.providers.re.RenderingEngineImpl; 
    7288import omeis.providers.re.codomain.CodomainMapContext; 
    7389import omeis.providers.re.data.PlaneDef; 
    74  
    75 interface RenderingWrapper extends RenderingEngine {} 
     90import omeis.providers.re.quantum.QuantizationException; 
    7691 
    7792/** 
    78  * Provides the {@link RenderingEngine} service. This class is a serializable  
    79  * wrapper around {@link RenderingEngineImpl}. 
     93 * Provides the {@link RenderingEngine} service. This class is an Adapter to 
     94 * wrap the {@link Renderer} so to make it thread-safe. 
     95 * <p> 
     96 * The multi-threaded design of this component is based on dynamic locking and 
     97 * confinement techiniques. All access to the component's internal parts happens 
     98 * through a <code>RenderingEngineImpl</code> object, which is fully 
     99 * synchronized. Internal parts are either never leaked out or given away only 
     100 * if read-only objects. (The only exception are the {@link CodomainMapContext} 
     101 * objects which are not read-only but are copied upon every method invocation 
     102 * so to maintain safety.) 
     103 * </p> 
     104 * <p> 
     105 * Finally the {@link RenderingEngine} component doesn't make use of constructs 
     106 * that could compromise liveness. 
     107 * </p> 
    80108 *  
    81  * @author  Josh Moore, josh.moore at gmx.de 
     109 * @author Jean-Marie Burel &nbsp;&nbsp;&nbsp;&nbsp; <a 
     110 *         href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a> 
     111 * @author <br> 
     112 *         Andrea Falconi &nbsp;&nbsp;&nbsp;&nbsp; <a 
     113 *         href="mailto:a.falconi@dundee.ac.uk"> a.falconi@dundee.ac.uk</a> 
     114 * @version 2.2 <small> (<b>Internal version:</b> $Revision: 1.4 $ $Date: 
     115 *          2005/07/05 16:13:52 $) </small> 
     116 * @since OME2.2 
     117 * @author Andrea Falconi, a.falconi at dundee.ac.uk 
     118 * @author Chris Allan, callan at blackcat.ca 
     119 * @author Jean-Marie Burel, j.burel at dundee.ac.uk 
     120 * @author Josh Moore, josh.moore at gmx.de 
    82121 * @version $Revision$, $Date$ 
    83  * @since   3.0-M3 
     122 * @see RenderingEngine 
     123 * @since 3.0-M3 
    84124 */ 
    85125@RevisionDate("$Date$") 
    86126@RevisionNumber("$Revision$") 
     127 
    87128@Stateful 
    88129@Remote(RenderingEngine.class) 
    … …  
    92133@SecurityDomain("OmeroSecurity") 
    93134@Cache(NoPassivationCache.class) 
     135@Transactional // TODO previously not here. examine the difference. 
    94136public class RenderingBean extends AbstractLevel2Service  
    95     implements RenderingWrapper, Serializable 
     137    implements RenderingEngine, Serializable 
    96138{ 
    97139 
    98     private static final long serialVersionUID = -4383698215540637038L; 
    99  
    100     private transient RenderingEngine delegate; 
    101  
    102     public final void setDelegate(RenderingEngine delegate) { 
    103         throwIfAlreadySet(this.delegate, delegate); 
    104                 this.delegate = delegate; 
    105         } 
     140    private static final long serialVersionUID = -4383698215540637039L; 
     141     
     142    private static final Log log = LogFactory.getLog(RenderingBean.class); 
    106143     
    107144    @Override 
    108145    protected Class<? extends ServiceInterface> getServiceInterface() { 
    109         return RenderingWrapper.class; 
     146        return RenderingEngine.class; 
     147    } 
     148     
     149    // ~ State 
     150        // ========================================================================= 
     151     
     152    /* 
     153     * LIFECYCLE:  
     154     * 1. new() || new(Services[])  
     155     * 2. (lookupX || useX)+ && load   
     156     * 3. call methods  
     157     * 4. optionally: return to 2. 
     158     * 5. destroy()  
     159     * 
     160     * TODO: when a setXXX() method is called, when do I reload? always? 
     161     * or ondirty? 
     162     */ 
     163 
     164    /** 
     165     * Transforms the raw data. Entry point to the unsych parts of the component. 
     166     * As soon as Renderer is not null, the Engine is ready to use. 
     167     */ 
     168    private transient Renderer                       renderer; 
     169     
     170    /** The pixels set to the rendering engine is for. */ 
     171    private transient Pixels                         pixelsObj; 
     172     
     173    /** The rendering settings associated to the pixels set. */ 
     174    private transient RenderingDef                   rendDefObj; 
     175     
     176    /** Reference to the service used to retrieve the pixels data. */ 
     177    private transient PixelsService                  pixDataSrv; 
     178     
     179    /** Reference to the service used to retrieve the pixels metadata. */ 
     180    private transient IPixels                        pixMetaSrv; 
     181     
     182    /** read-write lock to prevent READ-calls during WRITE operations. Unneeded 
     183     * for remote invocations (EJB synchronizes). 
     184     */ 
     185    private transient ReentrantReadWriteLock         rwl  
     186        = new ReentrantReadWriteLock(); 
     187     
     188    /** set injector. For use during configuration. Can only be called once. */ 
     189    public void setPixelsMetadata(IPixels metaService) 
     190    { 
     191        this.throwIfAlreadySet(this.pixMetaSrv, metaService); 
     192        pixMetaSrv = metaService; 
     193    } 
     194     
     195    /** set injector. For use during configuration. Can only be called once. */ 
     196    public void setPixelsData(PixelsService dataService) 
     197    { 
     198        throwIfAlreadySet(this.pixDataSrv, dataService); 
     199        pixDataSrv = dataService; 
    110200    } 
    111201     
    … …  
    113203        // ========================================================================= 
    114204     
     205    /** lifecycle method -- {@link PostActivate} and {@link PostConstruct}.  
     206     * Delegates to super class */ 
    115207    @PostActivate 
    116208    @PostConstruct 
     209    @Override 
    117210    public void create() 
    118211    { 
    … …  
    120213    } 
    121214 
     215    /** lifecycle method -- {@link PrePassivate}. Disallows all passivation. */ 
    122216    @PrePassivate 
    123217    public void passivate() 
    … …  
    126220    } 
    127221     
     222    /** lifecycle method -- {@link PreDestroy}. Nulls {@link Renderer} instance 
     223     * and delegates to super class with {@link ReentrantReadWriteLock write lock} 
     224     */ 
    128225    @PreDestroy 
     226    @Override 
    129227    public void destroy() 
    130228    { 
    131         super.destroy(); 
    132         delegate = null; 
    133     } 
    134      
    135     // ~ DELEGATION 
    136     // ========================================================================= 
    137  
     229        rwl.writeLock().lock(); 
     230 
     231        try { 
     232            renderer = null; // marks as unready. all other state is marked transient. 
     233            super.destroy(); 
     234        } finally { 
     235            rwl.writeLock().unlock(); 
     236        } 
     237    } 
     238     
     239    /* 
     240     * SETTERS for use in dependency injection. All invalidate the current 
     241     * renderer. Only possible with the WriteLock so no possibility of 
     242     * corrupting data. 
     243     *  
     244     * a.k.a. STATE-MANAGEMENT 
     245     */ 
     246     
     247    /**  
     248     * Implemented as specified by the {@link RenderingEngine} interface.  
     249     * @see RenderingEngine#lookupPixels(long) 
     250     */ 
    138251    @RolesAllowed("user") 
    139252    @TransactionAttribute(REQUIRED) 
    140     public void lookupPixels(long arg0) 
    141     { 
    142         delegate.lookupPixels(arg0); 
    143     } 
    144  
     253    public void lookupPixels(long pixelsId) 
     254    { 
     255        rwl.writeLock().lock(); 
     256 
     257        try { 
     258 
     259            this.pixelsObj = pixMetaSrv.retrievePixDescription(pixelsId);  
     260            this.renderer = null; 
     261 
     262            if ( pixelsObj == null ) 
     263                throw new ValidationException( 
     264                        "Pixels object with id "+pixelsId+" not found."); 
     265             
     266        } finally { 
     267            rwl.writeLock().unlock(); 
     268        } 
     269         
     270        if (log.isDebugEnabled()) 
     271            log.debug("lookupPixels for id "+pixelsId+" succeeded: "+this.pixelsObj); 
     272    } 
     273 
     274    /**  
     275     * Implemented as specified by the {@link RenderingEngine} interface.  
     276     * @see RenderingEngine#lookupRenderingDef(long) 
     277     */ 
    145278    @RolesAllowed("user") 
    146279    @TransactionAttribute(REQUIRED) 
    147     public void lookupRenderingDef(long arg0) 
    148     { 
    149         delegate.lookupRenderingDef(arg0); 
    150     } 
    151      
     280    public void lookupRenderingDef(long pixelsId) 
     281    { 
     282        rwl.writeLock().lock(); 
     283         
     284        try { 
     285            this.rendDefObj = pixMetaSrv.retrieveRndSettings(pixelsId); 
     286            this.renderer = null; 
     287             
     288            if ( rendDefObj == null ) 
     289                throw new ValidationException( 
     290                        "RenderingDef for Pixels="+pixelsId+" not found."); 
     291        } finally { 
     292            rwl.writeLock().unlock(); 
     293        } 
     294         
     295        if (log.isDebugEnabled()) 
     296            log.debug("lookupRenderingDef for Pixels="+pixelsId+" succeeded: "+this.rendDefObj); 
     297         
     298    } 
     299     
     300    /**  
     301     * Implemented as specified by the {@link RenderingEngine} interface.  
     302     * @see RenderingEngine#load() 
     303     */ 
    152304    @RolesAllowed("user") 
    153305    @TransactionAttribute(REQUIRED) 
    154306    public void load() 
    155307    { 
    156         delegate.load(); 
    157     } 
    158      
    159     // ------------------------------------------------------------------------- 
    160      
    161     @RolesAllowed("user")  
    162     public RGBBuffer render(PlaneDef arg0) 
    163     { 
    164         return delegate.render(arg0); 
    165     } 
    166      
    167     // ------------------------------------------------------------------------- 
    168      
     308        rwl.writeLock().lock(); 
     309 
     310        try { 
     311 
     312            errorIfNullPixels(); 
     313 
     314            /* 
     315             * TODO we could also allow for setting of the buffer! perhaps 
     316             * better caching, etc. 
     317             */ 
     318            PixelBuffer buffer = pixDataSrv.getPixelBuffer(pixelsObj); 
     319             
     320            renderer = new Renderer(pixMetaSrv, pixelsObj, rendDefObj, buffer); 
     321        } finally { 
     322            rwl.writeLock().unlock(); 
     323        } 
     324    }  
     325 
     326    /** Implemented as specified by the {@link RenderingEngine} interface. TODO 
     327     * @see RenderingEngine#getCurrentEventContext() 
     328     */ 
     329    @RolesAllowed("user") 
     330    @TransactionAttribute(REQUIRED) 
     331    public EventContext getCurrentEventContext() 
     332    { 
     333        return new SimpleEventContext( getSecuritySystem().getEventContext() ); 
     334    } 
     335     
     336    /* 
     337     * DELEGATING METHODS ================================================== 
     338     *   
     339     *  All following methods follow the pattern: 
     340     *   1) get read or write lock 
     341     *      try { 
     342     *   2)   error on null  
     343     *   3)   delegate method to renderer/renderingObj/pixelsObj 
     344     *      } finally { 
     345     *   4)   release lock 
     346     *      } 
     347     *   
     348     *  TODO for all of these methods it would be good to have an 
     349     *  interceptor to check for a null renderer value.  
     350     *      would have to be JBoss specific  
     351     *      or apply at the Renderer level 
     352     *      or this would have to be a delegate to REngine to Renderer! 
     353     *       
     354     *  @Write || @Read on each.  
     355     *  for example  
     356     *  see http://www.onjava.com/pub/a/onjava/2004/08/25/aoa.html?page=3 
     357     *  for asynch. annotations (also @TxSynchronized) 
     358     *    
     359     */ 
     360     
     361    /**  
     362     * Implemented as specified by the {@link RenderingEngine} interface.  
     363     * @see RenderingEngine#render(PlaneDef) 
     364     */ 
     365    @RolesAllowed("user")  
     366    public RGBBuffer render(PlaneDef pd) 
     367            throws ResourceError, ValidationException 
     368    { 
     369        rwl.readLock().lock(); 
     370 
     371        try { 
     372            errorIfInvalidState(); 
     373            return renderer.render(pd); 
     374        } catch (IOException e) { 
     375            ResourceError re = new ResourceError( 
     376                    "IO error while rendering:\n"+e.getMessage()); 
     377            re.initCause(e); 
     378            throw re; 
     379        } catch (QuantizationException e) { 
     380            InternalException ie = new InternalException( 
     381                    "QuantizationException while rendering:\n"+e.getMessage()); 
     382            ie.initCause(e); 
     383            throw ie; 
     384        } finally { 
     385            rwl.readLock().unlock(); 
     386        } 
     387    } 
     388     
     389    // ~ Settings 
     390        // ========================================================================= 
     391     
     392    /**  
     393     * Implemented as specified by the {@link RenderingEngine} interface.  
     394     * @see RenderingEngine#resetDefaults() 
     395     */ 
    169396    @RolesAllowed("user")  
    170397    public void resetDefaults() 
    171398    { 
    172         delegate.resetDefaults(); 
    173     } 
    174  
     399        rwl.writeLock().lock(); 
     400         
     401        try { 
     402            errorIfInvalidState(); 
     403            renderer.resetDefaults(); 
     404        } finally { 
     405            rwl.writeLock().unlock(); 
     406        } 
     407    } 
     408 
     409    /**  
     410     * Implemented as specified by the {@link RenderingEngine} interface.  
     411     * @see RenderingEngine#saveCurrentSettings() 
     412     */ 
    175413    @RolesAllowed("user")  
    176414    public void saveCurrentSettings() 
    177415    { 
    178         delegate.saveCurrentSettings(); 
     416        rwl.writeLock().lock(); 
     417 
     418        try { 
     419            errorIfNullRenderingDef(); 
     420            pixMetaSrv.saveRndSettings(rendDefObj); 
     421        } finally { 
     422            rwl.writeLock().unlock(); 
     423        } 
    179424        iUpdate.flush(); 
    180425        iUpdate.commit(); 
    181426    } 
    182427 
    183     // ------------------------------------------------------------------------- 
    184      
    185     @RolesAllowed("user")  
    186     public double getChannelCurveCoefficient(int arg0) 
    187     { 
    188         return delegate.getChannelCurveCoefficient(arg0); 
    189     } 
    190  
    191     @RolesAllowed("user")  
    192     public Family getChannelFamily(int arg0) 
    193     { 
    194         Family family = delegate.getChannelFamily(arg0); 
    195         return copyFamily(family); 
    196     } 
    197  
    198     @RolesAllowed("user")  
    199     public boolean getChannelNoiseReduction(int arg0) 
    200     { 
    201         return delegate.getChannelNoiseReduction(arg0); 
    202     } 
    203  
    204     @RolesAllowed("user")  
    205     public double[] getChannelStats(int arg0) 
    206     { 
    207         return delegate.getChannelStats(arg0); 
    208     } 
    209  
    210     @RolesAllowed("user")  
    211     public double getChannelWindowEnd(int arg0) 
    212     { 
    213         return delegate.getChannelWindowEnd(arg0); 
    214     } 
    215  
    216     @RolesAllowed("user")  
    217     public double getChannelWindowStart(int arg0) 
    218     { 
    219         return delegate.getChannelWindowStart(arg0); 
    220     } 
    221  
     428    //  ~ Renderer Delegation (READ) 
     429    // ========================================================================= 
     430 
     431    /**  
     432     * Implemented as specified by the {@link RenderingEngine} interface.  
     433     * @see RenderingEngine#getChannelCurveCoefficient(int) 
     434     */ 
     435    @RolesAllowed("user")  
     436    public double getChannelCurveCoefficient(int w) 
     437    { 
     438        rwl.readLock().lock(); 
     439 
     440        try { 
     441            errorIfInvalidState(); 
     442            ChannelBinding[] cb = renderer.getChannelBindings(); 
     443            return cb[w].getCoefficient().doubleValue(); 
     444        } finally { 
     445            rwl.readLock().unlock(); 
     446        } 
     447    } 
     448 
     449    /**  
     450     * Implemented as specified by the {@link RenderingEngine} interface. 
     451     * @see RenderingEngine#getChannelFamily(int) 
     452     */ 
     453    @RolesAllowed("user") 
     454    public Family getChannelFamily(int w) 
     455    { 
     456        rwl.readLock().lock(); 
     457 
     458        try { 
     459            errorIfInvalidState(); 
     460            ChannelBinding[] cb = renderer.getChannelBindings(); 
     461            Family family = cb[w].getFamily(); 
     462            return copyFamily(family); 
     463        } finally { 
     464            rwl.readLock().unlock(); 
     465        } 
     466    } 
     467 
     468    /** 
     469     * Implemented as specified by the {@link RenderingEngine} interface.  
     470     * @see RenderingEngine#getChannelNoiseReduction(int) 
     471     */ 
     472    @RolesAllowed("user")  
     473    public boolean getChannelNoiseReduction(int w) 
     474    { 
     475        rwl.readLock().lock(); 
     476 
     477        try { 
     478            errorIfInvalidState(); 
     479            ChannelBinding[] cb = renderer.getChannelBindings(); 
     480            return cb[w].getNoiseReduction().booleanValue(); 
     481        } finally { 
     482            rwl.readLock().unlock(); 
     483        } 
     484    } 
     485 
     486    /** Implemented as specified by the {@link RenderingEngine} interface. */ 
     487    @RolesAllowed("user")  
     488    public double[] getChannelStats(int w) 
     489    { 
     490        rwl.readLock().lock(); 
     491 
     492        try { 
     493            errorIfInvalidState(); 
     494//            ChannelBinding[] cb = renderer.getChannelBindings(); 
     495//        FIXME 
     496//        double[] stats = cb[w].getStats(), copy = new double[stats.length]; 
     497//        System.arraycopy(stats, 0, copy, 0, stats.length); 
     498            return null; 
     499        } finally { 
     500            rwl.readLock().unlock(); 
     501        }// FIXME copy; 
     502        // NOTE: These stats are supposed to be read-only; however we make a 
     503        // copy to be on the safe side. 
     504    } 
     505 
     506    /**  
     507     * Implemented as specified by the {@link RenderingEngine} interface.  
     508     * @see RenderingEngine#getChannelWindowEnd(int) 
     509     */ 
     510    @RolesAllowed("user")  
     511    public double getChannelWindowEnd(int w) 
     512    { 
     513        rwl.readLock().lock(); 
     514 
     515        try { 
     516            errorIfInvalidState(); 
     517            ChannelBinding[] cb = renderer.getChannelBindings(); 
     518            return cb[w].getInputEnd().intValue(); 
     519        } finally { 
     520            rwl.readLock().unlock(); 
     521        } 
     522    } 
     523 
     524    /**  
     525     * Implemented as specified by the {@link RenderingEngine} interface.  
     526     * @see RenderingEngine#getChannelWindowStart(int) 
     527     */ 
     528    @RolesAllowed("user")  
     529    public double getChannelWindowStart(int w) 
     530    { 
     531        rwl.readLock().lock(); 
     532 
     533        try { 
     534            errorIfInvalidState(); 
     535            ChannelBinding[] cb = renderer.getChannelBindings(); 
     536            return cb[w].getInputStart().intValue(); 
     537        } finally { 
     538            rwl.readLock().unlock(); 
     539        } 
     540    } 
     541     
     542    /** 
     543     * Implemented as specified by the {@link RenderingEngine} interface.  
     544     * @see RenderingEngine#getRGBA(int) 
     545     */ 
     546    @RolesAllowed("user")  
     547    public int[] getRGBA(int w) 
     548    { 
     549 
     550        rwl.readLock().lock(); 
     551 
     552        try { 
     553            errorIfInvalidState(); 
     554            int[] rgba = new int[4]; 
     555            ChannelBinding[] cb = renderer.getChannelBindings(); 
     556            // NOTE: The rgba is supposed to be read-only; however we make a 
     557            // copy to be on the safe side. 
     558            rgba[0] = cb[w].getColor().getRed().intValue(); 
     559            rgba[1] = cb[w].getColor().getGreen().intValue(); 
     560            rgba[2] = cb[w].getColor().getBlue().intValue(); 
     561            rgba[3] = cb[w].getColor().getAlpha().intValue(); 
     562            return rgba; 
     563        } finally { 
     564            rwl.readLock().unlock(); 
     565        } 
     566    } 
     567 
     568    /**  
     569     * Implemented as specified by the {@link RenderingEngine} interface.  
     570     * @see RenderingEngine#isActive(int) 
     571     */ 
     572    @RolesAllowed("user")  
     573    public boolean isActive(int w) 
     574    { 
     575        rwl.readLock().lock(); 
     576