]> source.dussan.org Git - archiva.git/blob
00b6cc16e4858662b1a0ff0ce9f3b98ab556522f
[archiva.git] /
1 package org.apache.maven.repository.indexing;
2
3 /*
4  * Copyright 2001-2005 The Apache Software Foundation.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 import java.io.File;
21 import java.io.FileInputStream;
22 import java.io.FileNotFoundException;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.security.MessageDigest;
26 import java.security.NoSuchAlgorithmException;
27 import java.util.Collection;
28 import java.util.Enumeration;
29 import java.util.zip.ZipEntry;
30 import java.util.zip.ZipException;
31 import java.util.zip.ZipFile;
32
33 import org.apache.lucene.document.Document;
34 import org.apache.lucene.document.Field;
35
36 import org.apache.maven.artifact.Artifact;
37 import org.apache.maven.artifact.repository.ArtifactRepository;
38
39 /**
40  * Class used to index Artifact objects in a specified repository
41  *
42  * @author Edwin Punzalan
43  */
44 public class ArtifactRepositoryIndexer
45     extends AbstractRepositoryIndexer
46 {
47     private static final String NAME = "name";
48     private static final String GROUPID = "groupId";
49     private static final String ARTIFACTID = "artifactId";
50     private static final String VERSION = "version";
51     private static final String SHA1 = "sha1";
52     private static final String MD5 = "md5";
53     private static final String CLASSES = "classes";
54     private static final String PACKAGES = "packages";
55     private static final String FILES = "files";
56     
57     private static final String[] FIELDS = { NAME, GROUPID, ARTIFACTID, VERSION, SHA1, MD5,
58                                                CLASSES, PACKAGES, FILES };
59     
60     private ArtifactRepository repository;
61
62     private StringBuffer classes;
63     private StringBuffer packages;
64     private StringBuffer files;
65     
66     /**
67      * Constructor
68      * @todo change repository to layout ???
69      *
70      * @param repository the repository where the indexed artifacts are located.  This is necessary only to distinguish
71      *                   between default and legacy directory structure of the artifact location.
72      * @param path the directory where the index is located or will be created.
73      */
74     public ArtifactRepositoryIndexer( ArtifactRepository repository, String path )
75         throws RepositoryIndexerException
76     {
77         this.repository = repository;
78         indexPath = path;
79         validateIndex();
80     }
81     
82     /**
83      * method for collecting the available index fields usable for searching
84      *
85      * @return index field names
86      */
87     public String[] getIndexFields()
88     {
89         return FIELDS;
90     }
91
92     /**
93      * generic method for indexing
94      *
95      * @param obj the object to be indexed by this indexer
96      */
97     public void addObjectIndex(Object obj) 
98         throws RepositoryIndexerException
99     {
100         if ( obj instanceof Artifact )
101         {
102             addArtifactIndex( (Artifact) obj );
103         }
104         else
105         {
106             throw new RepositoryIndexerException( "This instance of indexer cannot index instances of " + 
107                     obj.getClass().getName() );
108         }
109     }
110
111     /**
112      * method to index a given artifact
113      *
114      * @param artifact the Artifact object to be indexed
115      */
116     public void addArtifactIndex( Artifact artifact )
117         throws RepositoryIndexerException
118     {
119         if ( !isOpen() )
120         {
121             throw new RepositoryIndexerException( "Unable to add artifact index on a closed index" );
122         }
123
124         try
125         {
126             getIndexWriter();
127
128             processArtifactContents( artifact.getFile() );
129             
130             //@todo should some of these fields be Keyword instead of Text ?
131             Document doc = new Document();
132             doc.add( Field.Text( NAME, repository.pathOf( artifact ) ) );
133             doc.add( Field.Text( GROUPID, artifact.getGroupId() ) );
134             doc.add( Field.Text( ARTIFACTID, artifact.getArtifactId() ) );
135             doc.add( Field.Text( VERSION, artifact.getVersion() ) );
136             doc.add( Field.Text( SHA1, getSha1( artifact ) ) );
137             doc.add( Field.Text( MD5, getMd5( artifact ) ) );
138             doc.add( Field.Text( CLASSES, classes.toString() ) );
139             doc.add( Field.Text( PACKAGES, packages.toString() ) );
140             doc.add( Field.Text( FILES, files.toString() ) );
141             indexWriter.addDocument( doc );
142
143             removeBuffers();
144         }
145         catch( Exception e )
146         {
147             throw new RepositoryIndexerException( e );
148         }
149     }
150
151     private String getSha1( Artifact artifact )
152         throws FileNotFoundException, IOException, NoSuchAlgorithmException
153     {
154         FileInputStream fIn = new FileInputStream( artifact.getFile() );
155         return new String( getChecksum( fIn, "SHA-1" ) );
156     }
157     
158     private String getMd5( Artifact artifact )
159         throws FileNotFoundException, IOException, NoSuchAlgorithmException
160     {
161         FileInputStream fIn = new FileInputStream( artifact.getFile() );
162         return new String( getChecksum( fIn, "MD5" ) );
163     }
164
165     private byte[] getChecksum( InputStream inStream, String algorithm )
166         throws IOException, NoSuchAlgorithmException
167     {
168         byte[] buffer = new byte[ 256 ];
169         MessageDigest complete = MessageDigest.getInstance( algorithm );
170         int numRead;
171         do
172         {
173             numRead = inStream.read( buffer );
174             if ( numRead > 0 )
175             {
176                 complete.update( buffer, 0, numRead );
177             }
178         }
179         while ( numRead != -1 );
180         inStream.close();
181
182         return complete.digest();
183     }
184
185     private void initBuffers()
186     {
187         classes = new StringBuffer();
188         packages = new StringBuffer();
189         files = new StringBuffer();
190     }
191
192     private void removeBuffers()
193     {
194         classes = null;
195         packages = null;
196         files = null;
197     }
198
199     private void processArtifactContents( File artifact )
200         throws IOException, ZipException
201     {
202         initBuffers();
203         ZipFile jar = new ZipFile( artifact );
204         for ( Enumeration entries = jar.entries(); entries.hasMoreElements(); )
205         {
206             ZipEntry entry = (ZipEntry) entries.nextElement();
207             if ( addIfClassEntry( entry ) )
208             {
209                 addClassPackage( entry.getName() );
210             }
211             addFile( entry );
212         }
213     }
214
215     private boolean addIfClassEntry( ZipEntry entry )
216     {
217         boolean isAdded = false;
218         
219         String name = entry.getName();
220         if( name.endsWith( ".class") )
221         {
222             // TODO verify if class is public or protected
223             if( name.lastIndexOf( "$" ) == -1)
224             {
225                 int idx = name.lastIndexOf( '/' );
226                 if ( idx < 0 ) idx = 0;
227                 String classname = name.substring( idx, name.length() - 6 );
228                 classes.append( classname ).append( "\n" );
229                 isAdded = true;
230             }
231         }
232         
233         return isAdded;
234     }
235
236     private boolean addClassPackage( String name )
237     {
238         boolean isAdded = false;
239
240         int idx = name.lastIndexOf( '/' );
241         if ( idx > 0 )
242         {
243             String packageName = name.substring( 0, idx ).replace( '/', '.' ) + "\n";
244             if ( packages.indexOf( packageName ) < 0 )
245             {
246                 packages.append( packageName ).append( "\n" );
247             }
248             isAdded = true;
249         }
250         
251         return isAdded;
252     }
253
254     private boolean addFile( ZipEntry entry )
255     {
256         boolean isAdded = false;
257
258         String name = entry.getName();
259         int idx = name.lastIndexOf( '/' );
260         if ( idx >= 0 )
261         {
262             name = name.substring( idx + 1 );
263         }
264
265         if ( files.indexOf( name + "\n" ) < 0 )
266         {
267             files.append( name ).append( "\n" );
268             isAdded = true;
269         }
270         
271         return isAdded;
272     }
273 }