001    /*
002    Copyright (c) 1996-2011, Damon Hart-Davis
003    All rights reserved.
004    
005    Redistribution and use in source and binary forms, with or without
006    modification, are permitted provided that the following conditions are
007    met:
008    
009      * Redistributions of source code must retain the above copyright
010        notice, this list of conditions and the following disclaimer.
011    
012      * Redistributions in binary form must reproduce the above copyright
013        notice, this list of conditions and the following disclaimer in the
014        documentation and/or other materials provided with the
015        distribution.
016    
017    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
018    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
019    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
020    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
021    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
022    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
023    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
024    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
025    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
026    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
027    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028    */
029    package org.hd.d.pg2k.svrCore.datasource;
030    
031    import java.io.IOException;
032    import java.nio.ByteBuffer;
033    import java.util.BitSet;
034    
035    import org.hd.d.pg2k.svrCore.AllExhibitImmutableData;
036    import org.hd.d.pg2k.svrCore.AllExhibitProperties;
037    import org.hd.d.pg2k.svrCore.ExhibitStaticAttr;
038    import org.hd.d.pg2k.svrCore.ExhibitThumbnails;
039    import org.hd.d.pg2k.svrCore.Name;
040    import org.hd.d.pg2k.svrCore.Name.ExhibitFull;
041    import org.hd.d.pg2k.svrCore.Stratum;
042    import org.hd.d.pg2k.svrCore.props.GenProps;
043    import org.hd.d.pg2k.svrCore.vars.EventPeriod;
044    import org.hd.d.pg2k.svrCore.vars.EventVariableValue;
045    import org.hd.d.pg2k.svrCore.vars.SimpleVariableDefinition;
046    import org.hd.d.pg2k.svrCore.vars.SimpleVariableValue;
047    
048    /**Simple extendable base class which acts as a pipeline filter.
049     * Analogous to a FilterInputStream, a SimpleExhibitPipelineFilter
050     * wraps another data source/stage, which it uses as its basic source of data,
051     * possibly transforming the data along the way or providing additional
052     * functionality.
053     * <p>
054     * The class SimpleExhibitPipelineFilter itself simply implements all methods of
055     * SimpleExhibitPipelineIF with versions that pass all requests to the wrapped
056     * source.  Subclasses of SimpleExhibitPipelineFilter may further override
057     * some of these methods and may also provide additional methods and fields.
058     * <p>
059     * A bare SimpleExhibitPipelineFilter is like a null/identity stage
060     * which leaves the semantics of a data pipeline intact.
061     * <p>
062     * One possible use of this is to build a "Mock Object" for testing purposes.
063     */
064    public class SimpleExhibitPipelineFilter implements SimpleExhibitPipelineIF
065        {
066        /**Construct a new instance of this filter.
067         * @param source  the upstream data source; never null
068         */
069        public SimpleExhibitPipelineFilter(final SimpleExhibitPipelineIF source)
070            {
071            if(source == null)
072                { throw new IllegalArgumentException(); }
073            this.source = source;
074            }
075    
076        /**The upstream source; never null. */
077        protected final SimpleExhibitPipelineIF source;
078    
079        /**Get the static attributes for a given exhibit.
080         * Returns null if the named exhibit does not exist.
081         *
082         * @throws IOException if the operation cannot be completed due to I/O
083         *     restrictions or failure
084         */
085        public ExhibitStaticAttr getStaticAttr(final ExhibitFull name)
086            throws IOException
087            { return(source.getStaticAttr(name)); }
088    
089        /**Read a chunk of the raw exhibit binary into the given buffer.
090         * The start index and the index after the last required
091         * byte is supplied.  The start value must be non-negative
092         * and the afterEnd value no smaller than start and no larger
093         * than the exhibit data length.
094         * <p>
095         * This always reads all the bytes requested or throws an IOException.
096         *
097         * @param dontCache  if true, this is a hint not to attempt to cache this
098         *     or displace anything from extant caches for this data
099         *     as it maqy for example be precaching or random activity;
100         *     by default callers should leave this false to allow cacheing
101         *
102         * @throws IllegalArgumentException  for invalid arguments such as
103         *     a null or invalid name,
104         *     a negative offset or start,
105         *     a negative (or in some cases, non-positive) len
106         * @throws IOException for requests that cannot be fulfilled because of
107         *     I/O restrictions or problems, such as link failure or
108         *     an upper bound on the length of a request
109         */
110        public void getRawFile(final ByteBuffer buf,
111                               final Name.ExhibitFull exhibitName, final int position, final boolean dontCache)
112            throws IOException
113            { source.getRawFile(buf, exhibitName, position, dontCache); }
114    
115        /**Gets set of all static exhibit data if its timestamp is not that specified.
116         * If the time specified is negative the object will be returned unconditionally.
117         * <p>
118         * If no exhibits are currently installed a default set with a zero
119         * timestamp is returned.
120         * <p>
121         * If the caller's copy appears to be up-to-date (eg the oldStamp
122         * matches that that would have been returned) null is returned.
123         *
124         * @throws IOException if the operation cannot be completed due to I/O
125         *     restrictions or failure
126         */
127        public AllExhibitImmutableData getAllExhibitImmutableData(final long oldStamp)
128            throws IOException
129            { return(source.getAllExhibitImmutableData(oldStamp)); }
130    
131        /**Gets set of all exhibit properties if its hash is not that specified.
132         * If the hash specified is negative the object will be returned unconditionally.
133         * <p>
134         * If no exhibits are currently installed a default set with a zero
135         * timestamp is returned.
136         * <p>
137         * If the caller's copy appears to be up-to-date (eg the oldHash
138         * matches that that would have been returned) null is returned.
139         *
140         * @throws IOException if the operation cannot be completed due to I/O
141         *     restrictions or failure
142         */
143        public AllExhibitProperties getAllExhibitProperties(final long oldHash)
144            throws IOException
145            { return(source.getAllExhibitProperties(oldHash)); }
146    
147        /**Gets the general properties as a GenProps object if its timestamp is not that specified.
148         * If the time specified is negative the object will be returned unconditionally.
149         * <p>
150         * If no props are currently installed/available a default set with a zero
151         * timestamp is returned.
152         * <p>
153         * If the caller's copy appears to be up-to-date (eg the oldStamp
154         * matches that that would have been returned) null is returned.
155         *
156         * @throws IOException if the operation cannot be completed due to I/O
157         *     restrictions or failure
158         */
159        public GenProps getGenProps(final long oldStamp)
160            throws IOException
161            { return(source.getGenProps(oldStamp)); }
162    
163        /**Gets the generic security properties as a Properties object if its timestamp is not that specified.
164         * If the time specified is negative the object will be returned unconditionally.
165         * <p>
166         * If no props are currently installed/available a default set with a zero
167         * timestamp is returned.
168         * <p>
169         * If the caller's copy appears to be up-to-date (eg the oldStamp
170         * matches that that would have been returned) null is returned.
171         *
172         * @throws IOException if the operation cannot be completed due to I/O
173         *     restrictions or failure
174         */
175        public java.util.Properties getGenSecProps(final long oldStamp)
176            throws IOException
177            { return(source.getGenSecProps(oldStamp)); }
178    
179        /**Gets the thumbnails for an exhibit.
180         * A data source is at liberty to refuse to compute thumbnails
181         * in which case it may return null, else it returns a
182         * non-null value which may include the `could-not-compute'
183         * value to indicate that a thumbnail/sample cannot be made
184         * for this exhibit and no attempt need be made in future.
185         *
186         * @param create  if true, and no thumbnail yet exists, try to
187         *     create one if possible, else if create is false
188         *     only return an existing one and return null if none is to hand
189         *
190         * @throws IOException if the operation cannot be completed due to I/O
191         *     restrictions or failure
192         */
193        public ExhibitThumbnails getThumbnails(final ExhibitFull name, final boolean create)
194            throws IOException
195            { return(source.getThumbnails(name, create)); }
196    
197        /**Poll periodically (of the order of seconds) to do bg work.
198         * The current generic system properties are passed in...
199         * <p>
200         * @throws IOException in case of difficulty, but even if a sub-ordinate
201         *     call throws IOException the poll() call should make some effort
202         *     to do as much of its work as reasonably possible
203         */
204        public void poll(final GenProps gp)
205            throws IOException
206            { source.poll(gp); }
207    
208        /**Synchronise variables with upstream values.
209         * Pushes updated values upstream to the source,
210         * calls sync on the source if called with the "force" argument true,
211         * and then retrieves changed values from upstream.
212         * <p>
213         * When called with force==true, this acts like a full "memory barrier",
214         * flushing all write-cached items downstream immediately and afterwards
215         * getting the value of all upstream values with getVariables(-1),
216         * but may be expensive in terms of CPU or bandwidth, so use sparingly.
217         * <p>
218         * When called with force=false, this incrementally flushes outstanding
219         * writes and will then fetch all, or only new, values from upstream,
220         * so is potentally much less resource-intensive.
221         * In particular, this does not propagate the sync() upstream.
222         * <p>
223         * In any case, it is rarely the right thing for a casual user
224         * to vall this as it may be very expensive.
225         *
226         * @param force  if true, this will force a full write flush,
227         *     a full sync upstream,
228         *     then full read with getVariables(-1),
229         *     to get the effect of a full "barrier";
230         *     otherwise, in general, a more incremental and non-propagating
231         *     mode is used which still does a write flush but may chose
232         *     to do a partial read of "new" upstream values
233         *
234         * @throws IOException if one is received from upstream
235         */
236        public void syncVariables(final boolean force)
237            throws IOException
238            {
239            source.syncVariables(force);
240            }
241    
242        /**Get set of variable values altered on or after specified time, or get all values with -1; never null.
243         * This may be slow if there are many live variables.
244         *
245         * @throws IOException  in case of I/O difficulty
246         */
247        public SimpleVariableValue[] getVariables(final long changedSince)
248            throws IOException
249            {
250            return(source.getVariables(changedSince));
251            }
252    
253        /**Get a single variable value; returns null if no such value or wrong type.
254         * Implementations should, where possible,
255         * trim from the globalMap of returned values any apparently-stale data,
256         * so as to return only reasonably-live data to the caller.
257         *
258         * @param var definition of variable to fetch; never null
259         *
260         * @throws IOException  in case of I/O difficulty
261         * @throws UnsupportedOperationException  if a variable is requested that
262         *     we could never supply, eg a non-System-ID local variable at
263         *     the client end of a tunnel
264         */
265        public SimpleVariableValue getVariable(final SimpleVariableDefinition var)
266            throws IOException,
267            UnsupportedOperationException
268            {
269            return(source.getVariable(var));
270            }
271    
272        /**Update a number of variables at once for efficiency; returns the number of variables set.
273         * Is passed a set of SimpleVariableValues and behaves as if it
274         * operates on all of them by calling setVariable() for each item
275         * in the set.
276         * <p>
277         * An implementation may "fail fast" on the first error/exception,
278         * or may attempt to continue and do as much as possible.
279         * <p>
280         * An implementation may throw an IllegalArgumentException on attempt to:
281         *     set a variable with value of wrong type or incompatible definition,
282         *     set a non-existent or read-only variable (or these may be ignored)
283         *
284         * @return the number of variable values set;
285         *     never negative, never more than the number passed in
286         */
287        public int setVariables(final SimpleVariableValue[] newValues)
288            throws IOException
289            {
290            return(source.setVariables(newValues));
291            }
292    
293        /**Set variable to the given value (the variable name and definition are implicit).
294         * The value set should be immediately readable with getVariable()
295         * as the "main" value of the variable even for global variables.
296         *
297         * @throws IOException  in case of I/O difficulty
298         * @throws UnsupportedOperationException  if a variable is set that
299         *     we could never handle, eg a non-System-ID local variable at
300         *     the client end of a tunnel
301         */
302        public void setVariable(final SimpleVariableValue newValue)
303            throws IOException,
304            UnsupportedOperationException
305            {
306            source.setVariable(newValue);
307            }
308    
309        /**Get the current partial, or previous full, event set at the specified interval.
310         * This is a simplified interface to return either the current event set
311         * that is being collected, or the previous completed set.
312         * <p>
313         * The current set is the most timely, but may not contain enough data
314         * to be meaningful if the new interval has just started.
315         * <p>
316         * The previous set is complete and thus most likely to have enough samples
317         * to be useful, but is not completely current.
318         *
319         * @param def  event definition (must be for an event); never null
320         * @param intervalSelector  one of EVENT_INTERVAL_SELECTOR_xxx values
321         * @param current  if true the current event set is returned,
322         *     else the previous complete set is returned
323         *
324         * @return  requested event set; may be null if requested set not available
325         */
326        public EventVariableValue getEventValue(final SimpleVariableDefinition def,
327                                                final EventPeriod intervalSelector,
328                                                final boolean current)
329            {
330            return(source.getEventValue(def, intervalSelector, current));
331            }
332    
333        /**Get the specified event sets for the specified intervals; never null.
334         * This allows retrieval of zero or more event sets for the specified
335         * interval size.
336         * <p>
337         * Requests for more than SystemVariables.EVENT_SAMPLES_RETAINED in the
338         * past (or for the future!) cannot be satisfied and data will not be
339         * returned for them.
340         * <p>
341         * Usually not more than SystemVariables.EVENT_SAMPLES_RETAINED samples
342         * will be returned in response to any one request as a safety measure.
343         * <p>
344         * (An implementation that is not an end-point may go upstream to fetch
345         * missing values and cache them to satisfy future requests.)
346         *
347         * @param def  event definition (must be for an event); never null
348         * @param intervalSelector  one of EVENT_INTERVAL_SELECTOR_xxx values
349         * @param intervalNumber  a time (as from System.currentTimeMillis())
350         *     which identifies the first interval for which data is potentially
351         *     required; if too far in the past or future then possibly no data
352         *     will be available,
353         *     zero is used to access the "all" bucket
354         * @param whichValues  each true bit represents a slot for which data is
355         *     required, bit 0 indicating data from the slot within which
356         *     firstIntervalTime is located, bit 1 the previous slot, etc;
357         *     null is treated as the common case equivalent to just bit 0 set
358         *
359         * @return as many of the requested values as available,
360         *     at least long enough to return all the available values,
361         *     with [0] corresponding to bit 0 in the BitSet;
362         *     may contain nulls or be zero-length but is never null
363         */
364        public EventVariableValue[] getEventValues(final SimpleVariableDefinition def,
365                                                   final EventPeriod intervalSelector,
366                                                   final long intervalNumber,
367                                                   final BitSet whichValues)
368            {
369            return(source.getEventValues(def, intervalSelector, intervalNumber, whichValues));
370            }
371    
372        /**Get requested Properties selected by key and versionID.
373         * Fetches a Properties set unconditionally (versionID == -1)
374         * else if the versionID presented is not current.
375         *
376         * @param key  selector (with possible embedded sub-key)
377         *     for desired properties set; never null
378         * @param versionID  if -1 then map is always returned if available,
379         *     else must be non-negative and null is returned if the versionID
380         *     presented matches that of the current version
381         *     (ie if the caller has presumably got the up-to-date version);
382         *     may be a timestamp or a hash or other value,
383         *     and by convention is zero only for an empty properties set
384         *
385         * @return null, or Properties map guaranteed to contain only
386         *     String keys and values
387         */
388        public java.util.Properties getProperties(final PropsKey key,
389                                                  final long versionID)
390            throws IOException
391            {
392            return(source.getProperties(key, versionID));
393            }
394    
395        /* Non-javadoc: delegates to source by default. */
396        public Stratum getStratum() throws IOException
397            {
398            return(source.getStratum());
399            }
400    
401        /**Shut down the data pipeline.
402         * Simply calls source.destroy().
403         */
404        public void destroy()
405            {
406            source.destroy();
407            }
408        }