Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 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.maven.shared.osgi; |
| 20 | |
Stuart McCulloch | d98b02e | 2011-06-28 23:20:37 +0000 | [diff] [blame^] | 21 | |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 22 | import java.io.File; |
| 23 | import java.io.IOException; |
| 24 | import java.util.Enumeration; |
| 25 | import java.util.HashSet; |
| 26 | import java.util.Iterator; |
| 27 | import java.util.Map; |
| 28 | import java.util.Set; |
| 29 | import java.util.jar.JarFile; |
| 30 | import java.util.regex.Matcher; |
| 31 | import java.util.regex.Pattern; |
| 32 | import java.util.zip.ZipEntry; |
| 33 | |
| 34 | import org.apache.maven.artifact.Artifact; |
| 35 | |
| 36 | import aQute.lib.osgi.Analyzer; |
| 37 | |
Stuart McCulloch | d98b02e | 2011-06-28 23:20:37 +0000 | [diff] [blame^] | 38 | |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 39 | /** |
| 40 | * Default implementation of {@link Maven2OsgiConverter} |
| 41 | * |
| 42 | * @plexus.component |
| 43 | * |
| 44 | * @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a> |
| 45 | * @version $Id: DefaultMaven2OsgiConverter.java 661727 2008-05-30 14:21:49Z bentmann $ |
| 46 | */ |
Stuart McCulloch | d98b02e | 2011-06-28 23:20:37 +0000 | [diff] [blame^] | 47 | public class DefaultMaven2OsgiConverter implements Maven2OsgiConverter |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 48 | { |
| 49 | |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 50 | private static final String FILE_SEPARATOR = System.getProperty( "file.separator" ); |
| 51 | |
Stuart McCulloch | d98b02e | 2011-06-28 23:20:37 +0000 | [diff] [blame^] | 52 | |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 53 | private String getBundleSymbolicName( String groupId, String artifactId ) |
| 54 | { |
| 55 | return groupId + "." + artifactId; |
| 56 | } |
| 57 | |
Stuart McCulloch | d98b02e | 2011-06-28 23:20:37 +0000 | [diff] [blame^] | 58 | |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 59 | /** |
| 60 | * Get the symbolic name as groupId + "." + artifactId, with the following exceptions |
| 61 | * <ul> |
| 62 | * <li>if artifact.getFile is not null and the jar contains a OSGi Manifest with |
| 63 | * Bundle-SymbolicName property then that value is returned</li> |
| 64 | * <li>if groupId has only one section (no dots) and artifact.getFile is not null then the |
| 65 | * first package name with classes is returned. eg. commons-logging:commons-logging -> |
| 66 | * org.apache.commons.logging</li> |
| 67 | * <li>if artifactId is equal to last section of groupId then groupId is returned. eg. |
| 68 | * org.apache.maven:maven -> org.apache.maven</li> |
| 69 | * <li>if artifactId starts with last section of groupId that portion is removed. eg. |
| 70 | * org.apache.maven:maven-core -> org.apache.maven.core</li> |
| 71 | * </ul> |
| 72 | */ |
| 73 | public String getBundleSymbolicName( Artifact artifact ) |
| 74 | { |
Stuart McCulloch | 3fcc729 | 2009-01-29 17:53:38 +0000 | [diff] [blame] | 75 | if ( ( artifact.getFile() != null ) && artifact.getFile().isFile() ) |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 76 | { |
| 77 | Analyzer analyzer = new Analyzer(); |
| 78 | |
Stuart McCulloch | 3262a0b | 2008-08-06 17:14:25 +0000 | [diff] [blame] | 79 | JarFile jar = null; |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 80 | try |
| 81 | { |
Stuart McCulloch | 3262a0b | 2008-08-06 17:14:25 +0000 | [diff] [blame] | 82 | jar = new JarFile( artifact.getFile(), false ); |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 83 | |
| 84 | if ( jar.getManifest() != null ) |
| 85 | { |
| 86 | String symbolicNameAttribute = jar.getManifest().getMainAttributes() |
| 87 | .getValue( Analyzer.BUNDLE_SYMBOLICNAME ); |
| 88 | Map bundleSymbolicNameHeader = analyzer.parseHeader( symbolicNameAttribute ); |
| 89 | |
| 90 | Iterator it = bundleSymbolicNameHeader.keySet().iterator(); |
| 91 | if ( it.hasNext() ) |
| 92 | { |
Stuart McCulloch | d98b02e | 2011-06-28 23:20:37 +0000 | [diff] [blame^] | 93 | return ( String ) it.next(); |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 94 | } |
| 95 | } |
| 96 | } |
| 97 | catch ( IOException e ) |
| 98 | { |
| 99 | throw new ManifestReadingException( "Error reading manifest in jar " |
| 100 | + artifact.getFile().getAbsolutePath(), e ); |
| 101 | } |
Stuart McCulloch | 3262a0b | 2008-08-06 17:14:25 +0000 | [diff] [blame] | 102 | finally |
| 103 | { |
| 104 | if ( jar != null ) |
| 105 | { |
| 106 | try |
| 107 | { |
| 108 | jar.close(); |
| 109 | } |
| 110 | catch ( IOException e ) |
| 111 | { |
| 112 | } |
| 113 | } |
| 114 | } |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 115 | } |
| 116 | |
| 117 | int i = artifact.getGroupId().lastIndexOf( '.' ); |
Stuart McCulloch | 3fcc729 | 2009-01-29 17:53:38 +0000 | [diff] [blame] | 118 | if ( ( i < 0 ) && ( artifact.getFile() != null ) && artifact.getFile().isFile() ) |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 119 | { |
| 120 | String groupIdFromPackage = getGroupIdFromPackage( artifact.getFile() ); |
| 121 | if ( groupIdFromPackage != null ) |
| 122 | { |
| 123 | return groupIdFromPackage; |
| 124 | } |
| 125 | } |
| 126 | String lastSection = artifact.getGroupId().substring( ++i ); |
| 127 | if ( artifact.getArtifactId().equals( lastSection ) ) |
| 128 | { |
| 129 | return artifact.getGroupId(); |
| 130 | } |
| 131 | if ( artifact.getArtifactId().startsWith( lastSection ) ) |
| 132 | { |
| 133 | String artifactId = artifact.getArtifactId().substring( lastSection.length() ); |
| 134 | if ( Character.isLetterOrDigit( artifactId.charAt( 0 ) ) ) |
| 135 | { |
| 136 | return getBundleSymbolicName( artifact.getGroupId(), artifactId ); |
| 137 | } |
| 138 | else |
| 139 | { |
| 140 | return getBundleSymbolicName( artifact.getGroupId(), artifactId.substring( 1 ) ); |
| 141 | } |
| 142 | } |
| 143 | return getBundleSymbolicName( artifact.getGroupId(), artifact.getArtifactId() ); |
| 144 | } |
| 145 | |
Stuart McCulloch | d98b02e | 2011-06-28 23:20:37 +0000 | [diff] [blame^] | 146 | |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 147 | private String getGroupIdFromPackage( File artifactFile ) |
| 148 | { |
| 149 | try |
| 150 | { |
| 151 | /* get package names from jar */ |
| 152 | Set packageNames = new HashSet(); |
| 153 | JarFile jar = new JarFile( artifactFile, false ); |
| 154 | Enumeration entries = jar.entries(); |
| 155 | while ( entries.hasMoreElements() ) |
| 156 | { |
Stuart McCulloch | d98b02e | 2011-06-28 23:20:37 +0000 | [diff] [blame^] | 157 | ZipEntry entry = ( ZipEntry ) entries.nextElement(); |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 158 | if ( entry.getName().endsWith( ".class" ) ) |
| 159 | { |
| 160 | File f = new File( entry.getName() ); |
| 161 | String packageName = f.getParent(); |
| 162 | if ( packageName != null ) |
| 163 | { |
| 164 | packageNames.add( packageName ); |
| 165 | } |
| 166 | } |
| 167 | } |
Stuart McCulloch | 3262a0b | 2008-08-06 17:14:25 +0000 | [diff] [blame] | 168 | jar.close(); |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 169 | |
| 170 | /* find the top package */ |
| 171 | String[] groupIdSections = null; |
| 172 | for ( Iterator it = packageNames.iterator(); it.hasNext(); ) |
| 173 | { |
Stuart McCulloch | d98b02e | 2011-06-28 23:20:37 +0000 | [diff] [blame^] | 174 | String packageName = ( String ) it.next(); |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 175 | |
| 176 | String[] packageNameSections = packageName.split( "\\" + FILE_SEPARATOR ); |
| 177 | if ( groupIdSections == null ) |
| 178 | { |
| 179 | /* first candidate */ |
| 180 | groupIdSections = packageNameSections; |
| 181 | } |
| 182 | else |
| 183 | // if ( packageNameSections.length < groupIdSections.length ) |
| 184 | { |
| 185 | /* |
| 186 | * find the common portion of current package and previous selected groupId |
| 187 | */ |
| 188 | int i; |
| 189 | for ( i = 0; ( i < packageNameSections.length ) && ( i < groupIdSections.length ); i++ ) |
| 190 | { |
| 191 | if ( !packageNameSections[i].equals( groupIdSections[i] ) ) |
| 192 | { |
| 193 | break; |
| 194 | } |
| 195 | } |
| 196 | groupIdSections = new String[i]; |
| 197 | System.arraycopy( packageNameSections, 0, groupIdSections, 0, i ); |
| 198 | } |
| 199 | } |
| 200 | |
| 201 | if ( ( groupIdSections == null ) || ( groupIdSections.length == 0 ) ) |
| 202 | { |
| 203 | return null; |
| 204 | } |
| 205 | |
| 206 | /* only one section as id doesn't seem enough, so ignore it */ |
| 207 | if ( groupIdSections.length == 1 ) |
| 208 | { |
| 209 | return null; |
| 210 | } |
| 211 | |
| 212 | StringBuffer sb = new StringBuffer(); |
| 213 | for ( int i = 0; i < groupIdSections.length; i++ ) |
| 214 | { |
| 215 | sb.append( groupIdSections[i] ); |
| 216 | if ( i < groupIdSections.length - 1 ) |
| 217 | { |
| 218 | sb.append( '.' ); |
| 219 | } |
| 220 | } |
| 221 | return sb.toString(); |
| 222 | } |
| 223 | catch ( IOException e ) |
| 224 | { |
| 225 | /* we took all the precautions to avoid this */ |
| 226 | throw new RuntimeException( e ); |
| 227 | } |
| 228 | } |
| 229 | |
Stuart McCulloch | d98b02e | 2011-06-28 23:20:37 +0000 | [diff] [blame^] | 230 | |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 231 | public String getBundleFileName( Artifact artifact ) |
| 232 | { |
| 233 | return getBundleSymbolicName( artifact ) + "_" + getVersion( artifact.getVersion() ) + ".jar"; |
| 234 | } |
| 235 | |
Stuart McCulloch | d98b02e | 2011-06-28 23:20:37 +0000 | [diff] [blame^] | 236 | |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 237 | public String getVersion( Artifact artifact ) |
| 238 | { |
| 239 | return getVersion( artifact.getVersion() ); |
| 240 | } |
| 241 | |
Stuart McCulloch | d98b02e | 2011-06-28 23:20:37 +0000 | [diff] [blame^] | 242 | |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 243 | public String getVersion( String version ) |
| 244 | { |
Stuart McCulloch | d98b02e | 2011-06-28 23:20:37 +0000 | [diff] [blame^] | 245 | return cleanupVersion( version ); |
Guillaume Nodet | 6da2254 | 2010-03-05 14:12:41 +0000 | [diff] [blame] | 246 | } |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 247 | |
Guillaume Nodet | 6da2254 | 2010-03-05 14:12:41 +0000 | [diff] [blame] | 248 | /** |
| 249 | * Clean up version parameters. Other builders use more fuzzy definitions of |
| 250 | * the version syntax. This method cleans up such a version to match an OSGi |
| 251 | * version. |
| 252 | * |
| 253 | * @param VERSION_STRING |
| 254 | * @return |
| 255 | */ |
Stuart McCulloch | d98b02e | 2011-06-28 23:20:37 +0000 | [diff] [blame^] | 256 | static final Pattern FUZZY_VERSION = Pattern.compile( "(\\d+)(\\.(\\d+)(\\.(\\d+))?)?([^a-zA-Z0-9](.*))?", |
| 257 | Pattern.DOTALL ); |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 258 | |
Stuart McCulloch | d98b02e | 2011-06-28 23:20:37 +0000 | [diff] [blame^] | 259 | |
| 260 | static public String cleanupVersion( String version ) |
| 261 | { |
Guillaume Nodet | 6da2254 | 2010-03-05 14:12:41 +0000 | [diff] [blame] | 262 | StringBuffer result = new StringBuffer(); |
Stuart McCulloch | d98b02e | 2011-06-28 23:20:37 +0000 | [diff] [blame^] | 263 | Matcher m = FUZZY_VERSION.matcher( version ); |
| 264 | if ( m.matches() ) |
| 265 | { |
| 266 | String major = m.group( 1 ); |
| 267 | String minor = m.group( 3 ); |
| 268 | String micro = m.group( 5 ); |
| 269 | String qualifier = m.group( 7 ); |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 270 | |
Stuart McCulloch | d98b02e | 2011-06-28 23:20:37 +0000 | [diff] [blame^] | 271 | if ( major != null ) |
| 272 | { |
| 273 | result.append( major ); |
| 274 | if ( minor != null ) |
| 275 | { |
| 276 | result.append( "." ); |
| 277 | result.append( minor ); |
| 278 | if ( micro != null ) |
| 279 | { |
| 280 | result.append( "." ); |
| 281 | result.append( micro ); |
| 282 | if ( qualifier != null ) |
| 283 | { |
| 284 | result.append( "." ); |
| 285 | cleanupModifier( result, qualifier ); |
Guillaume Nodet | 6da2254 | 2010-03-05 14:12:41 +0000 | [diff] [blame] | 286 | } |
Guillaume Nodet | 6da2254 | 2010-03-05 14:12:41 +0000 | [diff] [blame] | 287 | } |
Stuart McCulloch | d98b02e | 2011-06-28 23:20:37 +0000 | [diff] [blame^] | 288 | else if ( qualifier != null ) |
| 289 | { |
| 290 | result.append( ".0." ); |
| 291 | cleanupModifier( result, qualifier ); |
| 292 | } |
| 293 | else |
| 294 | { |
| 295 | result.append( ".0" ); |
| 296 | } |
| 297 | } |
| 298 | else if ( qualifier != null ) |
| 299 | { |
| 300 | result.append( ".0.0." ); |
| 301 | cleanupModifier( result, qualifier ); |
| 302 | } |
| 303 | else |
| 304 | { |
| 305 | result.append( ".0.0" ); |
Guillaume Nodet | 6da2254 | 2010-03-05 14:12:41 +0000 | [diff] [blame] | 306 | } |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 307 | } |
Stuart McCulloch | d98b02e | 2011-06-28 23:20:37 +0000 | [diff] [blame^] | 308 | } |
| 309 | else |
| 310 | { |
| 311 | result.append( "0.0.0." ); |
| 312 | cleanupModifier( result, version ); |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 313 | } |
Guillaume Nodet | 6da2254 | 2010-03-05 14:12:41 +0000 | [diff] [blame] | 314 | return result.toString(); |
| 315 | } |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 316 | |
Stuart McCulloch | d98b02e | 2011-06-28 23:20:37 +0000 | [diff] [blame^] | 317 | |
| 318 | static void cleanupModifier( StringBuffer result, String modifier ) |
| 319 | { |
| 320 | for ( int i = 0; i < modifier.length(); i++ ) |
| 321 | { |
| 322 | char c = modifier.charAt( i ); |
| 323 | if ( ( c >= '0' && c <= '9' ) || ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == '_' |
| 324 | || c == '-' ) |
| 325 | result.append( c ); |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 326 | else |
Stuart McCulloch | d98b02e | 2011-06-28 23:20:37 +0000 | [diff] [blame^] | 327 | result.append( '_' ); |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 328 | } |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 329 | } |
| 330 | |
Stuart McCulloch | 8798f6d | 2008-08-06 17:07:33 +0000 | [diff] [blame] | 331 | } |