Removed deprecated classes CategoryPurpose, part 1.

git-svn-id: https://svn.libreccm.org/ccm/trunk@2654 8810af33-2d31-482b-a856-94f89814c4df
master
pb 2014-05-26 15:51:14 +00:00
parent aa06c3e866
commit fca3bbaf8a
19 changed files with 310 additions and 100 deletions

View File

@ -19,59 +19,70 @@
package com.arsdigita.cms.contentitem;
import com.arsdigita.categorization.Category;
import com.arsdigita.categorization.CategoryPurpose;
import com.arsdigita.categorization.CategoryCollection;
// import com.arsdigita.categorization.CategoryPurpose;
//import com.arsdigita.categorization.CategoryCollection;
import com.arsdigita.cms.ContentItem;
import com.arsdigita.cms.ContentPage;
import com.arsdigita.cms.ContentSection;
import com.arsdigita.cms.Folder;
import org.apache.log4j.Logger;
import java.util.Iterator;
//import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
/** Parses and XML file definition of content items in a folder.
/**
* Parses and XML file definition of content items in a folder.
* the XML configuration should look like this:
*/
public class ContentPageHelper extends ContentBundleHelper {
private static final Logger s_log = Logger
.getLogger(ContentPageHelper.class);
private Category m_category;
private List m_categories = new LinkedList();
private Random m_random;
private static final Logger s_log = Logger.getLogger(ContentPageHelper.class);
/**
* Constructor.
*
* @param section
*/
public ContentPageHelper(ContentSection section) {
super(section);
m_category = section.getRootCategory();
// Look for categories CategoryPurpose.NAVIGATION
CategoryPurpose nav = CategoryPurpose
.getPurpose(CategoryPurpose.NAVIGATION);
if (null != nav) {
s_log.debug("purpose key " + nav.getKey() + " name " + nav.getName());
// CategoryPurpose is deprecated and not used anymore
// CategoryPurpose nav = CategoryPurpose
// .getPurpose(CategoryPurpose.NAVIGATION);
// if (null != nav) {
// s_log.debug("purpose key " + nav.getKey() + " name " + nav.getName());
//
// Iterator navs = nav.getCategories().iterator();
//
// while (navs.hasNext()) {
// Category cat = (Category) navs.next();
// CategoryCollection scions = cat.getDescendants();
// while ( scions.next() ) {
// m_categories.add(scions.getCategory());
// }
// scions.close();
// }
//
// }
Iterator navs = nav.getCategories().iterator();
while (navs.hasNext()) {
Category cat = (Category) navs.next();
CategoryCollection scions = cat.getDescendants();
while ( scions.next() ) {
m_categories.add(scions.getCategory());
}
scions.close();
}
}
if ( m_categories.size() == 0 ) {
if ( m_categories.isEmpty() ) {
s_log.debug("Category list is empty, adding root");
m_categories.add(m_category);
}
m_random = new Random();
}
@Override
public void setBodyText(String body) {
// do nothing
}
@ -85,6 +96,7 @@ public class ContentPageHelper extends ContentBundleHelper {
}
}
@Override
public ContentItem create() {
return createContentPage();
}
@ -104,6 +116,7 @@ public class ContentPageHelper extends ContentBundleHelper {
// }
// Save everything at the very end
@Override
public void save() {
super.save();
Category cat = getCategory();
@ -112,6 +125,7 @@ public class ContentPageHelper extends ContentBundleHelper {
}
/** Assigning pages to random categories */
@Override
public ContentItem cloneItem ( String name, Folder parent, boolean save ) {
ContentPage page = (ContentPage)super.cloneItem(name, parent, save);
page.save();

View File

@ -30,6 +30,18 @@ import org.apache.log4j.Logger;
* @author <a href="mailto:jorris@redhat.com">Jon Orris</a>
*
*/
// ///////////////////////////////////////////////////////////
//
// Parent class ContentPageHelper looks for CategoryPurposes
// to ensure that at least one category exists.
// CategoryPurpose is no longer used so that never any
// CategoryPurpose exists.
//
// //////////////////////////////////////////////////////////
public class GenericArticleHelper extends ContentPageHelper {
private static final Logger s_log = Logger.getLogger(GenericArticleHelper.class);

View File

@ -106,6 +106,7 @@ import org.xml.sax.helpers.DefaultHandler;
*
*/
public class XMLContentItemHandler extends DefaultHandler {
private static final Logger s_log
= Logger.getLogger(XMLContentItemHandler.class);
@ -132,7 +133,6 @@ public class XMLContentItemHandler extends DefaultHandler {
* @param section the ContentSection where the items will be
* created
*/
public XMLContentItemHandler(ContentSection section) {
super();
s_log.debug(XMLContentItemHandler.class.getName());
@ -142,6 +142,13 @@ public class XMLContentItemHandler extends DefaultHandler {
}
/**
*
* @param uri
* @param name
* @param qName
* @param atts
*/
@Override
public void startElement( String uri, String name,
String qName, Attributes atts) {
@ -227,6 +234,12 @@ public class XMLContentItemHandler extends DefaultHandler {
}
}
/**
*
* @param ch
* @param start
* @param length
*/
@Override
public void characters(char[] ch,
int start,
@ -235,6 +248,12 @@ public class XMLContentItemHandler extends DefaultHandler {
m_body = new String(ch, start, length);
}
/**
*
* @param uri
* @param name
* @param qName
*/
@Override
public void endElement( String uri, String name,
String qName) {
@ -314,11 +333,18 @@ public class XMLContentItemHandler extends DefaultHandler {
}
} else {
s_log.warn("Using default ContentItemHelper");
// Might be a typo. All in this class is about items!
// XXX: Check if ContentItemHelper is better.
return new ContentPageHelper(m_section);
// return new ContentItemHelper(m_section);
}
}
/**
*
*/
public ContentType getContentType(String typeName)
throws UncheckedWrapperException {
ContentType type = null;
@ -342,6 +368,12 @@ public class XMLContentItemHandler extends DefaultHandler {
}
// Utilities
/**
*
* @param name
* @return
*/
private String validateTitle(String name) {
Perl5Util util = new Perl5Util();
String pattern = "/[^A-Za-z_0-9\\-]+ /";
@ -468,13 +500,12 @@ public class XMLContentItemHandler extends DefaultHandler {
* @param child the xmlContentItem to clone
* @param parent the folder to attach all the new children to
*/
private void autoCloneChild ( xmlContentItem child, Folder parent ) {
final int numClone = child.getHelperClass().getCloneCount();
private void autoCloneChild ( xmlContentItem child,
Folder parent ) {
final int numClone = child.getHelperClass()
.getCloneCount();
for ( int i=1; i<numClone; i++ ) {
child.clone (
i,
parent,
true );
child.clone ( i,parent,true );
}
}
@ -517,7 +548,12 @@ public class XMLContentItemHandler extends DefaultHandler {
}
/**
*
*/
private class FolderHelper extends ContentItemHelper {
/** */
int m_treeDepth;
public FolderHelper(ContentSection section) {
@ -534,6 +570,7 @@ public class XMLContentItemHandler extends DefaultHandler {
return m_treeDepth;
}
@Override
public ContentItem createContentItem ( boolean save ) {
s_log.warn("creating folder");
Folder folder = (Folder)super.createContentItem( false );
@ -545,6 +582,7 @@ public class XMLContentItemHandler extends DefaultHandler {
return folder;
}
@Override
public ContentItem cloneItem ( String name, Folder parent, boolean save ) {
Folder folder= (Folder)super.cloneItem(name, parent, save);
folder.setLabel(folder.getName());
@ -750,9 +788,7 @@ public class XMLContentItemHandler extends DefaultHandler {
int cloneNumber,
Folder parent,
boolean save,
boolean replicate
)
{
boolean replicate ) {
// clone and set associations here as well
if ( replicate ) {
s_log.debug ( "About to replicate: "

View File

@ -23,6 +23,15 @@ import com.arsdigita.categorization.CategoryPurpose;
import java.util.Iterator;
// /////////////////////////////////////////////////////////////
// Construct CategoryPurpose is deprecated and no longer used.
// Temporarly retained for easy reference until refactoring completed.
// /////////////////////////////////////////////////////////////
/**
* A {@link ListModel} that iterates over categories via an iterator
*/

View File

@ -117,10 +117,12 @@ public class CategorizedObject {
* @param purposeKey the Integer key for the desired CategoryPurpose
* @return a collection of categories that this object is classified under.
* @throws DataObjectNotFoundException
* @deprecated the notion of "category purposes" has been deprecated. Use
* @ deprecated the notion of "category purposes" has been deprecated. Use
* the use-context-based API, as explained in {@link Category}.
**/
public Collection getParentCategories(String purposeKey) {
// Construct CategoryPurpose is deprecated and no longer used.
// Temporarly retained for easy reference until refactoring completed.
/* public Collection getParentCategories(String purposeKey) {
Iterator parents = getParentCategories().iterator();
Collection filteredParents = new LinkedList();
while (parents.hasNext()) {
@ -148,7 +150,7 @@ public class CategorizedObject {
}
return filteredParents;
}
} */
/**
* Gets the default parent category.

View File

@ -42,12 +42,14 @@ import com.arsdigita.util.Assert;
import com.arsdigita.util.HierarchyDenormalization;
import com.arsdigita.util.StringUtils;
import com.arsdigita.util.UncheckedWrapperException;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;
import org.apache.log4j.Logger;
/**
@ -865,44 +867,55 @@ public class Category extends ACSObject {
}
/**
* @deprecated use the "use context" APIs instead
* @ deprecated use the "use context" APIs instead
* (specifically #getRootForObject(ACSObject, String) here)
*
*/
public Collection getPurposes() {
DataAssociationCursor purposeCur = ((DataAssociation) get(PURPOSES)).
cursor();
Collection purposes = new LinkedList();
while (purposeCur.next()) {
CategoryPurpose cp = (CategoryPurpose) DomainObjectFactory.
newInstance(purposeCur.getDataObject());
purposes.add(cp);
}
return purposes;
}
// No longer used anywhere in the Code. Temporarily retained for easy reference
// until the process of migrating Terms into Categorization is
// completed.
// public Collection getPurposes() {
// DataAssociationCursor purposeCur = ((DataAssociation) get(PURPOSES)).
// cursor();
// Collection purposes = new LinkedList();
// while (purposeCur.next()) {
// CategoryPurpose cp = (CategoryPurpose) DomainObjectFactory.
// newInstance(purposeCur.getDataObject());
// purposes.add(cp);
// }
// return purposes;
// }
/**
* Adds the specified purpose to this category.
*
* @param purpose The purpose
*
* @deprecated use the "use context" APIs instead
* @ deprecated use the "use context" APIs instead
* (specifically setRootForObject(ACSObject, Category,String))
*
*/
public void addPurpose(CategoryPurpose purpose) {
add(PURPOSES, purpose);
}
// No longer used anywhere in the Code. Temporarily retained for easy reference
// until the process of migrating Terms into Categorization is
// completed.
// public void addPurpose(CategoryPurpose purpose) {
// add(PURPOSES, purpose);
// }
/**
* Removes the specified purpose from this category.
*
* @param purpose the purpose
*
* @deprecated use the "use context" APIs instead
* @ deprecated use the "use context" APIs instead
*
*/
public void removePurpose(CategoryPurpose purpose) {
remove(PURPOSES, purpose);
}
// No longer used anywhere in the Code. Temporarily retained for easy reference
// until the process of migrating Terms into Categorization is
// completed.
// public void removePurpose(CategoryPurpose purpose) {
// remove(PURPOSES, purpose);
// }
public void setDefaultAncestors(Category defaultParent) {
String value;
@ -2164,9 +2177,12 @@ public class Category extends ACSObject {
/**
* A shortcut for calling {@link #setRootForObject(ACSObject, Category,
* String)} with the null context.
* String)} with the null context. A null context is used as default
* context. Currently there MUST a default context exist for each pair of
* ACSObject - RootCategory (i.e. with a null context).
*
* @see #setRootForObject(ACSObject, Category, String)
*
* @param object the object to own the root category
* @param root the root category for the object
*/
@ -2192,11 +2208,12 @@ public class Category extends ACSObject {
* should have no parents. This method does not check if this is indeed the
* case.</p>
*
* @see #setRootForObject(ACSObject, Category, String)
* @param object the object to own the root category
* @param root the root category for the object
* @param context
*/
public static void setRootForObject(ACSObject acsObj, Category rootCat,
public static void setRootForObject(ACSObject acsObj,
Category rootCat,
String context) {
DataCollection rootCats = getRootCategoriesAssoc(acsObj);

View File

@ -44,7 +44,7 @@ import com.arsdigita.persistence.OID;
import java.util.HashSet;
/**
* abstract form for assigning categories to acs_objects. The assigned
* Abstract form for assigning categories to acs_objects. The assigned
* categories are those specified by the category widget, which is
* retrieved by the concrete subclass' implementation of getCategoryWidget.
*
@ -59,8 +59,8 @@ import java.util.HashSet;
*
*
*/
// this class has been abstracted out from the original cms specific category form
// in ccm-cms
// this class has been abstracted out from the original cms specific
// category form in ccm-cms
public abstract class ACSObjectCategoryForm extends Form {
private Widget m_category;

View File

@ -47,6 +47,7 @@ import com.arsdigita.util.UncheckedWrapperException;
*/
public class Domain extends ObservableDomainObject {
@Override
public void delete() throws PersistenceException {
Category model = getModel();
super.delete();
@ -79,6 +80,7 @@ public class Domain extends ObservableDomainObject {
super(dobj);
}
@Override
public void initialize() {
super.initialize();
@ -112,6 +114,7 @@ public class Domain extends ObservableDomainObject {
Category model = new Category();
model.setAbstract(true);
domain.set(MODEL, model);
domain.setURL(url);
@ -124,7 +127,8 @@ public class Domain extends ObservableDomainObject {
}
/**
* Retrieve a domain based on its unique key
* Retrieve a domain based on its unique key.
*
* @param key the unique key of the domain
* @return the domain corresponding to the key
* @throws DataObjectNotFoundException if no matching domain is found
@ -147,7 +151,8 @@ public class Domain extends ObservableDomainObject {
}
/**
* Finds a domain based on its url
* Finds a domain based on its url.
*
* @param url the location of the domain
* @return the domain corresponding to the url
* @throws DataObjectNotFoundException if no matching domain is found
@ -239,6 +244,10 @@ public class Domain extends ObservableDomainObject {
}
/**
* Sets the unique key for this domain.
* @return this domain's unique key
*/
private void setKey(String key) {
Assert.exists(key, String.class);
set(KEY, key);
@ -418,7 +427,8 @@ public class Domain extends ObservableDomainObject {
}
/**
* Highly experimental. Don't use this
* Highly experimental. Don't use this.
* PB (2014) obviously outdated. Used in admin ui.
*/
public DomainCollection getUseContexts() {
DataCollection objs = SessionManager.getSession()
@ -452,6 +462,7 @@ public class Domain extends ObservableDomainObject {
/**
* Ensure that the domain's terms are orphaned.
*/
@Override
protected void beforeDelete() {
Category category = getModel();
DeleteCheckObserver.observe( category );

View File

@ -44,27 +44,49 @@ public class Term extends ACSObject {
private static final Logger s_log = Logger.getLogger(Term.class);
// PDF stuff
/** Object type of the associated PDL modell */
public static final String BASE_DATA_OBJECT_TYPE =
"com.arsdigita.london.terms.Term";
/** PDL property to store the unique ID, usually specified by the (formal)
* taxanomie. May be choosen arbitrarily if no formal taxonimie
* is in use. */
public static final String UNIQUE_ID = "uniqueID";
/** PDL property to store whether the term is to be included in the AtoZ
* list of categories. */
public static final String IN_ATOZ = "inAtoZ";
/** PDL property to store the url shortcut for the domain this term is
* part of.*/
public static final String SHORTCUT = "shortcut";
/** PDL property to store the domain this term is belonging to. */
public static final String DOMAIN = "domain";
/** PDL property to store the category used to store the generic
* properties (e.g. name, description, etc) this term. */
public static final String MODEL = "model";
/** Handle to the models (category) name value */
public static final String NAME = MODEL + "." + Category.NAME;
/** Handle to the models (category) description value */
public static final String DESCRIPTION = MODEL + "." + Category.DESCRIPTION;
/**
* Contructor.
*/
Term() {
this(BASE_DATA_OBJECT_TYPE);
}
/**
* Contructor.
*/
protected Term(String type) {
super(type);
}
/**
* Contructor, creating a domain object from the specified data object.
*/
Term(DataObject dobj) {
super(dobj);
}
@ -83,6 +105,7 @@ public class Term extends ACSObject {
/**
* Creates a new term within a domain. All
* parameters are required except for shortcut
*
* @param uniqueID the unique identifier for the term
* @param name the name of the term
* @param inAtoZ whether it is relevant for an A-Z listing
@ -140,6 +163,11 @@ public class Term extends ACSObject {
}
/**
* Sets the unique ID
*
* @param uniqueID
*/
private void setUniqueID(String uniqueID) {
Assert.exists(uniqueID, String.class);
set(UNIQUE_ID, uniqueID);
@ -153,7 +181,9 @@ public class Term extends ACSObject {
}
/**
* Updates the name of this term
* Updates the name of this term just by using the underlying
* model (category core service).
*
* @param name the term's new name
*/
public void setName(String name) {
@ -163,7 +193,9 @@ public class Term extends ACSObject {
}
/**
* Retrieves the name of this term
* Retrieves the name of this term just by retrieving it from the
* underlying model (category service).
*
* @return the name of the term
*/
public String getName() {
@ -171,7 +203,9 @@ public class Term extends ACSObject {
}
/**
* Updates the description of this term
* Updates the description of this term just by using (delegating) to the
* underlying model (category core service).
*
* @param description the term's new description
*/
public void setDescription(String description) {
@ -180,7 +214,8 @@ public class Term extends ACSObject {
}
/**
* Retrieves the description of this term
* Retrieves the description of this term just by using (delegate) to the
* underlying model (category core service).
* @return the description of the term
*/
public String getDescription() {
@ -189,7 +224,7 @@ public class Term extends ACSObject {
/**
* Update the flag indicating whether this
* term is suitable for inclusion in an A-Z
* term is suitable for inclusion in an A-Z.
* @param inAtoZ the new value for the flag
*/
public void setInAtoZ(boolean inAtoZ) {
@ -198,7 +233,7 @@ public class Term extends ACSObject {
/**
* Determines whether the term is suitable
* for inclusion in an A-Z
* for inclusion in an A-Z.
*/
public boolean isInAtoZ() {
return ((Boolean)get(IN_ATOZ)).booleanValue();
@ -220,13 +255,19 @@ public class Term extends ACSObject {
return (String)get(SHORTCUT);
}
/**
* Associates this term to the domain it is going to be a part of.
*
* @param domain
*/
private void setDomain(Domain domain) {
Assert.exists(domain, Domain.class);
setAssociation(DOMAIN, domain);
}
/**
* Retrieves the domain containing this term
* Retrieves the domain containing this term.
*
* @return the domain containing this term
*/
public Domain getDomain() {
@ -234,6 +275,12 @@ public class Term extends ACSObject {
.newInstance((DataObject)get(DOMAIN));
}
/**
* Fetch an Instance of the underlying model to store / retrieve the
* generic category properties.
*
* @return a Category object.
*/
public Category getModel() {
return (Category)DomainObjectFactory
.newInstance((DataObject)get(MODEL));
@ -248,8 +295,10 @@ public class Term extends ACSObject {
}
/**
* Is this term a preferred term ?
* @return <code>true</code> if this term has no preferred term, otherwise <code>false</code>.
* Is this term a preferred term?
*
* @return <code>true</code> if this term has no preferred term,
* otherwise <code>false</code>.
*/
public boolean isPreferredTerm() {
DomainCollection dc = getPreferredTerms();

View File

@ -18,8 +18,6 @@
package com.arsdigita.london.terms.ui.admin;
import java.util.TooManyListenersException;
import com.arsdigita.bebop.Form;
import com.arsdigita.bebop.FormProcessException;
import com.arsdigita.bebop.PageState;
@ -43,7 +41,13 @@ import com.arsdigita.util.UncheckedWrapperException;
import com.arsdigita.web.Application;
import com.arsdigita.web.ApplicationCollection;
import java.util.TooManyListenersException;
/**
*
*
*/
public class DomainContextForm extends Form {
private DomainObjectParameter m_domain;

View File

@ -19,10 +19,6 @@
package com.arsdigita.london.terms.ui.admin;
import java.util.Set;
import org.apache.log4j.Logger;
import com.arsdigita.bebop.PageState;
import com.arsdigita.categorization.Category;
import com.arsdigita.domain.DeleteException;
@ -38,6 +34,15 @@ import com.arsdigita.london.util.ui.event.DomainObjectActionListener;
import com.arsdigita.london.util.ui.parameters.DomainObjectParameter;
import com.arsdigita.xml.Element;
import java.util.Set;
import org.apache.log4j.Logger;
/**
*
*
*/
public class DomainDetails extends AbstractDomainObjectDetails {
private static final Logger s_log =
Logger.getLogger( DomainDetails.class );
@ -66,6 +71,7 @@ public class DomainDetails extends AbstractDomainObjectDetails {
addDomainObjectActionListener(
ACTION_DELETE,
new DomainObjectActionListener() {
@Override
public void actionPerformed(DomainObjectActionEvent e) {
PageState ps = e.getPageState();
@ -105,6 +111,7 @@ public class DomainDetails extends AbstractDomainObjectDetails {
});
addDomainObjectActionListener(ACTION_TRAIN, new DomainObjectActionListener() {
@Override
public void actionPerformed(DomainObjectActionEvent e) {
Domain domain = (Domain) e.getObject();
Indexer indexer = Indexer.retrieve(domain);
@ -116,6 +123,7 @@ public class DomainDetails extends AbstractDomainObjectDetails {
});
addDomainObjectActionListener(ACTION_UNTRAIN, new DomainObjectActionListener() {
@Override
public void actionPerformed(DomainObjectActionEvent e) {
Domain domain = (Domain) e.getObject();
Indexer indexer = Indexer.retrieve(domain);
@ -126,10 +134,23 @@ public class DomainDetails extends AbstractDomainObjectDetails {
});
}
/**
*
* @param state
* @return
*/
@Override
protected DomainObject getDomainObject(PageState state) {
return (DomainObject)state.getValue(m_domain);
}
/**
*
* @param ps
* @param parent
* @param dobj
*/
@Override
public void generateActionXML( PageState ps, Element parent,
DomainObject dobj ) {
s_log.debug( "In generateActionXML" );

View File

@ -59,7 +59,13 @@ public class DomainEditForm extends Form {
private Date released;
private SaveCancelSection saveCancel;
public DomainEditForm(final String name, final DomainObjectParameter selected) {
/**
*
* @param name
* @param selected
*/
public DomainEditForm(final String name,
final DomainObjectParameter selected) {
super(name, new ColumnPanel(2));
setClassAttr("domainEdit");
@ -133,8 +139,16 @@ public class DomainEditForm extends Form {
addProcessListener(new Processlistener());
}
/**
*
*/
private class InitListener implements FormInitListener {
/**
*
* @param event
* @throws FormProcessException
*/
@Override
public void init(final FormSectionEvent event) throws FormProcessException {
final PageState state = event.getPageState();
@ -159,8 +173,17 @@ public class DomainEditForm extends Form {
}
/**
*
*/
private class SubmissionListener implements FormSubmissionListener {
/**
*
* @param event
* @throws FormProcessException
*/
@Override
public void submitted(final FormSectionEvent event) throws FormProcessException {
final PageState state = event.getPageState();
@ -180,8 +203,16 @@ public class DomainEditForm extends Form {
}
/**
*
*/
private class Processlistener implements FormProcessListener {
/**
*
* @param event
* @throws FormProcessException
*/
@Override
public void process(final FormSectionEvent event) throws FormProcessException {
final PageState state = event.getPageState();

View File

@ -28,6 +28,10 @@ import com.arsdigita.london.util.ui.event.DomainObjectActionEvent;
import com.arsdigita.london.util.ui.event.DomainObjectActionListener;
import com.arsdigita.london.util.ui.parameters.DomainObjectParameter;
/**
*
*
*/
public class TermDetails extends AbstractDomainObjectDetails {
private DomainObjectParameter m_term;

View File

@ -204,6 +204,7 @@ public class TermForm extends Form {
private class UniqueValidationListener implements ParameterListener {
@Override
public void validate(ParameterEvent e)
throws FormProcessException {
PageState state = e.getPageState();

View File

@ -18,7 +18,6 @@
package com.arsdigita.rssfeed;
// import com.arsdigita.categorization.CategoryPurpose;
import com.arsdigita.domain.DataObjectNotFoundException;
import com.arsdigita.kernel.Kernel;
import com.arsdigita.kernel.KernelExcursion;