package org.openedit.data;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.dom4j.Attribute;
import org.dom4j.Element;
import org.entermedia.cache.CacheManager;
import org.entermedia.locks.Lock;
import org.openedit.Data;
import org.openedit.xml.ElementData;
import org.openedit.xml.XmlArchive;
import org.openedit.xml.XmlFile;
import com.openedit.OpenEditException;
import com.openedit.users.User;
public class XmlDataArchive implements DataArchive
{
protected XmlArchive fieldXmlArchive;
public String getPathToData()
{
return fieldPathToData;
}
public void setPathToData(String inPathToData)
{
fieldPathToData = inPathToData;
}
public String getDataFileName()
{
return fieldDataFileName;
}
public void setDataFileName(String inDataFileName)
{
fieldDataFileName = inDataFileName;
}
protected String fieldPathToData;
protected String fieldDataFileName;
protected String fieldElementName;
public String getElementName()
{
return fieldElementName;
}
public void setElementName(String inElementName)
{
fieldElementName = inElementName;
}
public XmlArchive getXmlArchive()
{
return fieldXmlArchive;
}
public void setXmlArchive(XmlArchive inXmlArchive)
{
fieldXmlArchive = inXmlArchive;
}
private void addRow(Data inData, XmlFile xml)
{
Element element = xml.getElementById(inData.getId());
if( element == null )
{
//New element
element = xml.getRoot().addElement(xml.getElementName());
element.addAttribute("id", inData.getId());
}
if(inData instanceof ElementData)
{
populateElementData(element, (ElementData)inData);
}
else
{
element.setAttributes(new ArrayList());
populateElement(element, inData);
}
}
//Not recommeneded, use populateElementData
protected void populateElement(Element inElement, Data inData)
{
for (Iterator iterator = inData.getProperties().keySet().iterator(); iterator.hasNext();)
{
String detail = (String) iterator.next();
if( !detail.equals("id") && !detail.equals("sourcepath") && !detail.startsWith("."))
{
String value = inData.get(detail);
if( value != null)
{
inElement.addAttribute(detail, value);
}
}
}
}
protected void populateElementData(Element inElement, ElementData inData)
{
List attributes = inData.getAttributes();
List attributessaved = new ArrayList(attributes.size());
boolean foundname = false;
for (Iterator iterator = attributes.iterator(); iterator.hasNext();) {
Attribute attr = (Attribute) iterator.next();
if( !attr.getName().startsWith(".") )
{
attributessaved.add(attr);
}
if( attr.getName().equals("name") )
{
foundname = true;
}
}
inElement.setAttributes(attributessaved);
inElement.clearContent();
//Mixed content is ok
for (Iterator iterator = inData.getElement().elementIterator(); iterator.hasNext();)
{
Element child = (Element) iterator.next();
inElement.add(child.createCopy());
if( "name".equals( child.attributeValue("id") ) )
{
foundname = true;
}
}
// boolean foundname = false;
// for(Iterator iterator = attributes.iterator(); iterator.hasNext();)
// {
// Attribute attr = (Attribute)iterator.next();
// String id = attr.getName();
// if(!id.equals("id") && !id.startsWith("."))
// {
// if( id.equals("name"))
// {
// foundname = true;
// }
// inElement.addAttribute(attr.getName(), attr.getValue());
// }
// }
//This should not happen any more
if( !foundname && inData.getName() != null)
{
inElement.addCDATA(inData.getName());
}
}
public String getPathToXml( String inSourcePath )
{
String path = getPathToData() + "/" + inSourcePath;
if( !path.endsWith("/"))
{
path = path + "/";
}
path = path + getDataFileName();
return path;
}
protected String getCacheName()
{
return getPathToData() + getDataFileName();
}
public Data loadData(DataFactory inFactory, String inSourcePath, String inId)
{
//This is used a bunch when loading and editing the same xml file
String path = getPathToXml(inSourcePath);
XmlFile xml = getXmlArchive().getXml(path, getElementName());
Element elem = xml.getElementById(inId);
if(elem == null)
{
return null;
}
ElementData data = (ElementData)inFactory.createNewData();
data.setElement(elem);
data.setSourcePath(inSourcePath);
return data;
}
public void clearCache()
{
//getIdCache().clear();
}
public void delete(Data inData, User inUser)
{
String path = getPathToXml(inData.getSourcePath());
XmlFile xml = getXmlArchive().getXml(path, getElementName());
Element element = xml.getElementById(inData.getId());
if( element != null )
{
xml.deleteElement(element);
}
getXmlArchive().saveXml(xml, inUser);
}
// public XmlFile getXml(String inPath, String inSearchType)
// {
// return getXmlArchive().getXml(inPath,inSearchType);
// }
public void saveData(Data inData, User inUser, Lock inLock) {
if( inData == null )
{
throw new OpenEditException("Cannot save null data.");
}
if( inData.getSourcePath() == null )
{
throw new OpenEditException("sourcepath is required ");
}
String path = getPathToXml(inData.getSourcePath());
//TODO: Need to lock this file so another person does not call save
XmlFile xml = getXmlArchive().getXml(path, getElementName());
addRow(inData, xml);
getXmlArchive().saveXml(xml, null,inLock);
}
public void saveAllData(Collection<Data> inAll, String catalogid, String inLockPrefix, User inUser)
{
XmlFile xml = null;//
Lock lock = null;
try
{
for (Iterator iterator = inAll.iterator(); iterator.hasNext();)
{
Data data = (Data) iterator.next();
String path = getPathToXml(data.getSourcePath());
//open the xml file. May reuse this file for other rows
//TODO: Add Lock Manager so that two threads dont save on top of one another
if( xml == null || !xml.getPath().equals(path))
{
if( xml != null)
{
getXmlArchive().saveXml(xml, null, lock);
getXmlArchive().getLockManager().release(catalogid, lock);
}
lock = getXmlArchive().getLockManager().lock(catalogid, inLockPrefix + data.getSourcePath(), null);
xml = getXmlArchive().getXml(path, getElementName());
}
addRow(data, xml);
}
if( xml != null)
{
getXmlArchive().saveXml(xml, null, lock);
}
}
finally
{
if( lock != null)
{
getXmlArchive().getLockManager().release(catalogid, lock);
}
}
}
}