View Javadoc

1   /* ==========================================================================
2    * Copyright 2007 Mevenide Team
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   * =========================================================================
16   */
17  package org.codehaus.mojo.nbm;
18  
19  import java.io.File;
20  import org.apache.maven.plugin.MojoExecutionException;
21  import org.apache.maven.plugins.annotations.LifecyclePhase;
22  import org.apache.maven.plugins.annotations.Mojo;
23  import org.apache.maven.plugins.annotations.Parameter;
24  import org.apache.maven.project.MavenProject;
25  import org.codehaus.plexus.archiver.jar.JarArchiver;
26  import org.codehaus.plexus.util.DirectoryScanner;
27  import org.codehaus.plexus.util.FileUtils;
28  
29  /**
30   * Package branding resources for NetBeans platform/IDE based application.
31   * The format of branding resources is the same as in
32   * NetBeans Ant-based projects.
33   * 
34   * The <code>src/main/nbm-branding</code> folder of the project is assumed to 
35   * contain the branding content. Within the directory, the following folder structure is assumed:
36   * <ul>
37   * <li>
38   * 1. pick the IDE/platform module which contents you want to brand. eg. org-openide-windows.jar
39   * </li><li>
40   * 2. locate the jar within the IDE/platform installation and it's cluster, eg. modules/org-openide-windows.jar 
41   * </li><li>
42   * 3. create the same folder structure in src/main/nbm-branding, make folder with the module's jar name as well.
43   * eg. create folder by name modules/org-openide-windows.jar
44   * </li><li>
45   * 4. within that folder place your branding modifications at the same location, as if they were withn the jar,
46   * eg. org/openide/windows/ui/Bundle.properties and place the changed bundle keys there.
47   * </li></ul>
48   * @author <a href="mailto:mkleint@codehaus.org">Milos Kleint</a>
49   *
50   *
51   */
52  @Mojo(name="branding",
53          requiresProject=true,
54          threadSafe = true,
55          defaultPhase= LifecyclePhase.PACKAGE)
56  public class BrandingMojo
57          extends AbstractNbmMojo
58  {
59  
60      /**
61       * directory where the the binary content is created.
62       */
63      @Parameter(required=true, defaultValue="${project.build.directory}/nbm")
64      protected File nbmBuildDir;
65      
66      /**
67      * output directory.
68      */
69      @Parameter(defaultValue="${project.build.directory}", required=true)
70      protected File outputDirectory;
71      
72      /**
73       * Location of the branded resources.
74       */
75      @Parameter(required=true, defaultValue="${basedir}/src/main/nbm-branding")
76      private File brandingSources;
77      /**
78       * The branding token used by the application.
79       * Required unless {@code nbmBuildDir} does not exist and the mojo is thus skipped.
80       */
81      @Parameter(property="netbeans.branding.token")
82      private String brandingToken;
83      /**
84       * cluster of the branding.
85       */
86      @Parameter(required=true, defaultValue="extra")
87      protected String cluster;
88      /**
89       * @parameter expression="${project}"
90       * @required
91       * @readonly
92       */
93      @Parameter(required=true, readonly=true, property="project")
94      private MavenProject project;
95  
96      public void execute()
97          throws MojoExecutionException
98      {
99          if ( !"nbm".equals( project.getPackaging() ) ) 
100         {
101             getLog().error( "The nbm:branding goal shall be used within a NetBeans module project only (packaging 'nbm')" );
102         }
103         if ( !brandingSources.isDirectory() )
104         {
105             getLog().info( "No branding to process." );
106             return;
107         }
108         if ( brandingToken == null )
109         {
110             throw new MojoExecutionException( "brandingToken must be defined for mojo:branding" );
111         }
112         try
113         {
114 
115             DirectoryScanner scanner = new DirectoryScanner();
116             scanner.setIncludes( new String[]
117                     {
118                         "**/*.*"
119                     } );
120             scanner.addDefaultExcludes();
121             scanner.setBasedir( brandingSources );
122             scanner.scan();
123 
124             final String clusterPathPart = "netbeans" + File.separator + cluster;
125             File outputDir = new File(outputDirectory, "branding_and_locales");
126             outputDir.mkdirs();
127             File clusterDir = new File( nbmBuildDir, clusterPathPart );
128             clusterDir.mkdirs();
129 
130             // copy all files and see to it that they get the correct names
131             for ( String brandingFilePath : scanner.getIncludedFiles() )
132             {
133                 File brandingFile = new File( brandingSources, brandingFilePath );
134                 String[] locale = getLocale( brandingFile.getName());
135                 String token = locale[1] == null ? brandingToken : brandingToken + "_" + locale[1];
136                 File root = new File(outputDir, token);
137                 root.mkdirs();
138                 String destinationName = locale[0] + "_" + token + locale[2];
139                 File brandingDestination = new File( root, brandingFilePath.replace( brandingFile.getName(), destinationName) );
140                 if ( !brandingDestination.getParentFile().exists() )
141                 {
142                     brandingDestination.getParentFile().mkdirs();
143                 }
144                 FileUtils.copyFile( brandingFile, brandingDestination );
145             }
146             for (File rootDir : outputDir.listFiles()) {
147                 if (!rootDir.isDirectory()) {
148                     continue;
149                 }
150                 String effectiveBranding = rootDir.getName();
151                 // create jar-files from each toplevel .jar directory
152                 scanner.setIncludes( new String[]
153                     {
154                         "**/*.jar"
155                     } );
156                 scanner.setBasedir( rootDir );
157                 scanner.scan();
158                 for ( String jarDirectoryPath : scanner.getIncludedDirectories() )
159                 {
160                     // move nnn.jar directory to nnn.jar.tmp
161                     File jarDirectory = new File( rootDir, jarDirectoryPath );
162                     File destinationLocation = new File(clusterDir, jarDirectoryPath).getParentFile();
163                     destinationLocation.mkdirs();
164                     // jars should be placed in locales/ under the same directory the jar-directories are
165                     File destinationJar =
166                         new File( destinationLocation + File.separator + "locale"
167                             + File.separator + destinationFileName( jarDirectory.getName(), effectiveBranding ) );
168 
169                     // create nnn.jar archive of contents
170                     JarArchiver archiver = new JarArchiver();
171                     archiver.setDestFile( destinationJar );
172                     archiver.addDirectory( jarDirectory );
173                     archiver.createArchive();
174                 }
175             }
176 
177         }
178         catch ( Exception ex )
179         {
180             throw new MojoExecutionException( "Error creating branding", ex );
181         }
182     }
183 
184     static  String destinationFileName( String brandingFilePath, String branding )
185     {
186         // use first underscore in filename 
187         int lastSeparator = brandingFilePath.lastIndexOf( File.separator );
188         String infix = "_" + branding;
189 
190         // no underscores, use dot
191         int lastDot = brandingFilePath.lastIndexOf( "." );
192         if (lastDot == -1 || lastDot < lastSeparator) {
193             return brandingFilePath + infix;
194         }
195         return brandingFilePath.substring( 0, lastDot ) + infix + brandingFilePath.substring( lastDot );
196     }
197     
198     //[0] prefix
199     //[1] locale
200     //[2] suffix
201     static String[] getLocale(String name) {
202         String suffix = "";
203         int dot = name.indexOf( ".");
204         if (dot > -1) { //remove file extension
205             suffix = name.substring( dot );
206             name = name.substring( 0, dot);
207         }
208         String locale = null;
209         int count = 1;
210         //iterate from back of the string, max 3 times and see if the pattern patches local pattern
211         while (count <= 3) {
212             int underscore = name.lastIndexOf( '_');
213             if (underscore > -1) {
214                 String loc1 = name.substring( underscore  + 1);
215                 if (loc1.length() != 2) {
216                     break;
217                 } 
218                 locale = loc1 + (locale == null ? "" : "_" + locale);
219                 name = name.substring( 0, underscore);
220             } else {
221                 break;
222             }
223             count = count + 1;
224         }
225         return new String[] {name, locale, suffix};
226     }
227 }