1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 package com.sun.star.help;
25 
26 import java.io.FileInputStream;
27 import java.io.FileOutputStream;
28 import java.util.Arrays;
29 import java.util.HashSet;
30 import java.util.List;
31 import java.util.zip.ZipEntry;
32 import java.util.zip.ZipOutputStream;
33 import java.util.zip.CRC32;
34 import org.apache.lucene.analysis.standard.StandardAnalyzer;
35 import org.apache.lucene.analysis.cjk.CJKAnalyzer;
36 import org.apache.lucene.analysis.Analyzer;
37 import org.apache.lucene.index.IndexWriter;
38 import org.apache.lucene.util.Version;
39 import org.apache.lucene.store.NIOFSDirectory;
40 
41 import java.io.File;
42 import java.io.FileNotFoundException;
43 import java.io.IOException;
44 import java.util.Date;
45 
46 public class HelpIndexerTool
47 {
48     public HelpIndexerTool()
49 	{
50     }
51 
52 
53     /**
54      * @param args the command line arguments
55      */
56     public static void main( String[] args )
57 	{
58 		boolean bExtensionMode = false;
59 		mainImpl( args, bExtensionMode );
60 	}
61 
62     public static void mainImpl( String[] args, boolean bExtensionMode )
63 	{
64         String aDirToZipStr = "";
65         String aSrcDirStr = "";
66         String aLanguageStr = "";
67         String aModule = "";
68         String aTargetZipFileStr = "";
69         String aCfsName = "";
70         String aSegmentName = "";
71 
72         // Scan arguments
73         //If this tool is invoked in the build process for extensions help,
74         //then -extension must be set.
75         boolean bExtension = false;
76         boolean bLang = false;
77         boolean bMod = false;
78         boolean bZipDir = false;
79         boolean bSrcDir = false;
80         boolean bOutput = false;
81         boolean bCfsName = false;
82         boolean bSegmentName = false;
83 
84         int nArgCount = args.length;
85         for( int i = 0 ; i < nArgCount ; i++ )
86 		{
87             if( "-extension".equals(args[i]) )
88 			{
89                 bExtension = true;
90             }
91             else if( "-lang".equals(args[i]) )
92 			{
93                 if( i + 1 < nArgCount )
94 				{
95                     aLanguageStr = args[i + 1];
96                     bLang = true;
97                 }
98                 i++;
99             }
100 			else if( "-mod".equals(args[i]) )
101 			{
102                 if( i + 1 < nArgCount )
103 				{
104                     aModule = args[i + 1];
105                     bMod = true;
106                 }
107                 i++;
108             }
109 			else if( "-zipdir".equals(args[i]) )
110 			{
111                 if( i + 1 < nArgCount )
112 				{
113                     aDirToZipStr = args[i + 1];
114                     bZipDir = true;
115                 }
116                 i++;
117             }
118 			else if( "-srcdir".equals(args[i]) )
119 			{
120                 if( i + 1 < nArgCount )
121 				{
122                     aSrcDirStr = args[i + 1];
123                     bSrcDir = true;
124                 }
125                 i++;
126             }
127 			else if( "-o".equals(args[i]) )
128 			{
129                 if( i + 1 < nArgCount )
130 				{
131                     aTargetZipFileStr = args[i + 1];
132                     bOutput = true;
133                 }
134                 i++;
135             }
136 			else if( "-checkcfsandsegname".equals(args[i]) )
137 			{
138                 if( i + 1 < nArgCount )
139 				{
140                     aCfsName = args[i + 1] + ".cfs";
141                     bCfsName = true;
142                 }
143                 i++;
144                 if( i + 1 < nArgCount )
145 				{
146                     aSegmentName = "segments" + args[i + 1];
147                     bSegmentName = true;
148                 }
149                 i++;
150                 if (!(bCfsName && bSegmentName))
151                 {
152                     System.out.println("Usage: HelpIndexer -checkcfsandsegname _0 _3 (2 arguments needed)");
153                     System.exit( -1 );
154                 }
155             }
156         }
157 
158         if( !bLang || !bMod || !bZipDir || (!bOutput && !bExtensionMode && !bExtension) )
159 		{
160 			if( bExtensionMode )
161 				return;
162 
163 			System.out.println("Usage: HelpIndexer -lang ISOLangCode -mod HelpModule -zipdir TempZipDir -o OutputZipFile");
164             System.out.println("Usage: HelpIndexer -extension -lang ISOLangCode -mod HelpModule -zipdir PathToLangDir");
165 			System.exit( -1 );
166         }
167 
168         String aIndexDirName = aModule + ".idxl";
169         File aIndexDir = new File( aDirToZipStr + File.separator + aIndexDirName );
170 		if( !bSrcDir )
171 			aSrcDirStr = aDirToZipStr;
172         File aCaptionFilesDir = new File( aSrcDirStr + File.separator + "caption" );
173         File aContentFilesDir = new File( aSrcDirStr + File.separator + "content" );
174 
175         try
176 		{
177             Date start = new Date();
178 	    Analyzer analyzer = aLanguageStr.equals("ja") ? (Analyzer)new CJKAnalyzer(Version.LUCENE_29) : (Analyzer)new StandardAnalyzer(Version.LUCENE_29);
179 	    IndexWriter writer = new IndexWriter( NIOFSDirectory.open(aIndexDir), analyzer, true, IndexWriter.MaxFieldLength.LIMITED );
180 			if( !bExtensionMode )
181 	            System.out.println( "Lucene: Indexing to directory '" + aIndexDir + "'..." );
182             int nRet = indexDocs( writer, aModule, bExtensionMode, aCaptionFilesDir, aContentFilesDir );
183             if( nRet != -1 )
184 			{
185 				if( !bExtensionMode )
186 				{
187 					System.out.println();
188 					System.out.println( "Optimizing ..." );
189 				}
190                 writer.optimize();
191             }
192             writer.close();
193 
194 			boolean bCfsFileOk = true;
195 			boolean bSegmentFileOk = true;
196 			if( bCfsName && bSegmentName && !bExtensionMode && nRet != -1 )
197 			{
198 				String aCompleteCfsFileName = aDirToZipStr + File.separator + aIndexDirName + File.separator + aCfsName;
199 				String aCompleteSegmentFileName = aDirToZipStr + File.separator + aIndexDirName + File.separator + aSegmentName;
200 				File aCfsFile = new File( aCompleteCfsFileName );
201 				File aSegmentFile = new File( aCompleteSegmentFileName );
202 				bCfsFileOk = aCfsFile.exists();
203 				bSegmentFileOk = aSegmentFile.exists();
204 				System.out.println( "Checking cfs file " + aCfsName+ ": " + (bCfsFileOk ? "Found" : "Not found") );
205 				System.out.println( "Checking segment file " + aSegmentName+ ": " + (bSegmentFileOk ? "Found" : "Not found") );
206 			}
207 
208 			if( bExtensionMode || bExtension)
209 			{
210 				if( !bSrcDir )
211 				{
212 					deleteRecursively( aCaptionFilesDir );
213 					deleteRecursively( aContentFilesDir );
214 				}
215 			}
216 			else
217 			{
218 				if( nRet == -1 )
219 					deleteRecursively( aIndexDir );
220 
221 				if( bCfsFileOk && bSegmentFileOk )
222 					System.out.println( "Zipping ..." );
223 				File aDirToZipFile = new File( aDirToZipStr );
224 				createZipFile( aDirToZipFile, aTargetZipFileStr );
225 				deleteRecursively( aDirToZipFile );
226 			}
227 
228 			if( !bCfsFileOk )
229 			{
230 				System.out.println( "cfs file check failed, terminating..." );
231 				System.exit( -1 );
232 			}
233 
234 			if( !bSegmentFileOk )
235 			{
236 				System.out.println( "segment file check failed, terminating..." );
237 				System.exit( -1 );
238 			}
239 
240 			Date end = new Date();
241 			if( !bExtensionMode )
242 				System.out.println(end.getTime() - start.getTime() + " total milliseconds");
243         }
244 		catch (IOException e)
245 		{
246 			if( bExtensionMode )
247 				return;
248 
249 			System.out.println(" caught a " + e.getClass() +
250 				"\n with message: " + e.getMessage());
251 			System.exit( -1 );
252         }
253     }
254 
255 	private static int indexDocs(IndexWriter writer, String aModule, boolean bExtensionMode,
256 		File aCaptionFilesDir, File aContentFilesDir) throws IOException
257 	{
258         if( !aCaptionFilesDir.canRead() || !aCaptionFilesDir.isDirectory() )
259 		{
260 			if( !bExtensionMode )
261 	            System.out.println( "Not found: " + aCaptionFilesDir );
262             return -1;
263         }
264         if( !aContentFilesDir.canRead() || !aContentFilesDir.isDirectory() )
265 		{
266 			if( !bExtensionMode )
267 	            System.out.println( "Not found: " + aContentFilesDir );
268             return -1;
269         }
270 
271         String[] aCaptionFiles = aCaptionFilesDir.list();
272         List aCaptionFilesList = Arrays.asList( aCaptionFiles );
273         HashSet aCaptionFilesHashSet = new HashSet( aCaptionFilesList );
274 
275         String[] aContentFiles = aContentFilesDir.list();
276         List aContentFilesList = Arrays.asList( aContentFiles );
277         HashSet aContentFilesHashSet = new HashSet( aContentFilesList );
278 
279         // Loop over caption files and find corresponding content file
280 		if( !bExtensionMode )
281 	        System.out.println( "Indexing, adding files" );
282         int nCaptionFilesLen = aCaptionFiles.length;
283         for( int i = 0 ; i < nCaptionFilesLen ; i++ )
284 		{
285             String aCaptionFileStr = aCaptionFiles[i];
286             File aCaptionFile = new File( aCaptionFilesDir, aCaptionFileStr );
287             File aContentFile = null;
288             if( aContentFilesHashSet.contains( aCaptionFileStr ) )
289                 aContentFile = new File( aContentFilesDir, aCaptionFileStr );
290 
291 			if( !bExtensionMode )
292 				System.out.print( "." );
293             writer.addDocument( HelpFileDocument.Document( aModule, aCaptionFile, aContentFile ) );
294         }
295 
296         // Loop over content files to find remaining files not mapped to caption files
297         int nContentFilesLen = aContentFiles.length;
298         for( int i = 0 ; i < nContentFilesLen ; i++ )
299 		{
300             String aContentFileStr = aContentFiles[i];
301             if( !aCaptionFilesHashSet.contains( aContentFileStr ) )
302 			{
303                 // Not already handled in caption files loop
304                 File aCaptionFile = null;
305                 File aContentFile = new File( aContentFilesDir, aContentFileStr );
306 				if( !bExtensionMode )
307 					System.out.print( "." );
308                 writer.addDocument( HelpFileDocument.Document( aModule, aCaptionFile, aContentFile ) );
309             }
310         }
311         return 0;
312     }
313 
314     public static void createZipFile( File aDirToZip, String aTargetZipFileStr )
315             throws FileNotFoundException, IOException
316 	{
317         FileOutputStream fos = new FileOutputStream( aTargetZipFileStr );
318         ZipOutputStream zos = new ZipOutputStream( fos );
319 
320         File[] aChildrenFiles = aDirToZip.listFiles();
321         int nFileCount = aChildrenFiles.length;
322         for( int i = 0 ; i < nFileCount ; i++ )
323             addToZipRecursively( zos, aChildrenFiles[i], null );
324 
325         zos.close();
326     }
327 
328     public static void addToZipRecursively( ZipOutputStream zos, File aFile, String aBasePath )
329             throws FileNotFoundException, IOException
330 	{
331         if( aFile.isDirectory() )
332 		{
333             String aDirName = aFile.getName();
334             if( aDirName.equalsIgnoreCase( "caption" ) || aDirName.equalsIgnoreCase( "content" ) )
335                 return;
336 
337             File[] aChildrenFiles = aFile.listFiles();
338             String aNewBasePath = "";
339             if( aBasePath != null )
340                 aNewBasePath += aBasePath + File.separator;
341             aNewBasePath += aDirName;
342 
343             int nFileCount = aChildrenFiles.length;
344             for( int i = 0 ; i < nFileCount ; i++ )
345                 addToZipRecursively( zos, aChildrenFiles[i], aNewBasePath );
346 
347             return;
348         }
349 
350         // No directory
351         // read contents of file we are going to put in the zip
352         int fileLength = (int) aFile.length();
353         FileInputStream fis = new FileInputStream( aFile );
354         byte[] wholeFile = new byte[fileLength];
355         int bytesRead = fis.read( wholeFile, 0, fileLength );
356         fis.close();
357 
358         String aFileName = aFile.getName();
359         String aEntryName = "";
360         if( aBasePath != null )
361             aEntryName += aBasePath + "/";
362         aEntryName += aFileName;
363         ZipEntry aZipEntry = new ZipEntry( aEntryName );
364         aZipEntry.setTime( aFile.lastModified() );
365         aZipEntry.setSize( fileLength );
366 
367         int nMethod = ( aFileName.toLowerCase().endsWith( ".jar" ) )
368                 ? ZipEntry.STORED : ZipEntry.DEFLATED;
369         aZipEntry.setMethod( nMethod );
370 
371         CRC32 tempCRC = new CRC32();
372         tempCRC.update( wholeFile, 0, wholeFile.length );
373         aZipEntry.setCrc( tempCRC.getValue() );
374 
375         // write the contents into the zip element
376         zos.putNextEntry( aZipEntry );
377         zos.write( wholeFile, 0, fileLength );
378         zos.closeEntry();
379     }
380 
381     static public boolean deleteRecursively( File aFile )
382 	{
383         if( aFile.isDirectory() )
384 		{
385             File[] aChildrenFiles = aFile.listFiles();
386             int nFileCount = aChildrenFiles.length;
387             for( int i = 0 ; i < nFileCount ; i++ )
388 			{
389                 File aChildrenFile = aChildrenFiles[i];
390                 boolean bSuccess = deleteRecursively( aChildrenFile );
391                 if( !bSuccess )
392                     return false;
393             }
394         }
395 
396         return aFile.delete();
397     }
398 }
399 
400