File: SourcePathCache.java

package info (click to toggle)
emma-coverage 2.0.5312%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd, stretch, wheezy
  • size: 2,000 kB
  • ctags: 3,667
  • sloc: java: 23,109; xml: 414; makefile: 22
file content (228 lines) | stat: -rw-r--r-- 7,732 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
/* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
 * 
 * This program and the accompanying materials are made available under
 * the terms of the Common Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/cpl-v10.html
 * 
 * $Id: SourcePathCache.java,v 1.1.1.1 2004/05/09 16:57:39 vlad_r Exp $
 */
package com.vladium.emma.report;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.vladium.util.asserts.$assert;

// ----------------------------------------------------------------------------
/**
 * @author Vlad Roubtsov, (C) 2003
 */
public
final class SourcePathCache
{
    // public: ................................................................
    
    // TODO: use soft cache for m_packageCache?
    
    /**
     * @param sourcepath [can be empty]
     */
    public SourcePathCache (final String [] sourcepath, final boolean removeNonExistent)
    {
        if (sourcepath == null) throw new IllegalArgumentException ("null input: sourcepath");
        
        final List _sourcepath = new ArrayList (sourcepath.length);
        for (int i = 0; i < sourcepath.length; ++ i)
        {
            final File dir = new File (sourcepath [i]);
            
            if (! removeNonExistent || (dir.isDirectory () && dir.exists ()))
                _sourcepath.add (dir);
        }
        
        m_sourcepath = new File [_sourcepath.size ()];
        _sourcepath.toArray (m_sourcepath);
        
        m_packageCache = new HashMap ();
    }
    
    /**
     * @param sourcepath [can be empty]
     */
    public SourcePathCache (final File [] sourcepath, final boolean removeNonExistent)
    {
        if (sourcepath == null) throw new IllegalArgumentException ("null input: sourcepath");
        
        final List _sourcepath = new ArrayList (sourcepath.length);
        for (int i = 0; i < sourcepath.length; ++ i)
        {
            final File dir = sourcepath [i];
            
            if (! removeNonExistent || (dir.isDirectory () && dir.exists ()))
                _sourcepath.add (dir);
        }
        
        m_sourcepath = new File [_sourcepath.size ()];
        _sourcepath.toArray (m_sourcepath);
        
        m_packageCache = new HashMap ();
    }
    
    /**
     * @return absolute pathname [null if 'name' was not found in cache]
     */
    public synchronized File find (final String packageVMName, final String name)
    {
        if (packageVMName == null) throw new IllegalArgumentException ("null input: packageVMName");
        if (name == null) throw new IllegalArgumentException ("null input: name");
        
        if (m_sourcepath.length == 0) return null;
        
        CacheEntry entry = (CacheEntry) m_packageCache.get (packageVMName);
        
        if (entry == null)
        {
            entry = new CacheEntry (m_sourcepath.length);
            m_packageCache.put (packageVMName, entry);
        }
        
        final Set [] listings = entry.m_listings;
        for (int p = 0; p < listings.length; ++ p)
        {
            Set listing = listings [p];
            if (listing == null)
            {
                listing = faultListing (m_sourcepath [p], packageVMName);
                listings [p] = listing;
            }
            
            // TODO: this is case-sensitive at this point
            if (listing.contains (name))
            {
                final File relativeFile = new File (packageVMName.replace ('/', File.separatorChar), name);
                
                return new File (m_sourcepath [p], relativeFile.getPath ()).getAbsoluteFile ();
            }
        }
        
        return null;
    }
    
    // protected: .............................................................

    // package: ...............................................................
    
    // private: ...............................................................
    
    
    private static final class CacheEntry
    {
        CacheEntry (final int size)
        {
            m_listings = new Set [size];
        }
        
        
        final Set /* String */ [] m_listings;
        
    } // end of nested class
    
    
    // NOTE: because java.io.* implements file filtering in bytecode
    // there is no real perf advantage in using a filter here (I might
    // as well do list() and filter the result myself 
    
    private static final class FileExtensionFilter implements FileFilter
    {
        public boolean accept (final File file)
        {
            if ($assert.ENABLED) $assert.ASSERT (file != null, "file = null");
            
            if (file.isDirectory ()) return false; // filter out directories

            final String name = file.getName ();
            final int lastDot = name.lastIndexOf ('.');
            if (lastDot <= 0) return false;
            
            // [assertion: lastDot > 0]
            
            // note: match is case sensitive
            return m_extension.equals (name.substring (lastDot));
        }
        
        public String toString ()
        {
            return super.toString () + ", extension = [" + m_extension + "]";
        }
        
        FileExtensionFilter (final String extension)
        {
            if (extension == null)
                throw new IllegalArgumentException ("null input: extension");
            
            // ensure starting '.':
            final String canonical = canonicalizeExtension (extension); 
            
            if (extension.length () <= 1)
                throw new IllegalArgumentException ("empty input: extension");
            
            m_extension = canonical;
        }
        
        private static String canonicalizeExtension (final String extension)
        {
            if (extension.charAt (0) != '.')
                return ".".concat (extension);
            else
                return extension;
        }
        
        
        private final String m_extension;
        
    } // end of nested class
    
    
    private Set /* String */ faultListing (final File dir, final String packageVMName)
    {
        if ($assert.ENABLED) $assert.ASSERT (dir != null, "dir = null");
        if ($assert.ENABLED) $assert.ASSERT (packageVMName != null, "packageVMName = null");
        
        final File packageFile = new File (dir, packageVMName.replace ('/', File.separatorChar));
        
        final File [] listing = packageFile.listFiles (FILE_EXTENSION_FILTER);
        
        if ((listing == null) || (listing.length == 0))
            return Collections.EMPTY_SET;
        else
        {
            final Set result = new HashSet (listing.length);
            for (int f = 0; f < listing.length; ++ f)
            {
                result.add (listing [f].getName ());
            }
            
            return result;
        }
    }
    

    private final File [] m_sourcepath; // never null
    private final Map /* packageVMName:String->CacheEntry */ m_packageCache; // never null
    
    private static final FileExtensionFilter FILE_EXTENSION_FILTER; // set in <clinit>
    
    static
    {
        FILE_EXTENSION_FILTER = new FileExtensionFilter (".java");
    }

} // end of class
// ----------------------------------------------------------------------------