View Javadoc
1   package org.apache.maven.index.packer;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0    
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.FileInputStream;
24  import java.io.FileOutputStream;
25  import java.io.IOException;
26  import java.io.OutputStream;
27  import java.text.SimpleDateFormat;
28  import java.util.Date;
29  import java.util.List;
30  import java.util.Properties;
31  import java.util.TimeZone;
32  
33  import javax.inject.Inject;
34  import javax.inject.Named;
35  import javax.inject.Singleton;
36  
37  import org.apache.maven.index.context.IndexingContext;
38  import org.apache.maven.index.incremental.IncrementalHandler;
39  import org.apache.maven.index.updater.IndexDataWriter;
40  import org.codehaus.plexus.util.FileUtils;
41  import org.slf4j.Logger;
42  import org.slf4j.LoggerFactory;
43  
44  /**
45   * A default {@link IndexPacker} implementation. Creates the properties, legacy index zip and new gz files.
46   *
47   * @author Tamas Cservenak
48   * @author Eugene Kuleshov
49   */
50  @Singleton
51  @Named
52  public class DefaultIndexPacker
53      implements IndexPacker
54  {
55  
56      private final Logger logger = LoggerFactory.getLogger( getClass() );
57  
58      protected Logger getLogger()
59      {
60          return logger;
61      }
62  
63      private final IncrementalHandler incrementalHandler;
64  
65  
66      @Inject
67      public DefaultIndexPacker( IncrementalHandler incrementalHandler )
68      {
69          this.incrementalHandler = incrementalHandler;
70      }
71  
72      public void packIndex( IndexPackingRequest request )
73          throws IOException, IllegalArgumentException
74      {
75          if ( request.getTargetDir() == null )
76          {
77              throw new IllegalArgumentException( "The target dir is null" );
78          }
79  
80          if ( request.getTargetDir().exists() )
81          {
82              if ( !request.getTargetDir().isDirectory() )
83              {
84                  throw new IllegalArgumentException( //
85                                                      String.format( "Specified target path %s is not a directory",
86                                                                     request.getTargetDir().getAbsolutePath() ) );
87              }
88              if ( !request.getTargetDir().canWrite() )
89              {
90                  throw new IllegalArgumentException( String.format( "Specified target path %s is not writtable",
91                                                                     request.getTargetDir().getAbsolutePath() ) );
92              }
93          }
94          else
95          {
96              if ( !request.getTargetDir().mkdirs() )
97              {
98                  throw new IllegalArgumentException( "Can't create " + request.getTargetDir().getAbsolutePath() );
99              }
100         }
101 
102         // These are all of the files we'll be dealing with (except for the incremental chunks of course)
103         File v1File = new File( request.getTargetDir(), IndexingContext.INDEX_FILE_PREFIX + ".gz" );
104 
105         Properties info = null;
106 
107         try
108         {
109             // Note that for incremental indexes to work properly, a valid index.properties file
110             // must be present
111             info = readIndexProperties( request );
112 
113             if ( request.isCreateIncrementalChunks() )
114             {
115                 List<Integer> chunk = incrementalHandler.getIncrementalUpdates( request, info );
116 
117                 if ( chunk == null )
118                 {
119                     getLogger().debug( "Problem with Chunks, forcing regeneration of whole index" );
120                     incrementalHandler.initializeProperties( info );
121                 }
122                 else if ( chunk.isEmpty() )
123                 {
124                     getLogger().debug( "No incremental changes, not writing new incremental chunk" );
125                 }
126                 else
127                 {
128                     File file = new File( request.getTargetDir(), //
129                                           IndexingContext.INDEX_FILE_PREFIX + "." + info.getProperty(
130                                               IndexingContext.INDEX_CHUNK_COUNTER ) + ".gz" );
131 
132                     writeIndexData( request, chunk, file );
133 
134                     if ( request.isCreateChecksumFiles() )
135                     {
136                         FileUtils.fileWrite(
137                             new File( file.getParentFile(), file.getName() + ".sha1" ).getAbsolutePath(),
138                             DigesterUtils.getSha1Digest( file ) );
139 
140                         FileUtils.fileWrite(
141                             new File( file.getParentFile(), file.getName() + ".md5" ).getAbsolutePath(),
142                             DigesterUtils.getMd5Digest( file ) );
143                     }
144                 }
145             }
146         }
147         catch ( IOException e )
148         {
149             getLogger().info( "Unable to read properties file, will force index regeneration" );
150             info = new Properties();
151             incrementalHandler.initializeProperties( info );
152         }
153 
154         Date timestamp = request.getContext().getTimestamp();
155 
156         if ( timestamp == null )
157         {
158             timestamp = new Date( 0 ); // never updated
159         }
160 
161         if ( request.getFormats().contains( IndexPackingRequest.IndexFormat.FORMAT_V1 ) )
162         {
163             info.setProperty( IndexingContext.INDEX_TIMESTAMP, format( timestamp ) );
164 
165             writeIndexData( request, null, v1File );
166 
167             if ( request.isCreateChecksumFiles() )
168             {
169                 FileUtils.fileWrite( new File( v1File.getParentFile(), v1File.getName() + ".sha1" ).getAbsolutePath(),
170                                      DigesterUtils.getSha1Digest( v1File ) );
171 
172                 FileUtils.fileWrite( new File( v1File.getParentFile(), v1File.getName() + ".md5" ).getAbsolutePath(),
173                                      DigesterUtils.getMd5Digest( v1File ) );
174             }
175         }
176 
177         writeIndexProperties( request, info );
178     }
179 
180     private Properties readIndexProperties( IndexPackingRequest request )
181         throws IOException
182     {
183         File file = null;
184 
185         if ( request.isUseTargetProperties() || request.getContext().getIndexDirectoryFile() == null )
186         {
187             file = new File( request.getTargetDir(), IndexingContext.INDEX_REMOTE_PROPERTIES_FILE );
188         }
189         else
190         {
191             file =
192                 new File( request.getContext().getIndexDirectoryFile(), IndexingContext.INDEX_PACKER_PROPERTIES_FILE );
193         }
194 
195         Properties properties = new Properties();
196 
197         FileInputStream fos = null;
198 
199         try
200         {
201             fos = new FileInputStream( file );
202             properties.load( fos );
203         }
204         finally
205         {
206             if ( fos != null )
207             {
208                 fos.close();
209             }
210         }
211 
212         return properties;
213     }
214 
215     void writeIndexData( IndexPackingRequest request, List<Integer> docIndexes, File targetArchive )
216         throws IOException
217     {
218         if ( targetArchive.exists() )
219         {
220             targetArchive.delete();
221         }
222 
223         try ( OutputStream os = new FileOutputStream( targetArchive ) )
224         {
225             IndexDataWriter dw = new IndexDataWriter( os );
226             dw.write( request.getContext(), request.getIndexReader(), docIndexes );
227 
228             os.flush();
229         }
230     }
231 
232     void writeIndexProperties( IndexPackingRequest request, Properties info )
233         throws IOException
234     {
235         File propertyFile =
236             new File( request.getContext().getIndexDirectoryFile(), IndexingContext.INDEX_PACKER_PROPERTIES_FILE );
237         File targetPropertyFile = new File( request.getTargetDir(), IndexingContext.INDEX_REMOTE_PROPERTIES_FILE );
238 
239         info.setProperty( IndexingContext.INDEX_ID, request.getContext().getId() );
240 
241         try ( OutputStream os = new FileOutputStream( propertyFile ) )
242         {
243             info.store( os, null );
244         }
245 
246         try ( OutputStream os = new FileOutputStream( targetPropertyFile ) )
247         {
248             info.store( os, null );
249         }
250 
251         if ( request.isCreateChecksumFiles() )
252         {
253             FileUtils.fileWrite( new File( targetPropertyFile.getParentFile(),
254                                            targetPropertyFile.getName() + ".sha1" ).getAbsolutePath(),
255                                  DigesterUtils.getSha1Digest( targetPropertyFile ) );
256 
257             FileUtils.fileWrite(
258                 new File( targetPropertyFile.getParentFile(), targetPropertyFile.getName() + ".md5" ).getAbsolutePath(),
259                 DigesterUtils.getMd5Digest( targetPropertyFile ) );
260         }
261     }
262 
263     private String format( Date d )
264     {
265         SimpleDateFormat df = new SimpleDateFormat( IndexingContext.INDEX_TIME_FORMAT );
266         df.setTimeZone( TimeZone.getTimeZone( "GMT" ) );
267         return df.format( d );
268     }
269 }