/* * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package com.arsdigita.cms.ui; import com.arsdigita.bebop.PageState; import com.arsdigita.bebop.SimpleContainer; import com.arsdigita.domain.DomainObject; import com.arsdigita.domain.DomainObjectFactory; import com.arsdigita.domain.DomainServiceInterfaceExposer; import com.arsdigita.kernel.ui.DomainObjectSelectionModel; import com.arsdigita.persistence.DataAssociation; import com.arsdigita.persistence.DataAssociationCursor; import com.arsdigita.persistence.DataObject; import com.arsdigita.persistence.OID; import com.arsdigita.persistence.metadata.ObjectType; import com.arsdigita.persistence.metadata.Property; import com.arsdigita.util.Assert; import com.arsdigita.xml.Element; import org.apache.log4j.Logger; import java.util.HashSet; import java.util.Iterator; import java.util.Set; /** * @deprecated Use DomainObjectXMLRenderer instead * @see com.arsdigita.domain.DomainObjectXMLRenderer * * A Bebop component that takes a {@link DomainObject} and renders it * as XML. The XML can then be styled with XSL in order to insert the * object's properties into the page. *
* The XML generated by this component will follow the following pattern: *
* ** <cms:domainObjectRenderer oid="main_object_oid"> * <attributeOne>foo</attributeOne> * <attributeTwo>bar</attributeTwo> * <roleReferenceOne oid="child_object_oid"> * <otherAttribute>baz<otherAttribute> * ... * </roleReferenceOne> * ... * </cms:domainObjectRenderer> *
* The object which the DomainObjectRenderer should render is
* supplied by a {@link DomainObjectSelectionModel}. Thus, an
* {@link com.arsdigita.kernel.ui.ACSObjectSelectionModel}, an {@link com.arsdigita.cms.ItemSelectionModel}, or any other
* subclass of {@link DomainObjectSelectionModel} can be used. For example,
*
*
* String type = "com.arsdigita.kenel.User";
* ACSObjectSelectionModel model = new ACSObjectSelectionModel (
* type, type, "item_id");
* page.addGlobalStateParam(model.getStateParameter());
* page.add(new DomainObjectRenderer(model));
*
*
* Advanced notes:
*
* The {@link #setDepth} method controls how detailed the XML will be.
* At depth 1, only the attributes of the main object will be rendered.
* At depth 2, the attributes of the main object as well as the children
* of the main object will be rendered. At depth 3, the children as well as
* the grandchildren will be rendered... and so on. The default depth is 2.
*
* The XML-generating code is aware of loops. Any sub-object which has already
* been rendered in XML will be rendered as a stub. For example:
*
* ...
* <textAsset oid="[com.arsdigita.cms.TextAsset:42]"
* <content>I am the text</content>
* <parent oid="[com.arsdigita.cms.contenttypes.GenericPage:13]" />
* ...
* </textAsset>
* ...
*
*
* Null values are not rendered at all in the XML.
*
* @author Stanislav Freidin
* @version $Id: DomainObjectRenderer.java 1940 2009-05-29 07:15:05Z terry $
*
*/
public class DomainObjectRenderer extends SimpleContainer {
private DomainObjectSelectionModel m_model;
private int m_depth;
public final static String CMS_XML_NS = "http://www.arsdigita.com/cms/1.0";
private static final Logger s_log = Logger.getLogger(DomainObjectRenderer.class);
/**
* Construct a new DomainObjectRenderer.
*
* @param model Supplies the domain object to be rendered
*/
public DomainObjectRenderer(DomainObjectSelectionModel model) {
this(model, 2);
}
/**
* Construct a new DomainObjectRenderer.
*
* @param model Supplies the domain object to be rendered
* @param depth The object traversal will be limited to this depth
*/
public DomainObjectRenderer(DomainObjectSelectionModel model, int depth) {
super();
m_model = model;
m_depth = depth;
}
/**
* Return the current depth. The depth is a measure of how detailed
* the generated XML will be.
*/
public int getDepth() {
return m_depth;
}
/**
* Set a new depth. The depth is a measure of how detailed
* the generated XML will be.
*/
public void setDepth(int depth) {
Assert.isUnlocked(this);
m_depth = depth;
}
/**
* Return the current selection model, which will supply the domain object
*/
public DomainObjectSelectionModel getSelectionModel() {
return m_model;
}
/**
* Set the selection model which will supply the domain object
* @pre model != null
*/
public void setSelectionModel(DomainObjectSelectionModel model) {
Assert.isUnlocked(this);
m_model = model;
}
/**
* Return the current domain object
*
* @param state the request-specific page state
*/
public DomainObject getDomainObject(PageState state) {
return m_model.getSelectedObject(state);
}
/**
* Select a new domain object
*
* @param state the request-specific page state
* @param obj the {@link DomainObject} which will be selected into the
* selection model
*/
public void setDomainObject(PageState state, DomainObject obj) {
m_model.setSelectedObject(state, obj);
}
/**
* Render the specified object.
*
* @param obj the DataObject to be rendered
* @param elementName the name for the current element
* @param elementNameSpace the namespace for the current element
* @param depthRemaining if 0, render the object stub and return. Otherwise,
* recurse
* @param visited a set of all previously visited objects. If the object is
* already in the set, render the object stub and return.
* @return the generated XML element
*/
protected Element generateXML(
DomainObject obj, String elementName, String elementNameSpace,
int depthRemaining, Set visited
) {
Element node = new Element(elementName, elementNameSpace);
OID oid = obj.getOID();
node.addAttribute("oid", oid.toString());
// Check for termination
if(depthRemaining < 1) return node;
// Check for duplicates
if(visited.contains(oid)) return node;
// Render
visited.add(oid);
ObjectType type = oid.getObjectType();
for(Iterator i = type.getProperties(); i.hasNext(); ) {
Property prop = (Property) i.next();
String propName = prop.getName();
Object propValue = null;
// This is a hack to get around other hacks in CMS.
// The hacks deal with retrieving DataCollections of objects;
// for example,
// association {
// ContentType[0..n] allContentTypes;
// ContentType[0..n] allContentTypes2;
//
// retrieve allContentTypes {
// ...
// }
// }
// Trying to traverse this association will cause an error:
// com.arsdigita.persistence.PersistenceException: Unable to retrieve
// the associatedContentSectionsForType property of object type
// ContentType because there is no event handler defined for the
// retrieve associatedContentSectionsForType event.
try {
propValue = DomainServiceInterfaceExposer.
get(obj,propName);
} catch (Exception e) {
s_log.error("Ignoring some random exception", e);
// ignore
}
if(propValue != null) {
// Render role references
if(prop.isRole()) {
int newDepth = depthRemaining - 1;
if(propValue instanceof DataObject) {
// 0..1 or 1..1
node.addContent
(generateXML
(DomainObjectFactory.newInstance
((DataObject)propValue),
propName,
"",
newDepth,
visited));
} else if(propValue instanceof DataAssociation) {
// 0..N
DataAssociationCursor daCursor =
((DataAssociation)propValue).getDataAssociationCursor();
while (daCursor.next()) {
node.addContent
(generateXML
(DomainObjectFactory.newInstance
(daCursor.getDataObject()),
propName,
"",
newDepth,
visited));
}
} else {
// Unknown property value type - do nothing
}
} else {
// Render scalar attributes
Element child = new Element(propName);
child.setText(propValue.toString());
node.addContent(child);
}
}
}
return node;
}
/**
* Generate XML for the domain object supplied by the
* selection model.
*
* @return the generated element
*/
public Element generateXMLElement(PageState state) {
DomainObject obj = getDomainObject(state);
if(obj != null) {
return generateXML(
obj, "cms:domainObjectRenderer", CMS_XML_NS,
getDepth(), new HashSet());
} else {
return null;
}
}
/**
* Generate XML when you don't have a PageState, only the item
*
* @param obj the item to render
*
**/
public Element generateXMLElement(DomainObject obj) {
return generateXML(
obj, "cms:domainObjectRenderer", CMS_XML_NS,
getDepth(), new HashSet());
}
/**
* Generate XML for the domain object supplied by the
* selection model.
*/
public void generateXML(PageState state, Element parent) {
Element e = generateXMLElement(state);
if(e != null)
parent.addContent(e);
}
}