/* * Created on Oct 3, 2004 */ package org.openedit.entermedia.xmldb; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.entermedia.cache.CacheManager; import org.openedit.entermedia.Category; import org.openedit.entermedia.CategoryArchive; import org.openedit.repository.filesystem.StringItem; import com.openedit.OpenEditException; import com.openedit.OpenEditRuntimeException; import com.openedit.config.Configuration; import com.openedit.config.XMLConfiguration; import com.openedit.page.Page; import com.openedit.page.manage.PageManager; import com.openedit.util.PathUtilities; import com.openedit.util.XmlUtil; /** * @author cburkey * */ public class XmlCategoryArchive extends BaseXmlArchive implements CategoryArchive { private static final Log log = LogFactory.getLog(XmlCategoryArchive.class); protected Category fieldRootCatalog; protected PageManager fieldPageManager; protected XmlUtil fieldXmlUtil; protected CacheManager fieldCacheManager; protected Category NULL = new Category(); public XmlCategoryArchive() { log.info("created"); } public CacheManager getCacheManager() { return fieldCacheManager; } public void setCacheManager(CacheManager inCacheManager) { fieldCacheManager = inCacheManager; } public List listAllCategories() { List all = new ArrayList(); addCategories(all, getRootCategory()); return all; } /** * @param inAll * @param inRootCatalog */ private void addCategories(List inAll, Category inRootCatalog) { // TODO Auto-generated method stub inAll.add(inRootCatalog); for (Iterator iter = inRootCatalog.getChildren().iterator(); iter.hasNext();) { Category child = (Category) iter.next(); addCategories(inAll, child); } } public Category getCategory(String inCategory) { try { if(inCategory == null){ return null; } Category cat = (Category) getCacheManager().get(cacheId(),inCategory); if( cat == null) { //search twice. Once follow the id path cat = findChildByPath(getRootCategory(), inCategory ); //second time search everyone if( cat == null) { cat = findChild(getRootCategory(),inCategory); } if( cat == null) { cat = NULL; } getCacheManager().put(cacheId(), inCategory, cat); } if( cat == NULL) { return null; } return cat; } catch (Exception ex) { throw new OpenEditRuntimeException(ex); } } protected Category findChildByPath(Category inRoot, String inId) { String test = inRoot.getId(); if (test.equals(inId)) { return inRoot; } for (Iterator iterator = inRoot.getChildren().iterator(); iterator.hasNext();) { Category child = (Category)iterator.next(); if( child.getId().startsWith(inId)) { child = findChild(child, inId); if (child != null) { return child; } } } return null; } public Category findChild(Category inRoot, String inId) { String test = inRoot.getId(); if (test.equals(inId)) { return inRoot; } for (Iterator iterator = inRoot.getChildren().iterator(); iterator.hasNext();) { Category child = (Category)iterator.next(); child = findChild(child, inId); if (child != null) { return child; } } return null; } protected String cacheId() { return getCatalogId() + "categoryarchive"; } public Category getCategoryByName(String inCategoryName) { List catalogs = listAllCategories(); for (Iterator iter = catalogs.iterator(); iter.hasNext();) { Category catalog = (Category) iter.next(); if (catalog.getName().equals(inCategoryName)) { return catalog; } } return null; } public Category getRootCategory() { if (fieldRootCatalog == null) { reloadCategories(); } return fieldRootCatalog; } public void deleteCategory(Category inCategory) { if (getRootCategory().getId().equals(inCategory.getId())) { setRootCategory(new Category("index", "Index")); } else { deleteAll(inCategory); if (inCategory.getParentCategory() != null) { inCategory.getParentCategory().removeChild(inCategory); } } getCacheManager().remove(cacheId(),inCategory.getId()); saveAll(); } protected void deleteAll(Category inCategory) { for (Iterator iter = inCategory.getChildren().iterator(); iter.hasNext();) { Category child = (Category) iter.next(); child.setParentCategory(null); // to prevent // ConcurrentModificationException deleteAll(child); } } public void clearCategories() { getCacheManager().clear(cacheId()); fieldRootCatalog = null; } public void setRootCategory(Category inRootCatalog) { fieldRootCatalog = inRootCatalog; if (fieldRootCatalog != null) { // This is not used much anymore String home = fieldRootCatalog.getProperty("categoryhome"); if (home == null) { fieldRootCatalog.setProperty("categoryhome", "/" + getCatalogId() + "/categories/"); } cacheCategory(fieldRootCatalog); } } protected String listCatalogXml() { return "/WEB-INF/data/" + getCatalogId() + "/categories.xml"; } /* * (non-javadoc) * * @see com.openedit.store.CatalogArchive#saveCatalogs() */ public synchronized void saveAll() { try { Page catalogFile = getPageManager().getPage(listCatalogXml()); Element root = createElement(getRootCategory()); // lets write to a stream //TODO: Lock the path OutputStream out = getPageManager().saveToStream(catalogFile); getXmlUtil().saveXml(root, out, catalogFile.getCharacterEncoding()); } catch (Exception e) { throw new OpenEditException(e); } } /** * @param inRootCatalog * @return */ protected Element createElement(Category inRootCatalog) throws OpenEditException { Element child = DocumentHelper.createElement("catalog"); child.addAttribute("id", inRootCatalog.getId()); child.addAttribute("name", inRootCatalog.getName()); if (inRootCatalog.getShortDescription() != null) { child.addElement("shortdescription").setText(inRootCatalog.getShortDescription()); } if (inRootCatalog.getDescription() != null) { saveLongDescription(inRootCatalog); } // add any other attributes we might have for (Iterator iter = inRootCatalog.getProperties().keySet().iterator(); iter.hasNext();) { String id = (String) iter.next(); if (id != null && !"id".equals(id) && !"name".equals(id)) { Element prop = child.addElement("property"); prop.addAttribute("id", id); prop.setText(inRootCatalog.getProperty(id)); } } saveRelatedCategories(inRootCatalog, child); for (Iterator iter = inRootCatalog.getChildren().iterator(); iter.hasNext();) { Category subcatalog = (Category) iter.next(); Element newchild = createElement(subcatalog); child.add(newchild); } return child; } protected void saveLongDescription(Category inCategory) { try { Page fulldesc = getPageManager().getPage("/" + getCatalogId() + "/categories/" + inCategory.getId() + ".html"); if (!fulldesc.exists()) { String desc = inCategory.getDescription(); if (desc == null || desc.trim().length() == 0) { return; } StringItem item = new StringItem(fulldesc.getPath(), desc, "UTF-8"); fulldesc.setContentItem(item); getPageManager().putPage(fulldesc); } } catch (OpenEditException oee) { throw new OpenEditException(oee); } } public synchronized void reloadCategories() { getCacheManager().clear(cacheId()); try { Page catalogFile = getPageManager().getPage(listCatalogXml()); if (catalogFile.exists()) { try { Element rootE = getXmlUtil().getXml(catalogFile.getReader(), catalogFile.getCharacterEncoding()); XMLConfiguration rootConfig = new XMLConfiguration(); rootConfig.populate(rootE); Category root = createCatalog(rootConfig); setRootCategory(root); } catch (Exception ex) { ex.printStackTrace(); throw new OpenEditException(ex); } } else { log.error("No catalog file found " + catalogFile.getPath()); Category root = new Category(); root.setId("index"); root.setName("Index"); setRootCategory(root); } } catch (Exception ex) { throw new OpenEditException(ex); } } /** * @param inRootElement * @return */ protected Category createCatalog(Configuration inRootConfig) throws OpenEditException { Category cat = new Category(); cat.setId(inRootConfig.getAttribute("id")); if (cat.getId() == null) { log.error("Corrupt catalog with no id"); } cat.setName(inRootConfig.getAttribute("name")); for (Iterator iter = inRootConfig.getAttributeNames().iterator(); iter.hasNext();) { String attrName = (String) iter.next(); if (!attrName.equals("id") && !attrName.equals("name")) { cat.setProperty(attrName, inRootConfig.getAttribute(attrName)); } } // Also supports property for (Iterator iter = inRootConfig.getChildren("property").iterator(); iter.hasNext();) { Configuration config = (Configuration) iter.next(); cat.setProperty(config.getAttribute("id"), config.getValue()); } String shortdesc = inRootConfig.getChildValue("shortdescription"); cat.setShortDescription(shortdesc); loadRelatedCategoryIds(cat, inRootConfig); for (Iterator iter = inRootConfig.getChildren("catalog").iterator(); iter.hasNext();) { Configuration config = (Configuration) iter.next(); cat.addChild(createCatalog(config)); } return cat; } protected void loadRelatedCategoryIds(Category inCategory, Configuration inAssetConfig) { inCategory.clearRelatedCategoryIds(); Configuration relatedAssetsElem = inAssetConfig.getChild("related-categories"); if (relatedAssetsElem != null) { for (Iterator iter = relatedAssetsElem.getChildIterator("category"); iter.hasNext();) { Configuration relatedProdConfig = (Configuration) iter.next(); inCategory.addRelatedCategoryId(relatedProdConfig.getAttribute("id")); } } Configuration linkedToElem = inAssetConfig.getChild("linkedtocategory"); if (linkedToElem != null) { inCategory.setLinkedToCategoryId(linkedToElem.getAttribute("id")); } else { inCategory.setLinkedToCategoryId(null); } } protected void saveRelatedCategories(Category inCategory, Element inCategoryElement) { deleteElements(inCategoryElement, "related-categories"); if (inCategory.getRelatedCategoryIds().size() > 0) { Element relatedAssetsElem = inCategoryElement.addElement("related-categories"); for (Iterator iter = inCategory.getRelatedCategoryIds().iterator(); iter.hasNext();) { String relatedAssetId = (String) iter.next(); relatedAssetsElem.addElement("category").addAttribute("id", relatedAssetId); } } deleteElements(inCategoryElement, "linkedtocategory"); if (inCategory.getLinkedToCategoryId() != null) { Element linkedToElem = inCategoryElement.addElement("linkedtocategory"); if (linkedToElem != null) { linkedToElem.addAttribute("id", inCategory.getLinkedToCategoryId()); } } } public PageManager getPageManager() { return fieldPageManager; } public void setPageManager(PageManager inPageManager) { fieldPageManager = inPageManager; } public void saveCategory(Category inCategory) { if (inCategory.getParentCategory() == null && !inCategory.getId().equals(getRootCategory().getId())) // don't want to make child of the root cat if it is the root cat { addChild(inCategory); } else { cacheCategory(inCategory); } saveAll(); } public Category cacheCategory(Category inCat) { getCacheManager().put(cacheId(),inCat.getId(), inCat); for (Iterator iterator = inCat.getChildren().iterator(); iterator.hasNext();) { Category child = (Category) iterator.next(); cacheCategory(child); } return inCat; } /** * @deprecated use saveCategory */ public void saveCatalog(Category inCategory) { saveCategory(inCategory); } public Category addChild(Category inCatalog) { getRootCategory().addChild(inCatalog); cacheCategory(inCatalog); return inCatalog; } public XmlUtil getXmlUtil() { return fieldXmlUtil; } public void setXmlUtil(XmlUtil inXmlUtil) { fieldXmlUtil = inXmlUtil; } public Category createCategoryTree(String inPath) throws OpenEditException { Category created = createCategoryTree(inPath, null); return created; } public Category createCategoryTree(String inPath, List inNames) throws OpenEditException { if (inPath.length() < 1) { return getRootCategory(); } if (inPath.endsWith("/")) { inPath = inPath.substring(0, inPath.length() - 1); } String catid = createCategoryId(inPath); Category child = getCategory(catid); if (child == null) { // make sure we have a parent to put it in child = new Category(); child.setId(catid); if (inNames != null) { child.setName((String) inNames.remove(inNames.size() - 1)); } else { child.setName(PathUtilities.extractFileName(inPath)); } String parentPath = PathUtilities.extractDirectoryPath(inPath); if (parentPath == null || parentPath == "/") { return child; } Category inParentCategory = createCategoryTree(parentPath, inNames); inParentCategory.addChild(child); List children = inParentCategory.getChildren(); Collections.sort(children, new Comparator() { public int compare(Object o1, Object o2) { Category c1 = (Category)o1, c2 = (Category)o2; return c1.getName().compareTo(c2.getName()); } }); inParentCategory.setChildren(children); saveAll(); //This is slow. cacheCategory(child); } return child; } protected String createCategoryId(String inPath) { // subtract the start /store/assets/stuff/more -> stuff_more if (inPath.length() < 0) { return "index"; } if (inPath.startsWith("/")) { inPath = inPath.substring(1); } inPath = inPath.replace('/', '_'); String id = PathUtilities.extractId(inPath, true); return id; } /** * * @param inCategoryIds space separated list of category lists * @return */ public Collection getCategoriesByIds(String inCategoryIds) { if(inCategoryIds == null) { return null; } String[] categoryids = inCategoryIds.split(" "); List categories = new ArrayList(); for (int i = 0; i < categoryids.length; i++) { Category cat = getCategory(categoryids[i]); if (cat != null) { categories.add(cat); } } return categories; } public Category createNewCategory(String inLabel) { String id = createCategoryId(inLabel); Category cat = new Category(id, inLabel); return cat; } }