@Override
    public List<Intent> compile(MultiPointToSinglePointIntent intent, List<Intent> installable) {
        Map<DeviceId, Link> links = new HashMap<>();
        ConnectPoint egressPoint = intent.egressPoint();

        final boolean allowMissingPaths = intentAllowsPartialFailure(intent);
        boolean hasPaths = false;
        boolean missingSomePaths = false;

        for (ConnectPoint ingressPoint : intent.ingressPoints()) {
            if (ingressPoint.deviceId().equals(egressPoint.deviceId())) {
                if (deviceService.isAvailable(ingressPoint.deviceId())) {
                    hasPaths = true;
                } else {
                    missingSomePaths = true;
                }
                continue;
            }

            Path path = getPath(intent, ingressPoint.deviceId(), egressPoint.deviceId());

            if (path != null) {
                hasPaths = true;

                for (Link link : path.links()) {
                    if (links.containsKey(link.dst().deviceId())) {
                        // We've already reached the existing tree with the first
                        // part of this path. Add the merging point with different
                        // incoming port, but don't add the remainder of the path
                        // in case it differs from the path we already have.
                        links.put(link.src().deviceId(), link);
                        break;
                    }
                    links.put(link.src().deviceId(), link);
                }
            } else {
                missingSomePaths = true;
            }
        }

        // Allocate bandwidth on existing paths if a bandwidth constraint is set
        List<ConnectPoint> ingressCPs =
                intent.filteredIngressPoints().stream()
                                              .map(fcp -> fcp.connectPoint())
                                              .collect(Collectors.toList());
        ConnectPoint egressCP = intent.filteredEgressPoint().connectPoint();

        List<ConnectPoint> pathCPs =
                links.values().stream()
                              .flatMap(l -> Stream.of(l.src(), l.dst()))
                              .collect(Collectors.toList());

        pathCPs.addAll(ingressCPs);
        pathCPs.add(egressCP);

        allocateBandwidth(intent, pathCPs);

        if (!hasPaths) {
            throw new IntentException("Cannot find any path between ingress and egress points.");
        } else if (!allowMissingPaths && missingSomePaths) {
            throw new IntentException("Missing some paths between ingress and egress points.");
        }

        Intent result = LinkCollectionIntent.builder()
                .appId(intent.appId())
                .key(intent.key())
                .treatment(intent.treatment())
                .selector(intent.selector())
                .links(Sets.newHashSet(links.values()))
                .filteredIngressPoints(intent.filteredIngressPoints())
                .filteredEgressPoints(ImmutableSet.of(intent.filteredEgressPoint()))
                .priority(intent.priority())
                .constraints(intent.constraints())
                .resourceGroup(intent.resourceGroup())
                .build();

        return Collections.singletonList(result);
    }
@Test
    public void testBandwidthConstrainedIntentAllocation() {
        final double bpsTotal = 1000.0;
        final double bpsToReserve = 100.0;

        ContinuousResource resourceSw1P1 =
                Resources.continuous(DID_1, PORT_1, Bandwidth.class)
                        .resource(bpsToReserve);
        ContinuousResource resourceSw1P2 =
                Resources.continuous(DID_1, PORT_2, Bandwidth.class)
                        .resource(bpsToReserve);
        ContinuousResource resourceSw2P1 =
                Resources.continuous(DID_2, PORT_1, Bandwidth.class)
                        .resource(bpsToReserve);
        ContinuousResource resourceSw2P2 =
                Resources.continuous(DID_2, PORT_2, Bandwidth.class)
                        .resource(bpsToReserve);
        ContinuousResource resourceSw3P1 =
                Resources.continuous(DID_3, PORT_1, Bandwidth.class)
                        .resource(bpsToReserve);
        ContinuousResource resourceSw3P2 =
                Resources.continuous(DID_3, PORT_2, Bandwidth.class)
                        .resource(bpsToReserve);
        ContinuousResource resourceSw3P3 =
                Resources.continuous(DID_3, PORT_3, Bandwidth.class)
                        .resource(bpsToReserve);
        ContinuousResource resourceSw4P1 =
                Resources.continuous(DID_4, PORT_1, Bandwidth.class)
                        .resource(bpsToReserve);
        ContinuousResource resourceSw4P2 =
                Resources.continuous(DID_4, PORT_2, Bandwidth.class)
                        .resource(bpsToReserve);

        String[] hops = {DID_3.toString()};

        final ResourceService resourceService =
                MockResourceService.makeCustomBandwidthResourceService(bpsTotal);
        final List<Constraint> constraints =
                Collections.singletonList(new BandwidthConstraint(Bandwidth.bps(bpsToReserve)));

        Set<FilteredConnectPoint> ingress = ImmutableSet.of(
                new FilteredConnectPoint(new ConnectPoint(DID_1, PORT_1)),
                new FilteredConnectPoint(new ConnectPoint(DID_2, PORT_1)));

        TrafficSelector ipPrefixSelector = DefaultTrafficSelector.builder()
                .matchIPDst(IpPrefix.valueOf("192.168.100.0/24"))
                .build();

        FilteredConnectPoint egress = new FilteredConnectPoint(new ConnectPoint(DID_4, PORT_2));

        MultiPointToSinglePointIntent intent =
                makeIntent(ingress, egress, ipPrefixSelector, constraints);

        MultiPointToSinglePointIntentCompiler compiler =
                makeCompiler(null,
                             new IntentTestsMocks.FixedMP2MPMockPathService(hops),
                             resourceService);

        compiler.compile(intent, null);

        Key intentKey = intent.key();

        ResourceAllocation rA1 = new ResourceAllocation(resourceSw1P1, intentKey);
        ResourceAllocation rA2 = new ResourceAllocation(resourceSw1P2, intentKey);
        ResourceAllocation rA3 = new ResourceAllocation(resourceSw2P1, intentKey);
        ResourceAllocation rA4 = new ResourceAllocation(resourceSw2P2, intentKey);
        ResourceAllocation rA5 = new ResourceAllocation(resourceSw3P1, intentKey);
        ResourceAllocation rA6 = new ResourceAllocation(resourceSw3P2, intentKey);
        ResourceAllocation rA7 = new ResourceAllocation(resourceSw3P3, intentKey);
        ResourceAllocation rA8 = new ResourceAllocation(resourceSw4P1, intentKey);
        ResourceAllocation rA9 = new ResourceAllocation(resourceSw4P2, intentKey);

        Set<ResourceAllocation> expectedResourceAllocations =
                ImmutableSet.of(rA1, rA2, rA3, rA4, rA5, rA6, rA7, rA8, rA9);

        Set<ResourceAllocation> resourceAllocations =
                ImmutableSet.copyOf(resourceService.getResourceAllocations(intentKey));

        assertThat(resourceAllocations, hasSize(9));
        assertEquals(expectedResourceAllocations, resourceAllocations);
    }