View Javadoc

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  
20  package org.apache.myfaces.config;
21  
22  import org.apache.myfaces.shared.util.ClassUtils;
23  
24  import javax.faces.FacesException;
25  import java.net.URL;
26  import java.util.ArrayList;
27  import java.util.Collections;
28  import java.util.HashMap;
29  import java.util.Iterator;
30  import java.util.List;
31  import java.util.Map;
32  import java.util.logging.Level;
33  import java.util.logging.Logger;
34  import java.util.regex.Matcher;
35  import java.util.regex.Pattern;
36  
37  class LogMetaInfUtils
38  {
39  
40      private static final Logger log = Logger.getLogger(LogMetaInfUtils.class.getName());
41  
42      /**
43       * Regular expression used to extract the jar information from the
44       * files present in the classpath.
45       * <p>The groups found with the regular expression are:</p>
46       * <ul>
47       *   <li>Group 2: file path</li>
48       *   <li>Group 3: artifact id</li>
49       *   <li>Group 4: version</li>
50       * </ul>
51       * The regexp is searching in the file name to the first - followed by a digit to split artifact name and version.
52       */
53      public static final String REGEX_LIBRARY
54          = "(jar|besjar|wsjar|zip)"
55          + ":(file:.*/((myfaces|tomahawk|trinidad|tobago|commons\\-el|jsp\\-api)[\\w\\-\\_]+?)"
56          + "-(\\d+.*)\\.jar)!/META-INF/MANIFEST.MF";
57      private static final Pattern REGEX_LIBRARY_PATTERN = Pattern.compile(REGEX_LIBRARY);
58  
59      private static final int REGEX_LIBRARY_FILE_PATH = 2;
60      private static final int REGEX_LIBRARY_ARTIFACT_ID = 3;
61      private static final int REGEX_LIBRARY_VERSION = 5;
62  
63      /**
64       * This method performs part of the factory search outlined in section 10.2.6.1.
65       */
66      @SuppressWarnings("unchecked")
67      protected static void logMetaInf()
68      {
69          if (!log.isLoggable(Level.WARNING))
70          {
71            return;
72          }
73  
74          try
75          {
76              Map<String, List<JarInfo>> libs = new HashMap<String, List<JarInfo>>(30);
77  
78              Iterator<URL> it = ClassUtils.getResources("META-INF/MANIFEST.MF", LogMetaInfUtils.class);
79              while (it.hasNext())
80              {
81                  URL url = it.next();
82                  addJarInfo(libs, url);
83              }
84  
85              final List<String> keys = new ArrayList(libs.keySet());
86              Collections.sort(keys);
87  
88              if (log.isLoggable(Level.WARNING))
89              {
90                  for (String artifactId : keys)
91                  {
92                      List<JarInfo> versions = libs.get(artifactId);
93                      if (versions != null && versions.size() > 1)
94                      {
95                          StringBuilder builder = new StringBuilder(1024);
96                          builder.append("You are using the library: ");
97                          builder.append(artifactId);
98                          builder.append(" in different versions; first (and probably used) version is: ");
99                          builder.append(versions.get(0).getVersion());
100                         builder.append(" loaded from: ");
101                         builder.append(versions.get(0).getUrl());
102                         builder.append(", but also found the following versions: ");
103 
104                         boolean needComma = false;
105                         for (int i = 1; i < versions.size(); i++)
106                         {
107                             JarInfo info = versions.get(i);
108                             if (needComma)
109                             {
110                                 builder.append(", ");
111                             }
112 
113                             builder.append(info.getVersion());
114                             builder.append(" loaded from: ");
115                             builder.append(info.getUrl());
116 
117                             needComma = true;
118                         }
119 
120                         log.warning(builder.toString());
121                     }
122                 }
123             }
124 
125             if (log.isLoggable(Level.INFO))
126             {
127                 for (String artifactId : keys)
128                 {
129                     logArtifact(artifactId, libs);
130                 }
131             }
132         }
133         catch (Throwable e)
134         {
135             throw new FacesException(e);
136         }
137     }
138 
139     protected static void addJarInfo(Map<String, List<JarInfo>> libs, URL url)
140     {
141         Matcher matcher = REGEX_LIBRARY_PATTERN.matcher(url.toString());
142         if (matcher.matches())
143         {
144             // We have a valid JAR
145             String artifactId = matcher.group(REGEX_LIBRARY_ARTIFACT_ID);
146             List<JarInfo> versions = libs.get(artifactId);
147             if (versions == null)
148             {
149                 versions = new ArrayList<JarInfo>(1);
150                 libs.put(artifactId, versions);
151             }
152 
153             String path = matcher.group(REGEX_LIBRARY_FILE_PATH);
154 
155             String version = matcher.group(REGEX_LIBRARY_VERSION);
156 
157             JarInfo newInfo = new JarInfo(path, version);
158             if (!versions.contains(newInfo))
159             {
160                 versions.add(newInfo);
161             }
162         }
163     }
164 
165     private static void logArtifact(String artifactId, Map<String, List<JarInfo>> libs)
166     {
167         List<JarInfo> versions = libs.get(artifactId);
168         if (versions == null)
169         {
170             log.info("Artifact '" + artifactId + "' was not found.");
171         }
172         else
173         {
174             JarInfo info = versions.get(0);
175             log.info("Artifact '" + artifactId + "' was found in version '"
176                      + info.getVersion() + "' from path '" + info.getUrl() + "'");
177         }
178     }
179 
180 
181     protected static class JarInfo implements Comparable<JarInfo>
182     {
183         private String url;
184         private String version;
185 
186         public JarInfo(String url, String version)
187         {
188             this.url = url;
189             this.version = version;
190         }
191 
192         public String getVersion()
193         {
194             return version;
195         }
196 
197         public String getUrl()
198         {
199             return url;
200         }
201 
202         public int compareTo(JarInfo info)
203         {
204             return version.compareTo(info.version);
205         }
206 
207         @Override
208         public boolean equals(Object o)
209         {
210             if (o == this)
211             {
212                 return true;
213             }
214             else if (o instanceof JarInfo)
215             {
216                 JarInfo other = (JarInfo) o;
217                 return version.equals(other.version);
218             }
219             else
220             {
221                 return false;
222             }
223         }
224 
225         @Override
226         public int hashCode()
227         {
228             return version.hashCode();
229         }
230     }
231 
232 }