1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 package com.sun.star.help;
29 
30 import com.sun.star.lib.uno.helper.Factory;
31 import com.sun.star.lang.XMultiComponentFactory;
32 import com.sun.star.lang.XSingleComponentFactory;
33 import com.sun.star.lib.uno.helper.WeakBase;
34 import com.sun.star.uno.XComponentContext;
35 import com.sun.star.registry.XRegistryKey;
36 import com.sun.star.lang.XServiceInfo;
37 import com.sun.star.uno.Type;
38 import com.sun.star.uno.Any;
39 import com.sun.star.uno.AnyConverter;
40 
41 import org.apache.lucene.analysis.Analyzer;
42 import org.apache.lucene.analysis.standard.StandardAnalyzer;
43 import org.apache.lucene.analysis.cjk.CJKAnalyzer;
44 import org.apache.lucene.document.Document;
45 import org.apache.lucene.index.IndexReader;
46 import org.apache.lucene.index.Term;
47 import org.apache.lucene.search.Hits;
48 import org.apache.lucene.search.IndexSearcher;
49 import org.apache.lucene.search.Query;
50 import org.apache.lucene.search.Searcher;
51 import org.apache.lucene.search.TermQuery;
52 import org.apache.lucene.search.WildcardQuery;
53 
54 import com.sun.star.script.XInvocation;
55 import com.sun.star.beans.XIntrospectionAccess;
56 
57 /** This class capsulates the class, that implements the minimal component and a
58  * factory for creating the service (<CODE>__getComponentFactory</CODE>).
59  */
60 public class HelpSearch
61 {
62     /** This class implements the component. At least the interfaces XServiceInfo,
63      * XTypeProvider, and XInitialization should be provided by the service.
64      */
65     public static class _HelpSearch extends WeakBase
66         implements XServiceInfo, XInvocation
67 	{
68         /** The service name, that must be used to get an instance of this service.
69          */
70 		static private final String __serviceName =
71 	        "com.sun.star.help.HelpSearch";
72 		static private final String aSearchMethodName = "search";
73 
74         /** The initial component contextr, that gives access to
75          * the service manager, supported singletons, ...
76          * It's often later used
77          */
78         private XComponentContext m_cmpCtx;
79 
80         /** The service manager, that gives access to all registered services.
81          * It's often later used
82          */
83         private XMultiComponentFactory m_xMCF;
84 
85         /** The constructor of the inner class has a XMultiServiceFactory parameter.
86          * @param xmultiservicefactoryInitialization A special service factory
87          * could be introduced while initializing.
88          */
89         public _HelpSearch(XComponentContext xCompContext)
90 		{
91             try {
92                 m_cmpCtx = xCompContext;
93                 m_xMCF = m_cmpCtx.getServiceManager();
94             }
95             catch( Exception e ) {
96                 e.printStackTrace();
97             }
98         }
99 
100         /** This method returns an array of all supported service names.
101          * @return Array of supported service names.
102          */
103         public String[] getSupportedServiceNames()
104 		{
105             return getServiceNames();
106         }
107 
108         /** This method is a simple helper function to used in the
109          * static component initialisation functions as well as in
110          * getSupportedServiceNames.
111          */
112         public static String[] getServiceNames()
113 		{
114             String[] sSupportedServiceNames = { __serviceName };
115             return sSupportedServiceNames;
116         }
117 
118         /** This method returns true, if the given service will be
119          * supported by the component.
120          * @param sServiceName Service name.
121          * @return True, if the given service name will be supported.
122          */
123         public boolean supportsService( String sServiceName )
124 		{
125             return sServiceName.equals( __serviceName );
126         }
127 
128         /** Return the class name of the component.
129          * @return Class name of the component.
130          */
131         public String getImplementationName()
132 		{
133             return  _HelpSearch.class.getName();
134         }
135 
136 		//===================================================
137 		// XInvocation
138 		public XIntrospectionAccess getIntrospection()
139 		{
140             return  null;
141         }
142 
143 		public Object invoke( String aFunctionName, java.lang.Object[] aParams,
144 			short[][] aOutParamIndex, java.lang.Object[][] aOutParam )
145 				throws	com.sun.star.lang.IllegalArgumentException,
146 						com.sun.star.script.CannotConvertException,
147 						com.sun.star.reflection.InvocationTargetException
148 		{
149 			String[] aRet = null;
150 			if( !aFunctionName.equals( aSearchMethodName ) )
151 			    throw new com.sun.star.lang.IllegalArgumentException();
152 
153 			Object[] aScoreOutArray = new Object[1];
154 			aScoreOutArray[0] = null;
155 			try
156 			{
157 			    aRet =  doQuery( aParams, aScoreOutArray );
158 			}
159 			catch( Exception e )
160 			{
161 			    aRet = null;
162 			}
163 
164 			Object aScoreArray = aScoreOutArray[0];
165 			if( aScoreArray == null )
166 			{
167 				aOutParamIndex[0] = new short[0];
168 				aOutParam[0] = new Object[0];
169 			}
170 			else
171 			{
172 				short nInParamCount = (short)aParams.length;
173 				aOutParamIndex[0] = new short[1];
174 				aOutParamIndex[0][0] = nInParamCount;
175 				aOutParam[0] = new Object[1];
176 				aOutParam[0][0] = aScoreArray;
177 			}
178 
179 			Any aRetAny = new Any( new Type( String[].class ), aRet );
180 			return aRetAny;
181 		}
182 
183 		public void setValue( String aPropertyName, java.lang.Object aValue )
184 			throws	com.sun.star.beans.UnknownPropertyException,
185 					com.sun.star.script.CannotConvertException,
186 					com.sun.star.reflection.InvocationTargetException {
187 			throw new com.sun.star.beans.UnknownPropertyException();
188 		}
189 
190 		public Object getValue( String aPropertyName )
191 			throws com.sun.star.beans.UnknownPropertyException {
192 			throw new com.sun.star.beans.UnknownPropertyException();
193 		}
194 
195 		public boolean hasMethod( String aMethodName ) {
196 			boolean bRet = (aMethodName.equals( aSearchMethodName ) );
197 			return bRet;
198 		}
199 		public boolean hasProperty( String aName ) {
200 			return false;
201 		}
202 
203 		// Command line interface for testing
204 		private static String[] doQuery( Object[] args, Object[] aScoreOutArray ) throws Exception
205 		{
206  			String aLanguageStr = "";
207  			String aIndexStr = "";
208 			String aQueryStr = "";
209 			boolean bCaptionOnly = false;
210 
211 			int nParamCount = args.length;
212 			String aStrs[] = new String[nParamCount];
213 			for( int i = 0 ; i < nParamCount ; i++ )
214 			{
215 				try
216 				{
217 					aStrs[i] = AnyConverter.toString( args[i] );
218 				}
219 				catch( IllegalArgumentException e )
220 				{
221 					aStrs[i] = "";
222 				}
223 			}
224 
225 			// TODO: Error handling
226 			for( int i = 0 ; i < nParamCount ; i++ )
227 			{
228                 if ("-lang".equals(aStrs[i]) )
229 				{
230                     aLanguageStr = aStrs[i + 1];
231                     i++;
232 				}
233 				else if( "-index".equals(aStrs[i]) )
234 				{
235 					aIndexStr = aStrs[i+1];
236 					i++;
237 				}
238 				else if( "-query".equals(aStrs[i]) )
239 				{
240 					aQueryStr = aStrs[i+1];
241 					i++;
242 				}
243 				else if( "-caption".equals(aStrs[i]) )
244 				{
245 					bCaptionOnly = true;
246 				}
247 			}
248 			String[] aDocs = queryImpl( aLanguageStr, aIndexStr, aQueryStr, bCaptionOnly, aScoreOutArray );
249 
250 			return aDocs;
251         }
252 
253 		private static String[] queryImpl( String aLanguageStr, String aIndexStr, String aQueryStr,
254 			boolean bCaptionOnly, Object[] aScoreOutArray ) throws Exception
255 		{
256 			IndexReader reader = IndexReader.open( aIndexStr );
257 			Searcher searcher = new IndexSearcher( reader );
258             Analyzer analyzer = aLanguageStr.equals("ja") ? (Analyzer)new CJKAnalyzer() : (Analyzer)new StandardAnalyzer();
259 
260 			String aField;
261 			if( bCaptionOnly )
262 				aField = "caption";
263 			else
264 				aField = "content";
265 
266 			Query aQuery;
267 			if( aQueryStr.endsWith( "*" ) )
268 				aQuery = new WildcardQuery( new Term( aField, aQueryStr ) );
269 			else
270 				aQuery = new TermQuery( new Term( aField, aQueryStr ) );
271 
272 			// Perform search
273 			Hits aHits = searcher.search( aQuery );
274 			int nHitCount = aHits.length();
275 
276 			String aDocs[] = new String[nHitCount];
277 			float aScores[] = null;
278 			aScores = new float[nHitCount];
279 			for( int iHit = 0 ; iHit < nHitCount ; iHit++ )
280 			{
281 				Document aDoc = aHits.doc( iHit );
282 				String aPath = aDoc.get( "path" );
283 				aDocs[iHit] = ( aPath != null ) ? aPath : "";
284 				aScores[iHit] = aHits.score( iHit );
285 			}
286 			aScoreOutArray[0] = aScores;
287 
288 			reader.close();
289 
290 			return aDocs;
291 		}
292     }
293 
294     /**
295      * Gives a factory for creating the service.
296      * This method is called by the <code>JavaLoader</code>
297      * <p>
298      * @return  returns a <code>XSingleComponentFactory</code> for creating
299      *          the component
300      * @param   sImplName the name of the implementation for which a
301      *          service is desired
302      * @see     com.sun.star.comp.loader.JavaLoader
303      */
304     public static XSingleComponentFactory __getComponentFactory(String sImplName)
305     {
306         XSingleComponentFactory xFactory = null;
307 
308         if ( sImplName.equals( _HelpSearch.class.getName() ) )
309             xFactory = Factory.createComponentFactory(_HelpSearch.class,
310                                              _HelpSearch.getServiceNames());
311 
312         return xFactory;
313     }
314 
315         /** This method is a member of the interface for initializing an object
316          * directly after its creation.
317          * @param object This array of arbitrary objects will be passed to the
318          * component after its creation.
319          * @throws Exception Every exception will not be handled, but will be
320          * passed to the caller.
321          */
322         public void initialize( Object[] object )
323             throws com.sun.star.uno.Exception {
324             /* The component describes what arguments its expected and in which
325              * order!At this point you can read the objects and can intialize
326              * your component using these objects.
327              */
328         }
329 }
330