| /****************************************************************************** |
| * Copyright (c) 2010 Oracle |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Konstantin Komissarchik - initial implementation and ongoing maintenance |
| ******************************************************************************/ |
| |
| package org.eclipse.wst.common.project.facet.ui.internal.constraints; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.wst.common.project.facet.core.IConstraint; |
| import org.eclipse.wst.common.project.facet.core.IGroup; |
| import org.eclipse.wst.common.project.facet.core.IProjectFacet; |
| import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion; |
| import org.eclipse.wst.common.project.facet.core.IVersionExpr; |
| import org.eclipse.wst.common.project.facet.core.internal.ProjectFacetRef; |
| import org.eclipse.wst.common.project.facet.core.util.internal.VersionExpr; |
| |
| /** |
| * @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a> |
| */ |
| |
| public final class ConstraintUtil |
| { |
| private ConstraintUtil() {} |
| |
| public static ConstraintOperator convert( final IConstraint inputConstraint ) |
| { |
| final IConstraint.Type inputConstraintType = inputConstraint.getType(); |
| |
| if( inputConstraintType == IConstraint.Type.AND || |
| inputConstraintType == IConstraint.Type.OR ) |
| { |
| final ConstraintOperator.Type outputConstraintType |
| = ( inputConstraintType == IConstraint.Type.AND |
| ? ConstraintOperator.Type.AND : ConstraintOperator.Type.OR ); |
| |
| final GroupingConstraintOperator outputConstraint |
| = new GroupingConstraintOperator( outputConstraintType ); |
| |
| for( Object child : inputConstraint.getOperands() ) |
| { |
| outputConstraint.addChild( convert( (IConstraint) child ) ); |
| } |
| |
| return outputConstraint; |
| } |
| else if( inputConstraintType == IConstraint.Type.REQUIRES ) |
| { |
| final Object firstOperand = inputConstraint.getOperand( 0 ); |
| |
| final MultiFacetConstraintOperator outputConstraint |
| = new MultiFacetConstraintOperator( ConstraintOperator.Type.REQUIRES_ONE ); |
| |
| if( firstOperand instanceof IProjectFacet ) |
| { |
| final IProjectFacet f = (IProjectFacet) firstOperand; |
| final IVersionExpr vexpr = (IVersionExpr) inputConstraint.getOperand( 1 ); |
| outputConstraint.addProjectFacetRef( new ProjectFacetRef( f, vexpr ) ); |
| } |
| else |
| { |
| final IGroup group = (IGroup) firstOperand; |
| outputConstraint.addProjectFacetRefs( convertGroupToFacetRefs( group ) ); |
| } |
| |
| return outputConstraint; |
| } |
| else if( inputConstraintType == IConstraint.Type.CONFLICTS ) |
| { |
| final Object firstOperand = inputConstraint.getOperand( 0 ); |
| |
| final MultiFacetConstraintOperator outputConstraint |
| = new MultiFacetConstraintOperator( ConstraintOperator.Type.CONFLICTS ); |
| |
| if( firstOperand instanceof IProjectFacet ) |
| { |
| final IProjectFacet f = (IProjectFacet) firstOperand; |
| final IVersionExpr vexpr = (IVersionExpr) inputConstraint.getOperand( 1 ); |
| outputConstraint.addProjectFacetRef( new ProjectFacetRef( f, vexpr ) ); |
| } |
| else |
| { |
| final IGroup group = (IGroup) firstOperand; |
| outputConstraint.addProjectFacetRefs( convertGroupToFacetRefs( group ) ); |
| } |
| |
| return outputConstraint; |
| } |
| else |
| { |
| throw new IllegalStateException( inputConstraintType.name() ); |
| } |
| } |
| |
| private static Collection<ProjectFacetRef> convertGroupToFacetRefs( final IGroup group ) |
| { |
| final Map<IProjectFacet,List<IProjectFacetVersion>> members |
| = new HashMap<IProjectFacet,List<IProjectFacetVersion>>(); |
| |
| for( IProjectFacetVersion fv : group.getMembers() ) |
| { |
| final IProjectFacet f = fv.getProjectFacet(); |
| List<IProjectFacetVersion> versions = members.get( f ); |
| |
| if( versions == null ) |
| { |
| versions = new ArrayList<IProjectFacetVersion>(); |
| members.put( f, versions ); |
| } |
| |
| versions.add( fv ); |
| } |
| |
| final List<ProjectFacetRef> facetRefs = new ArrayList<ProjectFacetRef>( members.size() ); |
| |
| for( Map.Entry<IProjectFacet,List<IProjectFacetVersion>> entry : members.entrySet() ) |
| { |
| final IProjectFacet f = entry.getKey(); |
| final List<IProjectFacetVersion> versions = entry.getValue(); |
| final String vexprString; |
| |
| if( versions.size() == f.getVersions().size() ) |
| { |
| vexprString = IVersionExpr.WILDCARD_SYMBOL; |
| } |
| else |
| { |
| final StringBuilder buf = new StringBuilder(); |
| |
| for( IProjectFacetVersion fv : versions ) |
| { |
| if( buf.length() > 0 ) |
| { |
| buf.append( ',' ); |
| } |
| |
| buf.append( fv.getVersionString() ); |
| } |
| |
| vexprString = buf.toString(); |
| } |
| |
| final IVersionExpr vexpr; |
| |
| try |
| { |
| vexpr = new VersionExpr<IProjectFacetVersion>( f, vexprString, null ); |
| } |
| catch( CoreException e ) |
| { |
| throw new RuntimeException( e ); |
| } |
| |
| facetRefs.add( new ProjectFacetRef( f, vexpr ) ); |
| } |
| |
| return facetRefs; |
| } |
| |
| public static ConstraintOperator normalize( final ConstraintOperator input ) |
| { |
| if( input instanceof GroupingConstraintOperator ) |
| { |
| final List<ConstraintOperator> oldChildren = ( (GroupingConstraintOperator) input ).getChildren(); |
| final List<ConstraintOperator> newChildren = new ArrayList<ConstraintOperator>( oldChildren.size() ); |
| |
| for( ConstraintOperator child : oldChildren ) |
| { |
| newChildren.add( normalize( child ) ); |
| } |
| |
| if( input.getType() == ConstraintOperator.Type.AND ) |
| { |
| // Can merge any REQUIRES_ALL operators under an AND. Note that a REQUIRES_ONE with |
| // a single facet can be treated as REQUIRES_ALL. |
| |
| MultiFacetConstraintOperator firstRequiresAll = null; |
| |
| for( Iterator<ConstraintOperator> itr = newChildren.iterator(); itr.hasNext(); ) |
| { |
| final ConstraintOperator op = itr.next(); |
| |
| if( op.getType() == ConstraintOperator.Type.REQUIRES_ALL || |
| ( op.getType() == ConstraintOperator.Type.REQUIRES_ONE && |
| ( (MultiFacetConstraintOperator) op ).getProjectFacetRefs().size() == 1 ) ) |
| { |
| final MultiFacetConstraintOperator mfop = (MultiFacetConstraintOperator) op; |
| |
| if( firstRequiresAll == null ) |
| { |
| firstRequiresAll = mfop; |
| } |
| else |
| { |
| firstRequiresAll.addProjectFacetRefs( mfop.getProjectFacetRefs() ); |
| itr.remove(); |
| } |
| } |
| } |
| |
| if( firstRequiresAll != null && |
| firstRequiresAll.getType() == ConstraintOperator.Type.REQUIRES_ONE && |
| firstRequiresAll.getProjectFacetRefs().size() > 1 ) |
| { |
| firstRequiresAll.setType( ConstraintOperator.Type.REQUIRES_ALL ); |
| } |
| |
| // Can merge any CONFLICTS operators under an AND. |
| |
| MultiFacetConstraintOperator firstConflicts = null; |
| |
| for( Iterator<ConstraintOperator> itr = newChildren.iterator(); itr.hasNext(); ) |
| { |
| final ConstraintOperator op = itr.next(); |
| |
| if( op.getType() == ConstraintOperator.Type.CONFLICTS ) |
| { |
| final MultiFacetConstraintOperator mfop = (MultiFacetConstraintOperator) op; |
| |
| if( firstConflicts == null ) |
| { |
| firstConflicts = mfop; |
| } |
| else |
| { |
| firstConflicts.addProjectFacetRefs( mfop.getProjectFacetRefs() ); |
| itr.remove(); |
| } |
| } |
| } |
| } |
| else |
| { |
| // Can merge any REQUIRES_ONE operators under an OR that have only one child. |
| |
| MultiFacetConstraintOperator firstRequiresOne = null; |
| |
| for( Iterator<ConstraintOperator> itr = newChildren.iterator(); itr.hasNext(); ) |
| { |
| final ConstraintOperator op = itr.next(); |
| |
| if( op.getType() == ConstraintOperator.Type.REQUIRES_ONE ) |
| { |
| final MultiFacetConstraintOperator mfop = (MultiFacetConstraintOperator) op; |
| |
| if( firstRequiresOne == null ) |
| { |
| firstRequiresOne = mfop; |
| } |
| else |
| { |
| firstRequiresOne.addProjectFacetRefs( mfop.getProjectFacetRefs() ); |
| itr.remove(); |
| } |
| } |
| } |
| } |
| |
| if( newChildren.size() == 1 ) |
| { |
| return newChildren.get( 0 ); |
| } |
| else |
| { |
| final GroupingConstraintOperator output = new GroupingConstraintOperator( input.getType() ); |
| output.addChildren( newChildren ); |
| return output; |
| } |
| } |
| else |
| { |
| return input; |
| } |
| } |
| |
| } |