- Some preparation for the editor UI for PageModel
- SimpleItemResolver and MultilingualItemResolver ported to new API (still disabled because of circular dependencies in UI classes)


git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4486 8810af33-2d31-482b-a856-94f89814c4df

Former-commit-id: aa3f76e4a1
pull/2/head
jensp 2016-12-16 16:41:16 +00:00
parent 08ba214405
commit a38485014b
16 changed files with 1182 additions and 688 deletions

View File

@ -26,7 +26,6 @@ import org.librecms.contentsection.ContentSection;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.StringTokenizer; import java.util.StringTokenizer;
/** /**
@ -36,82 +35,45 @@ public abstract class AbstractItemResolver implements ItemResolver {
protected static final String TEMPLATE_CONTEXT_PREFIX = "tem_"; protected static final String TEMPLATE_CONTEXT_PREFIX = "tem_";
/* (non-Javadoc) @Override
* @see com.arsdigita.cms.dispatcher.ItemResolver#getItem(
* com.arsdigita.cms.ContentSection, java.lang.String, java.lang.String)
*/
public abstract ContentItem getItem( public abstract ContentItem getItem(
ContentSection section, ContentSection section,
String url, String url,
String context); String context);
/* (non-Javadoc) @Override
* @see com.arsdigita.cms.dispatcher.ItemResolver#getCurrentContext(
* com.arsdigita.bebop.PageState)
*/
public abstract String getCurrentContext(PageState state); public abstract String getCurrentContext(PageState state);
/* (non-Javadoc) @Override
* @see com.arsdigita.cms.dispatcher.ItemResolver#generateItemURL(
* com.arsdigita.bebop.PageState, java.math.BigDecimal,
* java.lang.String, com.arsdigita.cms.ContentSection,
* java.lang.String)
*/
public abstract String generateItemURL( public abstract String generateItemURL(
PageState state, PageState state,
BigDecimal itemId, Long itemId,
String name, String name,
ContentSection section, ContentSection section,
String context); String context);
/* (non-Javadoc) @Override
* @see com.arsdigita.cms.dispatcher.ItemResolver#generateItemURL( public abstract String generateItemURL(PageState state,
* com.arsdigita.bebop.PageState, Long itemId,
* java.math.BigDecimal, String name,
* java.lang.String, ContentSection section,
* com.arsdigita.cms.ContentSection, String context,
* java.lang.String, java.lang.String) String templateContext);
*/
public abstract String generateItemURL(
PageState state,
BigDecimal itemId,
String name,
ContentSection section,
String context,
String templateContext);
/* (non-Javadoc) @Override
* @see com.arsdigita.cms.dispatcher.ItemResolver#generateItemURL( public abstract String generateItemURL(PageState state,
* com.arsdigita.bebop.PageState, ContentItem item,
* com.arsdigita.cms.ContentItem, ContentSection section,
* com.arsdigita.cms.ContentSection, String context);
* java.lang.String)
*/
public abstract String generateItemURL(
PageState state,
ContentItem item,
ContentSection section,
String context);
/* (non-Javadoc) @Override
* @see com.arsdigita.cms.dispatcher.ItemResolver#generateItemURL( public abstract String generateItemURL(PageState state,
* com.arsdigita.bebop.PageState, ContentItem item,
* com.arsdigita.cms.ContentItem, ContentSection section,
* com.arsdigita.cms.ContentSection, String context,
* java.lang.String, java.lang.String) String templateContext);
*/
public abstract String generateItemURL(
PageState state,
ContentItem item,
ContentSection section,
String context,
String templateContext);
/* (non-Javadoc) @Override
* @see com.arsdigita.cms.dispatcher.ItemResolver#getMasterPage(
* com.arsdigita.cms.ContentItem,
* javax.servlet.http.HttpServletRequest)
*/
public abstract CMSPage getMasterPage(ContentItem item, public abstract CMSPage getMasterPage(ContentItem item,
HttpServletRequest request) HttpServletRequest request)
throws ServletException; throws ServletException;
@ -124,7 +86,8 @@ public abstract class AbstractItemResolver implements ItemResolver {
* *
* @return the template context, or null if there is no template context * @return the template context, or null if there is no template context
*/ */
public String getTemplateFromURL(String inUrl) { @Override
public String getTemplateFromURL(final String inUrl) {
String tempUrl; String tempUrl;
String url; String url;
if (inUrl.startsWith("/")) { if (inUrl.startsWith("/")) {
@ -155,13 +118,15 @@ public abstract class AbstractItemResolver implements ItemResolver {
* *
* @return <code>inUrl</code> with the template context removed * @return <code>inUrl</code> with the template context removed
*/ */
public String stripTemplateFromURL(String inUrl) { @Override
public String stripTemplateFromURL(final String inUrl) {
String sTemplateContext = getTemplateFromURL(inUrl); String sTemplateContext = getTemplateFromURL(inUrl);
if (sTemplateContext != null) { if (sTemplateContext != null) {
//there is a template context, so strip it //there is a template context, so strip it
int iTemplateLength = TEMPLATE_CONTEXT_PREFIX.length() int iTemplateLength = TEMPLATE_CONTEXT_PREFIX.length()
+ sTemplateContext.length() + 1; + sTemplateContext.length() + 1;
String sStripped = inUrl.substring(iTemplateLength, inUrl.length()); String sStripped = inUrl.substring(iTemplateLength, inUrl.length());
return sStripped; return sStripped;
} else { } else {

View File

@ -20,45 +20,64 @@ package com.arsdigita.cms.dispatcher;
import com.arsdigita.bebop.PageState; import com.arsdigita.bebop.PageState;
import com.arsdigita.cms.CMS; import com.arsdigita.cms.CMS;
import com.arsdigita.cms.ContentCenter; import com.arsdigita.cms.ui.ContentItemPage;
import com.arsdigita.kernel.KernelConfig;
import com.arsdigita.util.Assert; import com.arsdigita.util.Assert;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.libreccm.categorization.Category;
import org.librecms.contentsection.ContentItem; import org.librecms.contentsection.ContentItem;
import org.librecms.contentsection.ContentSection; import org.librecms.contentsection.ContentSection;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.Objects; import java.util.Objects;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.libreccm.cdi.utils.CdiUtil; import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.core.CcmObject;
import org.libreccm.l10n.GlobalizationHelper;
import org.librecms.CmsConstants; import org.librecms.CmsConstants;
import org.librecms.contentsection.ContentItemManager;
import org.librecms.contentsection.ContentItemRepository; import org.librecms.contentsection.ContentItemRepository;
import org.librecms.contentsection.ContentItemVersion; import org.librecms.contentsection.ContentItemVersion;
import org.librecms.contentsection.Folder; import org.librecms.contentsection.Folder;
import org.librecms.contentsection.FolderManager; import org.librecms.contentsection.FolderManager;
import org.librecms.util.LanguageUtil;
import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;
import static javax.naming.ldap.SortControl.*;
/** /**
* Resolves items to URLs and URLs to items for multiple language variants. * Resolves items to URLs and URLs to items for multiple language variants.
* *
* Created Mon Jan 20 14:30:03 2003. * * <strong>
* AS of version 7.0.0 this class not longer part of the public API. It is left
* here to keep the changes to the UI classes as minimal as possible. For new
* code other methods, for example from the {@link ContentItemManager} or the
* {@link ContentItemRepository} should be used. Because this class is no longer
* part of the public API the will might be removed or changed in future
* releases without prior warning.
* </strong>
*
*
* *
* @author <a href="mailto:mhanisch@redhat.com">Michael Hanisch</a> * @author <a href="mailto:mhanisch@redhat.com">Michael Hanisch</a>
* @version $Id: MultilingualItemResolver.java 2090 2010-04-17 08:04:14Z pboy $ * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
public class MultilingualItemResolver public class MultilingualItemResolver
extends AbstractItemResolver implements ItemResolver { extends AbstractItemResolver implements ItemResolver {
private static final Logger LOGGER = LogManager.getLogger( private static final Logger LOGGER = LogManager.getLogger(
MultilingualItemResolver.class); MultilingualItemResolver.class);
private static MasterPage s_masterP = null; private static MasterPage s_masterP = null;
private static final String ADMIN_PREFIX = "admin"; private static final String ADMIN_PREFIX = "admin";
@ -83,8 +102,10 @@ public class MultilingualItemResolver
* @param section The current content section * @param section The current content section
* @param itemUrl The section-relative URL * @param itemUrl The section-relative URL
* @param context The use context, e.g. <code>ContentItem.LIVE</code>, * @param context The use context, e.g. <code>ContentItem.LIVE</code>,
* <code>CMSDispatcher.PREVIEW</code> or <code>ContentItem.DRAFT</code>. See {@link * <code>CMSDispatcher.PREVIEW</code> or
* <code>ContentItem.DRAFT</code>. See {@link
* #getCurrentContext}. * #getCurrentContext}.
*
* @return The content item, or null if no such item exists * @return The content item, or null if no such item exists
*/ */
@Override @Override
@ -92,7 +113,7 @@ public class MultilingualItemResolver
final String itemUrl, final String itemUrl,
final String context) { final String context) {
LOGGER.debug("Resolving the item in content section \"{}\" at URL " LOGGER.debug("Resolving the item in content section \"{}\" at URL "
+ "\"{}\" for context \"{}\"...", + "\"{}\" for context \"{}\"...",
section.getLabel(), section.getLabel(),
itemUrl, itemUrl,
context); context);
@ -119,16 +140,16 @@ public class MultilingualItemResolver
LOGGER.debug("The root folder has a live version; recursing"); LOGGER.debug("The root folder has a live version; recursing");
final FolderManager folderManager = cdiUtil.findBean( final FolderManager folderManager = cdiUtil.findBean(
FolderManager.class); FolderManager.class);
final String prefix = String.join( final String prefix = String.join(
"", "",
section.getPrimaryUrl(), section.getPrimaryUrl(),
folderManager.getFolderPath(rootFolder)); folderManager.getFolderPath(rootFolder));
if (url.startsWith(prefix)) { if (url.startsWith(prefix)) {
LOGGER. LOGGER.
debug("The starts with prefix \"{}\"; removing it...", debug("The starts with prefix \"{}\"; removing it...",
prefix); prefix);
url = url.substring(prefix.length()); url = url.substring(prefix.length());
} }
@ -171,8 +192,8 @@ public class MultilingualItemResolver
if (url.startsWith(prefix)) { if (url.startsWith(prefix)) {
LOGGER.debug( LOGGER.debug(
"The URL starts with prefix \"{}\"; removing it", "The URL starts with prefix \"{}\"; removing it",
prefix); prefix);
url = url.substring(prefix.length()); url = url.substring(prefix.length());
} }
@ -186,7 +207,7 @@ public class MultilingualItemResolver
return item; return item;
} else { } else {
throw new IllegalArgumentException(String.format( throw new IllegalArgumentException(String.format(
"Invalid item resolver context \"%s\".", context)); "Invalid item resolver context \"%s\".", context));
} }
} }
@ -199,8 +220,10 @@ public class MultilingualItemResolver
* Fetches the current context based on the page state. * Fetches the current context based on the page state.
* *
* @param state the current page state * @param state the current page state
*
* @return the context of the current URL, such as * @return the context of the current URL, such as
* <code>ContentItem.LIVE</code> or <code>ContentItem.DRAFT</code> * <code>ContentItem.LIVE</code> or <code>ContentItem.DRAFT</code>
*
* @see ContentItem#LIVE * @see ContentItem#LIVE
* @see ContentItem#DRAFT * @see ContentItem#DRAFT
* *
@ -233,7 +256,7 @@ public class MultilingualItemResolver
// Determine if we are under the admin UI. // Determine if we are under the admin UI.
if (url.startsWith(ADMIN_PREFIX) if (url.startsWith(ADMIN_PREFIX)
|| url.startsWith(CmsConstants.CONTENT_CENTER_URL)) { || url.startsWith(CmsConstants.CONTENT_CENTER_URL)) {
return ContentItemVersion.DRAFT.toString(); return ContentItemVersion.DRAFT.toString();
} else { } else {
return ContentItemVersion.LIVE.toString(); return ContentItemVersion.LIVE.toString();
@ -243,17 +266,19 @@ public class MultilingualItemResolver
/** /**
* Generates a URL for a content item. * Generates a URL for a content item.
* *
* @param itemId The item ID * @param itemId The item ID
* @param name The name of the content page * @param name The name of the content page
* @param state The page state * @param state The page state
* @param section the content section to which the item belongs * @param section the content section to which the item belongs
* @param context the context of the URL, such as "live" or "admin" * @param context the context of the URL, such as "live" or "admin"
*
* @return The URL of the item * @return The URL of the item
*
* @see #getCurrentContext * @see #getCurrentContext
*/ */
@Override @Override
public String generateItemURL(final PageState state, public String generateItemURL(final PageState state,
final BigDecimal itemId, final Long itemId,
final String name, final String name,
final ContentSection section, final ContentSection section,
final String context) { final String context) {
@ -263,27 +288,29 @@ public class MultilingualItemResolver
/** /**
* Generates a URL for a content item. * Generates a URL for a content item.
* *
* @param itemId The item ID * @param itemId The item ID
* @param name The name of the content page * @param name The name of the content page
* @param state The page state * @param state The page state
* @param section the content section to which the item belongs * @param section the content section to which the item belongs
* @param context the context of the URL, such as "live" or "admin" * @param context the context of the URL, such as "live" or "admin"
* @param templateContext the context for the URL, such as "public" * @param templateContext the context for the URL, such as "public"
*
* @return The URL of the item * @return The URL of the item
*
* @see #getCurrentContext * @see #getCurrentContext
*/ */
@Override @Override
public String generateItemURL(final PageState state, public String generateItemURL(final PageState state,
final BigDecimal itemId, final Long itemId,
final String name, final String name,
final ContentSection section, final ContentSection section,
final String context, final String context,
final String templateContext) { final String templateContext) {
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Generating an item URL for item id " + itemId LOGGER.debug("Generating an item URL for item id " + itemId
+ ", section " + section + ", and context '" + ", section " + section + ", and context '"
+ context + context
+ "' with name '" + name + "'"); + "' with name '" + name + "'");
} }
Assert.exists(itemId, "BigDecimal itemId"); Assert.exists(itemId, "BigDecimal itemId");
@ -291,40 +318,35 @@ public class MultilingualItemResolver
Assert.exists(section, "ContentSection section"); Assert.exists(section, "ContentSection section");
final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final ContentItemRepository itemRepo = cdiUtil.findBean(ContentItemRepository.class); final ContentItemRepository itemRepo = cdiUtil.findBean(
ContentItemRepository.class);
if (ContentItemVersion.DRAFT.toString().equals(context)) { if (ContentItemVersion.DRAFT.toString().equals(context)) {
// No template context here. // No template context here.
return generateDraftURL(section, itemId); return generateDraftURL(section, itemId);
} else if (CMSDispatcher.PREVIEW.equals(context)) { } else if (CMSDispatcher.PREVIEW.equals(context)) {
ContentItem item = new ContentItem(itemId); final ContentItem item = itemRepo.findById(itemId);
return generatePreviewURL(section, item, templateContext); return generatePreviewURL(section, item, templateContext);
} else if (ContentItem.LIVE.equals(context)) { } else if (ContentItemVersion.LIVE.toString().equals(context)) {
ContentItem item = new ContentItem(itemId); final ContentItem item = itemRepo.findById(itemId);
if (Assert.isEnabled()) {
Assert.exists(item, "item");
Assert.isTrue(ContentItem.LIVE.equals(item.getVersion()),
"Generating " + ContentItem.LIVE + " "
+ "URL; this item must be the live version");
}
return generateLiveURL(section, item, templateContext); return generateLiveURL(section, item, templateContext);
} else { } else {
throw new IllegalArgumentException("Unknown context '" + context throw new IllegalArgumentException("Unknown context '" + context
+ "'"); + "'");
} }
} }
/** /**
* Generates a URL for a content item. * Generates a URL for a content item.
* *
* @param item The item * @param item The item
* @param state The page state * @param state The page state
* @param section the content section to which the item belongs * @param section the content section to which the item belongs
* @param context the context of the URL, such as "live" or "admin" * @param context the context of the URL, such as "live" or "admin"
*
* @return The URL of the item * @return The URL of the item
*
* @see #getCurrentContext * @see #getCurrentContext
*/ */
@Override @Override
@ -338,68 +360,61 @@ public class MultilingualItemResolver
/** /**
* Generates a URL for a content item. * Generates a URL for a content item.
* *
* @param item The item * @param item The item
* @param state The page state * @param state The page state
* @param section the content section to which the item belongs * @param section the content section to which the item belongs
* @param context the context of the URL, such as "live" or "admin" * @param context the context of the URL, such as "live" or "admin"
* @param templateContext the context for the URL, such as "public" * @param templateContext the context for the URL, such as "public"
*
* @return The URL of the item * @return The URL of the item
*
* @see #getCurrentContext * @see #getCurrentContext
*/ */
@Override @Override
public String generateItemURL(final PageState state, public String generateItemURL(final PageState state,
final ContentItem item, final ContentItem item,
ContentSection section, final ContentSection section,
final String context, final String context,
final String templateContext) { final String templateContext) {
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Generating an item URL for item " + item LOGGER.debug("Generating an item URL for item " + item
+ ", section " + ", section "
+ section + ", and context " + context); + section + ", and context " + context);
} }
Assert.exists(item, "ContentItem item"); final ContentSection contentSection;
Assert.exists(context, "String context");
if (section == null) { if (section == null) {
section = item.getContentSection(); contentSection = item.getContentType().getContentSection();
} else {
contentSection = section;
} }
if (ContentItem.DRAFT.equals(context)) { if (ContentItemVersion.DRAFT.toString().equals(context)) {
if (Assert.isEnabled()) { return generateDraftURL(section, item.getObjectId());
Assert.isTrue(ContentItem.DRAFT.equals(item.getVersion()),
"Generating " + ContentItem.DRAFT
+ " url: item must be draft version");
}
return generateDraftURL(section, item.getID());
} else if (CMSDispatcher.PREVIEW.equals(context)) { } else if (CMSDispatcher.PREVIEW.equals(context)) {
return generatePreviewURL(section, item, templateContext); return generatePreviewURL(section, item, templateContext);
} else if (ContentItem.LIVE.equals(context)) { } else if (ContentItemVersion.LIVE.toString().equals(context)) {
if (Assert.isEnabled()) { return generateLiveURL(contentSection, item, templateContext);
Assert.isTrue(ContentItem.LIVE.equals(item.getVersion()),
"Generating " + ContentItem.LIVE
+ " url: item must be live version");
}
return generateLiveURL(section, item, templateContext);
} else { } else {
throw new RuntimeException("Unknown context " + context); throw new IllegalArgumentException(String.format(
"Unknown context \"%s\".", context));
} }
} }
/** /**
* Returns a master page based on page state (and content section). * Returns a master page based on page state (and content section).
* *
* @param item The content item * @param item The content item
* @param request The HTTP request * @param request The HTTP request
*
* @return The master page * @return The master page
*
* @throws javax.servlet.ServletException * @throws javax.servlet.ServletException
*/ */
@Override @Override
public CMSPage getMasterPage(final ContentItem item, public CMSPage getMasterPage(final ContentItem item,
final HttpServletRequest request) final HttpServletRequest request)
throws ServletException { throws ServletException {
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Getting the master page for item " + item); LOGGER.debug("Getting the master page for item " + item);
} }
@ -421,25 +436,27 @@ public class MultilingualItemResolver
* Returns content item's draft version URL * Returns content item's draft version URL
* *
* @param section The content section to which the item belongs * @param section The content section to which the item belongs
* @param itemId The content item's ID * @param itemId The content item's ID
*
* @return generated URL string * @return generated URL string
*/ */
protected String generateDraftURL(final ContentSection section, protected String generateDraftURL(final ContentSection section,
final BigDecimal itemId) { final Long itemId) {
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Generating draft URL for item ID " + itemId LOGGER.debug("Generating draft URL for item ID " + itemId
+ " and section " + section); + " and section " + section);
} }
if (Assert.isEnabled()) { if (Assert.isEnabled()) {
Assert.isTrue(section != null && itemId != null, Assert.isTrue(section != null && itemId != null,
"get draft url: neither secion nor item " "get draft url: neither secion nor item "
+ "can be null"); + "can be null");
} }
final String url = ContentItemPage.getItemURL(section.getPath() + "/", final String url = ContentItemPage.getItemURL(
itemId, String.format("%s/", section.getPrimaryUrl()),
ContentItemPage.AUTHORING_TAB); itemId,
ContentItemPage.AUTHORING_TAB);
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Generated draft URL " + url); LOGGER.debug("Generated draft URL " + url);
@ -455,23 +472,23 @@ public class MultilingualItemResolver
* specific language instance of the item referenced here, i.e. this URL * specific language instance of the item referenced here, i.e. this URL
* will be resolved to a <em>language-specific</em> URL internally. * will be resolved to a <em>language-specific</em> URL internally.
* *
* @param section the <code>ContentSection</code> that contains this item * @param section the <code>ContentSection</code> that contains this
* @param item <code>ContentItem</code> for which a URL should be * item
* constructed. * @param item <code>ContentItem</code> for which a URL should be
* constructed.
* @param templateContext template context; will be ignored if * @param templateContext template context; will be ignored if
* <code>null</code> * <code>null</code>
* *
* @return a <em>language-independent</em> URL to the <code>item</code> in * @return a <em>language-independent</em> URL to the <code>item</code> in
* the given <code>section</code>, which will be presented within the given * the given <code>section</code>, which will be presented within
* <code>templateContext</code> * the given <code>templateContext</code>
*/ */
protected String generateLiveURL(final ContentSection section, protected String generateLiveURL(final ContentSection section,
final ContentItem item, final ContentItem item,
final String templateContext) { final String templateContext) {
if (LOGGER.isDebugEnabled()) { LOGGER.debug("Generating live URL for item {} in section {}",
LOGGER.debug("Generating live URL for item " + item + " in " Objects.toString(item),
+ "section " + section); Objects.toString(section));
}
/* /*
* URL = URL of section + templateContext + path to the ContentBundle * URL = URL of section + templateContext + path to the ContentBundle
@ -479,7 +496,9 @@ public class MultilingualItemResolver
*/ */
final StringBuffer url = new StringBuffer(400); final StringBuffer url = new StringBuffer(400);
//url.append(section.getURL()); //url.append(section.getURL());
url.append(section.getPath()).append("/"); url
.append(section.getPrimaryUrl())
.append("/");
/* /*
* add template context, if one is given * add template context, if one is given
@ -487,56 +506,17 @@ public class MultilingualItemResolver
// This is breaking URL's...not sure why it's here. XXX // This is breaking URL's...not sure why it's here. XXX
// this should work with the appropriate logic. trying again. // this should work with the appropriate logic. trying again.
if (!(templateContext == null || templateContext.length() == 0)) { if (!(templateContext == null || templateContext.length() == 0)) {
url.append(TEMPLATE_CONTEXT_PREFIX).append(templateContext).append( url
"/"); .append(TEMPLATE_CONTEXT_PREFIX)
.append(templateContext)
.append("/");
} }
// Try to retrieve the bundle. final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final ContentItem bundle = (ContentItem) item.getParent(); final ContentItemManager itemManager = cdiUtil.findBean(
ContentItemManager.class);
url.append(itemManager.getItemPath(item));
/*
* It would be nice if we had a ContentPage here, which
* supports the getContentBundle() method, but unfortunately
* the API sucks and there is no real distinction between mere
* ContentItems and top-level items, so we have to use this
* hack. TODO: add sanity check that bundle is actually a
* ContentItem.
*/
if (bundle != null && bundle instanceof ContentBundle) {
LOGGER.debug("Found a bundle; building its file name");
final String fname = bundle.getPath();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Appending the bundle's file name '" + fname + "'");
}
url.append(fname);
} else {
LOGGER.debug("No bundle found; using the item's path directly");
url.append(item.getPath());
}
/*
* This will append the language to the url, which will in turn render
* the language negotiation inoperative
final String language = item.getLanguage();
if (language == null) {
s_log.debug("The item has no language; omitting the " +
"language encoding");
} else {
s_log.debug("Encoding the language of the item passed in, '" +
language + "'");
url.append("." + language);
}
if (s_log.isDebugEnabled()) {
s_log.debug("Generated live URL " + url.toString());
}
*/
return url.toString(); return url.toString();
} }
@ -547,71 +527,44 @@ public class MultilingualItemResolver
* <em>no</em> language negotiation is involved when a request is made to a * <em>no</em> language negotiation is involved when a request is made to a
* URL that has been generated by this method. * URL that has been generated by this method.
* *
* @param section The <code>ContentSection</code> which contains the * @param section The <code>ContentSection</code> which contains the
* <code>item</code> * <code>item</code>
* @param item The <code>ContentItem</code> for which a URL should be * @param item The <code>ContentItem</code> for which a URL
* generated. * should be generated.
* @param templateContext the context that determines which template should * @param templateContext the context that determines which template should
* render the item when it is previewed; ignored if the argument given here * render the item when it is previewed; ignored if
* is <code>null</code> * the argument given here is <code>null</code>
*
* @return a URL which can be used to preview the given <code>item</code> * @return a URL which can be used to preview the given <code>item</code>
*/ */
protected String generatePreviewURL(ContentSection section, protected String generatePreviewURL(final ContentSection section,
ContentItem item, final ContentItem item,
String templateContext) { final String templateContext) {
Assert.exists(section, "ContentSection section"); Assert.exists(section, "ContentSection section");
Assert.exists(item, "ContentItem item"); Assert.exists(item, "ContentItem item");
final StringBuffer url = new StringBuffer(100); final StringBuffer url = new StringBuffer(100);
url.append(section.getPath()); url
url.append("/"); .append(section.getPrimaryUrl())
url.append(CMSDispatcher.PREVIEW); .append("/")
url.append("/"); .append(CMSDispatcher.PREVIEW)
.append("/");
/* /*
* add template context, if one is given * add template context, if one is given
*/ */
// This is breaking URL's...not sure why it's here. XXX // This is breaking URL's...not sure why it's here. XXX
// this should work with the appropriate logic. trying again. // this should work with the appropriate logic. trying again.
if (!(templateContext == null || templateContext.length() == 0)) { if (!(templateContext == null || templateContext.length() == 0)) {
url.append(TEMPLATE_CONTEXT_PREFIX).append(templateContext).append( url
"/"); .append(TEMPLATE_CONTEXT_PREFIX)
.append(templateContext)
.append("/");
} }
// Try to retrieve the bundle. final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
ContentItem bundle = (ContentItem) item.getParent(); final ContentItemManager itemManager = cdiUtil.findBean(
ContentItemManager.class);
/* It would be nice if we had a ContentPage here, which url.append(itemManager.getItemPath(item));
* supports the getContentBundle() method, but unfortunately
* the API sucks and there is no real distinction between mere
* ContentItems and top-level items, so we have to use this
* hack. TODO: add sanity check that bundle is actually a
* ContentItem.
*/
if (bundle != null && bundle instanceof ContentBundle) {
LOGGER.debug("Found a bundle; using its path");
url.append(bundle.getPath());
} else {
LOGGER.debug("No bundle found; using the item's path directly");
url.append(item.getPath());
}
final String language = item.getLanguage();
if (language == null) {
LOGGER.debug("The item has no language; omitting the "
+ "language encoding");
} else {
LOGGER.debug("Encoding the language of the item passed in, '"
+ language + "'");
url.append(".").append(language);
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Generated preview URL " + url.toString());
}
return url.toString(); return url.toString();
} }
@ -621,9 +574,11 @@ public class MultilingualItemResolver
* according to this ID. * according to this ID.
* *
* @param url URL that indicates which item should be retrieved; must * @param url URL that indicates which item should be retrieved; must
* contain the <code>ITEM_ID</code> parameter * contain the <code>ITEM_ID</code> parameter
*
* @return the <code>ContentItem</code> the given <code>url</code> points * @return the <code>ContentItem</code> the given <code>url</code> points
* to, or <code>null</code> if no ID has been found in the <code>url</code> * to, or <code>null</code> if no ID has been found in the
* <code>url</code>
*/ */
protected ContentItem getItemFromDraftURL(final String url) { protected ContentItem getItemFromDraftURL(final String url) {
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
@ -661,41 +616,45 @@ public class MultilingualItemResolver
LOGGER.debug("Looking up item using item ID " + item_id); LOGGER.debug("Looking up item using item ID " + item_id);
} }
OID oid = new OID(ContentItem.BASE_DATA_OBJECT_TYPE, new BigDecimal( final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
item_id)); final ContentItemRepository itemRepo = cdiUtil.findBean(
final ContentItem item = (ContentItem) DomainObjectFactory.newInstance( ContentItemRepository.class);
oid);
if (LOGGER.isDebugEnabled()) { final Optional<ContentItem> item = itemRepo.findById(Long.parseLong(
LOGGER.debug("Returning item " + item); item_id));
if (item.isPresent()) {
LOGGER.debug("Returning item {}", Objects.toString(item));
return item.get();
} else {
return null;
} }
return item;
} }
/** /**
* Returns a content item based on URL relative to the root folder. * Returns a content item based on URL relative to the root folder.
* *
* @param url The content item url * @param url The content item url
* @param parentFolder The parent folder object, url must be relevant to it * @param parentFolder The parent folder object, url must be relevant to it
*
* @return The Content Item instance, it can also be either Bundle or Folder * @return The Content Item instance, it can also be either Bundle or Folder
* objects, depending on URL and file language extension * objects, depending on URL and file language extension
*/ */
protected ContentItem getItemFromLiveURL(String url, protected ContentItem getItemFromLiveURL(final String url,
Folder parentFolder) { final Folder parentFolder) {
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Resolving the item for live URL " + url LOGGER.debug("Resolving the item for live URL " + url
+ " and parent folder " + parentFolder); + " and parent folder " + parentFolder);
} }
if (parentFolder == null || url == null || url.equals("")) { if (parentFolder == null || url == null || url.equals("")) {
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("The url is null or parent folder was null " LOGGER.debug("The url is null or parent folder was null "
+ "or something else is wrong, so just return " + "or something else is wrong, so just return "
+ "the parent folder"); + "null");
} }
return parentFolder; return null;
} }
int len = url.length(); int len = url.length();
@ -703,28 +662,28 @@ public class MultilingualItemResolver
if (index >= 0) { if (index >= 0) {
LOGGER.debug("The URL starts with a slash; paring off the first " LOGGER.debug("The URL starts with a slash; paring off the first "
+ "URL element and recursing"); + "URL element and recursing");
// If we got first slash (index == 0), ignore it and go final String liveUrl = index + 1 < len ? url.substring(index + 1)
// on, sample '/foo/bar/item.html.en', in next recursion : "";
// will have deal with 'foo' folder.
String name = index > 0 ? url.substring(0, index) : "";
parentFolder = "".equals(name) ? parentFolder
: (Folder) parentFolder.getItem(URLEncoder.encode(
name), true);
url = index + 1 < len ? url.substring(index + 1) : "";
return getItemFromLiveURL(url, parentFolder); return getItemFromLiveURL(liveUrl, parentFolder);
} else { } else {
LOGGER.debug("Found a file element in the URL"); LOGGER.debug("Found a file element in the URL");
String[] nameAndLang = getNameAndLangFromURLFrag(url); final String[] nameAndLang = getNameAndLangFromURLFrag(url);
String name = nameAndLang[0]; final String name = nameAndLang[0];
String lang = nameAndLang[1];
ContentItem item = parentFolder.getItem(URLEncoder.encode(name), final Optional<CcmObject> item = parentFolder.getObjects().stream()
false); .map(categorization -> categorization.getCategorizedObject())
return getItemFromLangAndBundle(lang, item); .filter(object -> object.getDisplayName().equals(name))
.findFirst();
if (item.isPresent() && item.get() instanceof ContentItem) {
return (ContentItem) item.get();
} else {
return null;
}
} }
} }
@ -732,11 +691,13 @@ public class MultilingualItemResolver
* Returns an array containing the the item's name and lang based on the URL * Returns an array containing the the item's name and lang based on the URL
* fragment. * fragment.
* *
* @param url
*
* @return a two-element string array, the first element containing the * @return a two-element string array, the first element containing the
* bundle name, and the second element containing the lang string * bundle name, and the second element containing the lang string
*/ */
protected String[] getNameAndLangFromURLFrag(String url) { protected String[] getNameAndLangFromURLFrag(final String url) {
String name = null; String name;
String lang = null; String lang = null;
/* /*
@ -749,7 +710,7 @@ public class MultilingualItemResolver
* from a bundle * from a bundle
* 2b if no match is found * 2b if no match is found
*/ */
final ArrayList exts = new ArrayList(5); final List<String> exts = new ArrayList<>(5);
final StringTokenizer tok = new StringTokenizer(url, "."); final StringTokenizer tok = new StringTokenizer(url, ".");
while (tok.hasMoreTokens()) { while (tok.hasMoreTokens()) {
@ -757,10 +718,9 @@ public class MultilingualItemResolver
} }
if (exts.size() > 0) { if (exts.size() > 0) {
if (LOGGER.isDebugEnabled()) { LOGGER.debug("Found some file extensions to look at; they "
LOGGER.debug("Found some file extensions to look at; they " + "are {}",
+ "are " + exts); exts);
}
/* /*
* We have found at least one extension, so we can * We have found at least one extension, so we can
@ -772,18 +732,16 @@ public class MultilingualItemResolver
/* /*
* First element is the NAME of the item, not an extension! * First element is the NAME of the item, not an extension!
*/ */
name = (String) exts.get(0); name = exts.get(0);
String ext = null; String ext;
Collection supportedLangs final Collection<String> supportedLangs = KernelConfig.getConfig()
= LanguageUtil.getSupportedLanguages2LA(); .getSupportedLanguages();
Iterator supportedLangIt = null; Iterator<String> supportedLangIt;
for (int i = 1; i < exts.size(); i++) { for (int i = 1; i < exts.size(); i++) {
ext = (String) exts.get(i); ext = exts.get(i);
if (LOGGER.isDebugEnabled()) { LOGGER.debug("Examining extension {}", ext);
LOGGER.debug("Examining extension " + ext);
}
/* /*
* Loop through all extensions, but discard the * Loop through all extensions, but discard the
@ -801,37 +759,26 @@ public class MultilingualItemResolver
while (supportedLangIt.hasNext()) { while (supportedLangIt.hasNext()) {
if (ext.equals(supportedLangIt.next())) { if (ext.equals(supportedLangIt.next())) {
lang = ext; lang = ext;
if (LOGGER.isDebugEnabled()) { LOGGER.debug("Found a match; using "
LOGGER.debug("Found a match; using " + "language {}", lang);
+ "language " + lang);
}
break; break;
} }
} }
} else { } else {
if (LOGGER.isDebugEnabled()) { LOGGER.debug("Discarding extension {}; it is too short",
LOGGER.debug("Discarding extension " + ext + "; " ext);
+ "it is too short");
}
} }
} }
} else { } else {
LOGGER.debug("The file has no extensions; no language was " LOGGER.debug("The file has no extensions; no language was encoded");
+ "encoded");
name = url; // no extension, so we just have a name here name = url; // no extension, so we just have a name here
lang = null; // no extension, so we cannot guess the language lang = null; // no extension, so we cannot guess the language
} }
if (Assert.isEnabled()) { LOGGER.debug("File name resolved to {}", name);
Assert.exists(name, "String name"); LOGGER.debug("File language resolved to {}", lang);
Assert.exists(lang == null || lang.length() == 2);
}
if (LOGGER.isDebugEnabled()) { final String[] returnArray = new String[2];
LOGGER.debug("File name resolved to " + name);
LOGGER.debug("File language resolved to " + lang);
}
String[] returnArray = new String[2];
returnArray[0] = name; returnArray[0] = name;
returnArray[1] = lang; returnArray[1] = lang;
return returnArray; return returnArray;
@ -839,62 +786,17 @@ public class MultilingualItemResolver
/** /**
* Finds a language instance of a content item given the bundle, name, and * Finds a language instance of a content item given the bundle, name, and
* lang string * lang string. Note: Because there not ContentBundles anymore this method
* simply returns the provided item.
* *
* @param lang The lang string from the URL * @param lang The lang string from the URL
* @param item The content bundle * @param item The content bundle
* *
* @return The negotiated lang instance for the current request. * @return The negotiated lang instance for the current request.
*/ */
protected ContentItem getItemFromLangAndBundle(String lang, ContentItem item) { protected ContentItem getItemFromLangAndBundle(final String lang,
if (item != null && item instanceof ContentBundle) { final ContentItem item) {
if (LOGGER.isDebugEnabled()) { return item;
LOGGER.debug("Found content bundle " + item);
}
if (lang == null) {
LOGGER.debug("The URL has no language encoded in it; "
+ "negotiating the language");
// There is no language, so we get the negotiated locale and call
// this method again with a proper language
return this.getItemFromLangAndBundle(GlobalizationHelper.
getNegotiatedLocale().getLanguage(), item);
} else {
LOGGER.debug("The URL is encoded with a langauge; "
+ "fetching the appropriate item from "
+ "the bundle");
/*
* So the request contains a language code as an
* extension of the "name" ==>go ahead and try to
* find the item from its ContentBundle. Fail if
* the bundle does not contain an instance for the
* given language.
*/
final ContentItem resolved
= ((ContentBundle) item).getInstance(lang);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Resolved URL to item " + resolved);
}
return resolved;
}
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.
debug("I expected to get a content bundle; I got "
+ item);
}
/*
* We expected something like a Bundle, but it seems
* like we got something completely different... just
* return this crap and let other people's code deal
* with it ;-).
*
* NOTE: This should never happen :-)
*/
return item; // might be null
}
} }
} }

View File

@ -18,56 +18,78 @@
*/ */
package com.arsdigita.cms.dispatcher; package com.arsdigita.cms.dispatcher;
import com.arsdigita.bebop.Page;
import com.arsdigita.bebop.PageState; import com.arsdigita.bebop.PageState;
import com.arsdigita.cms.CMS; import com.arsdigita.cms.CMS;
import org.librecms.contentsection.ContentItem; import org.librecms.contentsection.ContentItem;
import org.librecms.contentsection.ContentSection; import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.Folder; import org.librecms.contentsection.Folder;
import com.arsdigita.cms.ContentCenter;
import com.arsdigita.cms.ui.ContentItemPage; import com.arsdigita.cms.ui.ContentItemPage;
import com.arsdigita.dispatcher.DispatcherHelper; import com.arsdigita.dispatcher.DispatcherHelper;
import org.apache.log4j.Logger; import com.arsdigita.web.URL;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.core.CcmObject;
import org.librecms.CmsConstants;
import org.librecms.contentsection.ContentItemManager;
import org.librecms.contentsection.ContentItemRepository;
import org.librecms.contentsection.ContentItemVersion;
import java.util.Optional;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.StringTokenizer;
/** /**
* <p>This is the default implementation of * This is the default implementation of
* {@link com.arsdigita.cms.dispatcher.ItemResolver}.</p> * {@link com.arsdigita.cms.dispatcher.ItemResolver}.
* *
* <p>The <tt>getItem</tt> method of the default implementation of * The {@link #getItem(java.lang.String, org.librecms.contentsection.Folder) }
* <tt>ItemResolver</tt>, * method of the default implementation of {@link ItemResolver},
* {@link com.arsdigita.cms.dispatcher.SimpleItemResolver} * {@link com.arsdigita.cms.dispatcher.SimpleItemResolver} runs a simple query
* runs a simple query using the passed in information to retrieve the * using the passed in information to retrieve the content item with a name that
* content item with a name that matches the URL stub, in our example * matches the URL stub, in our example it looks for a content item with name
* it looks for a content item with name <tt>cheese</tt>. If no such item * {@code cheese}. If no such item exists, or if there is such an item, but
* exists, or if there is such an item, but without a live version, even * without a live version, even though one has been requested, {@code getItem}
* though one has been requested, <tt>getItem</tt> returns <tt>null</tt>.</p> * returns {@code null}.
* *
* <p>After the CMS Dispatcher received the content item from the * After the CMS Dispatcher received the content item from the
* <tt>ItemResolver</tt>, it also asks it for the * {@link ItemResolver}, it also asks it for the
* {@link com.arsdigita.cms.dispatcher.MasterPage} for that item in the * {@link com.arsdigita.cms.dispatcher.MasterPage} for that item in the current
* current request. With the content item and the master page in hand, * request. With the content item and the master page in hand, the dispatcher
* the dispatcher calls <tt>service</tt> on the page.</p> * calls {@code service} on the page.
*
* <strong>
* AS of version 7.0.0 this class not longer part of the public API. It is left
* here to keep the changes to the UI classes as minimal as possible. For new
* code other methods, for example from the {@link ContentItemManager} or
* the {@link ContentItemRepository} should be used. Because this class is no
* longer part of the public API the will might be removed or changed in future
* releases without prior warning.
* </strong>
* *
* @author Michael Pih (pihman@arsdigita.com) * @author Michael Pih (pihman@arsdigita.com)
* @version $Revision: #15 $ $DateTime: 2004/08/17 23:15:09 $ * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
* @version $Id: SimpleItemResolver.java 2090 2010-04-17 08:04:14Z pboy $
*/ */
public class SimpleItemResolver extends AbstractItemResolver implements ItemResolver { public class SimpleItemResolver
extends AbstractItemResolver
implements ItemResolver {
private static final Logger s_log = private static final Logger LOGGER = LogManager.getLogger(
Logger.getLogger(SimpleItemResolver.class.getName()); SimpleItemResolver.class.getName());
private static final String ADMIN_PREFIX = "admin"; private static final String ADMIN_PREFIX = "admin";
private static final String WORKSPACE_PREFIX = ContentCenter.getURL(); private static final String WORKSPACE_PREFIX
= CmsConstants.CONTENT_CENTER_URL;
private static MasterPage s_masterP = null; private static MasterPage masterPage = null;
public SimpleItemResolver() {} public SimpleItemResolver() {
}
/** /**
* Return a content item based on page state (and content section). * Return a content item based on page state (and content section).
@ -75,17 +97,20 @@ public class SimpleItemResolver extends AbstractItemResolver implements ItemReso
* @param section The current content section * @param section The current content section
* @param url The section-relative URL * @param url The section-relative URL
* @param context The LIVE/DRAFT context (*not* the template use context) * @param context The LIVE/DRAFT context (*not* the template use context)
* @return The content item mapped to the content section and URL, or *
* null if no such item exists * @return The content item mapped to the content section and URL, or null
* if no such item exists
*/ */
public ContentItem getItem(ContentSection section, String url, @Override
String context) { public ContentItem getItem(final ContentSection section,
final String url,
final String context) {
if (s_log.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
s_log.debug("trying to get " + context + " item for url " + url); LOGGER.debug("trying to get " + context + " item for url " + url);
} }
String itemUrl = stripTemplateFromURL(url); final String itemUrl = stripTemplateFromURL(url);
// getItem fails if called from a JSP template, because the request URL // getItem fails if called from a JSP template, because the request URL
// gets replaced with the filesystem path to the JSP (when // gets replaced with the filesystem path to the JSP (when
@ -95,58 +120,36 @@ public class SimpleItemResolver extends AbstractItemResolver implements ItemReso
ContentItem reqItem = (ContentItem) DispatcherHelper.getRequest(). ContentItem reqItem = (ContentItem) DispatcherHelper.getRequest().
getAttribute("com.arsdigita.cms.dispatcher.item"); getAttribute("com.arsdigita.cms.dispatcher.item");
if (reqItem != null) { if (reqItem != null) {
s_log.info("found item in the request, returning it"); LOGGER.info("found item in the request, returning it");
return reqItem; return reqItem;
} }
//ContentItem item = getCachedItem(section, itemUrl, context); final Folder rootFolder = section.getRootDocumentsFolder();
//if (item != null) { if (rootFolder == null) {
// return item; LOGGER.info("no root folder found, returning null");
//}
Folder rootFolder = section.getRootFolder();
if ( rootFolder == null ) {
s_log.info("no root folder found, returning null");
return null; return null;
} }
if ( context.equals(ContentItem.LIVE) ) { return getItem(itemUrl, rootFolder);
rootFolder = (Folder) rootFolder.getLiveVersion();
if ( rootFolder == null ) {
s_log.info("no LIVE version of root folder found, returning null");
return null;
}
} else if ( context.equals(ContentItem.DRAFT) ) {
// Do nothing ?
} else {
throw new RuntimeException(
"getItem: Invalid item resolver context " + context);
}
ContentItem item = getItem(itemUrl, rootFolder);
//if (item != null) {
// cacheItem(section, itemUrl, context, item);
//}
return item;
} }
/** /**
* @param state the current page state * @param state the current page state
*
* @return the context of the current URL, such as "live" or "admin" * @return the context of the current URL, such as "live" or "admin"
*/ */
public String getCurrentContext(PageState state) { @Override
public String getCurrentContext(final PageState state) {
String url = state.getRequest().getRequestURI(); String url = state.getRequest().getRequestURI();
ContentSection section = final ContentSection section = CMS.getContext().getContentSection();
CMS.getContext().getContentSection();
// If this page is associated with a content section, transform // If this page is associated with a content section, transform
// the URL so that it is relative to the content section site node. // the URL so that it is relative to the content section site node.
if ( section != null ) { if (section != null) {
String sectionURL = section.getURL(); final String sectionURL = section.getPrimaryUrl();
if ( url.startsWith(sectionURL) ) { if (url.startsWith(sectionURL)) {
url = url.substring(sectionURL.length()); url = url.substring(sectionURL.length());
} }
} }
@ -156,176 +159,256 @@ public class SimpleItemResolver extends AbstractItemResolver implements ItemReso
url = stripTemplateFromURL(url); url = stripTemplateFromURL(url);
// Determine if we are under the admin UI. // Determine if we are under the admin UI.
if ( url.startsWith(ADMIN_PREFIX) || if (url.startsWith(ADMIN_PREFIX) || url.startsWith(WORKSPACE_PREFIX)) {
url.startsWith(WORKSPACE_PREFIX) ) { return ContentItemVersion.DRAFT.toString();
return ContentItem.DRAFT;
} else { } else {
return ContentItem.LIVE; return ContentItemVersion.LIVE.toString();
} }
} }
/** /**
* Return the content item at the specified path, or null * Return the content item at the specified path, or null if no such item
* if no such item exists. The path is interpreted as a series * exists. The path is interpreted as a series of folders; for example,
* of folders; for example, "/foo/bar/baz" will look for * "/foo/bar/baz" will look for an item named "baz" in a folder named "bar"
* an item named "baz" in a folder named "bar" in a folder named "foo" * in a folder named "foo" under the specified root folder.
* under the specified root folder.
* *
* @param url the URL to the item * @param url the URL to the item
* @param rootFolder The root folder where the item search will start * @param rootFolder The root folder where the item search will start
*
* @return the item on success, null if no such item exists * @return the item on success, null if no such item exists
* @pre rootFolder != null
* @pre url != null
*/ */
public ContentItem getItem(String url, Folder rootFolder) { public ContentItem getItem(final String url, final Folder rootFolder) {
StringTokenizer tokenizer = new StringTokenizer(url, "/"); final String[] tokens = url.split("/");
String name = null;
Folder oldFolder = null;
while(rootFolder != null && tokenizer.hasMoreTokens()) { Folder currentFolder = rootFolder;
name = tokenizer.nextToken(); int i;
oldFolder = rootFolder; for (i = 0; i < tokens.length; i++) {
rootFolder = (Folder)rootFolder.getItem(name, true); final String token = tokens[i];
final Optional<Folder> folder = currentFolder.getSubFolders()
.stream()
.filter(subFolder -> subFolder.getDisplayName().equals(token))
.findFirst();
if (folder.isPresent()) {
currentFolder = folder.get();
} else {
break;
}
} }
if(tokenizer.hasMoreTokens()) { if (i >= tokens.length - 1) {
// failure // failure
s_log.debug("no more tokens found, returning null"); LOGGER.debug("no more tokens found, returning null");
return null; return null;
} else { } else {
// Get the content item which is the last token //Get the content item which is the last token
if (rootFolder != null ) { final String name = tokens[tokens.length - 1];
ContentItem indexItem = rootFolder.getIndexItem(); final Optional<CcmObject> item = currentFolder.getObjects()
if (indexItem != null) { .stream()
s_log.info("returning index item for folder"); .map(categorization -> categorization.getCategorizedObject())
return indexItem; .filter(object -> object.getDisplayName().equals(name))
} .findFirst();
} if (item.isPresent() && item.get() instanceof ContentItem) {
if ( name == null ) { return (ContentItem) item.get();
s_log.debug("no name found"); } else {
return null; return null;
} }
return oldFolder.getItem(name, false);
} }
} }
// Generate the URL for an item in the DRAFT context /**
private String generateDraftURL(BigDecimal itemId, ContentSection section) { * Generate the URL for an item in the DRAFT context
return ContentItemPage.getItemURL(section.getFullPath() + "/", itemId, *
ContentItemPage.AUTHORING_TAB); * @param itemId
* @param section
*
* @return
*/
private String generateDraftURL(final Long itemId,
final ContentSection section) {
return ContentItemPage.getItemURL(
String.format("%s%s/",
URL.getDispatcherPath(),
section.getPrimaryUrl()),
itemId,
ContentItemPage.AUTHORING_TAB);
} }
/**
* Generate the URL for an item in the LIVE context with a given template
* context
*
* @param item
* @param section
* @param templateContext
*
* @return
*
*/
private String generateLiveURL(final ContentItem item,
final ContentSection section,
final String templateContext) {
// Generate the URL for an item in the LIVE context with a given template context final String templateUrlFrag;
private String generateLiveURL(ContentItem item, ContentSection section, if (templateContext == null || templateContext.isEmpty()) {
String templateContext) { templateUrlFrag = "";
String templateURLFrag = } else {
(templateContext == null || templateContext.length() == 0) ? templateUrlFrag = String.format(TEMPLATE_CONTEXT_PREFIX + "%s/",
"" : TEMPLATE_CONTEXT_PREFIX + templateContext + "/"; templateContext);
return section.getPath() + "/" + templateURLFrag + item.getPath(); }
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final ContentItemManager itemManager = cdiUtil.findBean(
ContentItemManager.class);
return String.format("%s/%s%s",
section.getPrimaryUrl(),
templateUrlFrag,
itemManager.getItemPath(item));
} }
/**
* Generate the preview URL for an item in the DRAFT context.
*
* @param item
* @param section
* @param templateContext
*
* @return
*/
private String generatePreviewURL(final ContentItem item,
final ContentSection section,
final String templateContext) {
final String templateUrlFrag;
if (templateContext == null || templateContext.isEmpty()) {
templateUrlFrag = "";
} else {
templateUrlFrag = String.format(TEMPLATE_CONTEXT_PREFIX + "%s/",
templateContext);
}
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final ContentItemManager itemManager = cdiUtil.findBean(
ContentItemManager.class);
// Generate the preview URL for an item in the DRAFT context final StringBuilder url = new StringBuilder();
private String generatePreviewURL(ContentItem item, ContentSection section,
String templateContext) {
String templateURLFrag =
(templateContext == null || templateContext.length() == 0) ?
"" : TEMPLATE_CONTEXT_PREFIX + templateContext + "/";
StringBuffer url = new StringBuffer();
url url
.append(section.getPath()) .append(section.getPrimaryUrl())
.append("/" + CMSDispatcher.PREVIEW)
.append("/") .append("/")
.append(templateURLFrag) .append(CMSDispatcher.PREVIEW)
.append(item.getPath()); .append("/")
.append(templateUrlFrag)
.append(itemManager.getItemPath(item));
return url.toString(); return url.toString();
} }
/** /**
* Generates a URL for a content item. * Generates a URL for a content item.
* *
* @param itemId The item ID * @param itemId The item ID
* @param name The name of the content page * @param name The name of the content page
* @param state The page state * @param state The page state
* @param section the content section to which the item belongs * @param section the content section to which the item belongs
* @param context the context of the URL, such as "LIVE" or "DRAFT" * @param context the context of the URL, such as "LIVE" or "DRAFT"
*
* @return The URL of the item * @return The URL of the item
* @pre context != null
*/ */
public String generateItemURL(PageState state, BigDecimal itemId, @Override
String name, ContentSection section, public String generateItemURL(final PageState state,
String context) { final Long itemId,
final String name,
final ContentSection section,
final String context) {
return generateItemURL(state, itemId, name, section, context, null); return generateItemURL(state, itemId, name, section, context, null);
} }
/** /**
* Generates a URL for a content item. * Generates a URL for a content item.
* *
* @param itemId The item ID * @param itemId The item ID
* @param name The name of the content page * @param name The name of the content page
* @param state The page state * @param state The page state
* @param section the content section to which the item belongs * @param section the content section to which the item belongs
* @param context the context of the URL, such as "live" or "admin" * @param context the context of the URL, such as "live" or "admin"
* @param templateContext the context for the URL, such as "public" * @param templateContext the context for the URL, such as "public"
*
* @return The URL of the item * @return The URL of the item
* @pre context != null
*/ */
public String generateItemURL(PageState state, BigDecimal itemId, @Override
String name, ContentSection section, public String generateItemURL(final PageState state,
String context, String templateContext) { final Long itemId,
if ( ContentItem.DRAFT.equals(context) ) { final String name,
final ContentSection section,
final String context,
final String templateContext) {
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final ContentItemRepository itemRepo = cdiUtil.findBean(
ContentItemRepository.class);
if (ContentItemVersion.DRAFT.toString().equals(context)) {
return generateDraftURL(itemId, section); return generateDraftURL(itemId, section);
} else if (ContentItem.LIVE.equals(context)) { } else if (ContentItemVersion.LIVE.toString().equals(context)) {
ContentItem item = new ContentItem(itemId); final ContentItem item = itemRepo.findById(itemId);
return generateLiveURL(item, section, templateContext); return generateLiveURL(item, section, templateContext);
} else if (CMSDispatcher.PREVIEW.equals(context)) { } else if (CMSDispatcher.PREVIEW.equals(context)) {
ContentItem item = new ContentItem(itemId); final ContentItem item = itemRepo.findById(itemId);
return generatePreviewURL(item, section, templateContext); return generatePreviewURL(item, section, templateContext);
} else { } else {
throw new RuntimeException( (String) GlobalizationUtil.globalize("cms.dispatcher.unknown_context").localize() + context); throw new IllegalArgumentException(String.format(
"Unknown context \"%s\".", context));
} }
} }
/** /**
* Generates a URL for a content item. * Generates a URL for a content item.
* *
* @param item The item * @param item The item
* @param state The page state * @param state The page state
* @param section the content section to which the item belongs * @param section the content section to which the item belongs
* @param context the context of the URL, such as "LIVE" or "DRAFT" * @param context the context of the URL, such as "LIVE" or "DRAFT"
*
* @return The URL of the item * @return The URL of the item
*
* @see #getCurrentContext * @see #getCurrentContext
*/ */
public String generateItemURL ( @Override
PageState state, ContentItem item, ContentSection section, String context public String generateItemURL(final PageState state,
) { final ContentItem item,
final ContentSection section,
final String context) {
return generateItemURL(state, item, section, context, null); return generateItemURL(state, item, section, context, null);
} }
/** /**
* Generates a URL for a content item. * Generates a URL for a content item.
* *
* @param item The item * @param item The item
* @param state The page state * @param state The page state
* @param section the content section to which the item belongs * @param section the content section to which the item belongs
* @param context the context of the URL, such as "live" or "admin" * @param context the context of the URL, such as "live" or "admin"
* @param templateContext the context for the URL, such as "public" * @param templateContext the context for the URL, such as "public"
*
* @return The URL of the item * @return The URL of the item
*
* @see #getCurrentContext * @see #getCurrentContext
*/ */
public String generateItemURL ( @Override
PageState state, ContentItem item, ContentSection section, public String generateItemURL(final PageState state,
String context, String templateContext final ContentItem item,
) { final ContentSection section,
if (ContentItem.LIVE.equals(context)) { final String context,
final String templateContext) {
if (ContentItemVersion.LIVE.toString().equals(context)) {
return generateLiveURL(item, section, templateContext); return generateLiveURL(item, section, templateContext);
} else if (ContentItem.DRAFT.equals(context)) { } else if (ContentItemVersion.DRAFT.toString().equals(context)) {
return generateDraftURL(item.getID(), section); return generateDraftURL(item.getObjectId(), section);
} else if (CMSDispatcher.PREVIEW.equals(context)) { } else if (CMSDispatcher.PREVIEW.equals(context)) {
return generatePreviewURL(item, section, templateContext); return generatePreviewURL(item, section, templateContext);
} else { } else {
throw new RuntimeException( (String) GlobalizationUtil.globalize("cms.dispatcher.unknown_context").localize() + context); throw new IllegalArgumentException(String.format(
"Unknown context \"%s\".", context));
} }
} }
@ -334,16 +417,20 @@ public class SimpleItemResolver extends AbstractItemResolver implements ItemReso
* *
* @param item The content item * @param item The content item
* @param request The HTTP request * @param request The HTTP request
*
* @throws javax.servlet.ServletException
*/ */
public CMSPage getMasterPage(ContentItem item, HttpServletRequest request) @Override
public CMSPage getMasterPage(final ContentItem item,
final HttpServletRequest request)
throws ServletException { throws ServletException {
if ( s_masterP == null ) { if (masterPage == null) {
s_masterP = new MasterPage(); masterPage = new MasterPage();
s_masterP.init(); masterPage.init();
} }
return s_masterP; return masterPage;
} }
} }

