69c5e7914a8edc5835cdc34431f97731b18a27ce
[onosfw.git] /
1 /*
2  * Copyright 2015 Open Networking Laboratory
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 package org.onosproject.codec.impl;
17
18 import static org.onlab.util.Tools.nullIsIllegal;
19
20 import java.util.HashMap;
21 import java.util.Map;
22
23 import org.onlab.packet.Ip6Address;
24 import org.onlab.packet.IpPrefix;
25 import org.onlab.packet.MacAddress;
26 import org.onlab.packet.MplsLabel;
27 import org.onlab.packet.TpPort;
28 import org.onlab.packet.VlanId;
29 import org.onlab.util.HexString;
30 import org.onosproject.net.ChannelSpacing;
31 import org.onosproject.net.GridType;
32 import org.onosproject.net.Lambda;
33 import org.onosproject.net.OchSignalType;
34 import org.onosproject.net.OduSignalId;
35 import org.onosproject.net.OduSignalType;
36 import org.onosproject.net.PortNumber;
37 import org.onosproject.net.flow.criteria.Criteria;
38 import org.onosproject.net.flow.criteria.Criterion;
39
40 import com.fasterxml.jackson.databind.JsonNode;
41 import com.fasterxml.jackson.databind.node.ObjectNode;
42
43 /**
44  * Decode portion of the criterion codec.
45  */
46 public final class DecodeCriterionCodecHelper {
47
48     private final ObjectNode json;
49
50     protected static final String MISSING_MEMBER_MESSAGE =
51             " member is required in Criterion";
52
53     private interface CriterionDecoder {
54         Criterion decodeCriterion(ObjectNode json);
55     }
56     private final Map<String, CriterionDecoder> decoderMap;
57
58     /**
59      * Creates a decode criterion codec object.
60      * Initializes the lookup map for criterion subclass decoders.
61      *
62      * @param json JSON object to decode
63      */
64     public DecodeCriterionCodecHelper(ObjectNode json) {
65         this.json = json;
66         decoderMap = new HashMap<>();
67
68         decoderMap.put(Criterion.Type.IN_PORT.name(), new InPortDecoder());
69         decoderMap.put(Criterion.Type.IN_PHY_PORT.name(), new InPhyPortDecoder());
70         decoderMap.put(Criterion.Type.METADATA.name(), new MetadataDecoder());
71         decoderMap.put(Criterion.Type.ETH_DST.name(), new EthDstDecoder());
72         decoderMap.put(Criterion.Type.ETH_SRC.name(), new EthSrcDecoder());
73         decoderMap.put(Criterion.Type.ETH_TYPE.name(), new EthTypeDecoder());
74         decoderMap.put(Criterion.Type.VLAN_VID.name(), new VlanVidDecoder());
75         decoderMap.put(Criterion.Type.VLAN_PCP.name(), new VlanPcpDecoder());
76         decoderMap.put(Criterion.Type.IP_DSCP.name(), new IpDscpDecoder());
77         decoderMap.put(Criterion.Type.IP_ECN.name(), new IpEcnDecoder());
78         decoderMap.put(Criterion.Type.IP_PROTO.name(), new IpProtoDecoder());
79         decoderMap.put(Criterion.Type.IPV4_SRC.name(), new IpV4SrcDecoder());
80         decoderMap.put(Criterion.Type.IPV4_DST.name(), new IpV4DstDecoder());
81         decoderMap.put(Criterion.Type.TCP_SRC.name(), new TcpSrcDecoder());
82         decoderMap.put(Criterion.Type.TCP_DST.name(), new TcpDstDecoder());
83         decoderMap.put(Criterion.Type.UDP_SRC.name(), new UdpSrcDecoder());
84         decoderMap.put(Criterion.Type.UDP_DST.name(), new UdpDstDecoder());
85         decoderMap.put(Criterion.Type.SCTP_SRC.name(), new SctpSrcDecoder());
86         decoderMap.put(Criterion.Type.SCTP_DST.name(), new SctpDstDecoder());
87         decoderMap.put(Criterion.Type.ICMPV4_TYPE.name(), new IcmpV4TypeDecoder());
88         decoderMap.put(Criterion.Type.ICMPV4_CODE.name(), new IcmpV4CodeDecoder());
89         decoderMap.put(Criterion.Type.IPV6_SRC.name(), new IpV6SrcDecoder());
90         decoderMap.put(Criterion.Type.IPV6_DST.name(), new IpV6DstDecoder());
91         decoderMap.put(Criterion.Type.IPV6_FLABEL.name(), new IpV6FLabelDecoder());
92         decoderMap.put(Criterion.Type.ICMPV6_TYPE.name(), new IcmpV6TypeDecoder());
93         decoderMap.put(Criterion.Type.ICMPV6_CODE.name(), new IcmpV6CodeDecoder());
94         decoderMap.put(Criterion.Type.IPV6_ND_TARGET.name(), new V6NDTargetDecoder());
95         decoderMap.put(Criterion.Type.IPV6_ND_SLL.name(), new V6NDSllDecoder());
96         decoderMap.put(Criterion.Type.IPV6_ND_TLL.name(), new V6NDTllDecoder());
97         decoderMap.put(Criterion.Type.MPLS_LABEL.name(), new MplsLabelDecoder());
98         decoderMap.put(Criterion.Type.IPV6_EXTHDR.name(), new IpV6ExthdrDecoder());
99         decoderMap.put(Criterion.Type.OCH_SIGID.name(), new OchSigIdDecoder());
100         decoderMap.put(Criterion.Type.OCH_SIGTYPE.name(), new OchSigTypeDecoder());
101         decoderMap.put(Criterion.Type.TUNNEL_ID.name(), new TunnelIdDecoder());
102         decoderMap.put(Criterion.Type.ODU_SIGID.name(), new OduSigIdDecoder());
103         decoderMap.put(Criterion.Type.ODU_SIGTYPE.name(), new OduSigTypeDecoder());
104     }
105
106     private class EthTypeDecoder implements CriterionDecoder {
107         @Override
108         public Criterion decodeCriterion(ObjectNode json) {
109             int ethType = nullIsIllegal(json.get(CriterionCodec.ETH_TYPE),
110                     CriterionCodec.ETH_TYPE + MISSING_MEMBER_MESSAGE).asInt();
111             return Criteria.matchEthType(ethType);
112         }
113     }
114
115     private class EthDstDecoder implements CriterionDecoder {
116         @Override
117         public Criterion decodeCriterion(ObjectNode json) {
118             MacAddress mac = MacAddress.valueOf(nullIsIllegal(json.get(CriterionCodec.MAC),
119                     CriterionCodec.MAC + MISSING_MEMBER_MESSAGE).asText());
120
121             return Criteria.matchEthDst(mac);
122         }
123     }
124
125     private class EthSrcDecoder implements CriterionDecoder {
126         @Override
127         public Criterion decodeCriterion(ObjectNode json) {
128             MacAddress mac = MacAddress.valueOf(nullIsIllegal(json.get(CriterionCodec.MAC),
129                     CriterionCodec.MAC + MISSING_MEMBER_MESSAGE).asText());
130
131             return Criteria.matchEthSrc(mac);
132         }
133     }
134
135     private class InPortDecoder implements CriterionDecoder {
136         @Override
137         public Criterion decodeCriterion(ObjectNode json) {
138             PortNumber port = PortNumber.portNumber(nullIsIllegal(json.get(CriterionCodec.PORT),
139                     CriterionCodec.PORT + MISSING_MEMBER_MESSAGE).asLong());
140
141             return Criteria.matchInPort(port);
142         }
143     }
144
145     private class InPhyPortDecoder implements CriterionDecoder {
146         @Override
147         public Criterion decodeCriterion(ObjectNode json) {
148             PortNumber port = PortNumber.portNumber(nullIsIllegal(json.get(CriterionCodec.PORT),
149                     CriterionCodec.PORT + MISSING_MEMBER_MESSAGE).asLong());
150
151             return Criteria.matchInPhyPort(port);
152         }
153     }
154
155     private class MetadataDecoder implements CriterionDecoder {
156         @Override
157         public Criterion decodeCriterion(ObjectNode json) {
158             long metadata = nullIsIllegal(json.get(CriterionCodec.METADATA),
159                     CriterionCodec.METADATA + MISSING_MEMBER_MESSAGE).asLong();
160
161             return Criteria.matchMetadata(metadata);
162         }
163     }
164
165     private class VlanVidDecoder implements CriterionDecoder {
166         @Override
167         public Criterion decodeCriterion(ObjectNode json) {
168             short vlanId = (short) nullIsIllegal(json.get(CriterionCodec.VLAN_ID),
169                     CriterionCodec.VLAN_ID + MISSING_MEMBER_MESSAGE).asInt();
170
171             return Criteria.matchVlanId(VlanId.vlanId(vlanId));
172         }
173     }
174
175     private class VlanPcpDecoder implements CriterionDecoder {
176         @Override
177         public Criterion decodeCriterion(ObjectNode json) {
178             byte priority = (byte) nullIsIllegal(json.get(CriterionCodec.PRIORITY),
179                     CriterionCodec.VLAN_ID + MISSING_MEMBER_MESSAGE).asInt();
180
181             return Criteria.matchVlanPcp(priority);
182         }
183     }
184
185     private class IpDscpDecoder implements CriterionDecoder {
186         @Override
187         public Criterion decodeCriterion(ObjectNode json) {
188             byte ipDscp = (byte) nullIsIllegal(json.get(CriterionCodec.IP_DSCP),
189                     CriterionCodec.IP_DSCP + MISSING_MEMBER_MESSAGE).asInt();
190             return Criteria.matchIPDscp(ipDscp);
191         }
192     }
193
194     private class IpEcnDecoder implements CriterionDecoder {
195         @Override
196         public Criterion decodeCriterion(ObjectNode json) {
197             byte ipEcn = (byte) nullIsIllegal(json.get(CriterionCodec.IP_ECN),
198                     CriterionCodec.IP_ECN + MISSING_MEMBER_MESSAGE).asInt();
199             return Criteria.matchIPEcn(ipEcn);
200         }
201     }
202
203     private class IpProtoDecoder implements CriterionDecoder {
204         @Override
205         public Criterion decodeCriterion(ObjectNode json) {
206             short proto = (short) nullIsIllegal(json.get(CriterionCodec.PROTOCOL),
207                     CriterionCodec.PROTOCOL + MISSING_MEMBER_MESSAGE).asInt();
208             return Criteria.matchIPProtocol(proto);
209         }
210     }
211
212     private class IpV4SrcDecoder implements CriterionDecoder {
213         @Override
214         public Criterion decodeCriterion(ObjectNode json) {
215             String ip = nullIsIllegal(json.get(CriterionCodec.IP),
216                     CriterionCodec.IP + MISSING_MEMBER_MESSAGE).asText();
217             return Criteria.matchIPSrc(IpPrefix.valueOf(ip));
218         }
219     }
220
221     private class IpV4DstDecoder implements CriterionDecoder {
222         @Override
223         public Criterion decodeCriterion(ObjectNode json) {
224             String ip = nullIsIllegal(json.get(CriterionCodec.IP),
225                     CriterionCodec.IP + MISSING_MEMBER_MESSAGE).asText();
226             return Criteria.matchIPDst(IpPrefix.valueOf(ip));
227         }
228     }
229
230     private class IpV6SrcDecoder implements CriterionDecoder {
231         @Override
232         public Criterion decodeCriterion(ObjectNode json) {
233             String ip = nullIsIllegal(json.get(CriterionCodec.IP),
234                     CriterionCodec.IP + MISSING_MEMBER_MESSAGE).asText();
235             return Criteria.matchIPv6Src(IpPrefix.valueOf(ip));
236         }
237     }
238
239     private class IpV6DstDecoder implements CriterionDecoder {
240         @Override
241         public Criterion decodeCriterion(ObjectNode json) {
242             String ip = nullIsIllegal(json.get(CriterionCodec.IP),
243                     CriterionCodec.IP + MISSING_MEMBER_MESSAGE).asText();
244             return Criteria.matchIPv6Dst(IpPrefix.valueOf(ip));
245         }
246     }
247
248     private class TcpSrcDecoder implements CriterionDecoder {
249         @Override
250         public Criterion decodeCriterion(ObjectNode json) {
251             TpPort tcpPort = TpPort.tpPort(nullIsIllegal(json.get(CriterionCodec.TCP_PORT),
252                     CriterionCodec.TCP_PORT + MISSING_MEMBER_MESSAGE).asInt());
253             return Criteria.matchTcpSrc(tcpPort);
254         }
255     }
256
257     private class TcpDstDecoder implements CriterionDecoder {
258         @Override
259         public Criterion decodeCriterion(ObjectNode json) {
260             TpPort tcpPort = TpPort.tpPort(nullIsIllegal(json.get(CriterionCodec.TCP_PORT),
261                     CriterionCodec.TCP_PORT + MISSING_MEMBER_MESSAGE).asInt());
262             return Criteria.matchTcpDst(tcpPort);
263         }
264     }
265
266     private class UdpSrcDecoder implements CriterionDecoder {
267         @Override
268         public Criterion decodeCriterion(ObjectNode json) {
269             TpPort udpPort = TpPort.tpPort(nullIsIllegal(json.get(CriterionCodec.UDP_PORT),
270                     CriterionCodec.UDP_PORT + MISSING_MEMBER_MESSAGE).asInt());
271             return Criteria.matchUdpSrc(udpPort);
272         }
273     }
274
275     private class UdpDstDecoder implements CriterionDecoder {
276         @Override
277         public Criterion decodeCriterion(ObjectNode json) {
278             TpPort udpPort = TpPort.tpPort(nullIsIllegal(json.get(CriterionCodec.UDP_PORT),
279                     CriterionCodec.UDP_PORT + MISSING_MEMBER_MESSAGE).asInt());
280             return Criteria.matchUdpDst(udpPort);
281         }
282     }
283
284     private class SctpSrcDecoder implements CriterionDecoder {
285         @Override
286         public Criterion decodeCriterion(ObjectNode json) {
287             TpPort sctpPort = TpPort.tpPort(nullIsIllegal(json.get(CriterionCodec.SCTP_PORT),
288                     CriterionCodec.SCTP_PORT + MISSING_MEMBER_MESSAGE).asInt());
289             return Criteria.matchSctpSrc(sctpPort);
290         }
291     }
292
293     private class SctpDstDecoder implements CriterionDecoder {
294         @Override
295         public Criterion decodeCriterion(ObjectNode json) {
296             TpPort sctpPort = TpPort.tpPort(nullIsIllegal(json.get(CriterionCodec.SCTP_PORT),
297                     CriterionCodec.SCTP_PORT + MISSING_MEMBER_MESSAGE).asInt());
298             return Criteria.matchSctpDst(sctpPort);
299         }
300     }
301
302     private class IcmpV4TypeDecoder implements CriterionDecoder {
303         @Override
304         public Criterion decodeCriterion(ObjectNode json) {
305             short type = (short) nullIsIllegal(json.get(CriterionCodec.ICMP_TYPE),
306                     CriterionCodec.ICMP_TYPE + MISSING_MEMBER_MESSAGE).asInt();
307             return Criteria.matchIcmpType(type);
308         }
309     }
310
311     private class IcmpV4CodeDecoder implements CriterionDecoder {
312         @Override
313         public Criterion decodeCriterion(ObjectNode json) {
314             short code = (short) nullIsIllegal(json.get(CriterionCodec.ICMP_CODE),
315                     CriterionCodec.ICMP_CODE + MISSING_MEMBER_MESSAGE).asInt();
316             return Criteria.matchIcmpCode(code);
317         }
318     }
319
320     private class IpV6FLabelDecoder implements CriterionDecoder {
321         @Override
322         public Criterion decodeCriterion(ObjectNode json) {
323             int flowLabel = nullIsIllegal(json.get(CriterionCodec.FLOW_LABEL),
324                     CriterionCodec.FLOW_LABEL + MISSING_MEMBER_MESSAGE).asInt();
325             return Criteria.matchIPv6FlowLabel(flowLabel);
326         }
327     }
328
329     private class IcmpV6TypeDecoder implements CriterionDecoder {
330         @Override
331         public Criterion decodeCriterion(ObjectNode json) {
332             short type = (short) nullIsIllegal(json.get(CriterionCodec.ICMPV6_TYPE),
333                     CriterionCodec.ICMPV6_TYPE + MISSING_MEMBER_MESSAGE).asInt();
334             return Criteria.matchIcmpv6Type(type);
335         }
336     }
337
338     private class IcmpV6CodeDecoder implements CriterionDecoder {
339         @Override
340         public Criterion decodeCriterion(ObjectNode json) {
341             short code = (short) nullIsIllegal(json.get(CriterionCodec.ICMPV6_CODE),
342                     CriterionCodec.ICMPV6_CODE + MISSING_MEMBER_MESSAGE).asInt();
343             return Criteria.matchIcmpv6Code(code);
344         }
345     }
346
347     private class V6NDTargetDecoder implements CriterionDecoder {
348         @Override
349         public Criterion decodeCriterion(ObjectNode json) {
350             Ip6Address target = Ip6Address.valueOf(nullIsIllegal(json.get(CriterionCodec.TARGET_ADDRESS),
351                     CriterionCodec.TARGET_ADDRESS + MISSING_MEMBER_MESSAGE).asText());
352             return Criteria.matchIPv6NDTargetAddress(target);
353         }
354     }
355
356     private class V6NDSllDecoder implements CriterionDecoder {
357         @Override
358         public Criterion decodeCriterion(ObjectNode json) {
359             MacAddress mac = MacAddress.valueOf(nullIsIllegal(json.get(CriterionCodec.MAC),
360                     CriterionCodec.MAC + MISSING_MEMBER_MESSAGE).asText());
361             return Criteria.matchIPv6NDSourceLinkLayerAddress(mac);
362         }
363     }
364
365     private class V6NDTllDecoder implements CriterionDecoder {
366         @Override
367         public Criterion decodeCriterion(ObjectNode json) {
368             MacAddress mac = MacAddress.valueOf(nullIsIllegal(json.get(CriterionCodec.MAC),
369                     CriterionCodec.MAC + MISSING_MEMBER_MESSAGE).asText());
370             return Criteria.matchIPv6NDTargetLinkLayerAddress(mac);
371         }
372     }
373
374     private class MplsLabelDecoder implements CriterionDecoder {
375         @Override
376         public Criterion decodeCriterion(ObjectNode json) {
377             int label = nullIsIllegal(json.get(CriterionCodec.LABEL),
378                     CriterionCodec.LABEL + MISSING_MEMBER_MESSAGE).asInt();
379             return Criteria.matchMplsLabel(MplsLabel.mplsLabel(label));
380         }
381     }
382
383     private class IpV6ExthdrDecoder implements CriterionDecoder {
384         @Override
385         public Criterion decodeCriterion(ObjectNode json) {
386             int exthdrFlags = nullIsIllegal(json.get(CriterionCodec.EXT_HDR_FLAGS),
387                     CriterionCodec.EXT_HDR_FLAGS + MISSING_MEMBER_MESSAGE).asInt();
388             return Criteria.matchIPv6ExthdrFlags(exthdrFlags);
389         }
390     }
391
392     private class OchSigIdDecoder implements CriterionDecoder {
393         @Override
394         public Criterion decodeCriterion(ObjectNode json) {
395             if (json.get(CriterionCodec.LAMBDA) != null) {
396                 Lambda lambda = Lambda.indexedLambda(nullIsIllegal(json.get(CriterionCodec.LAMBDA),
397                         CriterionCodec.LAMBDA + MISSING_MEMBER_MESSAGE).asInt());
398                 return Criteria.matchLambda(lambda);
399             } else {
400                 JsonNode ochSignalId = nullIsIllegal(json.get(CriterionCodec.OCH_SIGNAL_ID),
401                         CriterionCodec.GRID_TYPE + MISSING_MEMBER_MESSAGE);
402                 GridType gridType =
403                         GridType.valueOf(
404                                 nullIsIllegal(ochSignalId.get(CriterionCodec.GRID_TYPE),
405                                 CriterionCodec.GRID_TYPE + MISSING_MEMBER_MESSAGE).asText());
406                 ChannelSpacing channelSpacing =
407                         ChannelSpacing.valueOf(
408                                 nullIsIllegal(ochSignalId.get(CriterionCodec.CHANNEL_SPACING),
409                                 CriterionCodec.CHANNEL_SPACING + MISSING_MEMBER_MESSAGE).asText());
410                 int spacingMultiplier = nullIsIllegal(ochSignalId.get(CriterionCodec.SPACING_MULIPLIER),
411                         CriterionCodec.SPACING_MULIPLIER + MISSING_MEMBER_MESSAGE).asInt();
412                 int slotGranularity = nullIsIllegal(ochSignalId.get(CriterionCodec.SLOT_GRANULARITY),
413                         CriterionCodec.SLOT_GRANULARITY + MISSING_MEMBER_MESSAGE).asInt();
414                 return Criteria.matchLambda(
415                         Lambda.ochSignal(gridType, channelSpacing,
416                                 spacingMultiplier, slotGranularity));
417             }
418         }
419     }
420
421     private class OchSigTypeDecoder implements CriterionDecoder {
422         @Override
423         public Criterion decodeCriterion(ObjectNode json) {
424             OchSignalType ochSignalType = OchSignalType.valueOf(nullIsIllegal(json.get(CriterionCodec.OCH_SIGNAL_TYPE),
425                     CriterionCodec.OCH_SIGNAL_TYPE + MISSING_MEMBER_MESSAGE).asText());
426             return Criteria.matchOchSignalType(ochSignalType);
427         }
428     }
429
430     private class TunnelIdDecoder implements CriterionDecoder {
431         @Override
432         public Criterion decodeCriterion(ObjectNode json) {
433             long tunnelId = nullIsIllegal(json.get(CriterionCodec.TUNNEL_ID),
434                     CriterionCodec.TUNNEL_ID + MISSING_MEMBER_MESSAGE).asLong();
435             return Criteria.matchTunnelId(tunnelId);
436         }
437     }
438
439     private class OduSigIdDecoder implements CriterionDecoder {
440         @Override
441         public Criterion decodeCriterion(ObjectNode json) {
442             JsonNode oduSignalId = nullIsIllegal(json.get(CriterionCodec.ODU_SIGNAL_ID),
443                     CriterionCodec.TRIBUTARY_PORT_NUMBER + MISSING_MEMBER_MESSAGE);
444
445             int tributaryPortNumber = nullIsIllegal(oduSignalId.get(CriterionCodec.TRIBUTARY_PORT_NUMBER),
446                     CriterionCodec.TRIBUTARY_PORT_NUMBER + MISSING_MEMBER_MESSAGE).asInt();
447             int tributarySlotLen = nullIsIllegal(oduSignalId.get(CriterionCodec.TRIBUTARY_SLOT_LEN),
448                     CriterionCodec.TRIBUTARY_SLOT_LEN + MISSING_MEMBER_MESSAGE).asInt();
449             byte[] tributarySlotBitmap = HexString.fromHexString(
450                     nullIsIllegal(oduSignalId.get(CriterionCodec.TRIBUTARY_SLOT_BITMAP),
451                     CriterionCodec.TRIBUTARY_SLOT_BITMAP + MISSING_MEMBER_MESSAGE).asText());
452
453             return Criteria.matchOduSignalId(
454                     OduSignalId.oduSignalId(tributaryPortNumber, tributarySlotLen, tributarySlotBitmap));
455         }
456     }
457
458     private class OduSigTypeDecoder implements CriterionDecoder {
459         @Override
460         public Criterion decodeCriterion(ObjectNode json) {
461             OduSignalType oduSignalType = OduSignalType.valueOf(nullIsIllegal(json.get(CriterionCodec.ODU_SIGNAL_TYPE),
462                     CriterionCodec.ODU_SIGNAL_TYPE + MISSING_MEMBER_MESSAGE).asText());
463             return Criteria.matchOduSignalType(oduSignalType);
464         }
465     }
466
467     /**
468      * Decodes the JSON into a criterion object.
469      *
470      * @return Criterion object
471      * @throws IllegalArgumentException if the JSON is invalid
472      */
473     public Criterion decode() {
474         String type = json.get(CriterionCodec.TYPE).asText();
475
476         CriterionDecoder decoder = decoderMap.get(type);
477         if (decoder != null) {
478             return decoder.decodeCriterion(json);
479         }
480
481         throw new IllegalArgumentException("Type " + type + " is unknown");
482     }
483
484
485 }