001: /*
002: * Copyright 2001-2006 C:1 Financial Services GmbH
003: *
004: * This software is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License Version 2.1, as published by the Free Software Foundation.
007: *
008: * This software is distributed in the hope that it will be useful,
009: * but WITHOUT ANY WARRANTY; without even the implied warranty of
010: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
011: * Lesser General Public License for more details.
012: *
013: * You should have received a copy of the GNU Lesser General Public
014: * License along with this library; if not, write to the Free Software
015: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
016: */
017:
018: package de.finix.contelligent.search.system;
019:
020: import java.io.IOException;
021: import java.util.Collection;
022: import java.util.HashSet;
023: import java.util.Iterator;
024: import java.util.LinkedList;
025: import java.util.List;
026:
027: import javax.transaction.SystemException;
028:
029: import de.finix.contelligent.CallData;
030: import de.finix.contelligent.ComponentPath;
031: import de.finix.contelligent.SessionCreationException;
032: import de.finix.contelligent.core.ThreadFactory;
033: import de.finix.contelligent.core.UserHome;
034: import de.finix.contelligent.core.security.ContelligentSecurityManager;
035: import de.finix.contelligent.core.security.User;
036: import de.finix.contelligent.event.ComponentEvent;
037: import de.finix.contelligent.event.ContelligentEvent;
038: import de.finix.contelligent.event.EventQueueListener;
039: import de.finix.contelligent.logging.LoggingService;
040:
041: public final class SystemIndexer implements EventQueueListener,
042: Runnable {
043: final static org.apache.log4j.Logger log = LoggingService
044: .getLogger(SystemIndexer.class);
045:
046: // holds the component paths of pending components to be indexed
047: private HashSet<ComponentPath> pendingComponents = new HashSet<ComponentPath>();
048:
049: private SystemIndex index;
050:
051: private Thread thread;
052:
053: private boolean skip = true;
054:
055: private int indexerPartition = 0;
056:
057: private final ComponentPath userHomePendingPath;
058:
059: // this flag is needed to escape the run() method in a save way.
060: private boolean stopThread = false;
061:
062: private boolean threadRunning = false;
063:
064: final boolean debugEnabled = log.isDebugEnabled();
065:
066: /**
067: * @param index
068: */
069: public SystemIndexer(SystemIndex index) {
070: this (index, null, 50);
071: }
072:
073: /**
074: * @param index
075: * @param pendingComponents Components to be indexed. For example components which weren't examined by SystemIndex in the previous contelligent server session.
076: */
077: public SystemIndexer(SystemIndex index,
078: Collection<ComponentPath> pendingComponents) {
079: this (index, pendingComponents, 50);
080: }
081:
082: /**
083: * @param index
084: * @param indexerPartition Defines, how many components will be indexed in a single SystemIndex update process.
085: */
086: public SystemIndexer(SystemIndex index, int indexerPartition) {
087: this (index, null, indexerPartition);
088: }
089:
090: /**
091: * @param index
092: * @param pendingComponents Components to be indexed. For example components which weren't examined by SystemIndex in the previous contelligent server session.
093: * @param indexerPartition Defines, how many components will be indexed in a single SystemIndex update process.
094: */
095: public SystemIndexer(SystemIndex index,
096: Collection<ComponentPath> pendingComponents,
097: int indexerPartition) {
098:
099: this .index = index;
100: this .thread = ThreadFactory.getInstance().createThread(
101: "SystemIndex." + index.getCm().getName(), this );
102: this .thread.setPriority(Thread.MIN_PRIORITY);
103: this .thread.setDaemon(true);
104: this .thread.start();
105:
106: this .threadRunning = true;
107:
108: // add "old" components (ComponentPaths) to list, which weren't examined in the previous contelligent server session,
109: // because the server was shutted down prematurely or similar
110: if (pendingComponents != null && pendingComponents.size() > 0) {
111: this .pendingComponents.addAll(pendingComponents);
112: }
113:
114: this .indexerPartition = indexerPartition;
115:
116: User indexUser = ContelligentSecurityManager.getIndexUser();
117:
118: // userHomePendingPath should be: '/contelligent/home/_contelligent_/index/'
119: this .userHomePendingPath = UserHome.getRootPath().append(
120: indexUser.getGroupId()).append(indexUser.getName());
121: }
122:
123: /**
124: * @param flag
125: */
126: public void setSkip(boolean flag) {
127: skip = flag;
128: }
129:
130: /* (non-Javadoc)
131: * @see de.finix.contelligent.event.EventQueueListener#onEvents(java.util.List)
132: */
133: public void onEvents(List eventList) {
134:
135: Iterator iterator = eventList.iterator();
136:
137: HashSet<ComponentPath> components = new HashSet<ComponentPath>();
138:
139: while (iterator.hasNext()) {
140: ContelligentEvent event = (ContelligentEvent) iterator
141: .next();
142: if (debugEnabled) {
143: log.debug("event=" + event);
144: }
145:
146: if (!(event instanceof ComponentEvent)
147: || !index.getCm().getName().equals(
148: event.getOrigin())) {
149: continue;
150: }
151:
152: if (event.getType() == ContelligentEvent.COMPONENT_CHANGE_EVENT
153: || event.getType() == ContelligentEvent.COMPONENT_ADD_EVENT
154: || event.getType() == ContelligentEvent.COMPONENT_REMOVE_EVENT) {
155:
156: // get target path
157: ComponentEvent componentEvent = (ComponentEvent) event;
158: ComponentPath targetPath = componentEvent
159: .getTargetPath();
160:
161: // exclude userHome from indexing
162: if (targetPath.toString().startsWith(
163: userHomePendingPath.toString())) {
164: // add, change or remove events on the SystemIndex home components, will NOT be indexed.
165: continue;
166: }
167:
168: components.add(targetPath);
169: }
170: }
171: // add target paths to pending components
172: addPendingComponents(components);
173: }
174:
175: /* (non-Javadoc)
176: * @see java.lang.Runnable#run()
177: */
178: public void run() {
179:
180: int counter = 0;
181: ComponentPath path = null;
182: List<ComponentPath> paths = new LinkedList<ComponentPath>();
183:
184: while (true) {
185:
186: if (skip) {
187: try {
188: Thread.sleep(1000);
189: continue;
190: } catch (InterruptedException e) {
191: break;
192: }
193: }
194:
195: // stops this run() method in a save way.
196: if (stopThread) {
197: this .threadRunning = false;
198: return;
199: }
200:
201: paths = new LinkedList<ComponentPath>();
202:
203: if (pendingComponents.size() > 0) {
204:
205: synchronized (pendingComponents) {
206:
207: Iterator iterator = pendingComponents.iterator();
208: counter = 0;
209:
210: // for performance reasons, SystemIndex checks a quantity of paths at once.
211: // variable indexerPartition defines the size of this quantity.
212: while (iterator.hasNext()
213: && counter < indexerPartition) {
214: // collect components that will be indexed.
215: path = (ComponentPath) iterator.next();
216: paths.add(path);
217: iterator.remove(); // remove examined component path.
218: counter++;
219: }
220: }
221: // invoke the update now.
222: updateSystemIndex(paths);
223: }
224:
225: try {
226: Thread.sleep(10);
227: } catch (InterruptedException e) {
228: break;
229: }
230: }
231: }
232:
233: /**
234: * @param paths
235: */
236: public void updateSystemIndex(List<ComponentPath> paths) {
237: try {
238: index.update(paths);
239: } catch (SessionCreationException e) {
240: log
241: .warn("Update of system index " + index
242: + " failed. ", e);
243: } catch (SystemException e) {
244: log
245: .warn("Update of system index " + index
246: + " failed. ", e);
247: } catch (IOException e) {
248: log
249: .warn("Update of system index " + index
250: + " failed. ", e);
251: }
252: }
253:
254: /**
255: *
256: */
257: public void stop() {
258: thread.interrupt();
259: }
260:
261: /**
262: * Stops the thread/the runnable.run() in a save way. Use this method to stop the thread instead of stop(), because that method might result in an undefined state of the used instances.
263: */
264: public void stopThread() {
265: this .stopThread = true;
266: }
267:
268: /**
269: * @return
270: */
271: public boolean isRunning() {
272: return threadRunning;
273: }
274:
275: /**
276: * @return
277: */
278: public HashSet<ComponentPath> getPendingComponents() {
279: return pendingComponents;
280: }
281:
282: /**
283: * @return
284: */
285: public boolean addPendingComponents(
286: Collection<ComponentPath> components) {
287:
288: if (components == null || components.size() < 1) {
289: return false;
290: }
291:
292: synchronized (pendingComponents) {
293: return this .pendingComponents.addAll(components);
294: }
295: }
296:
297: /**
298: * Saves the ComponentPaths of the components which haven't been indexed until now in a component as XML content.
299: */
300: public void savePendingComponents(CallData callData)
301: throws Exception {
302:
303: Iterator iterator = pendingComponents.iterator();
304:
305: // persist pending components in XML
306: StringBuffer buffer = new StringBuffer();
307: buffer.append("<paths>\n");
308:
309: while (iterator.hasNext()) {
310: ComponentPath targetPath = (ComponentPath) iterator.next();
311:
312: // add path to pending components
313: buffer.append("<path>" + targetPath.toString()
314: + "</path>\n");
315: }
316: buffer.append("</paths>");
317:
318: String componentManagerName = index.getCm().getName();
319:
320: // save componentPath list
321: UserHome.createContent(callData, buffer.toString(),
322: componentManagerName + ".pendingComponents");
323:
324: if (debugEnabled) {
325: log
326: .debug(pendingComponents.size()
327: + " pending components to be indexed by SystemIndex in context '"
328: + componentManagerName
329: + "' have been saved.");
330: }
331: }
332: }
|