View Javadoc

1   /*
2    * MMBase Lucene module
3    *
4    * The contents of this file are subject to the Mozilla Public License
5    * Version 1.0 (the "License"); you may not use this file except in
6    * compliance with the License. You may obtain a copy of the License at
7    * http://www.mozilla.org/MPL/
8    *
9    * Software distributed under the License is distributed on an "AS IS"
10   * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
11   * License for the specific language governing rights and limitations
12   * under the License.
13   */
14  package net.sf.mmapps.modules.lucenesearch;
15  
16  import java.io.File;
17  import java.util.Calendar;
18  import java.util.Date;
19  import java.util.Timer;
20  import java.util.TimerTask;
21  
22  import net.sf.mmapps.modules.cloudprovider.CloudProvider;
23  import net.sf.mmapps.modules.cloudprovider.CloudProviderFactory;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.mmbase.bridge.Cloud;
28  import org.mmbase.bridge.CloudContext;
29  import org.mmbase.bridge.ContextProvider;
30  import org.mmbase.module.Module;
31  import org.mmbase.module.core.MMBase;
32  import org.mmbase.module.core.MMBaseContext;
33  
34  /***
35   * This module enables the Lucene fulltext search engine to be used to index the MMBase cloud.
36   * 
37   * @author Wouter Heijke
38   * @version $Revision: 1.2 $
39   */
40  public class LuceneModule extends Module {
41      private static Log log = LogFactory.getLog(LuceneModule.class);
42      
43      private static CloudProvider cloudProvider = CloudProviderFactory.getCloudProvider();
44  
45      // timer to schedule the indexing
46      private static Timer timer = null;
47  
48      // Milliseconds how long the thread will sleep
49      private long interval;
50  
51      private int startHour;
52  
53      // Should we index on startup, default is true
54      private boolean indexOnStartup = true;
55  
56      private String configFile = "lucenemodule.xml";
57  
58      private LuceneManager config = null;
59  
60      private String configroot;
61  
62      /*** The mmbase instance */
63      private MMBase mmb = null;
64  
65      /***
66       * Number of tries to get cloud. A second between each try.
67       */
68      private static final int GETCLOUD_NUM_OF_TRIES = 60;
69  
70      /***
71       * Time to waite between tries.
72       */
73      private static final long GETCLOUD_INTERVAL_TRIES = 1000L;
74  
75      /***
76       * Number of seconds to wait before starting on-startup-index.
77       */
78      private Integer onStartupWait = null;
79  
80      /***
81       * @see org.mmbase.module.Module#onload()
82       */
83      public void onload() {
84          // implement
85      }
86  
87      /***
88       * @see org.mmbase.module.Module#init()
89       */
90      public void init() {
91          // Wait for mmbase to be up and running.
92          // MMBase.getMMBase();
93          mmb = (MMBase) Module.getModule("mmbaseroot");
94  
95          // Initialize the module.
96          String intervalStr = getInitParameter("interval");
97          if (intervalStr == null) {
98              throw new IllegalArgumentException("interval");
99          } else {
100             interval = Long.parseLong(intervalStr) * 1000L * 60L;
101         }
102 
103         String startHourStr = getInitParameter("starthour");
104         if (startHourStr == null) {
105             throw new IllegalArgumentException("starthour");
106         } else {
107             startHour = Integer.parseInt(startHourStr);
108         }
109 
110         // If there is a init paramater index-on-startup use it (default: false)
111         String indexOnStartupStr = getInitParameter("index-on-startup");
112         if (indexOnStartupStr != null) {
113             indexOnStartup = Boolean.valueOf(indexOnStartupStr).booleanValue();
114         } else {
115             log.warn("index-on-startup property not set");
116         }
117 
118         String onStartupWaitStr = getInitParameter("index-on-startup-wait");
119         if (onStartupWaitStr != null) {
120             onStartupWait = new Integer(onStartupWaitStr);
121         }
122 
123         String userConfigFile = getInitParameter("configfile");
124         if (userConfigFile == null) {
125             throw new IllegalArgumentException("configfile");
126         } else {
127             configFile = userConfigFile;
128         }
129 
130         config = new LuceneManager();
131 
132         configroot = MMBaseContext.getConfigPath();
133 
134         config.readConfig(configroot + File.separator + configFile);
135 
136         // index just once if indexOnStartup is true
137         if (indexOnStartup) {
138             Thread runOnce = new Thread(new IndexingTimerTask());
139             runOnce.setDaemon(true);
140             runOnce.start();
141         }
142 
143         // Create a new Timer object; true for daemon
144         timer = new Timer(true);
145 
146         // Get the current date and set the time to startHour
147         Calendar cal = Calendar.getInstance();
148         cal.set(Calendar.HOUR_OF_DAY, startHour);
149         cal.set(Calendar.MINUTE, 0);
150         cal.set(Calendar.SECOND, 0);
151 
152         // If the current date is after startHour then add one day
153         if (Calendar.getInstance().after(cal)) {
154             cal.add(Calendar.DAY_OF_YEAR, 1);
155         }
156         Date time = cal.getTime();
157 
158         // Schedule the actual thread at startHour with a period of interval
159         timer.scheduleAtFixedRate(new IndexingTimerTask(), time, interval);
160     }
161 
162     private class IndexingTimerTask extends TimerTask {
163         /***
164          * The thread in which the external links will be checked
165          */
166         public void run() {
167             if (onStartupWait != null) {
168                 log.debug("LuceneModule waiting for " + onStartupWait + " seconds");
169                 try {
170                     Thread.sleep(onStartupWait.intValue() * 1000L);
171                 } catch (InterruptedException e) {
172                     // ignore
173                 }
174                 // only wait the first time
175                 onStartupWait = null;
176             }
177 
178             log.info("LuceneModule thread started");
179             startIndexing();
180         }
181     }
182 
183     public LuceneManager getLuceneManager() {
184         return config;
185     }
186 
187     /***
188      * Start indexing the cloud after MMBase has really started.
189      */
190     private void startIndexing() {
191         try {
192             while (!mmb.hasStarted()) {
193                 // not started, sleep another minute
194                 Thread.sleep(60000);
195             }
196         } catch (InterruptedException e) {
197         }
198         Cloud cloud = getCloud();
199 
200         log.info("LuceneModule start indexing");
201         config.collectAll(cloud);
202     }
203 
204     /***
205      * Get a cloud reference. Wait for one if no reference available yet.
206      * 
207      * @return a cloud reference
208      * @throws RuntimeException when timed out
209      */
210     public Cloud getCloud() {
211         RuntimeException lastEx = null;
212         for (int i = 0; i < GETCLOUD_NUM_OF_TRIES; i++) {
213             try {
214                 return cloudProvider.getCloud();
215             } catch (RuntimeException ex) {
216                 lastEx = ex;
217                 try {
218                     Thread.sleep(GETCLOUD_INTERVAL_TRIES);
219                 } catch (InterruptedException e) {
220                     // ignore
221                 }
222             }
223         }
224 
225         log.error("can't get cloud: " + lastEx);
226         throw lastEx == null ? new RuntimeException("can't get cloud") : lastEx;
227     }
228 }