/*
* Created on Oct 3, 2004
*/
package org.openedit.entermedia.xmldb;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.entermedia.cache.CacheManager;
import org.entermedia.locks.Lock;
import org.entermedia.locks.LockManager;
import org.openedit.Data;
import org.openedit.data.PropertyDetail;
import org.openedit.data.PropertyDetails;
import org.openedit.entermedia.Asset;
import org.openedit.entermedia.AssetArchive;
import org.openedit.entermedia.AssetPathFinder;
import org.openedit.entermedia.Category;
import org.openedit.entermedia.CategoryArchive;
import org.openedit.entermedia.MediaArchive;
import org.openedit.entermedia.RelatedAsset;
import org.openedit.repository.ContentItem;
import org.openedit.util.DateStorageUtil;
import org.openedit.xml.XmlArchive;
import com.openedit.ModuleManager;
import com.openedit.OpenEditException;
import com.openedit.page.Page;
import com.openedit.page.manage.PageManager;
import com.openedit.users.User;
import com.openedit.util.FileUtils;
import com.openedit.util.XmlUtil;
/**
* A asset MediaArchive that stores the data about each asset in an
* <tt>.xconf</tt> file in the <tt>storehome/assets</tt> directory (as
* determined by its {@link AssetPathFinder}).
*
* @author cburkey
*/
public class XmlAssetArchive extends BaseXmlArchive implements AssetArchive
{
private static final Log log = LogFactory.getLog(XmlAssetArchive.class);
protected PageManager fieldPageManager;
protected ModuleManager fieldModuleManager;
protected MediaArchive fieldMediaArchive;
protected XmlUtil fieldXmlUtil;
protected boolean fieldUpdateExistingRecord = true;
protected CacheManager fieldCacheManager;
public XmlAssetArchive()
{
log.debug("Created archive");
}
public CacheManager getCacheManager()
{
return fieldCacheManager;
}
public void setCacheManager(CacheManager inCacheManager)
{
fieldCacheManager = inCacheManager;
}
protected String toCacheId()
{
return "/WEB-INF/data/" + getCatalogId() + "/assets/index";
}
public void clearAssets()
{
getPageManager().clearCache();
getCacheManager().clear(toCacheId());
}
public void deleteAsset(Asset inAsset)
{
try
{
Page page = getPageManager().getPage(buildXmlPath(inAsset));
if( page.exists() )
{
getPageManager().removePage(page);
}
}
catch (Exception ex)
{
throw new OpenEditException(ex);
}
}
public void clearAsset(Asset inAsset)
{
if (inAsset != null)
{
getPageManager().clearCache(buildXmlPath(inAsset));
}
}
public Asset getAssetBySourcePath(String inSourcePath)
{
if( inSourcePath == null )
{
return null;
}
return getAssetBySourcePath(inSourcePath, false);
}
public Asset getAssetBySourcePath(String inSourcePath, boolean inAutoCreate)
{
if (inSourcePath.endsWith("/"))
{
inSourcePath = inSourcePath.substring(0, inSourcePath.length() - 1);
}
Asset item = (Asset)getCacheManager().get(toCacheId(), inSourcePath);
if( item == null)
{
item = new Asset();
item.setCatalogId(getCatalogId());
item.setSourcePath(inSourcePath);
String url = buildXmlPath(item);
if( log.isDebugEnabled())
{
log.debug("Loading " + url);
}
boolean populated = populateAsset(item);
if (!populated && !inAutoCreate)
{
log.debug("No Such asset " + url);
return null;
}
getCacheManager().put(toCacheId(),inSourcePath,item);
getCacheManager().put(toCacheId(),item.getId(),item);
}
return item;
}
public String buildXmlPath(Asset inAsset)
{
if (inAsset == null || inAsset.getSourcePath() == null)
{
return null;
}
String prefix = "/WEB-INF/data";
String catalogId = getCatalogId();
String path = "/" + catalogId + "/assets/" + inAsset.getSourcePath();
String suffix = "/data.xml";
path = prefix + path + suffix;
return path;
}
/**
* This is temporal. Should be deleted soon.
* @author Jorge Valencia
*/
public String buildOldPath(Asset inAsset)
{
if (inAsset == null || inAsset.getSourcePath() == null)
{
return null;
}
String catalogId = getCatalogId();
String path = "/" + catalogId + "/assets/" + inAsset.getSourcePath();
String suffix = "/_site.xconf";
path = path + suffix;
return path;
}
protected boolean populateAsset(Asset inAsset)
{
Element asset = null;
String path = buildXmlPath(inAsset);
ContentItem assetPage = getPageManager().getRepository().get(path);
if (!assetPage.exists())
{
return false;
}
else
{
try
{
asset = getXmlUtil().getXml(assetPage.getInputStream(), "UTF-8");
// if(asset.getName().equals("page"))
// {
// asset = asset.element("product");
// }
}
catch ( Exception ex )
{
log.debug("Could not load: " + assetPage.getPath(), ex );
return false;
}
}
if (asset == null)
{
return false;
}
boolean ok = populateAsset(inAsset, asset);
if( inAsset.getId() == null)
{
throw new OpenEditException("Id is required " + assetPage.getPath());
}
return ok;
}
protected boolean populateAsset(Asset inAsset, Element inAssetElement)
{
String name = inAssetElement.attributeValue("name");
inAsset.setName(name);
String order = inAssetElement.attributeValue("ordering");
if (order != null && order.length() > 0)
{
inAsset.setOrdering(Integer.parseInt(order));
}
String id = inAssetElement.attributeValue("id");
inAsset.setId(id);
loadCategories(inAsset, inAssetElement);
List children = inAssetElement.elements("keyword");
List<String> keywords = new ArrayList<String>();
if (children == null || children.size() > 0)
{
for (Object o: children)
{
Element keyword = (Element)o;
keywords.add(keyword.getTextTrim());
}
}
else
{
Element keywordslist = inAssetElement.element("keywords");
if (keywordslist != null)
{
keywords.add(keywordslist.getTextTrim());
}
}
inAsset.setKeywords(keywords);
for (Object o: inAssetElement.elements("property"))
{
Element prop = (Element) o;
String key = prop.attributeValue("name");
if("originalfilename".equals(key) || "primaryimagename".equals(key) || "originalattachment".equals(key))
{
key = "primaryfile";
}
inAsset.setProperty(key, prop.getTextTrim());
}
ContentItem originalPage = getPageManager().getRepository().getStub("/WEB-INF/data/" + inAsset.getCatalogId() + "/originals/" + inAsset.getSourcePath());
inAsset.setFolder(originalPage.isFolder());
loadRelatedAssets(inAsset, inAssetElement);
return true;
}
protected void loadRelatedAssets(Asset inAsset, Element inAssetConfig)
{
inAsset.clearRelatedAssets();
Element relatedAssetsElem = inAssetConfig.element("related-assets");
if (relatedAssetsElem != null)
{
for (Object o: relatedAssetsElem.elements("asset"))
{
Element relatedAssetConfig = (Element) o;
RelatedAsset related = new RelatedAsset();
related.setAssetId(inAsset.getId());
String id = relatedAssetConfig.attributeValue("id");
related.setRelatedToAssetId(id);
String type = relatedAssetConfig.attributeValue("type");
related.setType(type);
String catid = relatedAssetConfig.attributeValue("catalogid");
if (catid == null)
{
catid = getCatalogId();
}
related.setRelatedToCatalogId(catid);
inAsset.addRelatedAsset(related);
}
}
}
public void saveAsset(Asset inAsset)
{
saveAsset(inAsset, (User) null);
}
public void saveData(Data inData, User inUser)
{
saveAsset((Asset)inData, inUser);
}
public void saveAsset(Asset inAsset, User inUser)
{
Lock lock = null;
try
{
lock = getMediaArchive().getLockManager().lock(getCatalogId(), "assets/" + inAsset.getSourcePath(),"admin");
saveAsset(inAsset, inUser, lock);
}
finally
{
getMediaArchive().getLockManager().release(getCatalogId(), lock);
}
}
public void saveAsset(Asset inAsset, User inUser, Lock inLock)
{
if( inAsset.getId() == null)
{
throw new OpenEditException("Saved asset has null ID");
}
if(inAsset.getSourcePath() == null)
{
throw new OpenEditException("asset does not have a sourcepath " + inAsset);
}
try
{
// TODO: Speed check this section
// TODO: Force users to set the sourcePath if it is not set
String path = buildXmlPath(inAsset);
ContentItem output = getPageManager().getRepository().get(path);
String encoding = "UTF-8";
Document document = DocumentHelper.createDocument();
document.setRootElement(DocumentHelper.createElement("asset"));
saveAsset(inAsset, document.getRootElement());
// save it to disk
//OutputStreamItem xconf = new OutputStreamItem(path);// , new
// ElementReader(rootElement,getXmlUtil().getWriter(encoding)),
// encoding);
//xconf.setMakeVersion(false);
//getPageManager().getPageSettingsManager().saveSetting(xconf); // This
// sets
// the
// output
// stream
//OutputStream out = getPageManager().saveToStream(output);
OutputStream out = output.getOutputStream();
try
{
getXmlUtil().saveXml(document.getRootElement(), out, encoding);
}
finally
{
FileUtils.safeClose(out);
}
getCacheManager().put(toCacheId(),inAsset.getSourcePath(),inAsset);
getCacheManager().put(toCacheId(),inAsset.getId(),inAsset);
}
catch (Exception ex)
{
ex.printStackTrace();
String msg = "Saving asset " + inAsset.getSourcePath() + " failed: ";
log.error(msg + ex);
throw new OpenEditException(msg + ex, ex);
}
}
public void saveAsset(Asset inAsset, Element assetelm)
{
saveAssetAttributes(inAsset, assetelm);
// save out catalogs
saveAssetCategories(inAsset, assetelm);
// clear out any old asset properties
deleteElements(assetelm, "property");
// saves out properties
PropertyDetails details = getMediaArchive().getAssetPropertyDetails();
PropertyDetail moddetail = details.getDetail("recordmodificationdate");
if (moddetail != null )
{
String recordmod = DateStorageUtil.getStorageUtil().formatForStorage(new Date());
inAsset.setProperty("recordmodificationdate", recordmod);
}
for (Iterator iter = inAsset.getProperties().keySet().iterator(); iter.hasNext();)
{
String key = (String) iter.next();
if( key.startsWith("_"))
{
continue;
}
PropertyDetail detail = details.getDetail(key);
String value = inAsset.getProperty(key);
if (value != null && value.length() > 0)
{
value = value.trim();
Element newProperty = assetelm.addElement("property");
newProperty.addAttribute("name", key);
// newProperty.addAttribute("id", key);
if (detail != null && detail.isViewType("html"))
{
newProperty.addCDATA(value);
}
else
{
if (value.contains(" "))
{
newProperty.addCDATA(value);
}
else
{
newProperty.setText(value);
}
}
}
}
saveRelatedAssets(inAsset, assetelm);
}
protected boolean hasProperty(Element inRootElement, String inName)
{
for (Iterator iter = inRootElement.elementIterator("property"); iter.hasNext();)
{
Element element = (Element) iter.next();
String name = element.attributeValue("name");
if (inName.equals(name))
{
return true;
}
}
return false;
}
private Document loadXconfDocument(ContentItem item, String encode) throws OpenEditException, DocumentException, IOException
{
Document document;
// String url = PRODUCTS_URL_PATH + "/" +
// getAssetPathFinder().idToPath(inId) + ".html";
if (item.exists())
{
document = getXmlUtil().getXml(item.getInputStream(), encode).getDocument();
}
else
{
document = DocumentHelper.createDocument();
document.setRootElement(DocumentHelper.createElement("page"));
}
return document;
}
protected void saveAssetAttributes(Asset inAsset, Element assetelm)
{
String name = inAsset.getName();
// name = SpecialCharacter.escapeSpecialCharacters(name);
assetelm.addAttribute("name", name);
assetelm.addAttribute("id", inAsset.getId());
if (inAsset.getOrdering() > 0)
{
assetelm.addAttribute("ordering", String.valueOf(inAsset.getOrdering()));
}
saveKeywords(inAsset, assetelm);
}
protected void saveKeywords(Asset inAsset, Element inAssetElment)
{
if (inAsset.getKeywords() != null)
{
deleteElements(inAssetElment, "keywords"); // legacy
deleteElements(inAssetElment, "keyword");
for (Iterator iter = inAsset.getKeywords().iterator(); iter.hasNext();)
{
String val = (String) iter.next();
Element keywordElement = inAssetElment.addElement("keyword");
keywordElement.addCDATA(val); // This will dodge invalid
// character problems
// keywordElement.setText(val); //This may give us an exception
// with invalid characters
}
}
}
/**
* @param inAsset
* @param assetelm
*/
private void saveAssetCategories(Asset inAsset, Element assetelm)
{
// remove old catalogs
deleteElements(assetelm, "category");
// TODO: Save over the old category
List existing = new ArrayList( inAsset.getCategories() );
for (Iterator iter = existing.iterator(); iter.hasNext();)
{
Category category = (Category) iter.next();
Element cat = assetelm.addElement("category");
cat.addAttribute("id", category.getId());
if( category.getName() == null )
{
//make sure we have a recent version
inAsset.removeCategory(category);
category = getCategoryArchive().getCategory(category.getId());
if( category != null )
{
inAsset.addCategory(category);
}
}
}
}
protected void saveRelatedAssets(Asset inAsset, Element inAssetElement)
{
deleteElements(inAssetElement, "related-assets");
if (inAsset.hasRelatedAssets())
{
Element relatedAssetsElem = inAssetElement.addElement("related-assets");
for (Iterator iter = inAsset.getRelatedAssets().iterator(); iter.hasNext();)
{
RelatedAsset related = (RelatedAsset) iter.next();
Element e = relatedAssetsElem.addElement("asset");
e.addAttribute("id", related.getRelatedToAssetId());
String catid = related.getRelatedToCatalogId();
e.addAttribute("catalogid", catid);
e.addAttribute("type", related.getType());
}
}
}
protected void loadCategories(Asset inAsset, Element inAssetConfig)
{
inAsset.clearCategories();
for (Object o: inAssetConfig.elements("category"))
{
Element categoriesConfig = (Element) o;
String catid = categoriesConfig.attributeValue("id");
Category category = getCategoryArchive().getCategory(catid);
if (category == null)
{
log.debug("Could not find a category with id: " + catid);
continue;
}
inAsset.addCategory(category);
}
}
public PageManager getPageManager()
{
return fieldPageManager;
}
public void setPageManager(PageManager inPageManager)
{
fieldPageManager = inPageManager;
}
protected CategoryArchive getCategoryArchive()
{
return getMediaArchive().getCategoryArchive();
}
public XmlUtil getXmlUtil()
{
if (fieldXmlUtil == null)
{
fieldXmlUtil = new XmlUtil();
}
return fieldXmlUtil;
}
public void setXmlUtil(XmlUtil inUtil)
{
fieldXmlUtil = inUtil;
}
public boolean isUpdateExistingRecord()
{
return fieldUpdateExistingRecord;
}
public void setUpdateExistingRecord(boolean inUpdateExistingRecord)
{
fieldUpdateExistingRecord = inUpdateExistingRecord;
}
public ModuleManager getModuleManager()
{
return fieldModuleManager;
}
public void setModuleManager(ModuleManager inModuleManager)
{
fieldModuleManager = inModuleManager;
}
public MediaArchive getMediaArchive()
{
if (fieldMediaArchive == null)
{
fieldMediaArchive = (MediaArchive) getModuleManager().getBean(getCatalogId(), "mediaArchive");
}
return fieldMediaArchive;
}
@Override
public void setXmlArchive(XmlArchive inXmlArchive)
{
// TODO Auto-generated method stub
}
@Override
public void setDataFileName(String inDataFileName)
{
// TODO Auto-generated method stub
}
@Override
public void setElementName(String inSearchType)
{
// TODO Auto-generated method stub
}
@Override
public void setPathToData(String inPathToData)
{
// TODO Auto-generated method stub
}
@Override
public XmlArchive getXmlArchive()
{
// TODO Auto-generated method stub
return null;
}
@Override
public void delete(Data inData, User inUser)
{
// TODO Auto-generated method stub
}
@Override
public void saveAllData(Collection<Data> inAll,String catalogid, String inLockPrefix, User inUser)
{
for (Iterator iterator = inAll.iterator(); iterator.hasNext();)
{
Asset asset = (Asset) iterator.next();
Lock lock = null;
try
{
lock = getMediaArchive().getLockManager().lock(getCatalogId(), inLockPrefix + asset.getSourcePath(),"admin");
saveAsset(asset, inUser, lock);
}
finally
{
getMediaArchive().getLockManager().release(getCatalogId(), lock);
}
}
}
@Override
public void saveData(Data inData, User inUser, Lock inLock) {
saveAsset((Asset)inData, inUser);
// TODO Auto-generated method stub
}
}