class NiciraNvpElement extends AdapterBase implements ConnectivityProvider, SourceNatServiceProvider, PortForwardingServiceProvider, StaticNatServiceProvider,
NiciraNvpElementService, ResourceStateAdapter, IpDeployer {

    @Override
    public boolean implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException,
    ResourceUnavailableException, InsufficientCapacityException {
        s_logger.debug("entering NiciraNvpElement implement function for network " + network.getDisplayText() + " (state " + network.getState() + ")");

        if (!canHandle(network, Service.Connectivity)) {
            return false;
        }

        if (network.getBroadcastUri() == null) {
            s_logger.error("Nic has no broadcast Uri with the LSwitch Uuid");
            return false;
        }

        final List<NiciraNvpDeviceVO> devices = niciraNvpDao.listByPhysicalNetwork(network.getPhysicalNetworkId());
        if (devices.isEmpty()) {
            s_logger.error("No NiciraNvp Controller on physical network " + network.getPhysicalNetworkId());
            return false;
        }
        final NiciraNvpDeviceVO niciraNvpDevice = devices.get(0);
        final HostVO niciraNvpHost = hostDao.findById(niciraNvpDevice.getHostId());
        hostDao.loadDetails(niciraNvpHost);

        final Account owner = context.getAccount();

        /*
         * TODO Shouldn't we lock the network as we might need to do
         * multiple operations that should be done only once.
         */

        // Implement SourceNat immediately as we have al the info already
        if (networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.SourceNat, Provider.NiciraNvp)) {
            s_logger.debug("Apparently we are supposed to provide SourceNat on this network");

            final PublicIp sourceNatIp = ipAddrMgr.assignSourceNatIpAddressToGuestNetwork(owner, network);
            final String publicCidr = sourceNatIp.getAddress().addr() + "/" + NetUtils.getCidrSize(sourceNatIp.getVlanNetmask());
            final String internalCidr = network.getGateway() + "/" + network.getCidr().split("/")[1];
            // assuming a vlan:
            String vtag = sourceNatIp.getVlanTag();
            BroadcastDomainType tiep = null;
            try {
                tiep = BroadcastDomainType.getTypeOf(vtag);
            } catch (final URISyntaxException use) {
                throw new CloudRuntimeException("vlantag for sourceNatIp is not valid: " + vtag, use);
            }
            if (tiep == BroadcastDomainType.Vlan) {
                vtag = BroadcastDomainType.Vlan.getValueFrom(BroadcastDomainType.fromString(vtag));
            } else if (!(tiep == BroadcastDomainType.UnDecided || tiep == BroadcastDomainType.Native)) {
                throw new CloudRuntimeException("only vlans are supported for sourceNatIp, at this moment: " + vtag);
            }
            final long vlanid = Vlan.UNTAGGED.equals(vtag) ? 0 : Long.parseLong(vtag);

            final CreateLogicalRouterCommand cmd =
                    new CreateLogicalRouterCommand(niciraNvpHost.getDetail("l3gatewayserviceuuid"), vlanid, BroadcastDomainType.getValue(network.getBroadcastUri()),
                            "router-" + network.getDisplayText(), publicCidr, sourceNatIp.getGateway(), internalCidr, context.getDomain().getName() + "-" +
                                    context.getAccount().getAccountName());
            final CreateLogicalRouterAnswer answer = (CreateLogicalRouterAnswer)agentMgr.easySend(niciraNvpHost.getId(), cmd);
            if (answer.getResult() == false) {
                s_logger.error("Failed to create Logical Router for network " + network.getDisplayText());
                return false;
            }

            // Store the uuid so we can easily find it during cleanup
            final NiciraNvpRouterMappingVO routermapping = new NiciraNvpRouterMappingVO(answer.getLogicalRouterUuid(), network.getId());
            niciraNvpRouterMappingDao.persist(routermapping);
        }

        return true;
    }

}