import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

class Ideone {
	public static void main (String[] args) {
		ArrayList<Mobile> mobiles = new ArrayList<>();
		mobiles.add(
			Mobile.of(
				Plan.of("P1", "Plan 1"),
				Plan.of("P2", "Plan 2")));
		mobiles.add(Mobile.of(
				Plan.of("P1", "Plan 1"),
				Plan.of("P2", "Plan 2"),
				Plan.of("P3", "Plan 3"),
				Plan.of("P4", "Plan 4")));
		mobiles.add(Mobile.of(
				Plan.of("P1", "Plan 1"),
				Plan.of("P2", "Plan 2"),
				Plan.of("P5", "Plan 5"),
				Plan.of("P6", "Plan 6")));
		Set<Plan> commonPlans = extractCommonPlans(mobiles);
		System.out.println(commonPlans);
	}
	
	public static Set<Plan> extractCommonPlans(List<Mobile> mobiles) {
		if (Objects.isNull(mobiles) || mobiles.isEmpty()) {
			return Collections.emptySet();
		}

		HashSet<Plan> initialSet = new HashSet<>(mobiles.get(0).getPlans());
		return mobiles.stream()
			.map(Mobile::getPlans)
			.map(HashSet<Plan>::new)
			.reduce(initialSet, (plan1, plan2) -> { 
				plan1.retainAll(plan2);
				return plan1;
			});
	}
}

class Mobile {
    private final List<Plan> plans;
    
    private Mobile(List<Plan> plans) {
    	this.plans = plans;
    }
    
    public static Mobile of(Plan... plans) {
    	return new Mobile(Arrays.asList(plans));
    }

    public List<Plan> getPlans() {
    	return plans;
    }
}

class Plan {
    private final String id;
    private final String name;
    
    private Plan(String id, String name) {
    	this.id = id;
    	this.name = name;
    }
    
    public static Plan of(String id, String name) {
    	return new Plan(id, name);
    }
    
    @Override 
    public boolean equals(Object thatObject) {
    	if (this == thatObject) {
    		return true;
    	}
    	if (getClass() != thatObject.getClass()) {
    		return false;
    	}
    	Plan that = (Plan) thatObject;
    	return Objects.equals(id, that.id) 
    			&& Objects.equals(name, that.name);
    }
    
    @Override 
    public int hashCode() {
    	return Objects.hash(id, name);
    }
    
    @Override
    public String toString() {
    	return String.format("Plan{id=\"%s\", name=\"%s\"}", id, name);
    }
}