View File

@ -36,7 +36,9 @@ import com.arsdigita.bebop.event.FormProcessListener;
import com.arsdigita.bebop.event.FormSectionEvent; import com.arsdigita.bebop.event.FormSectionEvent;
import com.arsdigita.bebop.Label; import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.list.ListCellRenderer; import com.arsdigita.bebop.list.ListCellRenderer;
import org.librecms.contentsection.ContentType; import org.librecms.contentsection.ContentType;
import com.arsdigita.cms.ItemSelectionModel; import com.arsdigita.cms.ItemSelectionModel;
import com.arsdigita.cms.ui.ContentItemPage; import com.arsdigita.cms.ui.ContentItemPage;
import com.arsdigita.cms.ui.item.ItemWorkflowRequestLocal; import com.arsdigita.cms.ui.item.ItemWorkflowRequestLocal;
@ -46,13 +48,13 @@ import com.arsdigita.cms.ui.workflow.TaskFinishForm;
import com.arsdigita.cms.ui.workflow.TaskRequestLocal; import com.arsdigita.cms.ui.workflow.TaskRequestLocal;
import com.arsdigita.cms.ui.workflow.WorkflowRequestLocal; import com.arsdigita.cms.ui.workflow.WorkflowRequestLocal;
import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.kernel.KernelConfig;
import com.arsdigita.toolbox.ui.LayoutPanel; import com.arsdigita.toolbox.ui.LayoutPanel;
import com.arsdigita.toolbox.ui.ModalPanel; import com.arsdigita.toolbox.ui.ModalPanel;
import com.arsdigita.toolbox.ui.Section; import com.arsdigita.toolbox.ui.Section;
import com.arsdigita.util.Assert; import com.arsdigita.util.Assert;
import com.arsdigita.util.SequentialMap; import com.arsdigita.util.SequentialMap;
import com.arsdigita.util.UncheckedWrapperException; import com.arsdigita.util.UncheckedWrapperException;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
@ -60,9 +62,9 @@ import java.lang.reflect.InvocationTargetException;
import java.util.Iterator; import java.util.Iterator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.arsdigita.cms.CMSConfig; import org.arsdigita.cms.CMSConfig;
import org.libreccm.cdi.utils.CdiUtil; import org.libreccm.cdi.utils.CdiUtil;

