001: /*
002: * Copyright 2004-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.compass.core.impl;
018:
019: import javax.naming.NamingException;
020: import javax.naming.Reference;
021: import javax.naming.StringRefAddr;
022:
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025: import org.compass.core.Compass;
026: import org.compass.core.CompassException;
027: import org.compass.core.CompassSession;
028: import org.compass.core.CompassTransaction;
029: import org.compass.core.ResourceFactory;
030: import org.compass.core.cache.first.FirstLevelCache;
031: import org.compass.core.cache.first.FirstLevelCacheFactory;
032: import org.compass.core.config.CompassEnvironment;
033: import org.compass.core.config.CompassSettings;
034: import org.compass.core.config.RuntimeCompassSettings;
035: import org.compass.core.converter.ConverterLookup;
036: import org.compass.core.engine.SearchEngineFactory;
037: import org.compass.core.engine.SearchEngineIndexManager;
038: import org.compass.core.engine.SearchEngineOptimizer;
039: import org.compass.core.engine.naming.PropertyNamingStrategy;
040: import org.compass.core.engine.spellcheck.SearchEngineSpellCheckManager;
041: import org.compass.core.engine.spi.InternalSearchEngineFactory;
042: import org.compass.core.executor.ExecutorManager;
043: import org.compass.core.id.IdentifierGenerator;
044: import org.compass.core.id.UUIDGenerator;
045: import org.compass.core.jndi.CompassObjectFactory;
046: import org.compass.core.lucene.engine.LuceneSearchEngineFactory;
047: import org.compass.core.mapping.CompassMapping;
048: import org.compass.core.metadata.CompassMetaData;
049: import org.compass.core.spi.InternalCompass;
050: import org.compass.core.transaction.InternalCompassTransaction;
051: import org.compass.core.transaction.LocalTransactionFactory;
052: import org.compass.core.transaction.TransactionException;
053: import org.compass.core.transaction.TransactionFactory;
054: import org.compass.core.transaction.TransactionFactoryFactory;
055: import org.compass.core.transaction.context.TransactionContext;
056: import org.compass.core.transaction.context.TransactionContextCallback;
057:
058: /**
059: * @author kimchy
060: */
061: public class DefaultCompass implements InternalCompass {
062:
063: private static final Log log = LogFactory
064: .getLog(DefaultCompass.class);
065:
066: private static final long serialVersionUID = 3256446884762891059L;
067:
068: private static final IdentifierGenerator UUID_GENERATOR = new UUIDGenerator();
069:
070: private final String name;
071:
072: private String uuid;
073:
074: private CompassMapping mapping;
075:
076: private InternalSearchEngineFactory searchEngineFactory;
077:
078: private TransactionFactory transactionFactory;
079:
080: private LocalTransactionFactory localTransactionFactory;
081:
082: private ConverterLookup converterLookup;
083:
084: private CompassMetaData compassMetaData;
085:
086: private PropertyNamingStrategy propertyNamingStrategy;
087:
088: private ExecutorManager executorManager;
089:
090: protected CompassSettings settings;
091:
092: private FirstLevelCacheFactory firstLevelCacheFactory;
093:
094: private boolean duplicate;
095:
096: private volatile boolean closed = false;
097:
098: public DefaultCompass(CompassMapping mapping,
099: ConverterLookup converterLookup,
100: CompassMetaData compassMetaData,
101: PropertyNamingStrategy propertyNamingStrategy,
102: ExecutorManager executorManager, CompassSettings settings)
103: throws CompassException {
104: this (mapping, converterLookup, compassMetaData,
105: propertyNamingStrategy, executorManager, settings,
106: false);
107: }
108:
109: public DefaultCompass(CompassMapping mapping,
110: ConverterLookup converterLookup,
111: CompassMetaData compassMetaData,
112: PropertyNamingStrategy propertyNamingStrategy,
113: ExecutorManager executorManager, CompassSettings settings,
114: boolean duplicate) throws CompassException {
115:
116: this (mapping, converterLookup, compassMetaData,
117: propertyNamingStrategy, executorManager, settings,
118: duplicate, new LuceneSearchEngineFactory(
119: propertyNamingStrategy, settings, mapping,
120: executorManager));
121: }
122:
123: public DefaultCompass(CompassMapping mapping,
124: ConverterLookup converterLookup,
125: CompassMetaData compassMetaData,
126: PropertyNamingStrategy propertyNamingStrategy,
127: CompassSettings settings,
128: LuceneSearchEngineFactory searchEngineFactory)
129: throws CompassException {
130: this (mapping, converterLookup, compassMetaData,
131: propertyNamingStrategy, searchEngineFactory
132: .getExecutorManager(), settings, false,
133: searchEngineFactory);
134: }
135:
136: public DefaultCompass(CompassMapping mapping,
137: ConverterLookup converterLookup,
138: CompassMetaData compassMetaData,
139: PropertyNamingStrategy propertyNamingStrategy,
140: ExecutorManager executorManager, CompassSettings settings,
141: boolean duplicate,
142: LuceneSearchEngineFactory searchEngineFactory)
143: throws CompassException {
144:
145: this .mapping = mapping;
146: this .converterLookup = converterLookup;
147: this .compassMetaData = compassMetaData;
148: this .propertyNamingStrategy = propertyNamingStrategy;
149: this .executorManager = executorManager;
150: this .name = settings.getSetting(CompassEnvironment.NAME,
151: "default");
152: this .settings = settings;
153: this .duplicate = duplicate;
154:
155: if (!duplicate) {
156: registerJndi();
157: }
158:
159: searchEngineFactory
160: .setTransactionContext(new CompassTransactionContext(
161: this ));
162: this .searchEngineFactory = searchEngineFactory;
163:
164: // build the transaction factory
165: transactionFactory = TransactionFactoryFactory
166: .createTransactionFactory(this , settings);
167: localTransactionFactory = TransactionFactoryFactory
168: .createLocalTransactionFactory(this , settings);
169:
170: firstLevelCacheFactory = new FirstLevelCacheFactory();
171: firstLevelCacheFactory.configure(settings);
172:
173: searchEngineFactory.getIndexManager().verifyIndex();
174:
175: if (!duplicate) {
176: start();
177: }
178: }
179:
180: public Compass clone(CompassSettings addedSettings) {
181: CompassSettings copySettings = settings.copy();
182: copySettings.addSettings(addedSettings);
183: return new DefaultCompass(mapping, converterLookup,
184: compassMetaData, propertyNamingStrategy,
185: executorManager, copySettings, true);
186: }
187:
188: public String getName() {
189: return this .name;
190: }
191:
192: public ResourceFactory getResourceFactory() {
193: return searchEngineFactory.getResourceFactory();
194: }
195:
196: public CompassMapping getMapping() {
197: return this .mapping;
198: }
199:
200: public ExecutorManager getExecutorManager() {
201: return executorManager;
202: }
203:
204: public CompassSession openSession() {
205: return openSession(true);
206: }
207:
208: public CompassSession openSession(boolean allowCreate) {
209: return openSession(allowCreate, true);
210: }
211:
212: public CompassSession openSession(boolean allowCreate,
213: boolean checkClosed) {
214: if (checkClosed) {
215: checkClosed();
216: }
217: CompassSession session = transactionFactory
218: .getTransactionBoundSession();
219:
220: if (session != null) {
221: return session;
222: }
223:
224: if (!allowCreate) {
225: return null;
226: }
227:
228: FirstLevelCache firstLevelCache = firstLevelCacheFactory
229: .createFirstLevelCache();
230: RuntimeCompassSettings runtimeSettings = new RuntimeCompassSettings(
231: getSettings());
232: return new DefaultCompassSession(runtimeSettings, this ,
233: searchEngineFactory.openSearchEngine(runtimeSettings),
234: firstLevelCache);
235: }
236:
237: public void start() {
238: searchEngineFactory.start();
239: }
240:
241: public void stop() {
242: searchEngineFactory.stop();
243: }
244:
245: public void close() {
246: if (closed) {
247: return;
248: }
249: closed = true;
250: log.info("Closing Compass [" + name + "]");
251: if (settings.getSettingAsBoolean(
252: CompassEnvironment.Jndi.ENABLE, false)
253: && !duplicate) {
254: CompassObjectFactory.removeInstance(uuid, name, settings);
255: }
256: searchEngineFactory.close();
257:
258: if (!duplicate) {
259: executorManager.close();
260: }
261:
262: log.info("Closed Compass [" + name + "]");
263: }
264:
265: public boolean isClosed() {
266: return this .closed;
267: }
268:
269: // from javax.naming.Referenceable
270: public Reference getReference() throws NamingException {
271: return new Reference(DefaultCompass.class.getName(),
272: new StringRefAddr("uuid", uuid),
273: CompassObjectFactory.class.getName(), null);
274: }
275:
276: public CompassSettings getSettings() {
277: return settings;
278: }
279:
280: public SearchEngineOptimizer getSearchEngineOptimizer() {
281: return searchEngineFactory.getOptimizer();
282: }
283:
284: public SearchEngineIndexManager getSearchEngineIndexManager() {
285: return searchEngineFactory.getIndexManager();
286: }
287:
288: public SearchEngineSpellCheckManager getSpellCheckManager() {
289: return searchEngineFactory.getSpellCheckManager();
290: }
291:
292: public SearchEngineFactory getSearchEngineFactory() {
293: return searchEngineFactory;
294: }
295:
296: public CompassMetaData getMetaData() {
297: return compassMetaData;
298: }
299:
300: public TransactionFactory getTransactionFactory() {
301: return transactionFactory;
302: }
303:
304: public LocalTransactionFactory getLocalTransactionFactory() {
305: return this .localTransactionFactory;
306: }
307:
308: public ConverterLookup getConverterLookup() {
309: return converterLookup;
310: }
311:
312: public PropertyNamingStrategy getPropertyNamingStrategy() {
313: return propertyNamingStrategy;
314: }
315:
316: private void registerJndi() throws CompassException {
317: if (!settings.getSettingAsBoolean(
318: CompassEnvironment.Jndi.ENABLE, false)) {
319: return;
320: }
321: // JNDI
322: try {
323: uuid = (String) UUID_GENERATOR.generate();
324: } catch (Exception e) {
325: throw new CompassException(
326: "Could not generate UUID for JNDI binding");
327: }
328:
329: CompassObjectFactory.addInstance(uuid, name, this , settings);
330: }
331:
332: private void checkClosed() throws IllegalStateException {
333: if (closed) {
334: throw new IllegalStateException("Compass already closed");
335: }
336: }
337:
338: private static class CompassTransactionContext implements
339: TransactionContext {
340:
341: private InternalCompass compass;
342:
343: public CompassTransactionContext(InternalCompass compass) {
344: this .compass = compass;
345: }
346:
347: public <T> T execute(TransactionContextCallback<T> callback)
348: throws TransactionException {
349: CompassSession session = compass.openSession(true, false);
350: CompassTransaction tx = null;
351: try {
352: tx = session.beginTransaction();
353: T result = callback
354: .doInTransaction((InternalCompassTransaction) tx);
355: tx.commit();
356: return result;
357: } catch (RuntimeException e) {
358: if (tx != null) {
359: try {
360: tx.rollback();
361: } catch (Exception e1) {
362: log
363: .error(
364: "Failed to rollback transaction, ignoring",
365: e1);
366: }
367: }
368: throw e;
369: } catch (Error err) {
370: if (tx != null) {
371: try {
372: tx.rollback();
373: } catch (Exception e1) {
374: log
375: .error(
376: "Failed to rollback transaction, ignoring",
377: e1);
378: }
379: }
380: throw err;
381: } finally {
382: session.close();
383: }
384: }
385: }
386: }
|