View Javadoc
1   package org.eclipse.aether.internal.impl;
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 org.eclipse.aether.SyncContext;
23  
24  import org.slf4j.Logger;
25  import org.slf4j.LoggerFactory;
26  
27  import java.io.ByteArrayInputStream;
28  import java.io.ByteArrayOutputStream;
29  import java.io.Closeable;
30  import java.io.File;
31  import java.io.FileInputStream;
32  import java.io.IOException;
33  import java.io.RandomAccessFile;
34  import java.util.Map;
35  import java.util.Properties;
36  
37  /**
38   * Manages access to a properties file. This override drops internal synchronization becauses it
39   * relies on external synchronization provided by outer {@link SyncContext} instances.
40   */
41  class TrackingFileManager
42  {
43  
44      private static final Logger LOGGER = LoggerFactory.getLogger( TrackingFileManager.class );
45  
46      public Properties read( File file )
47      {
48          FileInputStream stream = null;
49          try
50          {
51              if ( !file.exists() )
52              {
53                  return null;
54              }
55  
56              stream = new FileInputStream( file );
57  
58              Properties props = new Properties();
59              props.load( stream );
60  
61              return props;
62          }
63          catch ( IOException e )
64          {
65              LOGGER.warn( "Failed to read tracking file {}", file, e );
66          }
67          finally
68          {
69              close( stream, file );
70          }
71  
72          return null;
73      }
74  
75      public Properties update( File file, Map<String, String> updates )
76      {
77          Properties props = new Properties();
78  
79          File directory = file.getParentFile();
80          if ( !directory.mkdirs() && !directory.exists() )
81          {
82              LOGGER.warn( "Failed to create parent directories for tracking file {}", file );
83              return props;
84          }
85  
86          RandomAccessFile raf = null;
87          try
88          {
89              raf = new RandomAccessFile( file, "rw" );
90  
91              if ( file.canRead() )
92              {
93                  byte[] buffer = new byte[(int) raf.length()];
94  
95                  raf.readFully( buffer );
96  
97                  ByteArrayInputStream stream = new ByteArrayInputStream( buffer );
98  
99                  props.load( stream );
100             }
101 
102             for ( Map.Entry<String, String> update : updates.entrySet() )
103             {
104                 if ( update.getValue() == null )
105                 {
106                     props.remove( update.getKey() );
107                 }
108                 else
109                 {
110                     props.setProperty( update.getKey(), update.getValue() );
111                 }
112             }
113 
114             ByteArrayOutputStream stream = new ByteArrayOutputStream( 1024 * 2 );
115 
116             LOGGER.debug( "Writing tracking file {}", file );
117             props.store( stream, "NOTE: This is a Maven Resolver internal implementation file"
118                 + ", its format can be changed without prior notice." );
119 
120             raf.seek( 0 );
121             raf.write( stream.toByteArray() );
122             raf.setLength( raf.getFilePointer() );
123         }
124         catch ( IOException e )
125         {
126             LOGGER.warn( "Failed to write tracking file {}", file, e );
127         }
128         finally
129         {
130             close( raf, file );
131         }
132 
133         return props;
134     }
135 
136     private void close( Closeable closeable, File file )
137     {
138         if ( closeable != null )
139         {
140             try
141             {
142                 closeable.close();
143             }
144             catch ( IOException e )
145             {
146                 LOGGER.warn( "Error closing tracking file {}", file, e );
147             }
148         }
149     }
150 
151 }