View File

@ -21,26 +21,20 @@ package com.arsdigita.cms.ui.authoring;
import com.arsdigita.bebop.Component; import com.arsdigita.bebop.Component;
import com.arsdigita.bebop.PageState; import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.Resettable; import com.arsdigita.bebop.Resettable;
import com.arsdigita.bebop.SimpleContainer;
import com.arsdigita.bebop.SingleSelectionModel; import com.arsdigita.bebop.SingleSelectionModel;
import com.arsdigita.bebop.parameters.BigDecimalParameter;
import com.arsdigita.bebop.parameters.LongParameter; import com.arsdigita.bebop.parameters.LongParameter;
import com.arsdigita.bebop.parameters.StringParameter;
import org.librecms.contentsection.ContentItem; import org.librecms.contentsection.ContentItem;
import org.librecms.contentsection.ContentType; import org.librecms.contentsection.ContentType;
import com.arsdigita.cms.ItemSelectionModel; import com.arsdigita.cms.ItemSelectionModel;
import com.arsdigita.toolbox.ui.LayoutPanel; import com.arsdigita.kernel.ui.ACSObjectSelectionModel;
import com.arsdigita.util.UncheckedWrapperException; import com.arsdigita.util.UncheckedWrapperException;
import com.arsdigita.xml.Element; import com.arsdigita.xml.Element;
import oracle.jrockit.jfr.events.ContentTypeImpl;
import org.librecms.contenttypes.AuthoringKit;
import org.librecms.contenttypes.AuthoringKitInfo; import org.librecms.contenttypes.AuthoringKitInfo;
import org.librecms.contenttypes.ContentTypeInfo; import org.librecms.contenttypes.ContentTypeInfo;
import java.math.BigDecimal;
/** /**
* An invisible component which contains all the possible authoring kits. The * An invisible component which contains all the possible authoring kits. The
@ -55,7 +49,7 @@ import java.math.BigDecimal;
* @author unknown * @author unknown
*/ */
public class WizardSelector extends AuthoringKitSelector public class WizardSelector extends AuthoringKitSelector
implements Resettable { implements Resettable {
private final ItemSelectionModel itemSelectionModel; private final ItemSelectionModel itemSelectionModel;
@ -63,11 +57,11 @@ public class WizardSelector extends AuthoringKitSelector
* Construct a new WizardSelector. Load all the possible authoring kits from * Construct a new WizardSelector. Load all the possible authoring kits from
* the database and construct wizards for them. * the database and construct wizards for them.
* *
* @param model the {@link ItemSelectionModel} which will supply the wizard * @param model the {@link ItemSelectionModel} which will supply the
* with its item * wizard with its item
* *
* @param typeModel the {@link ACSObjectSelectionModel} which will supply * @param typeModel the {@link ACSObjectSelectionModel} which will supply
* the default content type * the default content type
* *
* @pre itemModel != null * @pre itemModel != null
*/ */
@ -83,6 +77,7 @@ public class WizardSelector extends AuthoringKitSelector
* *
* @param kit * @param kit
* @param type * @param type
*
* @return * @return
*/ */
@Override @Override
@ -90,9 +85,10 @@ public class WizardSelector extends AuthoringKitSelector
final ContentTypeInfo type) { final ContentTypeInfo type) {
final ItemSelectionModel itemModel = new ItemSelectionModel( final ItemSelectionModel itemModel = new ItemSelectionModel(
type, (LongParameter) itemSelectionModel.getStateParameter()); type, (LongParameter) itemSelectionModel.getStateParameter());
final AuthoringKitWizard wizard = new AuthoringKitWizard(type, itemModel); final AuthoringKitWizard wizard
= new AuthoringKitWizard(type, itemModel);
return wizard; return wizard;
} }
@ -111,8 +107,7 @@ public class WizardSelector extends AuthoringKitSelector
throw new UncheckedWrapperException("No item selected."); throw new UncheckedWrapperException("No item selected.");
} }
final ContentItem item = (ContentItem) itemSelectionModel final ContentItem item = itemSelectionModel.getSelectedObject(state);
.getSelectedObject(state);
final ContentType type = item.getContentType(); final ContentType type = item.getContentType();
final String typeClass; final String typeClass;
@ -128,7 +123,7 @@ public class WizardSelector extends AuthoringKitSelector
} }
// Return the selected wizard // Return the selected wizard
return (Component) getComponent(typeClass); return getComponent(typeClass);
} }
// Choose the right wizard and run it // Choose the right wizard and run it

