blob: d124f5a334733afce47a4acf840347e731e9bd39 [file] [log] [blame]
Andreas Wundsam27303462013-07-16 12:52:35 -07001# Copyright 2013, Big Switch Networks, Inc.
2#
3# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
4# the following special exception:
5#
6# LOXI Exception
7#
8# As a special exception to the terms of the EPL, you may distribute libraries
9# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
10# that copyright and licensing notices generated by LoxiGen are not altered or removed
11# from the LoxiGen Libraries and the notice provided below is (i) included in
12# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
13# documentation for the LoxiGen Libraries, if distributed in binary form.
14#
15# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
16#
17# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
18# a copy of the EPL at:
19#
20# http://www.eclipse.org/legal/epl-v10.html
21#
22# Unless required by applicable law or agreed to in writing, software
23# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25# EPL for the specific language governing permissions and limitations
26# under the EPL.
27
Andreas Wundsam40e14f72013-05-06 14:49:08 -070028# Prototype of an Intermediate Object model for the java code generator
29# A lot of this stuff could/should probably be merged with the python utilities
30
Andreas Wundsam27303462013-07-16 12:52:35 -070031import collections
Andreas Wundsam5204de22013-07-30 11:34:45 -070032from collections import namedtuple, defaultdict, OrderedDict
Andreas Wundsam27303462013-07-16 12:52:35 -070033import logging
Andreas Wundsam40e14f72013-05-06 14:49:08 -070034import os
35import pdb
36import re
37
Andreas Wundsam5204de22013-07-30 11:34:45 -070038from generic_utils import find, memoize, OrderedSet, OrderedDefaultDict
Andreas Wundsamc8912c12013-11-15 13:44:48 -080039from loxi_globals import OFVersions
40import loxi_globals
Andreas Wundsam27303462013-07-16 12:52:35 -070041from loxi_ir import *
Andreas Wundsam5204de22013-07-30 11:34:45 -070042import loxi_utils.loxi_utils as loxi_utils
Andreas Wundsam5204de22013-07-30 11:34:45 -070043import test_data
Andreas Wundsam40e14f72013-05-06 14:49:08 -070044
Andreas Wundsam27303462013-07-16 12:52:35 -070045import java_gen.java_type as java_type
Andreas Wundsame0d52be2013-08-22 07:52:13 -070046from java_gen.java_type import erase_type_annotation
Andreas Wundsam40e14f72013-05-06 14:49:08 -070047
Andreas Wundsamc8912c12013-11-15 13:44:48 -080048logger = logging.getLogger(__name__)
49
Andreas Wundsam27303462013-07-16 12:52:35 -070050class JavaModel(object):
Andreas Wundsamf1949682013-09-23 14:48:31 -070051 # registry for enums that should not be generated
52 # set(${java_enum_name})
Andreas Wundsamacd57d52013-10-18 17:35:01 -070053 enum_blacklist = set(("OFDefinitions", "OFPortNo", "OFVlanId", "OFGroup"))
Andreas Wundsamf1949682013-09-23 14:48:31 -070054 # registry for enum *entry* that should not be generated
55 # map: ${java_enum_name} -> set(${java_entry_entry_name})
Andreas Wundsam43526532013-08-01 22:03:50 -070056 enum_entry_blacklist = defaultdict(lambda: set(), OFFlowWildcards=set([ "NW_DST_BITS", "NW_SRC_BITS", "NW_SRC_SHIFT", "NW_DST_SHIFT" ]))
Andreas Wundsamf1949682013-09-23 14:48:31 -070057
58 # registry of interfaces that should not be generated
59 # set(java_names)
Andreas Wundsambe168f72013-08-03 22:49:35 -070060 # OFUint structs are there for god-knows what in loci. We certainly don't need them.
61 interface_blacklist = set( ("OFUint8", "OFUint32",))
Andreas Wundsamf1949682013-09-23 14:48:31 -070062 # registry of interface properties that should not be generated
63 # map: $java_type -> set(java_name_property)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -070064 read_blacklist = defaultdict(lambda: set(), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
Andreas Wundsamf1949682013-09-23 14:48:31 -070065 # map: $java_type -> set(java_name_property)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -070066 write_blacklist = defaultdict(lambda: set(), OFOxm=set(('typeLen',)), OFAction=set(('type',)), OFInstruction=set(('type',)), OFFlowMod=set(('command', )), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
Andreas Wundsamf1949682013-09-23 14:48:31 -070067 # interfaces that are virtual
Andreas Wundsam001b1822013-08-02 22:25:55 -070068 virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
Andreas Wundsam27303462013-07-16 12:52:35 -070069
Andreas Wundsam2be7da52013-08-22 07:34:25 -070070 OxmMapEntry = namedtuple("OxmMapEntry", ["type_name", "value", "masked" ])
Yotam Harchole5d92972013-08-22 14:18:36 -070071 oxm_map = { "OFOxmInPort": OxmMapEntry("OFPort", "IN_PORT", False),
72 "OFOxmInPortMasked": OxmMapEntry("OFPort", "IN_PORT", True),
73 "OFOxmInPhyPort": OxmMapEntry("OFPort", "IN_PHY_PORT", False),
74 "OFOxmInPhyPortMasked": OxmMapEntry("OFPort", "IN_PHY_PORT", True),
75 "OFOxmMetadata": OxmMapEntry("OFMetadata", "METADATA", False),
76 "OFOxmMetadataMasked": OxmMapEntry("OFMetadata", "METADATA", True),
77 "OFOxmEthDst": OxmMapEntry("MacAddress", "ETH_DST", False),
78 "OFOxmEthDstMasked": OxmMapEntry("MacAddress", "ETH_DST", True),
79 "OFOxmEthSrc": OxmMapEntry("MacAddress", "ETH_SRC", False),
80 "OFOxmEthSrcMasked": OxmMapEntry("MacAddress", "ETH_SRC", True),
81 "OFOxmEthType": OxmMapEntry("EthType", "ETH_TYPE", False),
82 "OFOxmEthTypeMasked": OxmMapEntry("EthType", "ETH_TYPE", True),
Andreas Wundsam98a18632013-11-05 11:34:24 -080083 "OFOxmVlanVid": OxmMapEntry("OFVlanVidMatch", "VLAN_VID", False),
84 "OFOxmVlanVidMasked": OxmMapEntry("OFVlanVidMatch", "VLAN_VID", True),
Yotam Harchole5d92972013-08-22 14:18:36 -070085 "OFOxmVlanPcp": OxmMapEntry("VlanPcp", "VLAN_PCP", False),
86 "OFOxmVlanPcpMasked": OxmMapEntry("VlanPcp", "VLAN_PCP", True),
87 "OFOxmIpDscp": OxmMapEntry("IpDscp", "IP_DSCP", False),
88 "OFOxmIpDscpMasked": OxmMapEntry("IpDscp", "IP_DSCP", True),
89 "OFOxmIpEcn": OxmMapEntry("IpEcn", "IP_ECN", False),
90 "OFOxmIpEcnMasked": OxmMapEntry("IpEcn", "IP_ECN", True),
91 "OFOxmIpProto": OxmMapEntry("IpProtocol", "IP_PROTO", False),
92 "OFOxmIpProtoMasked": OxmMapEntry("IpProtocol", "IP_PROTO", True),
Yotam Harchola289d552013-09-16 10:10:40 -070093 "OFOxmIpv4Src": OxmMapEntry("IPv4Address", "IPV4_SRC", False),
94 "OFOxmIpv4SrcMasked": OxmMapEntry("IPv4Address", "IPV4_SRC", True),
95 "OFOxmIpv4Dst": OxmMapEntry("IPv4Address", "IPV4_DST", False),
96 "OFOxmIpv4DstMasked": OxmMapEntry("IPv4Address", "IPV4_DST", True),
Yotam Harchole5d92972013-08-22 14:18:36 -070097 "OFOxmTcpSrc": OxmMapEntry("TransportPort", "TCP_SRC", False),
98 "OFOxmTcpSrcMasked": OxmMapEntry("TransportPort", "TCP_SRC", True),
99 "OFOxmTcpDst": OxmMapEntry("TransportPort", "TCP_DST", False),
100 "OFOxmTcpDstMasked": OxmMapEntry("TransportPort", "TCP_DST", True),
101 "OFOxmUdpSrc": OxmMapEntry("TransportPort", "UDP_SRC", False),
102 "OFOxmUdpSrcMasked": OxmMapEntry("TransportPort", "UDP_SRC", True),
103 "OFOxmUdpDst": OxmMapEntry("TransportPort", "UDP_DST", False),
104 "OFOxmUdpDstMasked": OxmMapEntry("TransportPort", "UDP_DST", True),
105 "OFOxmSctpSrc": OxmMapEntry("TransportPort", "SCTP_SRC", False),
106 "OFOxmSctpSrcMasked": OxmMapEntry("TransportPort", "SCTP_SRC", True),
107 "OFOxmSctpDst": OxmMapEntry("TransportPort", "SCTP_DST", False),
108 "OFOxmSctpDstMasked": OxmMapEntry("TransportPort", "SCTP_DST", True),
109 "OFOxmIcmpv4Type": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", False),
110 "OFOxmIcmpv4TypeMasked": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", True),
111 "OFOxmIcmpv4Code": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", False),
112 "OFOxmIcmpv4CodeMasked": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", True),
113 "OFOxmArpOp": OxmMapEntry("ArpOpcode", "ARP_OP", False),
114 "OFOxmArpOpMasked": OxmMapEntry("ArpOpcode", "ARP_OP", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700115 "OFOxmArpSpa": OxmMapEntry("IPv4Address", "ARP_SPA", False),
116 "OFOxmArpSpaMasked": OxmMapEntry("IPv4Address", "ARP_SPA", True),
117 "OFOxmArpTpa": OxmMapEntry("IPv4Address", "ARP_TPA", False),
118 "OFOxmArpTpaMasked": OxmMapEntry("IPv4Address", "ARP_TPA", True),
Yotam Harchole5d92972013-08-22 14:18:36 -0700119 "OFOxmArpSha": OxmMapEntry("MacAddress", "ARP_SHA", False),
120 "OFOxmArpShaMasked": OxmMapEntry("MacAddress", "ARP_SHA", True),
121 "OFOxmArpTha": OxmMapEntry("MacAddress", "ARP_THA", False),
122 "OFOxmArpThaMasked": OxmMapEntry("MacAddress", "ARP_THA", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700123 "OFOxmIpv6Src": OxmMapEntry("IPv6Address", "IPV6_SRC", False),
124 "OFOxmIpv6SrcMasked": OxmMapEntry("IPv6Address", "IPV6_SRC", True),
125 "OFOxmIpv6Dst": OxmMapEntry("IPv6Address", "IPV6_DST", False),
126 "OFOxmIpv6DstMasked": OxmMapEntry("IPv6Address", "IPV6_DST", True),
Yotam Harchole5d92972013-08-22 14:18:36 -0700127 "OFOxmIpv6Flabel": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", False),
Yotam Harchola86e4252013-09-06 15:36:28 -0700128 "OFOxmIpv6FlabelMasked": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", True),
129 "OFOxmIcmpv6Type": OxmMapEntry("U8", "ICMPV6_TYPE", False),
130 "OFOxmIcmpv6TypeMasked": OxmMapEntry("U8", "ICMPV6_TYPE", True),
131 "OFOxmIcmpv6Code": OxmMapEntry("U8", "ICMPV6_CODE", False),
132 "OFOxmIcmpv6CodeMasked": OxmMapEntry("U8", "ICMPV6_CODE", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700133 "OFOxmIpv6NdTarget": OxmMapEntry("IPv6Address", "IPV6_ND_TARGET", False),
134 "OFOxmIpv6NdTargetMasked": OxmMapEntry("IPv6Address", "IPV6_ND_TARGET", True),
Yotam Harchola86e4252013-09-06 15:36:28 -0700135 "OFOxmIpv6NdSll": OxmMapEntry("MacAddress", "IPV6_ND_SLL", False),
136 "OFOxmIpv6NdSllMasked": OxmMapEntry("MacAddress", "IPV6_ND_SLL", True),
137 "OFOxmIpv6NdTll": OxmMapEntry("MacAddress", "IPV6_ND_TLL", False),
138 "OFOxmIpv6NdTllMasked": OxmMapEntry("MacAddress", "IPV6_ND_TLL", True),
139 "OFOxmMplsLabel": OxmMapEntry("U32", "MPLS_LABEL", False),
140 "OFOxmMplsLabelMasked": OxmMapEntry("U32", "MPLS_LABEL", True),
141 "OFOxmMplsTc": OxmMapEntry("U8", "MPLS_TC", False),
Yotam Harchola11f38b2013-09-26 15:38:17 -0700142 "OFOxmMplsTcMasked": OxmMapEntry("U8", "MPLS_TC", True),
Yotam Harchol2c535582013-10-01 15:50:20 -0700143 "OFOxmBsnInPorts128": OxmMapEntry("OFBitMask128", "BSN_IN_PORTS_128", False),
Rich Lane1424d0b2013-10-24 17:16:24 -0700144 "OFOxmBsnInPorts128Masked": OxmMapEntry("OFBitMask128", "BSN_IN_PORTS_128", True),
Rich Lane376cafe2013-10-27 21:49:14 -0700145 "OFOxmBsnLagId": OxmMapEntry("LagId", "BSN_LAG_ID", False),
146 "OFOxmBsnLagIdMasked": OxmMapEntry("LagId", "BSN_LAG_ID", True),
Rich Laneeb21c4f2013-10-28 17:34:41 -0700147 "OFOxmBsnVrf": OxmMapEntry("VRF", "BSN_VRF", False),
148 "OFOxmBsnVrfMasked": OxmMapEntry("VRF", "BSN_VRF", True),
Rich Lane9c27b5d2013-10-30 17:14:32 -0700149 "OFOxmBsnGlobalVrfAllowed": OxmMapEntry("OFBooleanValue", "BSN_GLOBAL_VRF_ALLOWED", False),
150 "OFOxmBsnGlobalVrfAllowedMasked": OxmMapEntry("OFBooleanValue", "BSN_GLOBAL_VRF_ALLOWED", True),
Rich Laneeb21c4f2013-10-28 17:34:41 -0700151 "OFOxmBsnL3InterfaceClassId": OxmMapEntry("ClassId", "BSN_L3_INTERFACE_CLASS_ID", False),
152 "OFOxmBsnL3InterfaceClassIdMasked": OxmMapEntry("ClassId", "BSN_L3_INTERFACE_CLASS_ID", True),
153 "OFOxmBsnL3SrcClassId": OxmMapEntry("ClassId", "BSN_L3_SRC_CLASS_ID", False),
154 "OFOxmBsnL3SrcClassIdMasked": OxmMapEntry("ClassId", "BSN_L3_SRC_CLASS_ID", True),
155 "OFOxmBsnL3DstClassId": OxmMapEntry("ClassId", "BSN_L3_DST_CLASS_ID", False),
156 "OFOxmBsnL3DstClassIdMasked": OxmMapEntry("ClassId", "BSN_L3_DST_CLASS_ID", True),
Yotam Harchola86e4252013-09-06 15:36:28 -0700157 }
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700158
Andreas Wundsamf1949682013-09-23 14:48:31 -0700159 # Registry of nullable properties:
160 # ${java_class_name} -> set(${java_property_name})
161 nullable_map = defaultdict(lambda: set(),
162 )
163
164 # represents a subgroup of a bitmask enum that is actualy a normal enumerable within a masked part of the enum
165 # e.g., the flags STP.* in OF1.0 port state are bit mask entries, but instead enumerables according to the mask "STP_MASK"
166 # name: a name for the group
167 # mask: java name of the enum entry that defines the mask
168 # members: set of names of the members of the group
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700169 MaskedEnumGroup = namedtuple("MaskedEnumGroup", ("name", "mask", "members"))
170
Andreas Wundsamf1949682013-09-23 14:48:31 -0700171 # registry of MaskedEnumGroups (see above).
172 # map: ${java_enum_name}: tuple(MaskedEnumGroup)
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700173 masked_enum_groups = defaultdict(lambda: (),
Andreas Wundsamaebe5182013-09-24 13:01:07 -0700174 OFPortState = (MaskedEnumGroup("stp_flags", mask="STP_MASK", members=set(("STP_LISTEN", "STP_LEARN", "STP_FORWARD", "STP_BLOCK"))), ),
175 OFConfigFlags = (
176 MaskedEnumGroup("frag_flags", mask="FRAG_MASK", members=set(("FRAG_NORMAL", "FRAG_DROP", "FRAG_REASM"))),
Andreas Wundsam376cef52013-09-24 13:52:18 -0700177 ),
178 OFTableConfig = (
179 MaskedEnumGroup("table_miss_flags", mask="TABLE_MISS_MASK", members=set(("TABLE_MISS_CONTROLLER", "TABLE_MISS_CONTINUE", "TABLE_MISS_DROP"))),
180 ),
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700181 )
182
Andreas Wundsamf1949682013-09-23 14:48:31 -0700183 # represents a metadata property associated with an EnumClass
184 # name:
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700185 class OFEnumPropertyMetadata(namedtuple("OFEnumPropertyMetadata", ("name", "type", "value"))):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700186 """
187 represents a metadata property associated with an Enum Class
188 @param name name of metadata property
189 @param type java_type instance describing the type
190 @value: Generator function f(entry) that generates the value
191 """
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700192 @property
193 def variable_name(self):
194 return self.name[0].lower() + self.name[1:]
195
196 @property
197 def getter_name(self):
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700198 prefix = "is" if self.type == java_type.boolean else "get"
199 return prefix+self.name
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700200
Andreas Wundsamf1949682013-09-23 14:48:31 -0700201 """ Metadata container. """
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700202 OFEnumMetadata = namedtuple("OFEnumMetadata", ("properties", "to_string"))
203
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700204 def gen_port_speed(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700205 """ Generator function for OFortFeatures.PortSpeed"""
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700206 splits = enum_entry.name.split("_")
207 if len(splits)>=2:
208 m = re.match(r'\d+[MGTP]B', splits[1])
209 if m:
210 return "PortSpeed.SPEED_{}".format(splits[1])
211 return "PortSpeed.SPEED_NONE";
212
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700213 def gen_stp_state(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700214 """ Generator function for OFPortState.StpState"""
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700215 splits = enum_entry.name.split("_")
216 if len(splits)>=1:
217 if splits[0] == "STP":
218 return "true"
219 return "false"
220
Andreas Wundsamf1949682013-09-23 14:48:31 -0700221 # registry for metadata properties for enums
222 # map: ${java_enum_name}: OFEnumMetadata
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700223 enum_metadata_map = defaultdict(lambda: JavaModel.OFEnumMetadata((), None),
Rob Vaterlausa049dee2013-09-18 16:18:37 -0700224 OFPortFeatures = OFEnumMetadata((OFEnumPropertyMetadata("PortSpeed", java_type.port_speed, gen_port_speed),), None),
225 OFPortState = OFEnumMetadata((OFEnumPropertyMetadata("StpState", java_type.boolean, gen_stp_state),), None),
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700226 )
227
Andreas Wundsam27303462013-07-16 12:52:35 -0700228 @property
229 @memoize
230 def versions(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800231 return OrderedSet( JavaOFVersion(ir_version) for ir_version in OFVersions.target_versions)
Andreas Wundsam27303462013-07-16 12:52:35 -0700232
233 @property
234 @memoize
235 def interfaces(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800236 interfaces = [ JavaOFInterface(ir_class) for ir_class in loxi_globals.unified.classes ]
Andreas Wundsambe168f72013-08-03 22:49:35 -0700237 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
238
Andreas Wundsam27303462013-07-16 12:52:35 -0700239 return interfaces
240
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700241 @memoize
242 def interface_by_name(self, name):
243 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
244
Andreas Wundsam27303462013-07-16 12:52:35 -0700245 @property
246 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700247 def all_classes(self):
248 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
249
250 @property
251 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700252 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700253 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700254
255 for version in self.versions:
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800256 logger.info("version: {}".format(version.ir_version))
257 of_protocol = loxi_globals.ir[version.ir_version]
Andreas Wundsam27303462013-07-16 12:52:35 -0700258 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700259 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700260
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700261 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
262 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700263
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700264 # inelegant - need java name here
265 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700266 return enums
267
268 @memoize
269 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700270 res = find(lambda e: e.name == name, self.enums)
271 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700272 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700273 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700274
Andreas Wundsam5204de22013-07-30 11:34:45 -0700275 @property
276 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700277 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700278 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700279
280 factories = OrderedDict()
281
282 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
283 for base_class in sub_factory_classes:
284 package = base_class[2:].lower()
285 remove_prefix = base_class[2].lower() + base_class[3:]
286
287 # HACK need to have a better way to deal with parameterized base classes
288 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
289
290 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700291 name=base_class + "s", members=[], remove_prefix=remove_prefix, base_class=annotated_base_class, sub_factories={}, xid_generator=False)
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700292
293 factories[""] = OFFactory(
294 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700295 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700296 remove_prefix="",
297 members=[], base_class="OFMessage", sub_factories=OrderedDict(
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700298 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ),
299 xid_generator=True)
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700300
301 for i in self.interfaces:
302 for n, factory in factories.items():
303 if n == "":
304 factory.members.append(i)
305 break
306 else:
307 super_class = self.interface_by_name(n)
308 if i.is_instance_of(super_class):
309 factory.members.append(i)
310 break
311 return factories.values()
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800312
Yotam Harchol595c6442013-09-27 16:29:08 -0700313 @memoize
314 def factory_of(self, interface):
315 for factory in self.of_factories:
316 if interface in factory.members:
317 return factory
318 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700319
320 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700321 """ return wether or not to generate implementation class clazz.
322 Now true for everything except OFTableModVer10.
323 @param clazz JavaOFClass instance
324 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700325 if clazz.interface.name.startswith("OFMatchV"):
326 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700327 elif clazz.name == "OFTableModVer10":
328 # tablemod ver 10 is a hack and has no oftype defined
329 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700330 if loxi_utils.class_is_message(clazz.interface.c_name):
331 return True
332 if loxi_utils.class_is_oxm(clazz.interface.c_name):
333 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700334 if loxi_utils.class_is_action(clazz.interface.c_name):
335 return True
336 if loxi_utils.class_is_instruction(clazz.interface.c_name):
337 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700338 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700339 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700340
341
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700342class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories", "xid_generator"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700343 @property
344 def factory_classes(self):
345 return [ OFFactoryClass(
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800346 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.dotless_version),
347 name="{}Ver{}".format(self.name, version.dotless_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700348 interface=self,
349 version=version
350 ) for version in model.versions ]
351
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700352 def method_name(self, member, builder=True):
353 n = member.variable_name
354 if n.startswith(self.remove_prefix):
355 n = n[len(self.remove_prefix):]
356 n = n[0].lower() + n[1:]
357 if builder:
358 return "build" + n[0].upper() + n[1:]
359 else:
360 return n
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800361
Yotam Harchol595c6442013-09-27 16:29:08 -0700362 def of_version(self, version):
363 for fc in self.factory_classes:
364 if fc.version == version:
365 return fc
366 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700367
368OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700369class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
370 @property
371 def base_class(self):
372 return self.interface.base_class
373
374 @property
375 def versioned_base_class(self):
376 base_class_interface = model.interface_by_name(self.interface.base_class)
377 if base_class_interface and base_class_interface.has_version(self.version):
378 return base_class_interface.versioned_class(self.version)
379 else:
380 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700381
Andreas Wundsam27303462013-07-16 12:52:35 -0700382model = JavaModel()
383
384#######################################################################
385### OFVersion
386#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700387
388class JavaOFVersion(object):
389 """ Models a version of OpenFlow. contains methods to convert the internal
390 Loxi version to a java constant / a string """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800391 def __init__(self, ir_version):
392 assert isinstance(ir_version, OFVersion)
393 self.ir_version = ir_version
394 self.int_version = self.ir_version.wire_version
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700395
396 @property
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800397 def dotless_version(self):
398 return self.ir_version.version.replace(".", "")
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700399
400 @property
401 def constant_version(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800402 return "OF_" + self.dotless_version
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700403
Andreas Wundsam27303462013-07-16 12:52:35 -0700404 def __repr__(self):
405 return "JavaOFVersion(%d)" % self.int_version
406
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700407 def __str__(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800408 return self.ir_version.version
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700409
Andreas Wundsam27303462013-07-16 12:52:35 -0700410 def __hash__(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800411 return hash(self.ir_version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700412
413 def __eq__(self, other):
414 if other is None or type(self) != type(other):
415 return False
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800416 return (self.ir_version,) == (other.ir_version,)
Andreas Wundsam27303462013-07-16 12:52:35 -0700417
418#######################################################################
419### Interface
420#######################################################################
421
422class JavaOFInterface(object):
423 """ Models an OpenFlow Message class for the purpose of the java class.
424 Version agnostic, in contrast to the loxi_ir python model.
425 """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800426 def __init__(self, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700427 """"
428 @param c_name: loxi style name (e.g., of_flow_add)
429 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
430 """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800431 self.ir_class = ir_class
432 self.c_name = ir_class.name
433 self.version_map = { JavaOFVersion(v): c for v,c in ir_class.version_classes.items() }
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700434 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800435 self.name = java_type.name_c_to_caps_camel(self.c_name) if self.c_name != "of_header" else "OFMessage"
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700436 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700437 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700438 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700439 # name for use in constants: FLOW_ADD
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800440 self.constant_name = self.c_name.upper().replace("OF_", "")
Andreas Wundsam27303462013-07-16 12:52:35 -0700441
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700442 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700443 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700444 if self.name != parent_interface:
445 self.parent_interface = parent_interface
446 else:
447 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700448
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700449 @property
450 @memoize
451 def all_parent_interfaces(self):
452 return [ "OFObject" ] + \
453 ([ self.parent_interface ] if self.parent_interface else [] )+ \
454 self.additional_parent_interfaces
455 @property
456 @memoize
457 def additional_parent_interfaces(self):
458 if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
459 m = re.match(r'(.*)Request$', self.name)
460 if m:
461 reply_name = m.group(1) + "Reply"
462 if model.interface_by_name(reply_name):
463 return ["OFRequest<%s>" % reply_name ]
464 return []
465
466
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700467 def is_instance_of(self, other_class):
468 if self == other_class:
469 return True
470 parent = self.super_class
471 if parent is None:
472 return False
473 else:
474 return parent.is_instance_of(other_class)
475
476 @property
477 def super_class(self):
478 if not self.parent_interface:
479 return None
480 else:
481 return model.interface_by_name(self.parent_interface)
482
483
484 def inherited_declaration(self, type_spec="?"):
485 if self.type_annotation:
486 return "%s<%s>" % (self.name, type_spec)
487 else:
488 return "%s" % self.name
489
490 @property
491 def type_variable(self):
492 if self.type_annotation:
493 return "<T>"
494 else:
495 return "";
496
Andreas Wundsam27303462013-07-16 12:52:35 -0700497 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700498 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
499 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
500 # model (note, that the loxi model is on versioned classes). Should check/infer the
501 # inheritance information from the versioned lox_ir classes.
Andreas Wundsamd6b0cb02013-09-28 18:55:56 -0700502 if re.match(r'OFStatsRequest$', self.name):
503 return ("", "OFMessage", "T extends OFStatsReply")
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800504 elif self.ir_class.is_subclassof('of_stats_request'):
Andreas Wundsamd6b0cb02013-09-28 18:55:56 -0700505 return ("", "OFStatsRequest<{}>".format(re.sub(r'Request$', 'Reply', self.name)), None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800506 elif self.ir_class.is_subclassof('of_stats_reply'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700507 return ("", "OFStatsReply", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800508 elif self.ir_class.is_subclassof('of_error_msg'):
Rob Vaterlausfeee3712013-09-30 11:24:19 -0700509 return ("", "OFErrorMsg", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800510 elif self.ir_class.is_subclassof('of_flow_mod'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700511 return ("", "OFFlowMod", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800512 elif self.ir_class.is_subclassof('of_group_mod'):
513 return ("", "OFGroupMod", None)
514 elif self.ir_class.is_subclassof('of_bsn_header'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700515 return ("", "OFBsnHeader", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800516 elif self.ir_class.is_subclassof('of_nicira_header'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700517 return ("", "OFNiciraHeader", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800518 elif self.ir_class.is_subclassof('of_experimenter'):
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700519 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700520 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700521 return ("", "Match", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800522 elif self.ir_class.is_message:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700523 return ("", "OFMessage", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800524 elif self.ir_class.is_action:
525 if self.ir_class.is_subclassof('of_action_bsn'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700526 return ("action", "OFActionBsn", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800527 elif self.ir_class.is_subclassof('of_action_nicira'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700528 return ("action", "OFActionNicira", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800529 elif self.ir_class.is_subclassof('of_action_experimenter'):
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700530 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700531 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700532 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700533 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700534 return ("", "OFBsnVport", None)
535 elif self.name == "OFOxm":
536 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700537 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700538 if self.name in model.oxm_map:
539 return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
540 else:
541 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700542 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700543 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700544 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700545 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700546 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700547 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700548 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700549 return ("", "OFHelloElem", None)
Rich Lane26847562013-10-08 13:44:47 -0700550 elif loxi_utils.class_is_table_feature_prop(self.c_name):
551 return ("", "OFTableFeatureProp", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700552 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700553 return ("", None, None)
554
555 @property
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800556
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700557 @memoize
558 def writeable_members(self):
559 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700560
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700561 @memoize
562 def member_by_name(self, name):
563 return find(lambda m: m.name == name, self.members)
564
Andreas Wundsam27303462013-07-16 12:52:35 -0700565 @property
566 @memoize
567 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700568 return self.ir_model_members + self.virtual_members
569
570 @property
571 @memoize
572 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700573 """return a list of all members to be exposed by this interface. Corresponds to
574 the union of the members of the vesioned classes without length, fieldlength
575 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700576 all_versions = []
577 member_map = collections.OrderedDict()
578
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800579 member_version_map = {}
Andreas Wundsam27303462013-07-16 12:52:35 -0700580 for (version, of_class) in self.version_map.items():
581 for of_member in of_class.members:
582 if isinstance(of_member, OFLengthMember) or \
583 isinstance(of_member, OFFieldLengthMember) or \
584 isinstance(of_member, OFPadMember):
585 continue
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800586 java_member = JavaMember.for_of_member(self, of_member)
Andreas Wundsam27303462013-07-16 12:52:35 -0700587 if of_member.name not in member_map:
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800588 member_map[of_member.name] = java_member
589 member_version_map[of_member.name] = version
590 else:
591 existing = member_map[of_member.name]
592
593 if existing.java_type.public_type != java_member.java_type.public_type:
594 raise Exception(
595 "Error constructing interface {}: type signatures do not match up between versions.\n"
596 " Member Name: {}\n"
597 " Existing: Version={}, Java={}, IR={}\n"
598 " New: Version={}, Java={}, IR={}"
599 .format(self.name, existing.name,
600 member_version_map[of_member.name], existing.java_type.public_type, existing.member.oftype,
601 version, java_member.java_type.public_type, java_member.member.oftype)
602 )
Andreas Wundsam27303462013-07-16 12:52:35 -0700603
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700604 return tuple(m for m in member_map.values() if m.name not in model.read_blacklist[self.name])
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700605
606 @property
607 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700608 virtual_members = []
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700609 if self.name == "OFOxm":
Andreas Wundsama0981022013-10-02 18:15:06 -0700610 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700611 JavaVirtualMember(self, "value", java_type.generic_t),
612 JavaVirtualMember(self, "mask", java_type.generic_t),
613 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
614 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800615 JavaVirtualMember(self, "canonical", java_type.make_oxm_jtype("T"))
Andreas Wundsama0981022013-10-02 18:15:06 -0700616 ]
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800617 elif self.ir_class.is_subclassof("of_oxm"):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700618 field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
619 if self.name in model.oxm_map \
620 else java_type.make_match_field_jtype()
621
Andreas Wundsama0981022013-10-02 18:15:06 -0700622 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700623 JavaVirtualMember(self, "matchField", field_type),
624 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800625 JavaVirtualMember(self, "canonical", java_type.make_oxm_jtype(model.oxm_map[self.name].type_name),
626 custom_template=lambda builder: "OFOxm{}_getCanonical.java".format(".Builder" if builder else "")),
Andreas Wundsama0981022013-10-02 18:15:06 -0700627 ]
628 if not find(lambda x: x.name == "mask", self.ir_model_members):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800629 virtual_members.append(
630 JavaVirtualMember(self, "mask", find(lambda x: x.name == "value", self.ir_model_members).java_type))
Andreas Wundsama0981022013-10-02 18:15:06 -0700631
632 if not find(lambda m: m.name == "version", self.ir_model_members):
633 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version))
634
635 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700636
637 @property
638 @memoize
639 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700640 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700641 return self.name in model.virtual_interfaces or all(ir_class.virtual for ir_class in self.version_map.values())
Andreas Wundsam27303462013-07-16 12:52:35 -0700642
643 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700644 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700645 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700646 return len(self.all_versions) == len(model.versions)
647
648 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700649 @memoize
650 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700651 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700652 return self.version_map.keys()
653
Andreas Wundsam5204de22013-07-30 11:34:45 -0700654 def has_version(self, version):
655 return version in self.version_map
656
Andreas Wundsam27303462013-07-16 12:52:35 -0700657 def versioned_class(self, version):
658 return JavaOFClass(self, version, self.version_map[version])
659
660 @property
661 @memoize
662 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700663 return [ self.versioned_class(version) for version in self.all_versions ]
664
665#######################################################################
666### (Versioned) Classes
667#######################################################################
668
669class JavaOFClass(object):
670 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700671 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700672 """
673 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700674 """
675 @param interface JavaOFInterface instance of the parent interface
676 @param version JavaOFVersion
677 @param ir_class OFClass from loxi_ir
678 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700679 self.interface = interface
680 self.ir_class = ir_class
681 self.c_name = self.ir_class.name
682 self.version = version
683 self.constant_name = self.c_name.upper().replace("OF_", "")
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800684 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.dotless_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700685 self.generated = False
686
687 @property
688 @memoize
689 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700690 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700691
692 @property
693 def name(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800694 return "%sVer%s" % (self.interface.name, self.version.dotless_version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700695
696 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700697 def variable_name(self):
Andreas Wundsam781d99f2013-10-23 15:25:56 -0700698 return self.name[2].lower() + self.name[3:]
Andreas Wundsam5204de22013-07-30 11:34:45 -0700699
700 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700701 def length(self):
702 if self.is_fixed_length:
703 return self.min_length
704 else:
705 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
706
707 @property
708 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700709 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800710 return self.ir_class.base_length
Andreas Wundsam27303462013-07-16 12:52:35 -0700711
712 @property
713 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700714 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800715 return self.ir_class.is_fixed_length and not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700716
717 def all_properties(self):
718 return self.interface.members
719
Andreas Wundsam27303462013-07-16 12:52:35 -0700720 @property
721 @memoize
722 def data_members(self):
723 return [ prop for prop in self.members if prop.is_data ]
724
725 @property
726 @memoize
727 def fixed_value_members(self):
728 return [ prop for prop in self.members if prop.is_fixed_value ]
729
730 @property
731 @memoize
732 def public_members(self):
733 return [ prop for prop in self.members if prop.is_public ]
734
735 @property
736 @memoize
737 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700738 return self.ir_model_members + self.virtual_members
739
740 @property
Andreas Wundsama0981022013-10-02 18:15:06 -0700741 @memoize
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700742 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700743 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700744 return tuple(members)
745
746 @property
747 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700748 virtual_members = []
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700749 if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
750 if self.interface.name in model.oxm_map:
751 oxm_entry = model.oxm_map[self.interface.name]
Andreas Wundsama0981022013-10-02 18:15:06 -0700752 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700753 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
754 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800755 ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700756 else:
Andreas Wundsama0981022013-10-02 18:15:06 -0700757 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700758 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
759 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800760 ]
Andreas Wundsama0981022013-10-02 18:15:06 -0700761 if not find(lambda m: m.name == "version", self.ir_model_members):
762 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version, "OFVersion.%s" % self.version.constant_version))
763
764 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700765
Andreas Wundsam661a2222013-11-05 17:18:59 -0800766 @memoize
767 def member_by_name(self, name):
768 return find(lambda m: m.name == name, self.members)
769
Andreas Wundsam27303462013-07-16 12:52:35 -0700770 def all_versions(self):
771 return [ JavaOFVersion(int_version)
772 for int_version in of_g.unified[self.c_name]
773 if int_version != 'union' and int_version != 'object_id' ]
774
775 def version_is_inherited(self, version):
776 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
777
778 def inherited_from(self, version):
779 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
780
781 @property
782 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700783 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
784
785 @property
786 def discriminator(self):
787 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700788
789 @property
790 def is_extension(self):
791 return type_maps.message_is_extension(self.c_name, -1)
792
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700793 @property
794 def align(self):
795 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
796
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700797 @property
Andreas Wundsam5da68512013-10-22 22:18:00 -0700798 def length_includes_align(self):
799 return self.ir_class.params['length_includes_align'] == "True" if 'length_includes_align' in self.ir_class.params else False
800
801 @property
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700802 @memoize
803 def superclass(self):
804 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
805
806 @property
807 @memoize
808 def subclasses(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800809 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass
810 and c.ir_class.superclass.name == self.c_name ]
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700811
Andreas Wundsam27303462013-07-16 12:52:35 -0700812#######################################################################
813### Member
814#######################################################################
815
816
817class JavaMember(object):
818 """ Models a property (member) of an openflow class. """
819 def __init__(self, msg, name, java_type, member):
820 self.msg = msg
821 self.name = name
822 self.java_type = java_type
823 self.member = member
824 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700825
826 @property
827 def title_name(self):
828 return self.name[0].upper() + self.name[1:]
829
830 @property
831 def constant_name(self):
832 return self.c_name.upper()
833
834 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700835 def getter_name(self):
836 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
837
838 @property
839 def setter_name(self):
840 return "set" + self.title_name
841
842 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700843 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700844 if self.is_fixed_value:
845 return self.constant_name
846 else:
847 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700848
849 @property
850 def default_value(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700851 if self.is_fixed_value:
852 return self.enum_value
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700853 else:
Andreas Wundsam142dd2a2013-09-23 14:47:37 -0700854 default = self.java_type.default_op(self.msg.version)
855 if default == "null" and not self.is_nullable:
856 return None
857 else:
858 return default
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700859
860 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700861 def enum_value(self):
862 if self.name == "version":
863 return "OFVersion.%s" % self.msg.version.constant_version
864
865 java_type = self.java_type.public_type;
866 try:
867 global model
868 enum = model.enum_by_name(java_type)
869 entry = enum.entry_by_version_value(self.msg.version, self.value)
870 return "%s.%s" % ( enum.name, entry.name)
871 except KeyError, e:
872 print e.message
873 return self.value
874
875 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700876 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700877 return isinstance(self.member, OFPadMember)
878
879 def is_type_value(self, version=None):
880 if(version==None):
881 return any(self.is_type_value(version) for version in self.msg.all_versions)
882 try:
883 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
884 except:
885 return False
886
887 @property
888 def is_field_length_value(self):
889 return isinstance(self.member, OFFieldLengthMember)
890
891 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700892 def is_discriminator(self):
893 return isinstance(self.member, OFDiscriminatorMember)
894
895 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700896 def is_length_value(self):
897 return isinstance(self.member, OFLengthMember)
898
899 @property
900 def is_public(self):
901 return not (self.is_pad or self.is_length_value)
902
903 @property
904 def is_data(self):
905 return isinstance(self.member, OFDataMember) and self.name != "version"
906
907 @property
908 def is_fixed_value(self):
909 return hasattr(self.member, "value") or self.name == "version" \
910 or ( self.name == "length" and self.msg.is_fixed_length) \
911 or ( self.name == "len" and self.msg.is_fixed_length)
912
913 @property
914 def value(self):
915 if self.name == "version":
916 return self.msg.version.int_version
917 elif self.name == "length" or self.name == "len":
918 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700919 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700920 return self.java_type.format_value(self.member.value)
921
922 @property
923 def priv_value(self):
924 if self.name == "version":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700925 return self.java_type.format_value(self.msg.version.int_version, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700926 elif self.name == "length" or self.name == "len":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700927 return self.java_type.format_value(self.msg.length, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700928 else:
929 return self.java_type.format_value(self.member.value, pub_type=False)
930
Andreas Wundsam27303462013-07-16 12:52:35 -0700931
932 @property
933 def is_writeable(self):
934 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
935
936 def get_type_value_info(self, version):
937 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700938
939 @property
940 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700941 if hasattr(self.member, "length"):
942 return self.member.length
943 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700944 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700945 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700946
947 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700948 def for_of_member(java_class, member):
949 if isinstance(member, OFPadMember):
950 return JavaMember(None, "", None, member)
951 else:
952 if member.name == 'len':
953 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700954 elif member.name == 'value_mask':
955 name = 'mask'
Andreas Wundsamacd57d52013-10-18 17:35:01 -0700956 elif member.name == 'group_id':
957 name = 'group'
Andreas Wundsam27303462013-07-16 12:52:35 -0700958 else:
959 name = java_type.name_c_to_camel(member.name)
960 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
961 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700962
963 @property
964 def is_universal(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800965 for version, ir_class in self.msg.ir_class.version_classes.items():
966 if not ir_class.member_by_name(self.member.name):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700967 return False
968 return True
969
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700970 @property
971 def is_virtual(self):
972 return False
973
Andreas Wundsam27303462013-07-16 12:52:35 -0700974 def __hash__(self):
975 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700976
Andreas Wundsam27303462013-07-16 12:52:35 -0700977 def __eq__(self, other):
978 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700979 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700980 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700981
Andreas Wundsamf1949682013-09-23 14:48:31 -0700982 @property
983 def is_nullable(self):
984 return self.name in model.nullable_map[self.msg.name]
985
986
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700987class JavaVirtualMember(JavaMember):
988 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
Andreas Wundsam4b8661f2013-11-05 17:17:28 -0800989 def __init__(self, msg, name, java_type, value=None, custom_template=None):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700990 JavaMember.__init__(self, msg, name, java_type, member=None)
991 self._value = value
Andreas Wundsam4b8661f2013-11-05 17:17:28 -0800992 self.custom_template = custom_template
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700993
994 @property
995 def is_fixed_value(self):
996 return True
997
998 @property
999 def value(self):
1000 return self._value
1001
1002 @property
1003 def priv_value(self):
1004 return self._value
1005
1006
1007 @property
1008 def is_universal(self):
1009 return True
1010
1011 @property
1012 def is_virtual(self):
1013 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001014
1015#######################################################################
1016### Unit Test
1017#######################################################################
1018
Yotam Harchol466b3212013-08-15 12:14:46 -07001019class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001020 def __init__(self, java_class):
1021 self.java_class = java_class
Andreas Wundsamc8912c12013-11-15 13:44:48 -08001022 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.dotless_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001023 name=java_class.c_name[3:])
Andreas Wundsamc8912c12013-11-15 13:44:48 -08001024 glob_file_name = "of{version}/{name}__*.data".format(version=java_class.version.dotless_version,
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -07001025 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -07001026 test_class_name = self.java_class.name + "Test"
1027 self.test_units = []
1028 if test_data.exists(first_data_file_name):
1029 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -07001030
Yotam Harchol466b3212013-08-15 12:14:46 -07001031 i = 1
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -07001032 for f in test_data.glob(glob_file_name):
1033 m = re.match(".*__(.*).data", f)
1034 if m:
1035 suffix = java_type.name_c_to_caps_camel(m.group(1))
1036 else:
1037 suffix = str(i)
1038 i += 1
1039 test_class_name = self.java_class.name + suffix + "Test"
1040 self.test_units.append(JavaUnitTest(java_class, f, test_class_name))
Andreas Wundsamf1949682013-09-23 14:48:31 -07001041
Yotam Harchol466b3212013-08-15 12:14:46 -07001042 @property
1043 def package(self):
1044 return self.java_class.package
1045
1046 @property
1047 def has_test_data(self):
1048 return len(self.test_units) > 0
1049
1050 @property
1051 def length(self):
1052 return len(self.test_units)
Andreas Wundsamf1949682013-09-23 14:48:31 -07001053
Yotam Harchol466b3212013-08-15 12:14:46 -07001054 def get_test_unit(self, i):
1055 return self.test_units[i]
1056
1057
1058class JavaUnitTest(object):
1059 def __init__(self, java_class, file_name=None, test_class_name=None):
1060 self.java_class = java_class
1061 if file_name is None:
Andreas Wundsamc8912c12013-11-15 13:44:48 -08001062 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.dotless_version,
Yotam Harchol466b3212013-08-15 12:14:46 -07001063 name=java_class.c_name[3:])
1064 else:
1065 self.data_file_name = file_name
1066 if test_class_name is None:
1067 self.test_class_name = self.java_class.name + "Test"
1068 else:
1069 self.test_class_name = test_class_name
Andreas Wundsamf1949682013-09-23 14:48:31 -07001070
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001071 @property
1072 def package(self):
1073 return self.java_class.package
1074
1075 @property
1076 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -07001077 return self.test_class_name
Yotam Harchol595c6442013-09-27 16:29:08 -07001078
1079 @property
1080 def interface(self):
1081 return self.java_class.interface
1082
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001083 @property
1084 def has_test_data(self):
1085 return test_data.exists(self.data_file_name)
1086
1087 @property
1088 @memoize
1089 def test_data(self):
1090 return test_data.read(self.data_file_name)
1091
1092
Andreas Wundsam27303462013-07-16 12:52:35 -07001093#######################################################################
1094### Enums
1095#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001096
Andreas Wundsam27303462013-07-16 12:52:35 -07001097class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001098 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -07001099 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -07001100
Rob Vaterlausfeee3712013-09-30 11:24:19 -07001101 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001102
Andreas Wundsam27303462013-07-16 12:52:35 -07001103 # Port_features has constants that start with digits
1104 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001105
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001106 self.version_enums = version_enum_map
1107
1108 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1109 for version, ir_enum in version_enum_map.items():
1110 for ir_entry in ir_enum.entries:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001111 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1112
Andreas Wundsam27303462013-07-16 12:52:35 -07001113 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001114 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001115
1116 self.entries = [ e for e in self.entries if e.name not in model.enum_entry_blacklist[self.name] ]
Yotam Harchol791e4882013-09-05 16:32:56 -07001117 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001118
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001119 self.metadata = model.enum_metadata_map[self.name]
1120
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001121 def wire_type(self, version):
1122 ir_enum = self.version_enums[version]
1123 if "wire_type" in ir_enum.params:
1124 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1125 else:
1126 return java_type.u8
1127
1128 @property
Andreas Wundsam7cfeac32013-09-17 13:53:48 -07001129 @memoize
1130 def is_bitmask(self):
1131 return any(ir_enum.is_bitmask for ir_enum in self.version_enums.values())
1132
1133 @property
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001134 def versions(self):
1135 return self.version_enums.keys()
1136
Andreas Wundsam27303462013-07-16 12:52:35 -07001137 @memoize
1138 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001139 res = find(lambda e: e.name == name, self.entries)
1140 if res:
1141 return res
1142 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001143 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1144
1145 @memoize
1146 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001147 res = find(lambda e: e.c_name == name, self.entries)
1148 if res:
1149 return res
1150 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001151 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1152
1153 @memoize
1154 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001155 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1156 if res:
1157 return res
1158 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001159 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1160
1161# values: Map JavaVersion->Value
1162class JavaEnumEntry(object):
1163 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001164 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001165 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1166 self.values = values
1167
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001168 @property
1169 def constructor_params(self):
Rob Vaterlaus6035bf52013-09-17 19:32:38 -07001170 return [ m.value(self) for m in self.enum.metadata.properties ]
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001171
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001172 def has_value(self, version):
1173 return version in self.values
1174
Andreas Wundsam27303462013-07-16 12:52:35 -07001175 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001176 return self.values[version]
1177
1178 def format_value(self, version):
1179 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001180 return res
1181
Andreas Wundsam27303462013-07-16 12:52:35 -07001182 def all_values(self, versions, not_present=None):
1183 return [ self.values[version] if version in self.values else not_present for version in versions ]
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -07001184
1185 @property
1186 @memoize
1187 def masked_enum_group(self):
1188 group = find(lambda g: self.name in g.members, model.masked_enum_groups[self.enum.name])
1189 return group
1190
1191 @property
1192 @memoize
1193 def is_mask(self):
1194 return any(self.name == g.mask for g in model.masked_enum_groups[self.enum.name])