1%
2% Copyright (c) ZeroC, Inc. All rights reserved.
3%
4
5classdef (Abstract) EncapsDecoder < handle
6    methods
7        function obj = EncapsDecoder(is, encaps, sliceValues, valueFactoryManager, classResolver)
8            obj.is = is;
9            obj.encaps = encaps;
10            obj.sliceValues = sliceValues;
11            obj.valueFactoryManager = valueFactoryManager;
12            obj.classResolver = classResolver;
13            obj.patchMap = containers.Map('KeyType', 'int32', 'ValueType', 'any');
14            obj.unmarshaledMap = containers.Map('KeyType', 'int32', 'ValueType', 'any');
15            obj.typeIdMap = containers.Map('KeyType', 'int32', 'ValueType', 'char');
16            obj.typeIdIndex = 0;
17            obj.valueList = {};
18            obj.delayedPostUnmarshal = {};
19        end
20
21        function r = readOptional(obj, readTag, expectedFormat)
22            r = false;
23        end
24
25        function readPendingValues(obj)
26        end
27
28        function finish(obj)
29            %
30            % This is our opportunity for unmarshaled values to do some post processing after the initial round
31            % of unmarshaling is complete.
32            %
33            if ~isempty(obj.delayedPostUnmarshal)
34                %
35                % First call icePostUnmarshal on every instance. This allows the generated code to finish its tasks.
36                %
37                for i = 1:length(obj.delayedPostUnmarshal)
38                    v = obj.delayedPostUnmarshal{i};
39                    v.icePostUnmarshal();
40                end
41                %
42                % Then call ice_postUnmarshal on every instance. This is the application's interception point.
43                %
44                for i = 1:length(obj.delayedPostUnmarshal)
45                    v = obj.delayedPostUnmarshal{i};
46                    try
47                        v.ice_postUnmarshal();
48                    catch ex
49                        msg = sprintf('exception raised by ice_postUnmarshal:\n%s', getReport(ex, 'extended'));
50                        obj.is.getCommunicator().getLogger().warning(msg);
51                    end
52                end
53
54                obj.delayedPostUnmarshal = {};
55            end
56        end
57    end
58    methods(Abstract)
59        readValue(obj, cb)
60        throwException(obj)
61        startInstance(obj, sliceType)
62        r = endInstance(obj, preserve)
63        r = startSlice(obj)
64        endSlice(obj)
65        skipSlice(obj)
66    end
67    methods(Access=protected)
68        function r = readTypeId(obj, isIndex)
69            if isIndex
70                index = obj.is.readSize();
71                %
72                % The map raises an exception if the key isn't present.
73                %
74                try
75                    r = obj.typeIdMap(index);
76                catch ex
77                    throw(Ice.UnmarshalOutOfBoundsException());
78                end
79            else
80                r = obj.is.readString();
81                obj.typeIdIndex = obj.typeIdIndex + 1;
82                obj.typeIdMap(obj.typeIdIndex) = r;
83            end
84        end
85
86        function r = newInstance(obj, typeId)
87            %
88            % Try to find a factory registered for the specific type.
89            %
90            userFactory = obj.valueFactoryManager.find(typeId);
91            v = [];
92            if ~isempty(userFactory)
93                v = userFactory(typeId);
94            end
95
96            %
97            % If that fails, invoke the default factory if one has been registered.
98            %
99            if isempty(v)
100                userFactory = obj.valueFactoryManager.find('');
101                if ~isempty(userFactory)
102                    v = userFactory(typeId);
103                end
104            end
105
106            %
107            % Last chance: ask the class resolver to find it.
108            %
109            if isempty(v)
110                constructor = obj.classResolver.resolve(typeId);
111                if ~isempty(constructor)
112                    try
113                        v = constructor(); % Invoke the constructor.
114                    catch e
115                        reason = sprintf('constructor failed for %s', typeId);
116                        ex = Ice.NoValueFactoryException('', reason, reason, typeId);
117                        ex.addCause(e);
118                        throw(ex);
119                    end
120                end
121            end
122
123            r = v;
124        end
125
126        function addPatchEntry(obj, index, cb)
127            assert(index > 0);
128
129            %
130            % Check if we have already unmarshalled the instance. If that's the case,
131            % just invoke the callback and we're done.
132            %
133            if obj.unmarshaledMap.isKey(index)
134                v = obj.unmarshaledMap(index);
135                cb(v);
136                return;
137            end
138
139            %
140            % Add patch entry if the instance isn't unmarshaled yet,
141            % the callback will be called when the instance is
142            % unmarshaled.
143            %
144            pl = [];
145            if obj.patchMap.isKey(index)
146                pl = obj.patchMap(index);
147            else
148                %
149                % We have no outstanding instances to be patched for this
150                % index, so make a new entry in the patch map.
151                %
152                pl = IceInternal.PatchList();
153                obj.patchMap(index) = pl;
154            end
155
156            %
157            % Append a patch entry for this instance.
158            %
159            pl.list{end + 1} = cb;
160        end
161
162        function unmarshal(obj, index, v)
163            %
164            % Add the instance to the map of unmarshaled instances, this must
165            % be done before reading the instances (for circular references).
166            %
167            obj.unmarshaledMap(index) = v;
168
169            %
170            % Read the instance.
171            %
172            v.iceRead(obj.is);
173
174            if ~isempty(obj.patchMap) && obj.patchMap.isKey(index)
175                %
176                % Patch all instances now that the instance is unmarshaled.
177                %
178                l = obj.patchMap(index);
179                assert(length(l.list) > 0);
180
181                %
182                % Patch all pointers that refer to the instance.
183                %
184                for i = 1:length(l.list)
185                    cb = l.list{i};
186                    cb(v);
187                end
188
189                %
190                % Clear out the patch map for that index -- there is nothing left
191                % to patch for that index for the time being.
192                %
193                obj.patchMap.remove(index);
194            end
195
196            if (isempty(obj.patchMap) || obj.patchMap.Count == 0) && isempty(obj.valueList)
197                if v.iceDelayPostUnmarshal()
198                    obj.delayedPostUnmarshal{end + 1} = v; % See finish()
199                else
200                    try
201                        v.ice_postUnmarshal();
202                    catch ex
203                        msg = sprintf('exception raised by ice_postUnmarshal:\n%s', getReport(ex, 'extended'));
204                        obj.is.getCommunicator().getLogger().warning(msg);
205                    end
206                end
207            else
208                obj.valueList{end + 1} = v;
209
210                if isempty(obj.patchMap) || obj.patchMap.Count == 0
211                    %
212                    % Iterate over the instance list and invoke ice_postUnmarshal on
213                    % each instance. We must do this after all instances have been
214                    % unmarshaled in order to ensure that any instance data members
215                    % have been properly patched.
216                    %
217                    for i = 1:length(obj.valueList)
218                        p = obj.valueList{i};
219                        if p.iceDelayPostUnmarshal()
220                            obj.delayedPostUnmarshal{end + 1} = p; % See finish()
221                        else
222                            try
223                                p.ice_postUnmarshal();
224                            catch ex
225                                msg = sprintf('exception raised by ice_postUnmarshal:\n%s', getReport(ex, 'extended'));
226                                obj.is.getCommunicator().getLogger().warning(msg);
227                            end
228                        end
229                    end
230                    obj.valueList = {};
231                end
232            end
233        end
234    end
235    properties(Access=protected)
236        is
237        encaps
238        sliceValues
239        valueFactoryManager
240        classResolver
241        patchMap
242    end
243    properties(Access=private)
244        unmarshaledMap
245        typeIdMap
246        typeIdIndex
247        valueList
248        delayedPostUnmarshal
249    end
250end
251