/*
*
* Copyright 2005 AgileTec s.r.l. (http://www.agiletec.it) All rights reserved.
*
* This file is part of jAPS software.
* jAPS is a free software;
* you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) as published by the Free Software Foundation; version 2.
*
* See the file License for the specific language governing permissions
* and limitations under the License
*
*
*
* Copyright 2005 AgileTec s.r.l. (http://www.agiletec.it) All rights reserved.
*
*/
package com.agiletec.plugins.jacms.aps.system.services.searchengine;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.IndexWriter.MaxFieldLength;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import com.agiletec.aps.system.ApsSystemUtils;
import com.agiletec.aps.system.common.entity.model.IApsEntity;
import com.agiletec.aps.system.common.entity.model.attribute.AttributeInterface;
import com.agiletec.aps.system.common.searchengine.IndexableAttributeInterface;
import com.agiletec.aps.system.common.util.EntityAttributeIterator;
import com.agiletec.aps.system.exception.ApsSystemException;
import com.agiletec.aps.system.services.lang.ILangManager;
import com.agiletec.aps.system.services.lang.Lang;
/**
* Data Access Object dedita alla indicizzazione di documenti.
* @author W.Ambu
*/
public class IndexerDAO implements IIndexerDAO {
/**
* Inizializzazione dell'indicizzatore.
* @param dir La cartella locale contenitore dei dati persistenti.
* @param newIndex true se è una nuova indicizzazione (ed in tal caso
* cancella tutte le precedenti indicizzazioni), false in caso contrario.
* @throws ApsSystemException
*/
@Override
public void init(File dir, boolean newIndex) throws ApsSystemException {
try {
this._dir = FSDirectory.open(dir);
boolean indexExists = IndexReader.indexExists(this._dir);
IndexWriter writer = new IndexWriter(_dir, getAnalyzer(), !indexExists, new MaxFieldLength(IndexWriter.DEFAULT_MAX_FIELD_LENGTH));
writer.close();
} catch (Throwable t) {
throw new ApsSystemException("Errore in creazione directory", t);
}
ApsSystemUtils.getLogger().config("Indexer: search engine index ok.");
}
@Override
public void add(IApsEntity entity) throws ApsSystemException {
try {
Document document = this.createDocument(entity);
this.add(document);
} catch (ApsSystemException e) {
ApsSystemUtils.logThrowable(e, this, "addContentToIndex",
"Errore in aggiunta di un contenuto");
throw e;
}
}
/**
* Aggiunge un documento nel db del motore di ricerca.
* @param document Il documento da aggiungere.
* @throws ApsSystemException In caso di errori in accesso al db.
*/
private synchronized void add(Document document) throws ApsSystemException {
try {
IndexWriter writer = new IndexWriter(_dir, this.getAnalyzer(), false, new MaxFieldLength(IndexWriter.DEFAULT_MAX_FIELD_LENGTH));
writer.addDocument(document);
writer.optimize();
writer.close();
} catch (IOException e) {
throw new ApsSystemException(
"Errore nell'aggiunta di un documento", e);
}
}
/**
* Crea un oggetto Document pronto per l'indicizzazione da un oggetto Content.
* @param entity Il contenuto dal quale ricavare il Document.
* @return L'oggetto Document ricavato dal contenuto.
* @throws ApsSystemException
*/
private Document createDocument(IApsEntity entity) throws ApsSystemException {
Document document = new Document();
document.add(new Field(CONTENT_ID_FIELD_NAME, entity.getId(),
Field.Store.YES, Field.Index.NOT_ANALYZED));
document.add(new Field(CONTENT_GROUP_FIELD_NAME, entity.getMainGroup(),
Field.Store.YES, Field.Index.ANALYZED));
Iterator<String> iterGroups = entity.getGroups().iterator();
while (iterGroups.hasNext()) {
String groupName = (String) iterGroups.next();
document.add(new Field(CONTENT_GROUP_FIELD_NAME, groupName,
Field.Store.YES, Field.Index.ANALYZED));
}
try {
EntityAttributeIterator attributesIter = new EntityAttributeIterator(entity);
while (attributesIter.hasNext()) {
AttributeInterface currentAttribute = (AttributeInterface) attributesIter.next();
List<Lang> langs = this.getLangManager().getLangs();
for (int i=0; i<langs.size(); i++) {
Lang currentLang = (Lang) langs.get(i);
this.indexAttribute(document, currentAttribute, currentLang);
}
}
} catch (Exception e) {
throw new ApsSystemException(
"Errore nella creazione del Document da indicizzare", e);
}
return document;
}
private void indexAttribute(Document document,
AttributeInterface attribute, Lang lang) throws ApsSystemException {
attribute.setRenderingLang(lang.getCode());
if (attribute instanceof IndexableAttributeInterface) {
String valueToIndex = ((IndexableAttributeInterface) attribute).getIndexeableFieldValue();
String indexingType = attribute.getIndexingType();
if (null != indexingType &&
IndexableAttributeInterface.INDEXING_TYPE_UNSTORED.equalsIgnoreCase(indexingType)) {
document.add(new Field(lang.getCode(), valueToIndex,
Field.Store.NO, Field.Index.ANALYZED));
}
if (null != indexingType &&
IndexableAttributeInterface.INDEXING_TYPE_TEXT.equalsIgnoreCase(indexingType)) {
document.add(new Field(lang.getCode(), valueToIndex,
Field.Store.YES, Field.Index.ANALYZED));
}
}
}
/**
* Cancella un documento in base alla chiave (di nome "id")
* mediante il quale è stato indicizzato.
* Nel caso della cancellazione di un contenuto il nome del campo
* da utilizzare sarà "id" mentre il valore sarà l'identificativo del contenuto.
* @param name Il nome del campo Field da utilizzare per recupero del documento.
* @param value La chiave mediante il quale
* è stato indicizzato il documento.
* @throws ApsSystemException
*/
@Override
public synchronized void delete(String name, String value) throws ApsSystemException {
IndexReader reader = null;
try {
reader = IndexReader.open(this._dir, false);
reader.deleteDocuments(new Term(name, value));
reader.close();
IndexWriter writer = new IndexWriter(this._dir, this.getAnalyzer(), false, new MaxFieldLength(IndexWriter.DEFAULT_MAX_FIELD_LENGTH));
writer.optimize();
writer.close();
} catch (IOException e) {
throw new ApsSystemException(
"Errore nella cancellazione di un indice", e);
}
}
@Override
public void close() {
// nothing to do
}
private Analyzer getAnalyzer() {
return new StandardAnalyzer(Version.LUCENE_30);
}
protected ILangManager getLangManager() {
return _langManager;
}
public void setLangManager(ILangManager langManager) {
this._langManager = langManager;
}
private Directory _dir;
private ILangManager _langManager;
}