• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *            http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 
18 package android.filterfw.core;
19 
20 import android.filterfw.core.FilterContext;
21 import android.filterfw.core.FilterPort;
22 import android.filterfw.core.KeyValueMap;
23 import android.filterfw.io.TextGraphReader;
24 import android.filterfw.io.GraphIOException;
25 import android.filterfw.format.ObjectFormat;
26 import android.util.Log;
27 
28 import java.io.Serializable;
29 import java.lang.annotation.Annotation;
30 import java.lang.reflect.Field;
31 import java.lang.Thread;
32 import java.util.Collection;
33 import java.util.HashMap;
34 import java.util.HashSet;
35 import java.util.Map.Entry;
36 import java.util.LinkedList;
37 import java.util.Set;
38 
39 /**
40  * @hide
41  */
42 public abstract class Filter {
43 
44     static final int STATUS_PREINIT               = 0;
45     static final int STATUS_UNPREPARED            = 1;
46     static final int STATUS_PREPARED              = 2;
47     static final int STATUS_PROCESSING            = 3;
48     static final int STATUS_SLEEPING              = 4;
49     static final int STATUS_FINISHED              = 5;
50     static final int STATUS_ERROR                 = 6;
51     static final int STATUS_RELEASED              = 7;
52 
53     private String mName;
54 
55     private int mInputCount = -1;
56     private int mOutputCount = -1;
57 
58     private HashMap<String, InputPort> mInputPorts;
59     private HashMap<String, OutputPort> mOutputPorts;
60 
61     private HashSet<Frame> mFramesToRelease;
62     private HashMap<String, Frame> mFramesToSet;
63 
64     private int mStatus = 0;
65     private boolean mIsOpen = false;
66     private int mSleepDelay;
67 
68     private long mCurrentTimestamp;
69 
70     private boolean mLogVerbose;
71     private static final String TAG = "Filter";
72 
Filter(String name)73     public Filter(String name) {
74         mName = name;
75         mFramesToRelease = new HashSet<Frame>();
76         mFramesToSet = new HashMap<String, Frame>();
77         mStatus = STATUS_PREINIT;
78 
79         mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
80     }
81 
82     /** Tests to see if a given filter is installed on the system. Requires
83      * full filter package name, including filterpack.
84      */
isAvailable(String filterName)85     public static final boolean isAvailable(String filterName) {
86         ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
87         Class filterClass;
88         // First see if a class of that name exists
89         try {
90             filterClass = contextClassLoader.loadClass(filterName);
91         } catch (ClassNotFoundException e) {
92             return false;
93         }
94         // Then make sure it's a subclass of Filter.
95         try {
96             filterClass.asSubclass(Filter.class);
97         } catch (ClassCastException e) {
98             return false;
99         }
100         return true;
101     }
102 
initWithValueMap(KeyValueMap valueMap)103     public final void initWithValueMap(KeyValueMap valueMap) {
104         // Initialization
105         initFinalPorts(valueMap);
106 
107         // Setup remaining ports
108         initRemainingPorts(valueMap);
109 
110         // This indicates that final ports can no longer be set
111         mStatus = STATUS_UNPREPARED;
112     }
113 
initWithAssignmentString(String assignments)114     public final void initWithAssignmentString(String assignments) {
115         try {
116             KeyValueMap valueMap = new TextGraphReader().readKeyValueAssignments(assignments);
117             initWithValueMap(valueMap);
118         } catch (GraphIOException e) {
119             throw new IllegalArgumentException(e.getMessage());
120         }
121     }
122 
initWithAssignmentList(Object... keyValues)123     public final void initWithAssignmentList(Object... keyValues) {
124         KeyValueMap valueMap = new KeyValueMap();
125         valueMap.setKeyValues(keyValues);
126         initWithValueMap(valueMap);
127     }
128 
init()129     public final void init() throws ProtocolException {
130         KeyValueMap valueMap = new KeyValueMap();
131         initWithValueMap(valueMap);
132     }
133 
getFilterClassName()134     public String getFilterClassName() {
135         return getClass().getSimpleName();
136     }
137 
getName()138     public final String getName() {
139         return mName;
140     }
141 
isOpen()142     public boolean isOpen() {
143         return mIsOpen;
144     }
145 
setInputFrame(String inputName, Frame frame)146     public void setInputFrame(String inputName, Frame frame) {
147         FilterPort port = getInputPort(inputName);
148         if (!port.isOpen()) {
149             port.open();
150         }
151         port.setFrame(frame);
152     }
153 
setInputValue(String inputName, Object value)154     public final void setInputValue(String inputName, Object value) {
155         setInputFrame(inputName, wrapInputValue(inputName, value));
156     }
157 
prepare(FilterContext context)158     protected void prepare(FilterContext context) {
159     }
160 
parametersUpdated(Set<String> updated)161     protected void parametersUpdated(Set<String> updated) {
162     }
163 
delayNextProcess(int millisecs)164     protected void delayNextProcess(int millisecs) {
165         mSleepDelay = millisecs;
166         mStatus = STATUS_SLEEPING;
167     }
168 
setupPorts()169     public abstract void setupPorts();
170 
getOutputFormat(String portName, FrameFormat inputFormat)171     public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) {
172         return null;
173     }
174 
getInputFormat(String portName)175     public final FrameFormat getInputFormat(String portName) {
176         InputPort inputPort = getInputPort(portName);
177         return inputPort.getSourceFormat();
178     }
179 
open(FilterContext context)180     public void open(FilterContext context) {
181     }
182 
process(FilterContext context)183     public abstract void process(FilterContext context);
184 
getSleepDelay()185     public final int getSleepDelay() {
186         return 250;
187     }
188 
close(FilterContext context)189     public void close(FilterContext context) {
190     }
191 
tearDown(FilterContext context)192     public void tearDown(FilterContext context) {
193     }
194 
getNumberOfConnectedInputs()195     public final int getNumberOfConnectedInputs() {
196         int c = 0;
197         for (InputPort inputPort : mInputPorts.values()) {
198             if (inputPort.isConnected()) {
199                 ++c;
200             }
201         }
202         return c;
203     }
204 
getNumberOfConnectedOutputs()205     public final int getNumberOfConnectedOutputs() {
206         int c = 0;
207         for (OutputPort outputPort : mOutputPorts.values()) {
208             if (outputPort.isConnected()) {
209                 ++c;
210             }
211         }
212         return c;
213     }
214 
getNumberOfInputs()215     public final int getNumberOfInputs() {
216         return mOutputPorts == null ? 0 : mInputPorts.size();
217     }
218 
getNumberOfOutputs()219     public final int getNumberOfOutputs() {
220         return mInputPorts == null ? 0 : mOutputPorts.size();
221     }
222 
getInputPort(String portName)223     public final InputPort getInputPort(String portName) {
224         if (mInputPorts == null) {
225             throw new NullPointerException("Attempting to access input port '" + portName
226                 + "' of " + this + " before Filter has been initialized!");
227         }
228         InputPort result = mInputPorts.get(portName);
229         if (result == null) {
230             throw new IllegalArgumentException("Unknown input port '" + portName + "' on filter "
231                 + this + "!");
232         }
233         return result;
234     }
235 
getOutputPort(String portName)236     public final OutputPort getOutputPort(String portName) {
237         if (mInputPorts == null) {
238             throw new NullPointerException("Attempting to access output port '" + portName
239                 + "' of " + this + " before Filter has been initialized!");
240         }
241         OutputPort result = mOutputPorts.get(portName);
242         if (result == null) {
243             throw new IllegalArgumentException("Unknown output port '" + portName + "' on filter "
244                 + this + "!");
245         }
246         return result;
247     }
248 
pushOutput(String name, Frame frame)249     protected final void pushOutput(String name, Frame frame) {
250         if (frame.getTimestamp() == Frame.TIMESTAMP_NOT_SET) {
251             if (mLogVerbose) Log.v(TAG, "Default-setting output Frame timestamp on port " + name + " to " + mCurrentTimestamp);
252             frame.setTimestamp(mCurrentTimestamp);
253         }
254         getOutputPort(name).pushFrame(frame);
255     }
256 
pullInput(String name)257     protected final Frame pullInput(String name) {
258         Frame result = getInputPort(name).pullFrame();
259         if (mCurrentTimestamp == Frame.TIMESTAMP_UNKNOWN) {
260             mCurrentTimestamp = result.getTimestamp();
261             if (mLogVerbose) Log.v(TAG, "Default-setting current timestamp from input port " + name + " to " + mCurrentTimestamp);
262         }
263         // As result is retained, we add it to the release pool here
264         mFramesToRelease.add(result);
265 
266         return result;
267     }
268 
fieldPortValueUpdated(String name, FilterContext context)269     public void fieldPortValueUpdated(String name, FilterContext context) {
270     }
271 
272     /**
273      * Transfers any frame from an input port to its destination. This is useful to force a
274      * transfer from a FieldPort or ProgramPort to its connected target (field or program variable).
275      */
transferInputPortFrame(String name, FilterContext context)276     protected void transferInputPortFrame(String name, FilterContext context) {
277         getInputPort(name).transfer(context);
278     }
279 
280     /**
281      * Assigns all program variables to the ports they are connected to. Call this after
282      * constructing a Program instance with attached ProgramPorts.
283      */
initProgramInputs(Program program, FilterContext context)284     protected void initProgramInputs(Program program, FilterContext context) {
285         if (program != null) {
286             for (InputPort inputPort : mInputPorts.values()) {
287                 if (inputPort.getTarget() == program) {
288                     inputPort.transfer(context);
289                 }
290             }
291         }
292     }
293 
294     /**
295      * Adds an input port to the filter. You should call this from within setupPorts, if your
296      * filter has input ports. No type-checking is performed on the input. If you would like to
297      * check against a type mask, use
298      * {@link #addMaskedInputPort(String, FrameFormat) addMaskedInputPort} instead.
299      *
300      * @param name the name of the input port
301      */
addInputPort(String name)302     protected void addInputPort(String name) {
303         addMaskedInputPort(name, null);
304     }
305 
306     /**
307      * Adds an input port to the filter. You should call this from within setupPorts, if your
308      * filter has input ports. When type-checking is performed, the input format is
309      * checked against the provided format mask. An exception is thrown in case of a conflict.
310      *
311      * @param name the name of the input port
312      * @param formatMask a format mask, which filters the allowable input types
313      */
addMaskedInputPort(String name, FrameFormat formatMask)314     protected void addMaskedInputPort(String name, FrameFormat formatMask) {
315         InputPort port = new StreamPort(this, name);
316         if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + port);
317         mInputPorts.put(name, port);
318         port.setPortFormat(formatMask);
319     }
320 
321     /**
322      * Adds an output port to the filter with a fixed output format. You should call this from
323      * within setupPorts, if your filter has output ports. You cannot use this method, if your
324      * output format depends on the input format (e.g. in a pass-through filter). In this case, use
325      * {@link #addOutputBasedOnInput(String, String) addOutputBasedOnInput} instead.
326      *
327      * @param name the name of the output port
328      * @param format the fixed output format of this port
329      */
addOutputPort(String name, FrameFormat format)330     protected void addOutputPort(String name, FrameFormat format) {
331         OutputPort port = new OutputPort(this, name);
332         if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + port);
333         port.setPortFormat(format);
334         mOutputPorts.put(name, port);
335     }
336 
337     /**
338      * Adds an output port to the filter. You should call this from within setupPorts, if your
339      * filter has output ports. Using this method indicates that the output format for this
340      * particular port, depends on the format of an input port. You MUST also override
341      * {@link #getOutputFormat(String, FrameFormat) getOutputFormat} to specify what format your
342      * filter will output for a given input. If the output format of your filter port does not
343      * depend on the input, use {@link #addOutputPort(String, FrameFormat) addOutputPort} instead.
344      *
345      * @param outputName the name of the output port
346      * @param inputName the name of the input port, that this output depends on
347      */
addOutputBasedOnInput(String outputName, String inputName)348     protected void addOutputBasedOnInput(String outputName, String inputName) {
349         OutputPort port = new OutputPort(this, outputName);
350         if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + port);
351         port.setBasePort(getInputPort(inputName));
352         mOutputPorts.put(outputName, port);
353     }
354 
addFieldPort(String name, Field field, boolean hasDefault, boolean isFinal)355     protected void addFieldPort(String name,
356                                 Field field,
357                                 boolean hasDefault,
358                                 boolean isFinal) {
359         // Make sure field is accessible
360         field.setAccessible(true);
361 
362         // Create port for this input
363         InputPort fieldPort = isFinal
364             ? new FinalPort(this, name, field, hasDefault)
365             : new FieldPort(this, name, field, hasDefault);
366 
367         // Create format for this input
368         if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + fieldPort);
369         MutableFrameFormat format = ObjectFormat.fromClass(field.getType(),
370                                                            FrameFormat.TARGET_SIMPLE);
371         fieldPort.setPortFormat(format);
372 
373         // Add port
374         mInputPorts.put(name, fieldPort);
375     }
376 
addProgramPort(String name, String varName, Field field, Class varType, boolean hasDefault)377     protected void addProgramPort(String name,
378                                   String varName,
379                                   Field field,
380                                   Class varType,
381                                   boolean hasDefault) {
382         // Make sure field is accessible
383         field.setAccessible(true);
384 
385         // Create port for this input
386         InputPort programPort = new ProgramPort(this, name, varName, field, hasDefault);
387 
388         // Create format for this input
389         if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + programPort);
390         MutableFrameFormat format = ObjectFormat.fromClass(varType,
391                                                            FrameFormat.TARGET_SIMPLE);
392         programPort.setPortFormat(format);
393 
394         // Add port
395         mInputPorts.put(name, programPort);
396     }
397 
closeOutputPort(String name)398     protected void closeOutputPort(String name) {
399         getOutputPort(name).close();
400     }
401 
402     /**
403      * Specifies whether the filter should not be scheduled until a frame is available on that
404      * input port. Note, that setting this to false, does not block a new frame from coming in
405      * (though there is no necessity to pull that frame for processing).
406      * @param portName the name of the input port.
407      * @param waits true, if the filter should wait for a frame on this port.
408      */
setWaitsOnInputPort(String portName, boolean waits)409     protected void setWaitsOnInputPort(String portName, boolean waits) {
410         getInputPort(portName).setBlocking(waits);
411     }
412 
413     /**
414      * Specifies whether the filter should not be scheduled until the output port is free, i.e.
415      * there is no frame waiting on that output.
416      * @param portName the name of the output port.
417      * @param waits true, if the filter should wait for the port to become free.
418      */
setWaitsOnOutputPort(String portName, boolean waits)419     protected void setWaitsOnOutputPort(String portName, boolean waits) {
420         getOutputPort(portName).setBlocking(waits);
421     }
422 
toString()423     public String toString() {
424         return "'" + getName() + "' (" + getFilterClassName() + ")";
425     }
426 
427     // Core internal methods ///////////////////////////////////////////////////////////////////////
getInputPorts()428     final Collection<InputPort> getInputPorts() {
429         return mInputPorts.values();
430     }
431 
getOutputPorts()432     final Collection<OutputPort> getOutputPorts() {
433         return mOutputPorts.values();
434     }
435 
getStatus()436     final synchronized int getStatus() {
437         return mStatus;
438     }
439 
unsetStatus(int flag)440     final synchronized void unsetStatus(int flag) {
441         mStatus &= ~flag;
442     }
443 
performOpen(FilterContext context)444     final synchronized void performOpen(FilterContext context) {
445         if (!mIsOpen) {
446             if (mStatus == STATUS_UNPREPARED) {
447                 if (mLogVerbose) Log.v(TAG, "Preparing " + this);
448                 prepare(context);
449                 mStatus = STATUS_PREPARED;
450             }
451             if (mStatus == STATUS_PREPARED) {
452                 if (mLogVerbose) Log.v(TAG, "Opening " + this);
453                 open(context);
454                 mStatus = STATUS_PROCESSING;
455             }
456             if (mStatus != STATUS_PROCESSING) {
457                 throw new RuntimeException("Filter " + this + " was brought into invalid state during "
458                     + "opening (state: " + mStatus + ")!");
459             }
460             mIsOpen = true;
461         }
462     }
463 
performProcess(FilterContext context)464     final synchronized void performProcess(FilterContext context) {
465         if (mStatus == STATUS_RELEASED) {
466             throw new RuntimeException("Filter " + this + " is already torn down!");
467         }
468         transferInputFrames(context);
469         if (mStatus < STATUS_PROCESSING) {
470             performOpen(context);
471         }
472         if (mLogVerbose) Log.v(TAG, "Processing " + this);
473         mCurrentTimestamp = Frame.TIMESTAMP_UNKNOWN;
474         process(context);
475         releasePulledFrames(context);
476         if (filterMustClose()) {
477             performClose(context);
478         }
479     }
480 
performClose(FilterContext context)481     final synchronized void performClose(FilterContext context) {
482         if (mIsOpen) {
483             if (mLogVerbose) Log.v(TAG, "Closing " + this);
484             mIsOpen = false;
485             mStatus = STATUS_PREPARED;
486             close(context);
487             closePorts();
488         }
489     }
490 
performTearDown(FilterContext context)491     final synchronized void performTearDown(FilterContext context) {
492         performClose(context);
493         if (mStatus != STATUS_RELEASED) {
494             tearDown(context);
495             mStatus = STATUS_RELEASED;
496         }
497     }
498 
canProcess()499     synchronized final boolean canProcess() {
500         if (mLogVerbose) Log.v(TAG, "Checking if can process: " + this + " (" + mStatus + ").");
501         if (mStatus <= STATUS_PROCESSING) {
502             return inputConditionsMet() && outputConditionsMet();
503         } else {
504             return false;
505         }
506     }
507 
openOutputs()508     final void openOutputs() {
509         if (mLogVerbose) Log.v(TAG, "Opening all output ports on " + this + "!");
510         for (OutputPort outputPort : mOutputPorts.values()) {
511             if (!outputPort.isOpen()) {
512                 outputPort.open();
513             }
514         }
515     }
516 
clearInputs()517     final void clearInputs() {
518         for (InputPort inputPort : mInputPorts.values()) {
519             inputPort.clear();
520         }
521     }
522 
clearOutputs()523     final void clearOutputs() {
524         for (OutputPort outputPort : mOutputPorts.values()) {
525             outputPort.clear();
526         }
527     }
528 
notifyFieldPortValueUpdated(String name, FilterContext context)529     final void notifyFieldPortValueUpdated(String name, FilterContext context) {
530         if (mStatus == STATUS_PROCESSING || mStatus == STATUS_PREPARED) {
531             fieldPortValueUpdated(name, context);
532         }
533     }
534 
pushInputFrame(String inputName, Frame frame)535     final synchronized void pushInputFrame(String inputName, Frame frame) {
536         FilterPort port = getInputPort(inputName);
537         if (!port.isOpen()) {
538             port.open();
539         }
540         port.pushFrame(frame);
541     }
542 
pushInputValue(String inputName, Object value)543     final synchronized void pushInputValue(String inputName, Object value) {
544         pushInputFrame(inputName, wrapInputValue(inputName, value));
545     }
546 
547     // Filter internal methods /////////////////////////////////////////////////////////////////////
initFinalPorts(KeyValueMap values)548     private final void initFinalPorts(KeyValueMap values) {
549         mInputPorts = new HashMap<String, InputPort>();
550         mOutputPorts = new HashMap<String, OutputPort>();
551         addAndSetFinalPorts(values);
552     }
553 
initRemainingPorts(KeyValueMap values)554     private final void initRemainingPorts(KeyValueMap values) {
555         addAnnotatedPorts();
556         setupPorts();   // TODO: rename to addFilterPorts() ?
557         setInitialInputValues(values);
558     }
559 
addAndSetFinalPorts(KeyValueMap values)560     private final void addAndSetFinalPorts(KeyValueMap values) {
561         Class filterClass = getClass();
562         Annotation annotation;
563         for (Field field : filterClass.getDeclaredFields()) {
564             if ((annotation = field.getAnnotation(GenerateFinalPort.class)) != null) {
565                 GenerateFinalPort generator = (GenerateFinalPort)annotation;
566                 String name = generator.name().isEmpty() ? field.getName() : generator.name();
567                 boolean hasDefault = generator.hasDefault();
568                 addFieldPort(name, field, hasDefault, true);
569                 if (values.containsKey(name)) {
570                     setImmediateInputValue(name, values.get(name));
571                     values.remove(name);
572                 } else if (!generator.hasDefault()) {
573                     throw new RuntimeException("No value specified for final input port '"
574                         + name + "' of filter " + this + "!");
575                 }
576             }
577         }
578     }
579 
addAnnotatedPorts()580     private final void addAnnotatedPorts() {
581         Class filterClass = getClass();
582         Annotation annotation;
583         for (Field field : filterClass.getDeclaredFields()) {
584             if ((annotation = field.getAnnotation(GenerateFieldPort.class)) != null) {
585                 GenerateFieldPort generator = (GenerateFieldPort)annotation;
586                 addFieldGenerator(generator, field);
587             } else if ((annotation = field.getAnnotation(GenerateProgramPort.class)) != null) {
588                 GenerateProgramPort generator = (GenerateProgramPort)annotation;
589                 addProgramGenerator(generator, field);
590             } else if ((annotation = field.getAnnotation(GenerateProgramPorts.class)) != null) {
591                 GenerateProgramPorts generators = (GenerateProgramPorts)annotation;
592                 for (GenerateProgramPort generator : generators.value()) {
593                     addProgramGenerator(generator, field);
594                 }
595             }
596         }
597     }
598 
addFieldGenerator(GenerateFieldPort generator, Field field)599     private final void addFieldGenerator(GenerateFieldPort generator, Field field) {
600         String name = generator.name().isEmpty() ? field.getName() : generator.name();
601         boolean hasDefault = generator.hasDefault();
602         addFieldPort(name, field, hasDefault, false);
603     }
604 
addProgramGenerator(GenerateProgramPort generator, Field field)605     private final void addProgramGenerator(GenerateProgramPort generator, Field field) {
606         String name = generator.name();
607         String varName = generator.variableName().isEmpty() ? name
608                                                             : generator.variableName();
609         Class varType = generator.type();
610         boolean hasDefault = generator.hasDefault();
611         addProgramPort(name, varName, field, varType, hasDefault);
612     }
613 
setInitialInputValues(KeyValueMap values)614     private final void setInitialInputValues(KeyValueMap values) {
615         for (Entry<String, Object> entry : values.entrySet()) {
616             setInputValue(entry.getKey(), entry.getValue());
617         }
618     }
619 
setImmediateInputValue(String name, Object value)620     private final void setImmediateInputValue(String name, Object value) {
621         if (mLogVerbose) Log.v(TAG, "Setting immediate value " + value + " for port " + name + "!");
622         FilterPort port = getInputPort(name);
623         port.open();
624         port.setFrame(SimpleFrame.wrapObject(value, null));
625     }
626 
transferInputFrames(FilterContext context)627     private final void transferInputFrames(FilterContext context) {
628         for (InputPort inputPort : mInputPorts.values()) {
629             inputPort.transfer(context);
630         }
631     }
632 
wrapInputValue(String inputName, Object value)633     private final Frame wrapInputValue(String inputName, Object value) {
634         MutableFrameFormat inputFormat = ObjectFormat.fromObject(value, FrameFormat.TARGET_SIMPLE);
635         if (value == null) {
636             // If the value is null, the format cannot guess the class, so we adjust it to the
637             // class of the input port here
638             FrameFormat portFormat = getInputPort(inputName).getPortFormat();
639             Class portClass = (portFormat == null) ? null : portFormat.getObjectClass();
640             inputFormat.setObjectClass(portClass);
641         }
642 
643         // Serialize if serializable, and type is not an immutable primitive.
644         boolean shouldSerialize = !(value instanceof Number)
645             && !(value instanceof Boolean)
646             && !(value instanceof String)
647             && value instanceof Serializable;
648 
649         // Create frame wrapper
650         Frame frame = shouldSerialize
651             ? new SerializedFrame(inputFormat, null)
652             : new SimpleFrame(inputFormat, null);
653         frame.setObjectValue(value);
654         return frame;
655     }
656 
releasePulledFrames(FilterContext context)657     private final void releasePulledFrames(FilterContext context) {
658         for (Frame frame : mFramesToRelease) {
659             context.getFrameManager().releaseFrame(frame);
660         }
661         mFramesToRelease.clear();
662     }
663 
inputConditionsMet()664     private final boolean inputConditionsMet() {
665         for (FilterPort port : mInputPorts.values()) {
666             if (!port.isReady()) {
667                 if (mLogVerbose) Log.v(TAG, "Input condition not met: " + port + "!");
668                 return false;
669             }
670         }
671         return true;
672     }
673 
outputConditionsMet()674     private final boolean outputConditionsMet() {
675         for (FilterPort port : mOutputPorts.values()) {
676             if (!port.isReady()) {
677                 if (mLogVerbose) Log.v(TAG, "Output condition not met: " + port + "!");
678                 return false;
679             }
680         }
681         return true;
682     }
683 
closePorts()684     private final void closePorts() {
685         if (mLogVerbose) Log.v(TAG, "Closing all ports on " + this + "!");
686         for (InputPort inputPort : mInputPorts.values()) {
687             inputPort.close();
688         }
689         for (OutputPort outputPort : mOutputPorts.values()) {
690             outputPort.close();
691         }
692     }
693 
filterMustClose()694     private final boolean filterMustClose() {
695         for (InputPort inputPort : mInputPorts.values()) {
696             if (inputPort.filterMustClose()) {
697                 if (mLogVerbose) Log.v(TAG, "Filter " + this + " must close due to port " + inputPort);
698                 return true;
699             }
700         }
701         for (OutputPort outputPort : mOutputPorts.values()) {
702             if (outputPort.filterMustClose()) {
703                 if (mLogVerbose) Log.v(TAG, "Filter " + this + " must close due to port " + outputPort);
704                 return true;
705             }
706         }
707         return false;
708     }
709 }
710