View File

@ -65,76 +65,83 @@ import static org.librecms.CmsConstants.*;
@Table(name = "CONTENT_ITEMS", schema = DB_SCHEMA) @Table(name = "CONTENT_ITEMS", schema = DB_SCHEMA)
@NamedQueries({ @NamedQueries({
@NamedQuery( @NamedQuery(
name = "ContentItem.findByType", name = "ContentItem.findByType",
query = "SELECT i FROM ContentItem i WHERE TYPE(i) = :type") query = "SELECT i FROM ContentItem i WHERE TYPE(i) = :type")
, ,
@NamedQuery( @NamedQuery(
name = "ContentItem.findByFolder", name = "ContentItem.findByFolder",
query = "SELECT i FROM ContentItem i " query = "SELECT i FROM ContentItem i "
+ "JOIN i.categories c " + "JOIN i.categories c "
+ "WHERE c.category = :folder " + "WHERE c.category = :folder "
+ "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER + "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER
+ "'") + "'")
, ,
@NamedQuery( @NamedQuery(
name = "ContentItem.countItemsInFolder", name = "ContentItem.countItemsInFolder",
query = "SELECT count(i) FROM ContentItem i " query = "SELECT count(i) FROM ContentItem i "
+ "JOIN i.categories c " + "JOIN i.categories c "
+ "WHERE c.category = :folder " + "WHERE c.category = :folder "
+ "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER + "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER
+ "'") + "'")
, ,
@NamedQuery( @NamedQuery(
name = "ContentItem.countByNameInFolder", name = "ContentItem.findByNameInFolder",
query = "SELECT COUNT(i) FROM ContentItem i " query = "SELECT i FROM ContentItem i "
+ "JOIN i.categories c " + "JOIN i.categories c "
+ "WHERE c.category = :folder " + "WHERE c.category = :folder "
+ "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER + "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER + "' "
+ "' " + "AND i.displayName = :name")
+ "AND i.displayName = :name")
, ,
@NamedQuery( @NamedQuery(
name = "ContentItem.filterByFolderAndName", name = "ContentItem.countByNameInFolder",
query = "SELECT i FROM ContentItem i " query = "SELECT COUNT(i) FROM ContentItem i "
+ "JOIN i.categories c " + "JOIN i.categories c "
+ "WHERE c.category = :folder " + "WHERE c.category = :folder "
+ "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER + "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER + "' "
+ "' " + "AND i.displayName = :name")
+ "AND LOWER(i.displayName) LIKE CONCAT(LOWER(:name), '%')")
, ,
@NamedQuery( @NamedQuery(
name = "ContentItem.countFilterByFolderAndName", name = "ContentItem.filterByFolderAndName",
query = "SELECT COUNT(i) FROM ContentItem i " query = "SELECT i FROM ContentItem i "
+ "JOIN i.categories c " + "JOIN i.categories c "
+ "WHERE c.category = :folder " + "WHERE c.category = :folder "
+ "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER + "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER
+ "' " + "' "
+ "AND LOWER(i.displayName) LIKE CONCAT(LOWER(:name), '%')" + "AND LOWER(i.displayName) LIKE CONCAT(LOWER(:name), '%')")
,
@NamedQuery(
name = "ContentItem.countFilterByFolderAndName",
query = "SELECT COUNT(i) FROM ContentItem i "
+ "JOIN i.categories c "
+ "WHERE c.category = :folder "
+ "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER
+ "' "
+ "AND LOWER(i.displayName) LIKE CONCAT(LOWER(:name), '%')"
) )
, ,
@NamedQuery( @NamedQuery(
name = "ContentItem.hasLiveVersion", name = "ContentItem.hasLiveVersion",
query = "SELECT (CASE WHEN COUNT(i) > 0 THEN true ELSE false END) " query = "SELECT (CASE WHEN COUNT(i) > 0 THEN true ELSE false END) "
+ "FROM ContentItem i " + "FROM ContentItem i "
+ "WHERE i.itemUuid = :uuid " + "WHERE i.itemUuid = :uuid "
+ "AND i.version = org.librecms.contentsection.ContentItemVersion.LIVE") + "AND i.version = org.librecms.contentsection.ContentItemVersion.LIVE")
, ,
@NamedQuery( @NamedQuery(
name = "ContentItem.findDraftVersion", name = "ContentItem.findDraftVersion",
query = "SELECT i FROM ContentItem i " query = "SELECT i FROM ContentItem i "
+ "WHERE i.itemUuid = :uuid " + "WHERE i.itemUuid = :uuid "
+ "AND i.version = org.librecms.contentsection.ContentItemVersion.DRAFT") + "AND i.version = org.librecms.contentsection.ContentItemVersion.DRAFT")
, ,
@NamedQuery( @NamedQuery(
name = "ContentItem.findLiveVersion", name = "ContentItem.findLiveVersion",
query = "SELECT i FROM ContentItem i " query = "SELECT i FROM ContentItem i "
+ "WHERE i.itemUuid = :uuid " + "WHERE i.itemUuid = :uuid "
+ "AND i.version = org.librecms.contentsection.ContentItemVersion.LIVE") + "AND i.version = org.librecms.contentsection.ContentItemVersion.LIVE")
, ,
@NamedQuery( @NamedQuery(
name = "ContentItem.findItemWithWorkflow", name = "ContentItem.findItemWithWorkflow",
query = "SELECT i FROM ContentItem i " query = "SELECT i FROM ContentItem i "
+ "WHERE i.workflow = :workflow" + "WHERE i.workflow = :workflow"
) )
}) })
public class ContentItem extends CcmObject implements Serializable, public class ContentItem extends CcmObject implements Serializable,
@ -153,13 +160,13 @@ public class ContentItem extends CcmObject implements Serializable,
*/ */
@Embedded @Embedded
@AssociationOverride( @AssociationOverride(
name = "values", name = "values",
joinTable = @JoinTable(name = "CONTENT_ITEM_NAMES", joinTable = @JoinTable(name = "CONTENT_ITEM_NAMES",
schema = DB_SCHEMA, schema = DB_SCHEMA,
joinColumns = { joinColumns = {
@JoinColumn(name = "OBJECT_ID") @JoinColumn(name = "OBJECT_ID")
} }
) )
) )
private LocalizedString name; private LocalizedString name;
@ -176,13 +183,13 @@ public class ContentItem extends CcmObject implements Serializable,
*/ */
@Embedded @Embedded
@AssociationOverride( @AssociationOverride(
name = "values", name = "values",
joinTable = @JoinTable(name = "CONTENT_ITEM_TITLES", joinTable = @JoinTable(name = "CONTENT_ITEM_TITLES",
schema = DB_SCHEMA, schema = DB_SCHEMA,
joinColumns = { joinColumns = {
@JoinColumn(name = "OBJECT_ID") @JoinColumn(name = "OBJECT_ID")
} }
) )
) )
private LocalizedString title; private LocalizedString title;
@ -191,12 +198,12 @@ public class ContentItem extends CcmObject implements Serializable,
*/ */
@Embedded @Embedded
@AssociationOverride( @AssociationOverride(
name = "values", name = "values",
joinTable = @JoinTable(name = "CONTENT_ITEM_DESCRIPTIONS", joinTable = @JoinTable(name = "CONTENT_ITEM_DESCRIPTIONS",
schema = DB_SCHEMA, schema = DB_SCHEMA,
joinColumns = { joinColumns = {
@JoinColumn(name = "OBJECT_ID")} @JoinColumn(name = "OBJECT_ID")}
)) ))
private LocalizedString description; private LocalizedString description;
/** /**
@ -352,10 +359,10 @@ public class ContentItem extends CcmObject implements Serializable,
@Override @Override
public Optional<CcmObject> getParent() { public Optional<CcmObject> getParent() {
final List<Categorization> result = getCategories().stream().filter( final List<Categorization> result = getCategories().stream().filter(
categorization -> CmsConstants.CATEGORIZATION_TYPE_FOLDER. categorization -> CmsConstants.CATEGORIZATION_TYPE_FOLDER.
equals( equals(
categorization.getType())) categorization.getType()))
.collect(Collectors.toList()); .collect(Collectors.toList());
if (result.isEmpty()) { if (result.isEmpty()) {
return Optional.empty(); return Optional.empty();
@ -434,15 +441,15 @@ public class ContentItem extends CcmObject implements Serializable,
@Override @Override
public String toString(final String data) { public String toString(final String data) {
return super.toString(String.format(", itemUuid = %s, " return super.toString(String.format(", itemUuid = %s, "
+ "name = %s, " + "name = %s, "
+ "contentType = { %s }, " + "contentType = { %s }, "
+ "title = %s, " + "title = %s, "
+ "description = %s, " + "description = %s, "
+ "version = %s, " + "version = %s, "
+ "launchDate = %s, " + "launchDate = %s, "
+ "lifecycle = { %s }, " + "lifecycle = { %s }, "
+ "workflow = { %s }" + "workflow = { %s }"
+ "%s", + "%s",
itemUuid, itemUuid,
Objects.toString(name), Objects.toString(name),
Objects.toString(contentType), Objects.toString(contentType),

View File

@ -40,11 +40,14 @@ import org.libreccm.workflow.Workflow;
*/ */
@RequestScoped @RequestScoped
public class ContentItemRepository public class ContentItemRepository
extends AbstractAuditedEntityRepository<Long, ContentItem> { extends AbstractAuditedEntityRepository<Long, ContentItem> {
@Inject @Inject
private CcmObjectRepository ccmObjectRepo; private CcmObjectRepository ccmObjectRepo;
@Inject
private FolderRepository folderRepo;
@Override @Override
public Long getEntityId(final ContentItem item) { public Long getEntityId(final ContentItem item) {
return item.getObjectId(); return item.getObjectId();
@ -75,7 +78,7 @@ public class ContentItemRepository
* @param itemId The id of item to retrieve. * @param itemId The id of item to retrieve.
* *
* @return The content item identified by the provided {@code itemId} or * @return The content item identified by the provided {@code itemId} or
* nothing if there is such content item. * nothing if there is such content item.
*/ */
public Optional<ContentItem> findById(final long itemId) { public Optional<ContentItem> findById(final long itemId) {
final Optional<CcmObject> result = ccmObjectRepo.findObjectById(itemId); final Optional<CcmObject> result = ccmObjectRepo.findObjectById(itemId);
@ -89,13 +92,13 @@ public class ContentItemRepository
/** /**
* Finds a content item by its ID and ensures that is a the requested type. * Finds a content item by its ID and ensures that is a the requested type.
* *
* @param <T> The type of the content item. * @param <T> The type of the content item.
* @param itemId The id of item to retrieve. * @param itemId The id of item to retrieve.
* @param type The type of the content item. * @param type The type of the content item.
* *
* @return The content item identified by the provided id or an empty * @return The content item identified by the provided id or an empty
* {@link Optional} if there is no such item or if it is not of the * {@link Optional} if there is no such item or if it is not of the
* requested type. * requested type.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T extends ContentItem> Optional<T> findById(final long itemId, public <T extends ContentItem> Optional<T> findById(final long itemId,
@ -114,7 +117,7 @@ public class ContentItemRepository
* @param uuid The id of item to retrieve. * @param uuid The id of item to retrieve.
* *
* @return The content item identified by the provided {@code uuid} or * @return The content item identified by the provided {@code uuid} or
* nothing if there is such content item. * nothing if there is such content item.
*/ */
public Optional<ContentItem> findByUuid(final String uuid) { public Optional<ContentItem> findByUuid(final String uuid) {
final Optional<CcmObject> result = ccmObjectRepo.findObjectByUuid(uuid); final Optional<CcmObject> result = ccmObjectRepo.findObjectByUuid(uuid);
@ -129,13 +132,13 @@ public class ContentItemRepository
* Finds a content item by its UUID and ensures that is a the requested * Finds a content item by its UUID and ensures that is a the requested
* type. * type.
* *
* @param <T> The type of the content item. * @param <T> The type of the content item.
* @param uuid The UUID of item to retrieve. * @param uuid The UUID of item to retrieve.
* @param type The type of the content item. * @param type The type of the content item.
* *
* @return The content item identified by the provided UUID or an empty * @return The content item identified by the provided UUID or an empty
* {@link Optional} if there is no such item or if it is not of the * {@link Optional} if there is no such item or if it is not of the
* requested type. * requested type.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T extends ContentItem> Optional<T> findByUuid(final String uuid, public <T extends ContentItem> Optional<T> findByUuid(final String uuid,
@ -143,7 +146,7 @@ public class ContentItemRepository
final Optional<CcmObject> result = ccmObjectRepo.findObjectByUuid(uuid); final Optional<CcmObject> result = ccmObjectRepo.findObjectByUuid(uuid);
if (result.isPresent() if (result.isPresent()
&& result.get().getClass().isAssignableFrom(type)) { && result.get().getClass().isAssignableFrom(type)) {
return Optional.of((T) result.get()); return Optional.of((T) result.get());
} else { } else {
return Optional.empty(); return Optional.empty();
@ -153,7 +156,7 @@ public class ContentItemRepository
/** /**
* Finds all content items of a specific type. * Finds all content items of a specific type.
* *
* @param <T> The type of the items. * @param <T> The type of the items.
* @param type The type of the items. * @param type The type of the items.
* *
* @return A list of all content items of the requested type. * @return A list of all content items of the requested type.
@ -161,7 +164,7 @@ public class ContentItemRepository
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T extends ContentItem> List<T> findByType(final Class<T> type) { public <T extends ContentItem> List<T> findByType(final Class<T> type) {
final TypedQuery<ContentItem> query = getEntityManager() final TypedQuery<ContentItem> query = getEntityManager()
.createNamedQuery("ContentItem.findByType", ContentItem.class); .createNamedQuery("ContentItem.findByType", ContentItem.class);
query.setParameter("type", type); query.setParameter("type", type);
return (List<T>) query.getResultList(); return (List<T>) query.getResultList();
@ -176,8 +179,8 @@ public class ContentItemRepository
*/ */
public List<ContentItem> findByFolder(final Category folder) { public List<ContentItem> findByFolder(final Category folder) {
final TypedQuery<ContentItem> query = getEntityManager() final TypedQuery<ContentItem> query = getEntityManager()
.createNamedQuery("ContentItem.findByFolder", .createNamedQuery("ContentItem.findByFolder",
ContentItem.class); ContentItem.class);
query.setParameter("folder", folder); query.setParameter("folder", folder);
return query.getResultList(); return query.getResultList();
@ -187,26 +190,43 @@ public class ContentItemRepository
* Counts the items in a folder/category. * Counts the items in a folder/category.
* *
* @param folder The folder/category * @param folder The folder/category
*
* @return The number of content items in the category/folder. * @return The number of content items in the category/folder.
*/ */
public long countItemsInFolder(final Category folder) { public long countItemsInFolder(final Category folder) {
final TypedQuery<Long> query = getEntityManager() final TypedQuery<Long> query = getEntityManager()
.createNamedQuery("ContentItem.countItemsInFolder", Long.class); .createNamedQuery("ContentItem.countItemsInFolder", Long.class);
query.setParameter("folder", folder); query.setParameter("folder", folder);
return query.getSingleResult(); return query.getSingleResult();
} }
public Optional<ContentItem> findByNameInFolder(final Category folder,
final String name) {
final TypedQuery<ContentItem> query = getEntityManager()
.createNamedQuery("ContentItem.findByNameInFolder",
ContentItem.class);
query.setParameter("folder", folder);
query.setParameter("name", name);
try {
return Optional.of(query.getSingleResult());
} catch (NoResultException ex) {
return Optional.empty();
}
}
/** /**
* Counts the number of items with a specific name in a folder/category. * Counts the number of items with a specific name in a folder/category.
* *
* @param folder * @param folder
* @param name * @param name
*
* @return * @return
*/ */
public long countByNameInFolder(final Category folder, final String name) { public long countByNameInFolder(final Category folder, final String name) {
final TypedQuery<Long> query = getEntityManager().createNamedQuery( final TypedQuery<Long> query = getEntityManager().createNamedQuery(
"ContentItem.countByNameInFolder", Long.class); "ContentItem.countByNameInFolder", Long.class);
query.setParameter("folder", folder); query.setParameter("folder", folder);
query.setParameter("name", name); query.setParameter("name", name);
@ -219,14 +239,15 @@ public class ContentItemRepository
* pattern. * pattern.
* *
* @param folder The folder/category whose items are filtered. * @param folder The folder/category whose items are filtered.
* @param name The name pattern to use. * @param name The name pattern to use.
*
* @return A list with all items in the folder matching the provided filter. * @return A list with all items in the folder matching the provided filter.
*/ */
public List<ContentItem> filterByFolderAndName(final Category folder, public List<ContentItem> filterByFolderAndName(final Category folder,
final String name) { final String name) {
final TypedQuery<ContentItem> query = getEntityManager() final TypedQuery<ContentItem> query = getEntityManager()
.createNamedQuery("ContentItem.filterByFolderAndName", .createNamedQuery("ContentItem.filterByFolderAndName",
ContentItem.class); ContentItem.class);
query.setParameter("folder", folder); query.setParameter("folder", folder);
query.setParameter("name", name); query.setParameter("name", name);
@ -238,15 +259,16 @@ public class ContentItemRepository
* starts with the provided pattern. * starts with the provided pattern.
* *
* @param folder The folder/category to use. * @param folder The folder/category to use.
* @param name The name pattern to use. * @param name The name pattern to use.
*
* @return The number of items in the folder/category which match the * @return The number of items in the folder/category which match the
* provided pattern. * provided pattern.
*/ */
public long countFilterByFolderAndName(final Category folder, public long countFilterByFolderAndName(final Category folder,
final String name) { final String name) {
final TypedQuery<Long> query = getEntityManager() final TypedQuery<Long> query = getEntityManager()
.createNamedQuery("ContentItem.countFilterByFolderAndName", .createNamedQuery("ContentItem.countFilterByFolderAndName",
Long.class); Long.class);
query.setParameter("folder", folder); query.setParameter("folder", folder);
query.setParameter("name", name); query.setParameter("name", name);
@ -255,13 +277,72 @@ public class ContentItemRepository
public Optional<ContentItem> findItemWithWorkflow(final Workflow workflow) { public Optional<ContentItem> findItemWithWorkflow(final Workflow workflow) {
final TypedQuery<ContentItem> query = getEntityManager() final TypedQuery<ContentItem> query = getEntityManager()
.createNamedQuery("ContentItem.findItemWithWorkflow", .createNamedQuery("ContentItem.findItemWithWorkflow",
ContentItem.class); ContentItem.class);
query.setParameter("workflow", workflow); query.setParameter("workflow", workflow);
try { try {
return Optional.of(query.getSingleResult()); return Optional.of(query.getSingleResult());
} catch(NoResultException ex) { } catch (NoResultException ex) {
return Optional.empty();
}
}
/**
* Finds a {@link ContentItem} by its path inside a {@link ContentSection}.
*
* @param path The path of the item <strong>including</strong> the content
* section, separated from the rest of the path by a
* <code>:</code>.
*
* @return An {@link Optional} containing the content item identified by the
* provided path or an empty {@code Optional} if there is no such
* item.
*/
public Optional<ContentItem> findByPath(final String path) {
//The last token is the name of the item itself. Remove this part an get
//the folder containing the item using the FolderRepository.
final String normalizedPath = PathUtil.normalizePath(path);
final int lastTokenStart = normalizedPath.lastIndexOf('/');
final String folderPath = normalizedPath.substring(0, lastTokenStart);
final String itemName = normalizedPath.substring(lastTokenStart + 1);
final Optional<Folder> folder = folderRepo.findByPath(
folderPath, FolderType.DOCUMENTS_FOLDER);
if (folder.isPresent()) {
return findByNameInFolder(folder.get(), itemName);
} else {
return Optional.empty();
}
}
/**
* Finds a {@link ContentItem} by its path inside the provided
* {@link ContentSection}.
*
* @param section The section to which the item belongs.
* @param path The path of the item inside this content section.
*
* @return An {@link Optional} containing the content item identified by the
* provided path or an empty {@code Optional} if there is no such
* item.
*/
public Optional<ContentItem> findByPath(final ContentSection section,
final String path) {
//The last token is the name of the item itself. Remove this part an get
//the folder containing the item using the FolderRepository.
final String normalizedPath = PathUtil.normalizePath(path);
final int lastTokenStart = normalizedPath.lastIndexOf('/');
final String folderPath = normalizedPath.substring(0, lastTokenStart);
final String itemName = normalizedPath.substring(lastTokenStart + 1);
final Optional<Folder> folder = folderRepo.findByPath(
section, folderPath, FolderType.DOCUMENTS_FOLDER);
if (folder.isPresent()) {
return findByNameInFolder(folder.get(), itemName);
} else {
return Optional.empty(); return Optional.empty();
} }
} }

View File

@ -125,15 +125,17 @@ public class FolderRepository extends AbstractEntityRepository<Long, Folder> {
throw new IllegalArgumentException("Path can't be null or empty."); throw new IllegalArgumentException("Path can't be null or empty.");
} }
String normalizedPath = path.replace('.', '/'); // String normalizedPath = path.replace('.', '/');
if (normalizedPath.charAt(0) == '/') { // if (normalizedPath.charAt(0) == '/') {
normalizedPath = normalizedPath.substring(1); // normalizedPath = normalizedPath.substring(1);
} // }
//
if (normalizedPath.endsWith("/")) { // if (normalizedPath.endsWith("/")) {
normalizedPath = normalizedPath.substring(0, // normalizedPath = normalizedPath.substring(0,
normalizedPath.length()); // normalizedPath.length());
} // }
//
final String normalizedPath = PathUtil.normalizePath(path);
LOGGER.debug("Trying to find folder with path \"{}\" and type {} in" LOGGER.debug("Trying to find folder with path \"{}\" and type {} in"
+ "content section \"{}\".", + "content section \"{}\".",

View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2016 LibreCCM Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.librecms.contentsection;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public final class PathUtil {
private PathUtil() {
//Nothing
}
/**
* Normalises a path so that the path can be easily processed. This is a
* helper method used by several classes in this package.
*
* The method does the following:
* <ul>
* <li>Replace all "<code>.</code>" in the path with a slash.</li>
* <li>If the first character is a slash remove the character.</li>
* <li>If the last character is a slash remove the character.</li>
* </ul>
*
* @param path
* @return
*/
protected static final String normalizePath(final String path) {
String normalizedPath = path.replace('.', '/');
if (normalizedPath.charAt(0) == '/') {
normalizedPath = normalizedPath.substring(1);
}
if (normalizedPath.endsWith("/")) {
normalizedPath = normalizedPath.substring(0,
normalizedPath.length());
}
return normalizedPath;
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (C) 2016 LibreCCM Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.pagemodel.ui;
import com.arsdigita.bebop.tree.TreeNode;
import com.arsdigita.kernel.KernelConfig;
import java.util.Locale;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.l10n.GlobalizationHelper;
import org.libreccm.web.CcmApplication;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class ApplicationTreeNode implements TreeNode {
private final CcmApplication application;
public ApplicationTreeNode(final CcmApplication application) {
this.application = application;
}
public CcmApplication getApplication() {
return application;
}
@Override
public Object getKey() {
return application.getPrimaryUrl();
}
@Override
public Object getElement() {
final GlobalizationHelper globalizationHelper = CdiUtil.createCdiUtil().findBean(GlobalizationHelper.class);
final Locale locale = globalizationHelper.getNegotiatedLocale();
if (application.getTitle().hasValue(locale)) {
return application.getTitle().hasValue(locale);
} else {
final Locale defaultLocale = KernelConfig.getConfig().getDefaultLocale();
return application.getTitle().getValue(defaultLocale);
}
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2016 LibreCCM Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.pagemodel.ui;
import com.arsdigita.bebop.tree.TreeNode;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.web.CcmApplication;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
class ApplicationTypeTreeNode implements TreeNode {
private final Class<? extends CcmApplication> appType;
protected ApplicationTypeTreeNode(
final Class<? extends CcmApplication> appType) {
this.appType = appType;
}
@Override
public Object getKey() {
return appType.getName();
}
@Override
public Object getElement() {
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final PageModelTreeController controller = cdiUtil.findBean(
PageModelTreeController.class);
return controller.getAppTypeTitle(appType);
}
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2016 LibreCCM Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.pagemodel.ui;
import com.arsdigita.bebop.Tree;
import com.arsdigita.toolbox.ui.LayoutPanel;
import java.util.Map;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class PageModelPane extends LayoutPanel {
private final Tree tree;
public PageModelPane() {
super();
setClassAttr("sidebarNavPanel");
tree = new Tree(new PageModelTreeModelBuilder());
}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2016 LibreCCM Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.pagemodel.ui;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import org.libreccm.web.ApplicationManager;
import org.libreccm.web.ApplicationType;
import org.libreccm.web.CcmApplication;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class PageModelTreeController {
@Inject
private ApplicationManager applicationManager;
public String getAppTypeTitle(final Class<? extends CcmApplication> appType) {
final ApplicationType applicationType = applicationManager.
getApplicationTypes().get(appType.getClass().getName());
return applicationManager.getApplicationTypeTitle(applicationType);
}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2016 LibreCCM Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.pagemodel.ui;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.Tree;
import com.arsdigita.bebop.tree.TreeModel;
import com.arsdigita.bebop.tree.TreeModelBuilder;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
class PageModelTreeModelBuilder implements TreeModelBuilder {
@Override
public TreeModel makeModel(final Tree tree, final PageState state) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void lock() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public boolean isLocked() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (C) 2016 LibreCCM Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.pagemodel.ui;
import com.arsdigita.bebop.tree.TreeNode;
import com.arsdigita.kernel.KernelConfig;
import java.util.Locale;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.l10n.GlobalizationHelper;
import org.libreccm.pagemodel.PageModel;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
class PageModelTreeNode implements TreeNode {
private final PageModel pageModel;
protected PageModelTreeNode(final PageModel pageModel) {
this.pageModel = pageModel;
}
@Override
public Object getKey() {
return pageModel.getName();
}
@Override
public Object getElement() {
final GlobalizationHelper globalizationHelper = CdiUtil.createCdiUtil().
findBean(GlobalizationHelper.class);
final Locale locale = globalizationHelper.getNegotiatedLocale();
if (pageModel.getTitle().hasValue(locale)) {
return pageModel.getTitle().getValue(locale);
} else {
final Locale defaultLocale = KernelConfig.getConfig().
getDefaultLocale();
return pageModel.getTitle().getValue(defaultLocale);
}
}
}

View File

@ -0,0 +1,82 @@
/*
* Copyright (C) 2016 LibreCCM Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.pagemodel.ui;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.tree.TreeModel;
import com.arsdigita.bebop.tree.TreeNode;
import java.util.Iterator;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.pagemodel.PageModelRepository;
import org.libreccm.web.CcmApplication;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
class PageTreeModel implements TreeModel {
@Override
public TreeNode getRoot(final PageState state) {
return new RootNode();
}
@Override
public boolean hasChildren(final TreeNode node, final PageState state) {
if (node instanceof RootNode) {
return true;
} else if (node instanceof ApplicationTypeTreeNode) {
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final PageModelRepository pageModelRepo = cdiUtil.findBean(
PageModelRepository.class);
final CcmApplication application = ((ApplicationTreeNode) node)
.getApplication();
final long count = pageModelRepo.countByApplication(application);
return count > 0;
} else if (node instanceof PageModelTreeNode) {
return false;
} else {
throw new IllegalArgumentException(String.format(
"Unexpected node type: \"%s\".", node.getClass().getName()));
}
}
@Override
public Iterator getChildren(final TreeNode node, final PageState state) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
private class RootNode implements TreeNode {
@Override
public Object getKey() {
return "-1";
}
@Override
public Object getElement() {
return "PageModels";
}
}
}