1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.felix.bundleplugin;
20  
21  
22  import java.util.Collection;
23  import java.util.HashSet;
24  import java.util.Iterator;
25  import java.util.Map;
26  
27  import org.apache.maven.artifact.Artifact;
28  import org.apache.maven.plugin.MojoExecutionException;
29  
30  import aQute.lib.osgi.Instruction;
31  
32  
33  /**
34   * Apply clause-based filter over given dependencies
35   * 
36   * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
37   */
38  public abstract class AbstractDependencyFilter
39  {
40      /**
41       * Dependency artifacts.
42       */
43      private final Collection m_dependencyArtifacts;
44  
45  
46      public AbstractDependencyFilter( Collection dependencyArtifacts )
47      {
48          m_dependencyArtifacts = dependencyArtifacts;
49      }
50  
51      private static abstract class DependencyFilter
52      {
53          private final Instruction m_instruction;
54          private final String m_defaultValue;
55  
56  
57          public DependencyFilter( String expression )
58          {
59              this( expression, "" );
60          }
61  
62  
63          public DependencyFilter( String expression, String defaultValue )
64          {
65              m_instruction = Instruction.getPattern( expression );
66              m_defaultValue = defaultValue;
67          }
68  
69  
70          public void filter( Collection dependencies )
71          {
72              for ( Iterator i = dependencies.iterator(); i.hasNext(); )
73              {
74                  if ( false == matches( ( Artifact ) i.next() ) )
75                  {
76                      i.remove();
77                  }
78              }
79          }
80  
81  
82          abstract boolean matches( Artifact dependency );
83  
84  
85          boolean matches( String text )
86          {
87              boolean result;
88  
89              if ( null == text )
90              {
91                  result = m_instruction.matches( m_defaultValue );
92              }
93              else
94              {
95                  result = m_instruction.matches( text );
96              }
97  
98              return m_instruction.isNegated() ? !result : result;
99          }
100     }
101 
102 
103     protected final void processInstructions( Map instructions ) throws MojoExecutionException
104     {
105         DependencyFilter filter;
106         for ( Iterator clauseIterator = instructions.entrySet().iterator(); clauseIterator.hasNext(); )
107         {
108             String inline = "false";
109 
110             // must use a fresh *modifiable* collection for each unique clause
111             Collection filteredDependencies = new HashSet( m_dependencyArtifacts );
112 
113             // CLAUSE: REGEXP --> { ATTRIBUTE MAP }
114             Map.Entry clause = ( Map.Entry ) clauseIterator.next();
115             StringBuilder tag = new StringBuilder();
116             tag.append( clause.getKey() );
117 
118             if ( !( ( String ) clause.getKey() ).matches( "\\*~*" ) )
119             {
120                 filter = new DependencyFilter( ( String ) clause.getKey() )
121                 {
122                     boolean matches( Artifact dependency )
123                     {
124                         return super.matches( dependency.getArtifactId() );
125                     }
126                 };
127                 // FILTER ON MAIN CLAUSE
128                 filter.filter( filteredDependencies );
129             }
130 
131             for ( Iterator attrIterator = ( ( Map ) clause.getValue() ).entrySet().iterator(); attrIterator.hasNext(); )
132             {
133                 // ATTRIBUTE: KEY --> REGEXP
134                 Map.Entry attr = ( Map.Entry ) attrIterator.next();
135                 tag.append( ';' ).append( attr );
136 
137                 if ( "groupId".equals( attr.getKey() ) )
138                 {
139                     filter = new DependencyFilter( ( String ) attr.getValue() )
140                     {
141                         boolean matches( Artifact dependency )
142                         {
143                             return super.matches( dependency.getGroupId() );
144                         }
145                     };
146                 }
147                 else if ( "artifactId".equals( attr.getKey() ) )
148                 {
149                     filter = new DependencyFilter( ( String ) attr.getValue() )
150                     {
151                         boolean matches( Artifact dependency )
152                         {
153                             return super.matches( dependency.getArtifactId() );
154                         }
155                     };
156                 }
157                 else if ( "version".equals( attr.getKey() ) )
158                 {
159                     filter = new DependencyFilter( ( String ) attr.getValue() )
160                     {
161                         boolean matches( Artifact dependency )
162                         {
163                             try
164                             {
165                                 // use the symbolic version if available (ie. 1.0.0-SNAPSHOT)
166                                 return super.matches( dependency.getSelectedVersion().toString() );
167                             }
168                             catch ( Exception e )
169                             {
170                                 return super.matches( dependency.getVersion() );
171                             }
172                         }
173                     };
174                 }
175                 else if ( "scope".equals( attr.getKey() ) )
176                 {
177                     filter = new DependencyFilter( ( String ) attr.getValue(), "compile" )
178                     {
179                         boolean matches( Artifact dependency )
180                         {
181                             return super.matches( dependency.getScope() );
182                         }
183                     };
184                 }
185                 else if ( "type".equals( attr.getKey() ) )
186                 {
187                     filter = new DependencyFilter( ( String ) attr.getValue(), "jar" )
188                     {
189                         boolean matches( Artifact dependency )
190                         {
191                             return super.matches( dependency.getType() );
192                         }
193                     };
194                 }
195                 else if ( "classifier".equals( attr.getKey() ) )
196                 {
197                     filter = new DependencyFilter( ( String ) attr.getValue() )
198                     {
199                         boolean matches( Artifact dependency )
200                         {
201                             return super.matches( dependency.getClassifier() );
202                         }
203                     };
204                 }
205                 else if ( "optional".equals( attr.getKey() ) )
206                 {
207                     filter = new DependencyFilter( ( String ) attr.getValue(), "false" )
208                     {
209                         boolean matches( Artifact dependency )
210                         {
211                             return super.matches( "" + dependency.isOptional() );
212                         }
213                     };
214                 }
215                 else if ( "inline".equals( attr.getKey() ) )
216                 {
217                     inline = ( String ) attr.getValue();
218                     continue;
219                 }
220                 else
221                 {
222                     throw new MojoExecutionException( "Unexpected attribute " + attr.getKey() );
223                 }
224 
225                 // FILTER ON EACH ATTRIBUTE
226                 filter.filter( filteredDependencies );
227             }
228 
229             processDependencies( tag.toString(), inline, filteredDependencies );
230         }
231     }
232 
233 
234     protected abstract void processDependencies( String clause, String inline, Collection dependencies );
235 }