View Javadoc
1   /*
2    * (C) Copyright 2006-2014 Nuxeo SA (http://nuxeo.com/) and contributors.
3    *
4    * All rights reserved. This program and the accompanying materials
5    * are made available under the terms of the GNU Lesser General Public License
6    * (LGPL) version 2.1 which accompanies this distribution, and is available at
7    * http://www.gnu.org/licenses/lgpl-2.1.html
8    *
9    * This library is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12   * Lesser General Public License for more details.
13   *
14   * Contributors:
15   *     Julien Carsique, slacoin
16   *
17   */
18  
19  package org.nuxeo.build.maven.filter;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.util.ArrayList;
24  import java.util.Collection;
25  import java.util.List;
26  import java.util.StringTokenizer;
27  import java.util.jar.Attributes;
28  import java.util.jar.JarFile;
29  import java.util.jar.Manifest;
30  
31  import org.apache.maven.artifact.Artifact;
32  import org.apache.tools.ant.Project;
33  import org.eclipse.aether.graph.DependencyNode;
34  import org.nuxeo.build.ant.AntClient;
35  import org.nuxeo.build.maven.AntBuildMojo;
36  import org.nuxeo.build.maven.graph.Node;
37  
38  /**
39   * TODO NXBT-258
40   *
41   * @deprecated since 2.0
42   */
43  @Deprecated
44  public class ManifestBundleCategoryFilter extends AbstractFilter {
45  
46      public static final String MANIFEST_BUNDLE_CATEGORY = "Bundle-Category";
47  
48      public static final String MANIFEST_BUNDLE_CATEGORY_TOKEN = ",";
49  
50      protected List<char[]> patterns = new ArrayList<>();
51  
52      protected boolean isDependOnCategory;
53  
54      private String patternsStr;
55  
56      public ManifestBundleCategoryFilter(String patterns,
57              boolean isDependsOnCategory) {
58          this.isDependOnCategory = isDependsOnCategory;
59          StringTokenizer st = new StringTokenizer(patterns,
60                  MANIFEST_BUNDLE_CATEGORY_TOKEN);
61          while (st.hasMoreTokens()) {
62              this.patterns.add(st.nextToken().toCharArray());
63          }
64          this.patternsStr = patterns;
65      }
66  
67      protected List<String> getValuesToMatch(Artifact artifact) {
68          List<String> valuesToMatch = new ArrayList<>();
69          File file = artifact.getFile();
70          if (file == null) {
71              if (artifact.isResolved()) {
72                  AntClient.getInstance().log(
73                          "Artifact " + artifact + " doesn't contain a file",
74                          Project.MSG_WARN);
75              } else if (!Artifact.SCOPE_PROVIDED.equals(artifact.getScope())
76                      && !"pom".equalsIgnoreCase(artifact.getType())) {
77                  // ignore provided artifacts; raise a warning for non provided
78                  AntClient.getInstance().log(
79                          "Artifact " + artifact + " unresolved",
80                          Project.MSG_WARN);
81              }
82              return valuesToMatch;
83          }
84          // ignore non jar files
85          if (!file.getName().endsWith(".jar")) {
86              return valuesToMatch;
87          }
88          JarFile jarFile = null;
89          try {
90              jarFile = new JarFile(file, true);
91              Manifest mf = jarFile.getManifest();
92              if (mf != null) {
93                  Attributes attributes = mf.getMainAttributes();
94                  if (attributes != null) {
95                      String bundleCategories = attributes.getValue(MANIFEST_BUNDLE_CATEGORY);
96                      if (bundleCategories != null) {
97                          StringTokenizer st = new StringTokenizer(
98                                  bundleCategories,
99                                  MANIFEST_BUNDLE_CATEGORY_TOKEN);
100                         while (st.hasMoreTokens()) {
101                             valuesToMatch.add(st.nextToken());
102                         }
103                     }
104                 }
105             } else {
106                 AntClient.getInstance().log(
107                         "Artifact " + artifact + " doesn't contain a manifest",
108                         Project.MSG_WARN);
109             }
110         } catch (IOException e) {
111             AntClient.getInstance().log(
112                     "error while inspecting this jar manifest: "
113                             + artifact.getFile(), e, Project.MSG_ERR);
114         } finally {
115             if (jarFile != null) {
116                 try {
117                     jarFile.close();
118                 } catch (IOException e) {
119                     AntClient.getInstance().log(e.getMessage(), e,
120                             Project.MSG_ERR);
121                 }
122             }
123         }
124         return valuesToMatch;
125     }
126 
127     /**
128      * @deprecated 2.0
129      */
130     @Deprecated
131     protected boolean accept(Node node, boolean browseChildren,
132             boolean browseParents) {
133         // Exclude non Nuxeo artifacts
134         if (!node.getArtifact().getGroupId().startsWith("org.nuxeo")) {
135             return false;
136         }
137         if (AntBuildMojo.getInstance().getLog().isDebugEnabled()) {
138             AntClient.getInstance().log(
139                     "Filtering - " + getClass() + " looking at "
140                             + node.getArtifact(), Project.MSG_DEBUG);
141         }
142         // quick check of already accepted nodes
143         boolean accept = node.isAcceptedCategory(patterns);
144         // else check artifact's Manifest
145         if (!accept) {
146             // accept=accept(node.getArtifact());
147             accept = checkCategoryFromManifest(node);
148         }
149 
150         if (!accept && isDependOnCategory && browseChildren) {
151             // check if there's an acceptable/accepted child
152             if (AntBuildMojo.getInstance().getLog().isDebugEnabled()) {
153                 AntClient.getInstance().log(
154                         "Filtering - check children of " + node,
155                         Project.MSG_DEBUG);
156             }
157             Collection<DependencyNode> children = node.getChildren();
158             // if (children!=null) {
159             for (DependencyNode child : children) {
160                 if (accept((Node) child, true, false)) {
161                     accept = true;
162                     break;
163                 }
164             }
165             // }
166         }
167         if (!accept && browseParents) {
168             // check if there's an acceptable/accepted parent
169             if (AntBuildMojo.getInstance().getLog().isDebugEnabled()) {
170                 AntClient.getInstance().log(
171                         "Filtering - check parents of " + node,
172                         Project.MSG_DEBUG);
173             }
174             Collection<DependencyNode> parents = node.getParents();
175             // if (parents!=null) {
176             for (DependencyNode parent : parents) {
177                 if (accept((Node) parent, false, true)) {
178                     accept = true;
179                     break;
180                 }
181             }
182             // }
183         }
184         if (AntBuildMojo.getInstance().getLog().isDebugEnabled()) {
185             AntClient.getInstance().log(
186                     "Filtering - result for " + node.getArtifact() + " : "
187                             + accept, Project.MSG_DEBUG);
188         }
189         return accept;
190     }
191 
192     private boolean checkCategoryFromManifest(Node node) {
193         boolean accept = false;
194         for (String valueToMatch : getValuesToMatch(node.getMavenArtifact())) {
195             for (char[] pattern : patterns) {
196                 if (matchPattern(valueToMatch, pattern)) {
197                     if (AntBuildMojo.getInstance().getLog().isDebugEnabled()) {
198                         AntClient.getInstance().log(
199                                 "Filtering - match on "
200                                         + String.valueOf(pattern),
201                                 Project.MSG_DEBUG);
202                     }
203                     accept = true;
204                     node.setAcceptedCategory(pattern);
205                     break;
206                 }
207             }
208         }
209         return accept;
210     }
211 
212     /**
213      * @deprecated prefer use of {@link #accept(Node, boolean, boolean)} as it
214      *             remembers already parsed artifacts
215      */
216     @Deprecated
217     @Override
218     public boolean accept(Artifact artifact) {
219         boolean accept = matchPattern(getValuesToMatch(artifact));
220         if (AntBuildMojo.getInstance().getLog().isDebugEnabled()) {
221             AntClient.getInstance().log(
222                     (accept ? "Accepts " : "Rejects ") + artifact,
223                     Project.MSG_DEBUG);
224         }
225         return accept;
226     }
227 
228     private boolean matchPattern(List<String> valuesToMatch) {
229         for (String valueToMatch : valuesToMatch) {
230             for (char[] pattern : patterns) {
231                 if (matchPattern(valueToMatch, pattern)) {
232                     if (AntBuildMojo.getInstance().getLog().isDebugEnabled()) {
233                         AntClient.getInstance().log(
234                                 "Filtering - match on "
235                                         + String.valueOf(pattern),
236                                 Project.MSG_DEBUG);
237                     }
238                     return true;
239                 }
240             }
241         }
242         return false;
243     }
244 
245     public boolean matchPattern(String name, char[] pattern) {
246         return matchPattern(name.toCharArray(), pattern);
247     }
248 
249     public boolean matchPattern(char[] name, char[] pattern) {
250         return matchPattern(name, 0, name.length, pattern);
251     }
252 
253     public boolean matchPattern(char[] name, int offset, int len, char[] pattern) {
254         int i = offset;
255         boolean wildcard = false;
256         for (char c : pattern) {
257             switch (c) {
258             case '*':
259                 wildcard = true;
260                 break;
261             case '?':
262                 i++;
263                 break;
264             default:
265                 if (wildcard) {
266                     while (i < len) {
267                         if (name[i++] == c) {
268                             break;
269                         }
270                     }
271                     if (i == len) {
272                         return true;
273                     }
274                     wildcard = false;
275                 } else if (i >= len || name[i] != c) {
276                     return false;
277                 } else {
278                     i++;
279                 }
280                 break;
281             }
282         }
283         return wildcard || i == len;
284     }
285 
286     @Override
287     public String toString() {
288         return super.toString() + " patterns[" + patternsStr + "]";
289     }
290 
291     public void setDependsOnCategory(boolean isDependsOnCategory) {
292         this.isDependOnCategory = isDependsOnCategory;
293     }
294 
295     @Override
296     public boolean accept(DependencyNode node, List<DependencyNode> parents) {
297         throw new UnsupportedOperationException("Not supported");
298     }
299 
300 }