package org.openedit.data;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.facet.taxonomy.TaxonomyWriter;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.dom4j.Element;
import org.entermedia.locks.Lock;
import org.openedit.Data;
import org.openedit.data.lucene.BaseLuceneSearcher;
import org.openedit.entermedia.SourcePathCreator;
import org.openedit.repository.ContentItem;
import org.openedit.xml.ElementData;
import org.openedit.xml.XmlArchive;
import org.openedit.xml.XmlFile;
import com.openedit.OpenEditException;
import com.openedit.WebPageRequest;
import com.openedit.hittracker.HitTracker;
import com.openedit.hittracker.SearchQuery;
import com.openedit.page.Page;
import com.openedit.page.manage.PageManager;
import com.openedit.users.User;
import com.openedit.util.IntCounter;
import com.openedit.util.PathProcessor;
public class XmlFileSearcher extends BaseLuceneSearcher
{
protected Log log = LogFactory.getLog(XmlFileSearcher.class);
protected XmlArchive fieldXmlArchive;
protected XmlDataArchive fieldXmlDataArchive;
protected IntCounter fieldIntCounter;
protected PageManager fieldPageManager;
protected String fieldPrefix;
protected SourcePathCreator fieldSourcePathCreator;
public SourcePathCreator getSourcePathCreator()
{
return fieldSourcePathCreator;
}
public void setSourcePathCreator(SourcePathCreator inSourcePathCreator)
{
fieldSourcePathCreator = inSourcePathCreator;
}
protected XmlDataArchive getXmlDataArchive()
{
if (fieldXmlDataArchive == null)
{
fieldXmlDataArchive = new XmlDataArchive();
fieldXmlDataArchive.setXmlArchive(getXmlArchive());
fieldXmlDataArchive.setDataFileName(getDataFileName());
fieldXmlDataArchive.setElementName(getSearchType());
fieldXmlDataArchive.setPathToData(getPathToData());
}
return fieldXmlDataArchive;
}
public void setXmlDataArchive(XmlDataArchive inArchive)
{
fieldXmlDataArchive = inArchive;
}
public XmlArchive getXmlArchive()
{
return fieldXmlArchive;
}
public void setXmlArchive(XmlArchive inXmlArchive)
{
fieldXmlArchive = inXmlArchive;
}
public Data loadData(String inSourcePath, String inId)
{
//TODO: Load from cache?
Data data = getXmlDataArchive().loadData(this,inSourcePath,inId);
return data;
}
public Data createNewData()
{
if( getNewDataName() == null)
{
ElementData data = new ElementData();
return data;
}
return (Data)getModuleManager().getBean(getNewDataName());
}
public Object searchByField(String inId, String inValue)
{
if (fieldCacheManager != null && "id".equals(inId))
{
Object cached = getCacheManager().get(getIndexPath(), inValue);
if (cached != null)
{
return cached;
}
}
SearchQuery query = createSearchQuery();
query.addExact(inId, inValue);
HitTracker hits = search(query);
hits.setHitsPerPage(1);
Data first = (Data)hits.first();
if( first == null)
{
return null;
}
String sourcepath = first.getSourcePath();
if (sourcepath != null)
{
first = loadData(sourcepath, first.getId());
if (fieldCacheManager != null && first != null && "id".equals(inId))
{
getCacheManager().put(getIndexPath(), inValue, first);
}
}
return first;
}
public void saveAllData(Collection inAll, User inUser)
{
//check that all have ids
for (Object object: inAll)
{
Data data = (Data)object;
if(data.getId() == null)
{
data.setId(nextId());
}
if( data.getSourcePath() == null)
{
String sourcepath = getSourcePathCreator().createSourcePath(data, data.getId() );
data.setSourcePath(sourcepath);
}
}
getXmlDataArchive().saveAllData(inAll, getCatalogId(), getPrefix() + "/", inUser );
updateIndex(inAll);
//getLiveSearcher(); //should flush the index
}
public void updateIndex(IndexWriter inWriter, Data inData) throws OpenEditException
{
Document doc = new Document();
PropertyDetails details = getPropertyDetailsArchive().getPropertyDetailsCached(getSearchType());
if( details == null)
{
throw new OpenEditException("No " + getSearchType() + "properties.xml file available");
}
try
{
updateIndex(inData, doc, details);
Term term = new Term("id", inData.getId());
inWriter.updateDocument(term, doc, getAnalyzer());
if (fieldCacheManager != null)
{
getCacheManager().remove(getIndexPath(), inData.getId());
}
clearIndex();
}
catch (IOException ex)
{
throw new OpenEditException(ex);
}
}
/**
* @deprecated use updateIndex(Data)
* @param inWriter
* @param inElement
* @param inSourcePath
*/
protected void updateIndex(IndexWriter inWriter, Element inElement, String inSourcePath)
{
ElementData data = (ElementData)createNewData();
data.setElement(inElement);
data.setSourcePath(inSourcePath);
updateIndex(inWriter, data);
}
protected void updateIndex(Data inData, Document doc, PropertyDetails inDetails)
{
if( inData.getSourcePath() == null )
{
throw new OpenEditException("Cant save data without a sourcepath parameter");
}
super.updateIndex(inData, doc, inDetails);
doc.add(new Field("sourcepath", inData.getSourcePath(), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
}
public void saveData(Data data, User inUser)
{
if(data.getId() == null)
{
data.setId(nextId());
}
if( data.getSourcePath() == null)
{
String sourcepath = getSourcePathCreator().createSourcePath(data, data.getId() );
data.setSourcePath(sourcepath);
}
Lock lock = null;
try
{
lock = getLockManager().lock(getCatalogId(), getPrefix() + "/" + data.getSourcePath(),"admin");
getXmlDataArchive().saveData(data,inUser, lock);
// String nullcheck = data.get("publishqueueid");
// log.info( getSearchType() + " " + data.getId() + " " + nullcheck );
updateIndex(data);
} finally
{
getLockManager().release(getCatalogId(), lock);
}
}
protected IntCounter getIntCounter()
{
if (fieldIntCounter == null)
{
synchronized (this)
{
if (fieldIntCounter == null)
{
fieldIntCounter = new IntCounter();
fieldIntCounter.setLabelName("idCount");
String path = null;
// if( fieldIndexRootFolder != null)
// {
// path = "/WEB-INF/data/" + getCatalogId() +"/"+ getIndexRootFolder() + "/" + getSearchType() + "/idcounter.properties";
// }
// else
// {
path = "/WEB-INF/data/" + getCatalogId() +"/"+ getSearchType() + "s/idcounter.properties";
// }
Page prop = getPageManager().getPage(path);
File file = new File(prop.getContentItem().getAbsolutePath());
file.getParentFile().mkdirs();
fieldIntCounter.setCounterFile(file);
}
}
}
return fieldIntCounter;
}
public synchronized String nextId()
{
return String.valueOf(getIntCounter().incrementCount());
}
public PageManager getPageManager()
{
return fieldPageManager;
}
public void setPageManager(PageManager pageManager)
{
fieldPageManager = pageManager;
}
public String getPathToData()
{
return "/WEB-INF/data/" + getCatalogId() + "/" + getPrefix();
}
public String getDataFileName()
{
return getSearchType() + ".xml";
}
protected void reIndexAll(final IndexWriter inWriter, final TaxonomyWriter inTaxonomyWriter) throws OpenEditException
{
final List buffer = new ArrayList(100);
PathProcessor processor = new PathProcessor()
{
public void processFile(ContentItem inContent, User inUser)
{
if (!inContent.getName().equals(getSearchType() + ".xml"))
{
return;
}
String sourcepath = inContent.getPath();
sourcepath = sourcepath.substring(getPathToData().length() + 1,
sourcepath.length() - getDataFileName().length() - 1);
String path = inContent.getPath();
XmlFile content = getXmlArchive().getXml(path, getSearchType());
for (Iterator iterator = content.getElements().iterator(); iterator.hasNext();)
{
Element element = (Element) iterator.next();
ElementData data = (ElementData)createNewData();
data.setElement(element);
data.setSourcePath(sourcepath);
buffer.add(data);
if( buffer.size() > 99)
{
updateIndex(inWriter, inTaxonomyWriter, buffer);
}
}
}
};
processor.setRecursive(true);
processor.setRootPath(getPathToData());
processor.setPageManager(getPageManager());
processor.setIncludeExtensions("xml");
processor.process();
updateIndex(inWriter, inTaxonomyWriter, buffer);
}
public void delete(Data inData, User inUser)
{
// Delete from xml
if( inData == null || inData.getSourcePath() == null || inData.getId() == null )
{
throw new OpenEditException("Cannot delete null data.");
}
getXmlDataArchive().delete(inData,inUser);
// Remove from Index
deleteRecord(inData);
}
public void deleteAll(User inUser)
{
PathProcessor processor = new PathProcessor()
{
public void processFile(ContentItem inContent, User inUser)
{
if (inContent.getName().equals(getDataFileName()))
{
getPageManager().getRepository().remove(inContent);
}
}
};
processor.setRecursive(true);
processor.setRootPath(getPathToData());
processor.setPageManager(getPageManager());
processor.setIncludeExtensions("xml");
processor.process();
reIndexAll();
}
public String getPrefix()
{
if(fieldPrefix == null)
{
fieldPrefix = getPropertyDetails().getPrefix();
if( fieldPrefix == null)
{
fieldPrefix = getSearchType();
}
}
return fieldPrefix;
}
public void setPrefix(String prefix)
{
fieldPrefix = prefix;
}
public void clearIndex()
{
super.clearIndex();
getXmlDataArchive().clearCache(); //Is this needed? We should just clear one item at a time from the c
}
public HitTracker getAllHits(WebPageRequest inReq)
{
SearchQuery q = createSearchQuery();
q.addMatches("id","*"); //Had to do this since description is not always fully populated. TODO: use Lucene API to get All
addShowOnly(inReq, q);
if (inReq != null)
{
String sort = inReq.getRequestParameter("sortby");
if (sort == null)
{
sort = inReq.findValue("sortby");
}
if (sort != null)
{
q.setSortBy(sort);
}
return cachedSearch(inReq, q);
} else{
return search(q);
}
}
}