blob: 824a32019949f2cca486e4974632ffed4ab6abc6 [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)
Rich Lane97fd13d2013-11-13 11:25:48 -080064 read_blacklist = defaultdict(lambda: set(),
65 OFExperimenter=set(('data','subtype')),
66 OFActionExperimenter=set(('data',)),
67 OFExperimenterStatsRequest=set(('data','subtype')),
68 OFExperimenterStatsReply=set(('data','subtype')))
Andreas Wundsamf1949682013-09-23 14:48:31 -070069 # map: $java_type -> set(java_name_property)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -070070 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 -070071 # interfaces that are virtual
Andreas Wundsam001b1822013-08-02 22:25:55 -070072 virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
Andreas Wundsam27303462013-07-16 12:52:35 -070073
Andreas Wundsam2be7da52013-08-22 07:34:25 -070074 OxmMapEntry = namedtuple("OxmMapEntry", ["type_name", "value", "masked" ])
Yotam Harchole5d92972013-08-22 14:18:36 -070075 oxm_map = { "OFOxmInPort": OxmMapEntry("OFPort", "IN_PORT", False),
76 "OFOxmInPortMasked": OxmMapEntry("OFPort", "IN_PORT", True),
77 "OFOxmInPhyPort": OxmMapEntry("OFPort", "IN_PHY_PORT", False),
78 "OFOxmInPhyPortMasked": OxmMapEntry("OFPort", "IN_PHY_PORT", True),
79 "OFOxmMetadata": OxmMapEntry("OFMetadata", "METADATA", False),
80 "OFOxmMetadataMasked": OxmMapEntry("OFMetadata", "METADATA", True),
81 "OFOxmEthDst": OxmMapEntry("MacAddress", "ETH_DST", False),
82 "OFOxmEthDstMasked": OxmMapEntry("MacAddress", "ETH_DST", True),
83 "OFOxmEthSrc": OxmMapEntry("MacAddress", "ETH_SRC", False),
84 "OFOxmEthSrcMasked": OxmMapEntry("MacAddress", "ETH_SRC", True),
85 "OFOxmEthType": OxmMapEntry("EthType", "ETH_TYPE", False),
86 "OFOxmEthTypeMasked": OxmMapEntry("EthType", "ETH_TYPE", True),
Andreas Wundsam98a18632013-11-05 11:34:24 -080087 "OFOxmVlanVid": OxmMapEntry("OFVlanVidMatch", "VLAN_VID", False),
88 "OFOxmVlanVidMasked": OxmMapEntry("OFVlanVidMatch", "VLAN_VID", True),
Yotam Harchole5d92972013-08-22 14:18:36 -070089 "OFOxmVlanPcp": OxmMapEntry("VlanPcp", "VLAN_PCP", False),
90 "OFOxmVlanPcpMasked": OxmMapEntry("VlanPcp", "VLAN_PCP", True),
91 "OFOxmIpDscp": OxmMapEntry("IpDscp", "IP_DSCP", False),
92 "OFOxmIpDscpMasked": OxmMapEntry("IpDscp", "IP_DSCP", True),
93 "OFOxmIpEcn": OxmMapEntry("IpEcn", "IP_ECN", False),
94 "OFOxmIpEcnMasked": OxmMapEntry("IpEcn", "IP_ECN", True),
95 "OFOxmIpProto": OxmMapEntry("IpProtocol", "IP_PROTO", False),
96 "OFOxmIpProtoMasked": OxmMapEntry("IpProtocol", "IP_PROTO", True),
Yotam Harchola289d552013-09-16 10:10:40 -070097 "OFOxmIpv4Src": OxmMapEntry("IPv4Address", "IPV4_SRC", False),
98 "OFOxmIpv4SrcMasked": OxmMapEntry("IPv4Address", "IPV4_SRC", True),
99 "OFOxmIpv4Dst": OxmMapEntry("IPv4Address", "IPV4_DST", False),
100 "OFOxmIpv4DstMasked": OxmMapEntry("IPv4Address", "IPV4_DST", True),
Yotam Harchole5d92972013-08-22 14:18:36 -0700101 "OFOxmTcpSrc": OxmMapEntry("TransportPort", "TCP_SRC", False),
102 "OFOxmTcpSrcMasked": OxmMapEntry("TransportPort", "TCP_SRC", True),
103 "OFOxmTcpDst": OxmMapEntry("TransportPort", "TCP_DST", False),
104 "OFOxmTcpDstMasked": OxmMapEntry("TransportPort", "TCP_DST", True),
105 "OFOxmUdpSrc": OxmMapEntry("TransportPort", "UDP_SRC", False),
106 "OFOxmUdpSrcMasked": OxmMapEntry("TransportPort", "UDP_SRC", True),
107 "OFOxmUdpDst": OxmMapEntry("TransportPort", "UDP_DST", False),
108 "OFOxmUdpDstMasked": OxmMapEntry("TransportPort", "UDP_DST", True),
109 "OFOxmSctpSrc": OxmMapEntry("TransportPort", "SCTP_SRC", False),
110 "OFOxmSctpSrcMasked": OxmMapEntry("TransportPort", "SCTP_SRC", True),
111 "OFOxmSctpDst": OxmMapEntry("TransportPort", "SCTP_DST", False),
112 "OFOxmSctpDstMasked": OxmMapEntry("TransportPort", "SCTP_DST", True),
113 "OFOxmIcmpv4Type": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", False),
114 "OFOxmIcmpv4TypeMasked": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", True),
115 "OFOxmIcmpv4Code": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", False),
116 "OFOxmIcmpv4CodeMasked": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", True),
117 "OFOxmArpOp": OxmMapEntry("ArpOpcode", "ARP_OP", False),
118 "OFOxmArpOpMasked": OxmMapEntry("ArpOpcode", "ARP_OP", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700119 "OFOxmArpSpa": OxmMapEntry("IPv4Address", "ARP_SPA", False),
120 "OFOxmArpSpaMasked": OxmMapEntry("IPv4Address", "ARP_SPA", True),
121 "OFOxmArpTpa": OxmMapEntry("IPv4Address", "ARP_TPA", False),
122 "OFOxmArpTpaMasked": OxmMapEntry("IPv4Address", "ARP_TPA", True),
Yotam Harchole5d92972013-08-22 14:18:36 -0700123 "OFOxmArpSha": OxmMapEntry("MacAddress", "ARP_SHA", False),
124 "OFOxmArpShaMasked": OxmMapEntry("MacAddress", "ARP_SHA", True),
125 "OFOxmArpTha": OxmMapEntry("MacAddress", "ARP_THA", False),
126 "OFOxmArpThaMasked": OxmMapEntry("MacAddress", "ARP_THA", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700127 "OFOxmIpv6Src": OxmMapEntry("IPv6Address", "IPV6_SRC", False),
128 "OFOxmIpv6SrcMasked": OxmMapEntry("IPv6Address", "IPV6_SRC", True),
129 "OFOxmIpv6Dst": OxmMapEntry("IPv6Address", "IPV6_DST", False),
130 "OFOxmIpv6DstMasked": OxmMapEntry("IPv6Address", "IPV6_DST", True),
Yotam Harchole5d92972013-08-22 14:18:36 -0700131 "OFOxmIpv6Flabel": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", False),
Yotam Harchola86e4252013-09-06 15:36:28 -0700132 "OFOxmIpv6FlabelMasked": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", True),
133 "OFOxmIcmpv6Type": OxmMapEntry("U8", "ICMPV6_TYPE", False),
134 "OFOxmIcmpv6TypeMasked": OxmMapEntry("U8", "ICMPV6_TYPE", True),
135 "OFOxmIcmpv6Code": OxmMapEntry("U8", "ICMPV6_CODE", False),
136 "OFOxmIcmpv6CodeMasked": OxmMapEntry("U8", "ICMPV6_CODE", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700137 "OFOxmIpv6NdTarget": OxmMapEntry("IPv6Address", "IPV6_ND_TARGET", False),
138 "OFOxmIpv6NdTargetMasked": OxmMapEntry("IPv6Address", "IPV6_ND_TARGET", True),
Yotam Harchola86e4252013-09-06 15:36:28 -0700139 "OFOxmIpv6NdSll": OxmMapEntry("MacAddress", "IPV6_ND_SLL", False),
140 "OFOxmIpv6NdSllMasked": OxmMapEntry("MacAddress", "IPV6_ND_SLL", True),
141 "OFOxmIpv6NdTll": OxmMapEntry("MacAddress", "IPV6_ND_TLL", False),
142 "OFOxmIpv6NdTllMasked": OxmMapEntry("MacAddress", "IPV6_ND_TLL", True),
143 "OFOxmMplsLabel": OxmMapEntry("U32", "MPLS_LABEL", False),
144 "OFOxmMplsLabelMasked": OxmMapEntry("U32", "MPLS_LABEL", True),
145 "OFOxmMplsTc": OxmMapEntry("U8", "MPLS_TC", False),
Yotam Harchola11f38b2013-09-26 15:38:17 -0700146 "OFOxmMplsTcMasked": OxmMapEntry("U8", "MPLS_TC", True),
Yotam Harchol2c535582013-10-01 15:50:20 -0700147 "OFOxmBsnInPorts128": OxmMapEntry("OFBitMask128", "BSN_IN_PORTS_128", False),
Rich Lane1424d0b2013-10-24 17:16:24 -0700148 "OFOxmBsnInPorts128Masked": OxmMapEntry("OFBitMask128", "BSN_IN_PORTS_128", True),
Rich Lane376cafe2013-10-27 21:49:14 -0700149 "OFOxmBsnLagId": OxmMapEntry("LagId", "BSN_LAG_ID", False),
150 "OFOxmBsnLagIdMasked": OxmMapEntry("LagId", "BSN_LAG_ID", True),
Rich Laneeb21c4f2013-10-28 17:34:41 -0700151 "OFOxmBsnVrf": OxmMapEntry("VRF", "BSN_VRF", False),
152 "OFOxmBsnVrfMasked": OxmMapEntry("VRF", "BSN_VRF", True),
Rich Lane9c27b5d2013-10-30 17:14:32 -0700153 "OFOxmBsnGlobalVrfAllowed": OxmMapEntry("OFBooleanValue", "BSN_GLOBAL_VRF_ALLOWED", False),
154 "OFOxmBsnGlobalVrfAllowedMasked": OxmMapEntry("OFBooleanValue", "BSN_GLOBAL_VRF_ALLOWED", True),
Rich Laneeb21c4f2013-10-28 17:34:41 -0700155 "OFOxmBsnL3InterfaceClassId": OxmMapEntry("ClassId", "BSN_L3_INTERFACE_CLASS_ID", False),
156 "OFOxmBsnL3InterfaceClassIdMasked": OxmMapEntry("ClassId", "BSN_L3_INTERFACE_CLASS_ID", True),
157 "OFOxmBsnL3SrcClassId": OxmMapEntry("ClassId", "BSN_L3_SRC_CLASS_ID", False),
158 "OFOxmBsnL3SrcClassIdMasked": OxmMapEntry("ClassId", "BSN_L3_SRC_CLASS_ID", True),
159 "OFOxmBsnL3DstClassId": OxmMapEntry("ClassId", "BSN_L3_DST_CLASS_ID", False),
160 "OFOxmBsnL3DstClassIdMasked": OxmMapEntry("ClassId", "BSN_L3_DST_CLASS_ID", True),
Yotam Harchola86e4252013-09-06 15:36:28 -0700161 }
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700162
Andreas Wundsamf1949682013-09-23 14:48:31 -0700163 # Registry of nullable properties:
164 # ${java_class_name} -> set(${java_property_name})
165 nullable_map = defaultdict(lambda: set(),
166 )
167
168 # represents a subgroup of a bitmask enum that is actualy a normal enumerable within a masked part of the enum
169 # e.g., the flags STP.* in OF1.0 port state are bit mask entries, but instead enumerables according to the mask "STP_MASK"
170 # name: a name for the group
171 # mask: java name of the enum entry that defines the mask
172 # members: set of names of the members of the group
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700173 MaskedEnumGroup = namedtuple("MaskedEnumGroup", ("name", "mask", "members"))
174
Andreas Wundsamf1949682013-09-23 14:48:31 -0700175 # registry of MaskedEnumGroups (see above).
176 # map: ${java_enum_name}: tuple(MaskedEnumGroup)
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700177 masked_enum_groups = defaultdict(lambda: (),
Andreas Wundsamaebe5182013-09-24 13:01:07 -0700178 OFPortState = (MaskedEnumGroup("stp_flags", mask="STP_MASK", members=set(("STP_LISTEN", "STP_LEARN", "STP_FORWARD", "STP_BLOCK"))), ),
179 OFConfigFlags = (
180 MaskedEnumGroup("frag_flags", mask="FRAG_MASK", members=set(("FRAG_NORMAL", "FRAG_DROP", "FRAG_REASM"))),
Andreas Wundsam376cef52013-09-24 13:52:18 -0700181 ),
182 OFTableConfig = (
183 MaskedEnumGroup("table_miss_flags", mask="TABLE_MISS_MASK", members=set(("TABLE_MISS_CONTROLLER", "TABLE_MISS_CONTINUE", "TABLE_MISS_DROP"))),
184 ),
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700185 )
186
Andreas Wundsamf1949682013-09-23 14:48:31 -0700187 # represents a metadata property associated with an EnumClass
188 # name:
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700189 class OFEnumPropertyMetadata(namedtuple("OFEnumPropertyMetadata", ("name", "type", "value"))):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700190 """
191 represents a metadata property associated with an Enum Class
192 @param name name of metadata property
193 @param type java_type instance describing the type
194 @value: Generator function f(entry) that generates the value
195 """
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700196 @property
197 def variable_name(self):
198 return self.name[0].lower() + self.name[1:]
199
200 @property
201 def getter_name(self):
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700202 prefix = "is" if self.type == java_type.boolean else "get"
203 return prefix+self.name
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700204
Andreas Wundsamf1949682013-09-23 14:48:31 -0700205 """ Metadata container. """
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700206 OFEnumMetadata = namedtuple("OFEnumMetadata", ("properties", "to_string"))
207
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700208 def gen_port_speed(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700209 """ Generator function for OFortFeatures.PortSpeed"""
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700210 splits = enum_entry.name.split("_")
211 if len(splits)>=2:
212 m = re.match(r'\d+[MGTP]B', splits[1])
213 if m:
214 return "PortSpeed.SPEED_{}".format(splits[1])
215 return "PortSpeed.SPEED_NONE";
216
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700217 def gen_stp_state(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700218 """ Generator function for OFPortState.StpState"""
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700219 splits = enum_entry.name.split("_")
220 if len(splits)>=1:
221 if splits[0] == "STP":
222 return "true"
223 return "false"
224
Andreas Wundsamf1949682013-09-23 14:48:31 -0700225 # registry for metadata properties for enums
226 # map: ${java_enum_name}: OFEnumMetadata
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700227 enum_metadata_map = defaultdict(lambda: JavaModel.OFEnumMetadata((), None),
Rob Vaterlausa049dee2013-09-18 16:18:37 -0700228 OFPortFeatures = OFEnumMetadata((OFEnumPropertyMetadata("PortSpeed", java_type.port_speed, gen_port_speed),), None),
229 OFPortState = OFEnumMetadata((OFEnumPropertyMetadata("StpState", java_type.boolean, gen_stp_state),), None),
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700230 )
231
Andreas Wundsam27303462013-07-16 12:52:35 -0700232 @property
233 @memoize
234 def versions(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800235 return OrderedSet( JavaOFVersion(ir_version) for ir_version in OFVersions.target_versions)
Andreas Wundsam27303462013-07-16 12:52:35 -0700236
237 @property
238 @memoize
239 def interfaces(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800240 interfaces = [ JavaOFInterface(ir_class) for ir_class in loxi_globals.unified.classes ]
Andreas Wundsambe168f72013-08-03 22:49:35 -0700241 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
242
Andreas Wundsam27303462013-07-16 12:52:35 -0700243 return interfaces
244
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700245 @memoize
246 def interface_by_name(self, name):
247 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
248
Andreas Wundsam27303462013-07-16 12:52:35 -0700249 @property
250 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700251 def all_classes(self):
252 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
253
254 @property
255 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700256 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700257 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700258
259 for version in self.versions:
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800260 logger.info("version: {}".format(version.ir_version))
261 of_protocol = loxi_globals.ir[version.ir_version]
Andreas Wundsam27303462013-07-16 12:52:35 -0700262 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700263 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700264
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700265 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
266 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700267
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700268 # inelegant - need java name here
269 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700270 return enums
271
272 @memoize
273 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700274 res = find(lambda e: e.name == name, self.enums)
275 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700276 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700277 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700278
Andreas Wundsam5204de22013-07-30 11:34:45 -0700279 @property
280 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700281 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700282 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700283
284 factories = OrderedDict()
285
286 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
287 for base_class in sub_factory_classes:
288 package = base_class[2:].lower()
289 remove_prefix = base_class[2].lower() + base_class[3:]
290
291 # HACK need to have a better way to deal with parameterized base classes
292 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
293
294 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700295 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 -0700296
297 factories[""] = OFFactory(
298 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700299 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700300 remove_prefix="",
301 members=[], base_class="OFMessage", sub_factories=OrderedDict(
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700302 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ),
303 xid_generator=True)
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700304
305 for i in self.interfaces:
306 for n, factory in factories.items():
307 if n == "":
308 factory.members.append(i)
309 break
310 else:
311 super_class = self.interface_by_name(n)
312 if i.is_instance_of(super_class):
313 factory.members.append(i)
314 break
315 return factories.values()
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800316
Yotam Harchol595c6442013-09-27 16:29:08 -0700317 @memoize
318 def factory_of(self, interface):
319 for factory in self.of_factories:
320 if interface in factory.members:
321 return factory
322 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700323
324 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700325 """ return wether or not to generate implementation class clazz.
326 Now true for everything except OFTableModVer10.
327 @param clazz JavaOFClass instance
328 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700329 if clazz.interface.name.startswith("OFMatchV"):
330 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700331 elif clazz.name == "OFTableModVer10":
332 # tablemod ver 10 is a hack and has no oftype defined
333 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700334 if loxi_utils.class_is_message(clazz.interface.c_name):
335 return True
336 if loxi_utils.class_is_oxm(clazz.interface.c_name):
337 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700338 if loxi_utils.class_is_action(clazz.interface.c_name):
339 return True
340 if loxi_utils.class_is_instruction(clazz.interface.c_name):
341 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700342 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700343 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700344
345
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700346class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories", "xid_generator"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700347 @property
348 def factory_classes(self):
349 return [ OFFactoryClass(
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800350 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.dotless_version),
351 name="{}Ver{}".format(self.name, version.dotless_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700352 interface=self,
353 version=version
354 ) for version in model.versions ]
355
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700356 def method_name(self, member, builder=True):
357 n = member.variable_name
358 if n.startswith(self.remove_prefix):
359 n = n[len(self.remove_prefix):]
360 n = n[0].lower() + n[1:]
361 if builder:
362 return "build" + n[0].upper() + n[1:]
363 else:
364 return n
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800365
Yotam Harchol595c6442013-09-27 16:29:08 -0700366 def of_version(self, version):
367 for fc in self.factory_classes:
368 if fc.version == version:
369 return fc
370 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700371
372OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700373class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
374 @property
375 def base_class(self):
376 return self.interface.base_class
377
378 @property
379 def versioned_base_class(self):
380 base_class_interface = model.interface_by_name(self.interface.base_class)
381 if base_class_interface and base_class_interface.has_version(self.version):
382 return base_class_interface.versioned_class(self.version)
383 else:
384 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700385
Andreas Wundsam27303462013-07-16 12:52:35 -0700386model = JavaModel()
387
388#######################################################################
389### OFVersion
390#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700391
392class JavaOFVersion(object):
393 """ Models a version of OpenFlow. contains methods to convert the internal
394 Loxi version to a java constant / a string """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800395 def __init__(self, ir_version):
396 assert isinstance(ir_version, OFVersion)
397 self.ir_version = ir_version
398 self.int_version = self.ir_version.wire_version
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700399
400 @property
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800401 def dotless_version(self):
402 return self.ir_version.version.replace(".", "")
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700403
404 @property
405 def constant_version(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800406 return "OF_" + self.dotless_version
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700407
Andreas Wundsam27303462013-07-16 12:52:35 -0700408 def __repr__(self):
409 return "JavaOFVersion(%d)" % self.int_version
410
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700411 def __str__(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800412 return self.ir_version.version
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700413
Andreas Wundsam27303462013-07-16 12:52:35 -0700414 def __hash__(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800415 return hash(self.ir_version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700416
417 def __eq__(self, other):
418 if other is None or type(self) != type(other):
419 return False
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800420 return (self.ir_version,) == (other.ir_version,)
Andreas Wundsam27303462013-07-16 12:52:35 -0700421
422#######################################################################
423### Interface
424#######################################################################
425
426class JavaOFInterface(object):
427 """ Models an OpenFlow Message class for the purpose of the java class.
428 Version agnostic, in contrast to the loxi_ir python model.
429 """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800430 def __init__(self, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700431 """"
432 @param c_name: loxi style name (e.g., of_flow_add)
433 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
434 """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800435 self.ir_class = ir_class
436 self.c_name = ir_class.name
437 self.version_map = { JavaOFVersion(v): c for v,c in ir_class.version_classes.items() }
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700438 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800439 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 -0700440 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700441 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700442 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700443 # name for use in constants: FLOW_ADD
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800444 self.constant_name = self.c_name.upper().replace("OF_", "")
Andreas Wundsam27303462013-07-16 12:52:35 -0700445
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700446 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700447 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700448 if self.name != parent_interface:
449 self.parent_interface = parent_interface
450 else:
451 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700452
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700453 @property
454 @memoize
455 def all_parent_interfaces(self):
456 return [ "OFObject" ] + \
457 ([ self.parent_interface ] if self.parent_interface else [] )+ \
458 self.additional_parent_interfaces
459 @property
460 @memoize
461 def additional_parent_interfaces(self):
462 if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
463 m = re.match(r'(.*)Request$', self.name)
464 if m:
465 reply_name = m.group(1) + "Reply"
466 if model.interface_by_name(reply_name):
467 return ["OFRequest<%s>" % reply_name ]
468 return []
469
470
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700471 def is_instance_of(self, other_class):
472 if self == other_class:
473 return True
474 parent = self.super_class
475 if parent is None:
476 return False
477 else:
478 return parent.is_instance_of(other_class)
479
480 @property
481 def super_class(self):
482 if not self.parent_interface:
483 return None
484 else:
485 return model.interface_by_name(self.parent_interface)
486
487
488 def inherited_declaration(self, type_spec="?"):
489 if self.type_annotation:
490 return "%s<%s>" % (self.name, type_spec)
491 else:
492 return "%s" % self.name
493
494 @property
495 def type_variable(self):
496 if self.type_annotation:
497 return "<T>"
498 else:
499 return "";
500
Andreas Wundsam27303462013-07-16 12:52:35 -0700501 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700502 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
503 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
504 # model (note, that the loxi model is on versioned classes). Should check/infer the
505 # inheritance information from the versioned lox_ir classes.
Andreas Wundsamd6b0cb02013-09-28 18:55:56 -0700506 if re.match(r'OFStatsRequest$', self.name):
507 return ("", "OFMessage", "T extends OFStatsReply")
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800508 elif self.ir_class.is_subclassof('of_stats_request'):
Andreas Wundsam2c0a2d72013-11-15 15:16:36 -0800509 if self.ir_class.is_subclassof('of_bsn_stats_request'):
510 return ("", "OFBsnStatsRequest", None)
511 elif self.ir_class.is_subclassof('of_experimenter_stats_request'):
512 return ("", "OFExperimenterStatsRequest", None)
513 else:
514 return ("", "OFStatsRequest<{}>".format(re.sub(r'Request$', 'Reply', self.name)), None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800515 elif self.ir_class.is_subclassof('of_stats_reply'):
Andreas Wundsam2c0a2d72013-11-15 15:16:36 -0800516 if self.ir_class.is_subclassof('of_bsn_stats_reply'):
517 return ("", "OFBsnStatsReply", None)
518 elif self.ir_class.is_subclassof('of_experimenter_stats_reply'):
519 return ("", "OFExperimenterStatsReply", None)
520 else:
521 return ("", "OFStatsReply", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800522 elif self.ir_class.is_subclassof('of_error_msg'):
Rob Vaterlausfeee3712013-09-30 11:24:19 -0700523 return ("", "OFErrorMsg", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800524 elif self.ir_class.is_subclassof('of_flow_mod'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700525 return ("", "OFFlowMod", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800526 elif self.ir_class.is_subclassof('of_group_mod'):
527 return ("", "OFGroupMod", None)
528 elif self.ir_class.is_subclassof('of_bsn_header'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700529 return ("", "OFBsnHeader", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800530 elif self.ir_class.is_subclassof('of_nicira_header'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700531 return ("", "OFNiciraHeader", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800532 elif self.ir_class.is_subclassof('of_experimenter'):
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700533 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700534 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700535 return ("", "Match", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800536 elif self.ir_class.is_message:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700537 return ("", "OFMessage", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800538 elif self.ir_class.is_action:
539 if self.ir_class.is_subclassof('of_action_bsn'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700540 return ("action", "OFActionBsn", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800541 elif self.ir_class.is_subclassof('of_action_nicira'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700542 return ("action", "OFActionNicira", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800543 elif self.ir_class.is_subclassof('of_action_experimenter'):
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700544 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700545 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700546 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700547 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700548 return ("", "OFBsnVport", None)
549 elif self.name == "OFOxm":
550 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700551 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700552 if self.name in model.oxm_map:
553 return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
554 else:
555 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700556 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700557 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700558 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700559 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700560 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700561 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700562 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700563 return ("", "OFHelloElem", None)
Rich Lane26847562013-10-08 13:44:47 -0700564 elif loxi_utils.class_is_table_feature_prop(self.c_name):
565 return ("", "OFTableFeatureProp", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700566 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700567 return ("", None, None)
568
569 @property
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800570
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700571 @memoize
572 def writeable_members(self):
573 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700574
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700575 @memoize
576 def member_by_name(self, name):
577 return find(lambda m: m.name == name, self.members)
578
Andreas Wundsam27303462013-07-16 12:52:35 -0700579 @property
580 @memoize
581 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700582 return self.ir_model_members + self.virtual_members
583
584 @property
585 @memoize
586 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700587 """return a list of all members to be exposed by this interface. Corresponds to
588 the union of the members of the vesioned classes without length, fieldlength
589 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700590 all_versions = []
591 member_map = collections.OrderedDict()
592
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800593 member_version_map = {}
Andreas Wundsam27303462013-07-16 12:52:35 -0700594 for (version, of_class) in self.version_map.items():
595 for of_member in of_class.members:
596 if isinstance(of_member, OFLengthMember) or \
597 isinstance(of_member, OFFieldLengthMember) or \
598 isinstance(of_member, OFPadMember):
599 continue
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800600 java_member = JavaMember.for_of_member(self, of_member)
Andreas Wundsam27303462013-07-16 12:52:35 -0700601 if of_member.name not in member_map:
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800602 member_map[of_member.name] = java_member
603 member_version_map[of_member.name] = version
604 else:
605 existing = member_map[of_member.name]
606
607 if existing.java_type.public_type != java_member.java_type.public_type:
608 raise Exception(
609 "Error constructing interface {}: type signatures do not match up between versions.\n"
610 " Member Name: {}\n"
611 " Existing: Version={}, Java={}, IR={}\n"
612 " New: Version={}, Java={}, IR={}"
613 .format(self.name, existing.name,
614 member_version_map[of_member.name], existing.java_type.public_type, existing.member.oftype,
615 version, java_member.java_type.public_type, java_member.member.oftype)
616 )
Andreas Wundsam27303462013-07-16 12:52:35 -0700617
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700618 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 -0700619
620 @property
621 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700622 virtual_members = []
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700623 if self.name == "OFOxm":
Andreas Wundsama0981022013-10-02 18:15:06 -0700624 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700625 JavaVirtualMember(self, "value", java_type.generic_t),
626 JavaVirtualMember(self, "mask", java_type.generic_t),
627 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
628 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800629 JavaVirtualMember(self, "canonical", java_type.make_oxm_jtype("T"))
Andreas Wundsama0981022013-10-02 18:15:06 -0700630 ]
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800631 elif self.ir_class.is_subclassof("of_oxm"):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700632 field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
633 if self.name in model.oxm_map \
634 else java_type.make_match_field_jtype()
635
Andreas Wundsama0981022013-10-02 18:15:06 -0700636 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700637 JavaVirtualMember(self, "matchField", field_type),
638 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800639 JavaVirtualMember(self, "canonical", java_type.make_oxm_jtype(model.oxm_map[self.name].type_name),
640 custom_template=lambda builder: "OFOxm{}_getCanonical.java".format(".Builder" if builder else "")),
Andreas Wundsama0981022013-10-02 18:15:06 -0700641 ]
642 if not find(lambda x: x.name == "mask", self.ir_model_members):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800643 virtual_members.append(
644 JavaVirtualMember(self, "mask", find(lambda x: x.name == "value", self.ir_model_members).java_type))
Andreas Wundsama0981022013-10-02 18:15:06 -0700645
646 if not find(lambda m: m.name == "version", self.ir_model_members):
647 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version))
648
649 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700650
651 @property
652 @memoize
653 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700654 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700655 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 -0700656
657 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700658 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700659 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700660 return len(self.all_versions) == len(model.versions)
661
662 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700663 @memoize
664 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700665 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700666 return self.version_map.keys()
667
Andreas Wundsam5204de22013-07-30 11:34:45 -0700668 def has_version(self, version):
669 return version in self.version_map
670
Andreas Wundsam27303462013-07-16 12:52:35 -0700671 def versioned_class(self, version):
672 return JavaOFClass(self, version, self.version_map[version])
673
674 @property
675 @memoize
676 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700677 return [ self.versioned_class(version) for version in self.all_versions ]
678
679#######################################################################
680### (Versioned) Classes
681#######################################################################
682
683class JavaOFClass(object):
684 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700685 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700686 """
687 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700688 """
689 @param interface JavaOFInterface instance of the parent interface
690 @param version JavaOFVersion
691 @param ir_class OFClass from loxi_ir
692 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700693 self.interface = interface
694 self.ir_class = ir_class
695 self.c_name = self.ir_class.name
696 self.version = version
697 self.constant_name = self.c_name.upper().replace("OF_", "")
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800698 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.dotless_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700699 self.generated = False
700
701 @property
702 @memoize
703 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700704 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700705
706 @property
707 def name(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800708 return "%sVer%s" % (self.interface.name, self.version.dotless_version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700709
710 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700711 def variable_name(self):
Andreas Wundsam781d99f2013-10-23 15:25:56 -0700712 return self.name[2].lower() + self.name[3:]
Andreas Wundsam5204de22013-07-30 11:34:45 -0700713
714 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700715 def length(self):
716 if self.is_fixed_length:
717 return self.min_length
718 else:
719 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
720
721 @property
722 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700723 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800724 return self.ir_class.base_length
Andreas Wundsam27303462013-07-16 12:52:35 -0700725
726 @property
727 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700728 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800729 return self.ir_class.is_fixed_length and not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700730
731 def all_properties(self):
732 return self.interface.members
733
Andreas Wundsam27303462013-07-16 12:52:35 -0700734 @property
735 @memoize
736 def data_members(self):
737 return [ prop for prop in self.members if prop.is_data ]
738
739 @property
740 @memoize
741 def fixed_value_members(self):
742 return [ prop for prop in self.members if prop.is_fixed_value ]
743
744 @property
745 @memoize
746 def public_members(self):
747 return [ prop for prop in self.members if prop.is_public ]
748
749 @property
750 @memoize
751 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700752 return self.ir_model_members + self.virtual_members
753
754 @property
Andreas Wundsama0981022013-10-02 18:15:06 -0700755 @memoize
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700756 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700757 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700758 return tuple(members)
759
760 @property
761 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700762 virtual_members = []
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700763 if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
764 if self.interface.name in model.oxm_map:
765 oxm_entry = model.oxm_map[self.interface.name]
Andreas Wundsama0981022013-10-02 18:15:06 -0700766 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700767 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
768 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800769 ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700770 else:
Andreas Wundsama0981022013-10-02 18:15:06 -0700771 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700772 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
773 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800774 ]
Andreas Wundsama0981022013-10-02 18:15:06 -0700775 if not find(lambda m: m.name == "version", self.ir_model_members):
776 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version, "OFVersion.%s" % self.version.constant_version))
777
778 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700779
Andreas Wundsam661a2222013-11-05 17:18:59 -0800780 @memoize
781 def member_by_name(self, name):
782 return find(lambda m: m.name == name, self.members)
783
Andreas Wundsam27303462013-07-16 12:52:35 -0700784 def all_versions(self):
785 return [ JavaOFVersion(int_version)
786 for int_version in of_g.unified[self.c_name]
787 if int_version != 'union' and int_version != 'object_id' ]
788
789 def version_is_inherited(self, version):
790 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
791
792 def inherited_from(self, version):
793 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
794
795 @property
796 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700797 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
798
799 @property
800 def discriminator(self):
801 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700802
803 @property
804 def is_extension(self):
805 return type_maps.message_is_extension(self.c_name, -1)
806
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700807 @property
808 def align(self):
809 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
810
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700811 @property
Andreas Wundsam5da68512013-10-22 22:18:00 -0700812 def length_includes_align(self):
813 return self.ir_class.params['length_includes_align'] == "True" if 'length_includes_align' in self.ir_class.params else False
814
815 @property
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700816 @memoize
817 def superclass(self):
818 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
819
820 @property
821 @memoize
822 def subclasses(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800823 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass
824 and c.ir_class.superclass.name == self.c_name ]
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700825
Andreas Wundsam27303462013-07-16 12:52:35 -0700826#######################################################################
827### Member
828#######################################################################
829
830
831class JavaMember(object):
832 """ Models a property (member) of an openflow class. """
833 def __init__(self, msg, name, java_type, member):
834 self.msg = msg
835 self.name = name
836 self.java_type = java_type
837 self.member = member
838 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700839
840 @property
841 def title_name(self):
842 return self.name[0].upper() + self.name[1:]
843
844 @property
845 def constant_name(self):
846 return self.c_name.upper()
847
848 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700849 def getter_name(self):
850 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
851
852 @property
853 def setter_name(self):
854 return "set" + self.title_name
855
856 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700857 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700858 if self.is_fixed_value:
859 return self.constant_name
860 else:
861 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700862
863 @property
864 def default_value(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700865 if self.is_fixed_value:
866 return self.enum_value
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700867 else:
Andreas Wundsam142dd2a2013-09-23 14:47:37 -0700868 default = self.java_type.default_op(self.msg.version)
869 if default == "null" and not self.is_nullable:
870 return None
871 else:
872 return default
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700873
874 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700875 def enum_value(self):
876 if self.name == "version":
877 return "OFVersion.%s" % self.msg.version.constant_version
878
879 java_type = self.java_type.public_type;
880 try:
881 global model
882 enum = model.enum_by_name(java_type)
883 entry = enum.entry_by_version_value(self.msg.version, self.value)
884 return "%s.%s" % ( enum.name, entry.name)
885 except KeyError, e:
886 print e.message
887 return self.value
888
889 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700890 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700891 return isinstance(self.member, OFPadMember)
892
893 def is_type_value(self, version=None):
894 if(version==None):
895 return any(self.is_type_value(version) for version in self.msg.all_versions)
896 try:
897 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
898 except:
899 return False
900
901 @property
902 def is_field_length_value(self):
903 return isinstance(self.member, OFFieldLengthMember)
904
905 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700906 def is_discriminator(self):
907 return isinstance(self.member, OFDiscriminatorMember)
908
909 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700910 def is_length_value(self):
911 return isinstance(self.member, OFLengthMember)
912
913 @property
914 def is_public(self):
915 return not (self.is_pad or self.is_length_value)
916
917 @property
918 def is_data(self):
919 return isinstance(self.member, OFDataMember) and self.name != "version"
920
921 @property
922 def is_fixed_value(self):
923 return hasattr(self.member, "value") or self.name == "version" \
924 or ( self.name == "length" and self.msg.is_fixed_length) \
925 or ( self.name == "len" and self.msg.is_fixed_length)
926
927 @property
928 def value(self):
929 if self.name == "version":
930 return self.msg.version.int_version
931 elif self.name == "length" or self.name == "len":
932 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700933 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700934 return self.java_type.format_value(self.member.value)
935
936 @property
937 def priv_value(self):
938 if self.name == "version":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700939 return self.java_type.format_value(self.msg.version.int_version, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700940 elif self.name == "length" or self.name == "len":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700941 return self.java_type.format_value(self.msg.length, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700942 else:
943 return self.java_type.format_value(self.member.value, pub_type=False)
944
Andreas Wundsam27303462013-07-16 12:52:35 -0700945
946 @property
947 def is_writeable(self):
948 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
949
950 def get_type_value_info(self, version):
951 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700952
953 @property
954 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700955 if hasattr(self.member, "length"):
956 return self.member.length
957 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700958 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700959 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700960
961 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700962 def for_of_member(java_class, member):
963 if isinstance(member, OFPadMember):
964 return JavaMember(None, "", None, member)
965 else:
966 if member.name == 'len':
967 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700968 elif member.name == 'value_mask':
969 name = 'mask'
Andreas Wundsamacd57d52013-10-18 17:35:01 -0700970 elif member.name == 'group_id':
971 name = 'group'
Andreas Wundsam27303462013-07-16 12:52:35 -0700972 else:
973 name = java_type.name_c_to_camel(member.name)
974 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
975 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700976
977 @property
978 def is_universal(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800979 for version, ir_class in self.msg.ir_class.version_classes.items():
980 if not ir_class.member_by_name(self.member.name):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700981 return False
982 return True
983
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700984 @property
985 def is_virtual(self):
986 return False
987
Andreas Wundsam27303462013-07-16 12:52:35 -0700988 def __hash__(self):
989 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700990
Andreas Wundsam27303462013-07-16 12:52:35 -0700991 def __eq__(self, other):
992 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700993 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700994 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700995
Andreas Wundsamf1949682013-09-23 14:48:31 -0700996 @property
997 def is_nullable(self):
998 return self.name in model.nullable_map[self.msg.name]
999
1000
Andreas Wundsam2be7da52013-08-22 07:34:25 -07001001class JavaVirtualMember(JavaMember):
1002 """ 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 -08001003 def __init__(self, msg, name, java_type, value=None, custom_template=None):
Andreas Wundsam2be7da52013-08-22 07:34:25 -07001004 JavaMember.__init__(self, msg, name, java_type, member=None)
1005 self._value = value
Andreas Wundsam4b8661f2013-11-05 17:17:28 -08001006 self.custom_template = custom_template
Andreas Wundsam2be7da52013-08-22 07:34:25 -07001007
1008 @property
1009 def is_fixed_value(self):
1010 return True
1011
1012 @property
1013 def value(self):
1014 return self._value
1015
1016 @property
1017 def priv_value(self):
1018 return self._value
1019
1020
1021 @property
1022 def is_universal(self):
1023 return True
1024
1025 @property
1026 def is_virtual(self):
1027 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001028
1029#######################################################################
1030### Unit Test
1031#######################################################################
1032
Yotam Harchol466b3212013-08-15 12:14:46 -07001033class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001034 def __init__(self, java_class):
1035 self.java_class = java_class
Andreas Wundsamc8912c12013-11-15 13:44:48 -08001036 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.dotless_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001037 name=java_class.c_name[3:])
Andreas Wundsamc8912c12013-11-15 13:44:48 -08001038 glob_file_name = "of{version}/{name}__*.data".format(version=java_class.version.dotless_version,
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -07001039 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -07001040 test_class_name = self.java_class.name + "Test"
1041 self.test_units = []
1042 if test_data.exists(first_data_file_name):
1043 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -07001044
Yotam Harchol466b3212013-08-15 12:14:46 -07001045 i = 1
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -07001046 for f in test_data.glob(glob_file_name):
1047 m = re.match(".*__(.*).data", f)
1048 if m:
1049 suffix = java_type.name_c_to_caps_camel(m.group(1))
1050 else:
1051 suffix = str(i)
1052 i += 1
1053 test_class_name = self.java_class.name + suffix + "Test"
1054 self.test_units.append(JavaUnitTest(java_class, f, test_class_name))
Andreas Wundsamf1949682013-09-23 14:48:31 -07001055
Yotam Harchol466b3212013-08-15 12:14:46 -07001056 @property
1057 def package(self):
1058 return self.java_class.package
1059
1060 @property
1061 def has_test_data(self):
1062 return len(self.test_units) > 0
1063
1064 @property
1065 def length(self):
1066 return len(self.test_units)
Andreas Wundsamf1949682013-09-23 14:48:31 -07001067
Yotam Harchol466b3212013-08-15 12:14:46 -07001068 def get_test_unit(self, i):
1069 return self.test_units[i]
1070
1071
1072class JavaUnitTest(object):
1073 def __init__(self, java_class, file_name=None, test_class_name=None):
1074 self.java_class = java_class
1075 if file_name is None:
Andreas Wundsamc8912c12013-11-15 13:44:48 -08001076 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.dotless_version,
Yotam Harchol466b3212013-08-15 12:14:46 -07001077 name=java_class.c_name[3:])
1078 else:
1079 self.data_file_name = file_name
1080 if test_class_name is None:
1081 self.test_class_name = self.java_class.name + "Test"
1082 else:
1083 self.test_class_name = test_class_name
Andreas Wundsamf1949682013-09-23 14:48:31 -07001084
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001085 @property
1086 def package(self):
1087 return self.java_class.package
1088
1089 @property
1090 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -07001091 return self.test_class_name
Yotam Harchol595c6442013-09-27 16:29:08 -07001092
1093 @property
1094 def interface(self):
1095 return self.java_class.interface
1096
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001097 @property
1098 def has_test_data(self):
1099 return test_data.exists(self.data_file_name)
1100
1101 @property
1102 @memoize
1103 def test_data(self):
1104 return test_data.read(self.data_file_name)
1105
1106
Andreas Wundsam27303462013-07-16 12:52:35 -07001107#######################################################################
1108### Enums
1109#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001110
Andreas Wundsam27303462013-07-16 12:52:35 -07001111class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001112 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -07001113 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -07001114
Rob Vaterlausfeee3712013-09-30 11:24:19 -07001115 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001116
Andreas Wundsam27303462013-07-16 12:52:35 -07001117 # Port_features has constants that start with digits
1118 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001119
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001120 self.version_enums = version_enum_map
1121
1122 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1123 for version, ir_enum in version_enum_map.items():
1124 for ir_entry in ir_enum.entries:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001125 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1126
Andreas Wundsam27303462013-07-16 12:52:35 -07001127 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001128 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001129
1130 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 -07001131 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001132
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001133 self.metadata = model.enum_metadata_map[self.name]
1134
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001135 def wire_type(self, version):
1136 ir_enum = self.version_enums[version]
1137 if "wire_type" in ir_enum.params:
1138 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1139 else:
1140 return java_type.u8
1141
1142 @property
Andreas Wundsam7cfeac32013-09-17 13:53:48 -07001143 @memoize
1144 def is_bitmask(self):
1145 return any(ir_enum.is_bitmask for ir_enum in self.version_enums.values())
1146
1147 @property
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001148 def versions(self):
1149 return self.version_enums.keys()
1150
Andreas Wundsam27303462013-07-16 12:52:35 -07001151 @memoize
1152 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001153 res = find(lambda e: e.name == name, self.entries)
1154 if res:
1155 return res
1156 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001157 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1158
1159 @memoize
1160 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001161 res = find(lambda e: e.c_name == name, self.entries)
1162 if res:
1163 return res
1164 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001165 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1166
1167 @memoize
1168 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001169 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1170 if res:
1171 return res
1172 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001173 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1174
1175# values: Map JavaVersion->Value
1176class JavaEnumEntry(object):
1177 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001178 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001179 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1180 self.values = values
1181
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001182 @property
1183 def constructor_params(self):
Rob Vaterlaus6035bf52013-09-17 19:32:38 -07001184 return [ m.value(self) for m in self.enum.metadata.properties ]
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001185
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001186 def has_value(self, version):
1187 return version in self.values
1188
Andreas Wundsam27303462013-07-16 12:52:35 -07001189 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001190 return self.values[version]
1191
1192 def format_value(self, version):
1193 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001194 return res
1195
Andreas Wundsam27303462013-07-16 12:52:35 -07001196 def all_values(self, versions, not_present=None):
1197 return [ self.values[version] if version in self.values else not_present for version in versions ]
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -07001198
1199 @property
1200 @memoize
1201 def masked_enum_group(self):
1202 group = find(lambda g: self.name in g.members, model.masked_enum_groups[self.enum.name])
1203 return group
1204
1205 @property
1206 @memoize
1207 def is_mask(self):
1208 return any(self.name == g.mask for g in model.masked_enum_groups[self.enum.name])