Removed several deprecated packages from ccm-cms
parent
56e119e4f7
commit
a127e7ea62
|
|
@ -1,718 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.dispatcher;
|
||||
|
||||
import com.arsdigita.dispatcher.ChainedDispatcher;
|
||||
import com.arsdigita.dispatcher.Dispatcher;
|
||||
import com.arsdigita.dispatcher.DispatcherHelper;
|
||||
import com.arsdigita.dispatcher.JSPApplicationDispatcher;
|
||||
import com.arsdigita.dispatcher.RedirectException;
|
||||
import com.arsdigita.dispatcher.RequestContext;
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
import com.arsdigita.web.LoginSignal;
|
||||
import com.arsdigita.web.URL;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.shiro.authz.AuthorizationException;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.core.UnexpectedErrorException;
|
||||
import org.libreccm.security.PermissionChecker;
|
||||
import org.libreccm.security.Shiro;
|
||||
import org.libreccm.security.User;
|
||||
import org.librecms.CmsConstants;
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
import org.librecms.contentsection.ContentSectionManager;
|
||||
import org.librecms.contentsection.ContentSectionRepository;
|
||||
import org.librecms.contentsection.privileges.ItemPrivileges;
|
||||
import org.librecms.dispatcher.ItemResolver;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The CMS Dispatcher serves all request made within a content section. This
|
||||
* dispatcher is called by the Subsite dispatcher.</p>
|
||||
*
|
||||
* <p>
|
||||
* Here are the steps for a request to
|
||||
* <tt>http://yourserver/cms/cheese</tt> in excruciating detail:</p>
|
||||
*
|
||||
* <ol>
|
||||
* <li><p>
|
||||
* A client sends a request to the web server, which passes it on to the global
|
||||
* ACS dispatcher.</p></li>
|
||||
*
|
||||
* <li><p>
|
||||
* The global ACS dispatcher examines the first part of the URL, notices that
|
||||
* CMS is mounted at <tt>/cms</tt> and hands the request to the CMS
|
||||
* dispatcher.</p></li>
|
||||
*
|
||||
* <li><p>
|
||||
* The CMS dispatcher determines whether a <tt>Page</tt> has been registered to
|
||||
* the URL <tt>/cheese</tt> in this section via its
|
||||
* {@link com.arsdigita.cms.dispatcher.PageResolver}.</p></li>
|
||||
*
|
||||
* <li><p>
|
||||
* Since no page is registered to the URL, the CMS dispatcher asks the content
|
||||
* section (via its {@link com.arsdigita.cms.dispatcher.ItemResolver}) for a
|
||||
* content item for <tt>/cheese</tt> in this content section. The result of this
|
||||
* process is a {@link com.arsdigita.cms.ContentItem} object.</p></li>
|
||||
*
|
||||
* <li><p>
|
||||
* The CMS dispatcher asks the content section for a <tt>Page</tt>
|
||||
* to use as the "master template" for this item. The content section may apply
|
||||
* item-, type-, or request-specific rules to make this decision (for example,
|
||||
* check a user preference for normal or accessible style, or a query parameter
|
||||
* for a printable version).</p></li>
|
||||
*
|
||||
* <li><p>
|
||||
* The CMS dispatcher hands the master <tt>Page</tt> object to the
|
||||
* {@link com.arsdigita.sitenode.SiteNodePresentationManager} to serve the
|
||||
* page.</p></li>
|
||||
*
|
||||
* <li><p>
|
||||
* The presentation manager asks the master <tt>Page</tt> object for an XML
|
||||
* document representing the data for the page.</p></li>
|
||||
*
|
||||
* <li><p>
|
||||
* The master template begins walking through its component hierarchy,
|
||||
* converting each component to XML by calling its
|
||||
* <tt>generateXML</tt> method. The component responsible for rendering the
|
||||
* content item uses an {@link com.arsdigita.cms.dispatcher.XMLGenerator} to
|
||||
* convert the content item to XML.</p></li>
|
||||
*
|
||||
* <li><p>
|
||||
* The presentation manager receives the completed XML document, and selects an
|
||||
* XSL transformer to use for generating the HTML. The stylesheet on which the
|
||||
* transformer is based contains templates for all styles and all content types
|
||||
* in the content section, in particular those from the file
|
||||
* <tt>cms-item.xsl</tt>.</p></li>
|
||||
* </ol>
|
||||
*
|
||||
* @author Michael Pih (pihman@arsdigita.com)
|
||||
* @author Uday Mathur (umathur@arsdigita.com)
|
||||
* @author Jack Chung (flattop@arsdigita.com)
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
public class CMSDispatcher implements Dispatcher, ChainedDispatcher {
|
||||
|
||||
private static Logger LOGGER = LogManager.getLogger(CMSDispatcher.class);
|
||||
|
||||
public static final String CONTENT_SECTION
|
||||
= "com.arsdigita.cms.dispatcher.section";
|
||||
|
||||
public static final String CONTENT_ITEM
|
||||
= "com.arsdigita.cms.dispatcher.item";
|
||||
|
||||
public static final String[] INDEX_FILES = {
|
||||
"index.jsp", "index.html", "index.htm"};
|
||||
|
||||
private static final String DEBUG = "/debug";
|
||||
private static final String ADMIN_SECTION = "admin";
|
||||
|
||||
public static final String ADMIN_URL = "admin/index";
|
||||
|
||||
/**
|
||||
* The context for previewing items
|
||||
*/
|
||||
public static final String PREVIEW = "preview";
|
||||
|
||||
// Content section cache
|
||||
private static HashMap s_pageResolverCache = new HashMap();
|
||||
// private static HashMap s_itemResolverCache = new HashMap();
|
||||
private static HashMap s_xmlGeneratorCache = new HashMap();
|
||||
|
||||
private boolean m_adminPagesOnly = false;
|
||||
|
||||
public CMSDispatcher() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
public CMSDispatcher(boolean adminOnly) {
|
||||
m_adminPagesOnly = adminOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles requests made to a CMS package instance. 1) fetches the current
|
||||
* content section 2) fetches the resource mapped to the current section/URL
|
||||
* 3) if no resource, fetches the item associated with the current
|
||||
* section/URL 4) if no item, passes request to the JSP dispatcher, which
|
||||
* serves JSP's, HTML pages, and media from the cms/packages/www directory
|
||||
*
|
||||
* @param request The request
|
||||
* @param response The response
|
||||
* @param actx The request context
|
||||
*/
|
||||
public void dispatch(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
RequestContext actx)
|
||||
throws IOException, ServletException {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Dispatching request for " + new URL(request)
|
||||
.toDebugString());
|
||||
}
|
||||
|
||||
// This is the path to the current site node.
|
||||
String processedUrl = actx.getProcessedURLPart();
|
||||
String webappURLContext = request.getContextPath();
|
||||
if (processedUrl.startsWith(webappURLContext)) {
|
||||
processedUrl = processedUrl.substring(webappURLContext.length());
|
||||
}
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Determined the path to the current site node; it "
|
||||
+ "is '" + processedUrl + "' according to the "
|
||||
+ "request context");
|
||||
}
|
||||
|
||||
// This is the path within the site node.
|
||||
String remainingUrl = actx.getRemainingURLPart();
|
||||
if (remainingUrl.endsWith("/")) {
|
||||
remainingUrl = remainingUrl.substring(0, remainingUrl.length() - 1);
|
||||
} else if (remainingUrl.endsWith(ItemDispatcher.FILE_SUFFIX)) {
|
||||
remainingUrl = remainingUrl.substring(0, remainingUrl.length()
|
||||
- ItemDispatcher.FILE_SUFFIX
|
||||
.length());
|
||||
} else if (remainingUrl.equals("")) {
|
||||
remainingUrl = "index";
|
||||
}
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Determined the path after the current site node; "
|
||||
+ "it is '" + remainingUrl + "'");
|
||||
}
|
||||
|
||||
// Fetch the current content section.
|
||||
ContentSection section = null;
|
||||
try {
|
||||
section = findContentSection(processedUrl);
|
||||
} catch (Exception ex) {
|
||||
throw new ServletException(ex);
|
||||
}
|
||||
request.setAttribute(CONTENT_SECTION, section);
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Found content section '" + section + "'");
|
||||
}
|
||||
|
||||
// Check user access to this page and deny access if necessary.
|
||||
checkUserAccess(request, response, actx);
|
||||
|
||||
// Look for a site-node-specific asset (if any).
|
||||
// KG: This hack will be replaced by a ChainedDispatcher
|
||||
try {
|
||||
LOGGER.debug("Looking for a site node asset");
|
||||
|
||||
String siteNodeAssetURL = getSiteNodeAsset(request, actx);
|
||||
if (siteNodeAssetURL != null) {
|
||||
LOGGER.debug("Site node asset found at '" + siteNodeAssetURL
|
||||
+ "'");
|
||||
|
||||
DispatcherHelper.cacheDisable(response);
|
||||
DispatcherHelper.setRequestContext(request, actx);
|
||||
DispatcherHelper.forwardRequestByPath(siteNodeAssetURL,
|
||||
request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
LOGGER.debug("No site node asset found; proceeding with normal "
|
||||
+ "dispatching");
|
||||
} catch (RedirectException e) {
|
||||
throw new ServletException(e);
|
||||
}
|
||||
|
||||
// Fetch the requested resource (if any).
|
||||
ResourceHandler resource = getResource(section, remainingUrl);
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Got a resource '" + resource + "'");
|
||||
}
|
||||
|
||||
if (resource != null) {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Found resource '" + remainingUrl + "'; "
|
||||
+ "dispatching to it");
|
||||
}
|
||||
|
||||
LOGGER.info("resource dispatch for " + remainingUrl);
|
||||
// Found resource, now serve it.
|
||||
// NB, ResouceHandler implementations should take care of caching options
|
||||
resource.dispatch(request, response, actx);
|
||||
|
||||
} else {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("No resource found at '" + remainingUrl + "'; "
|
||||
+ "searching for a previewable content item at "
|
||||
+ "this path");
|
||||
}
|
||||
|
||||
// If the remaining URL starts with "preview/", then try and
|
||||
// preview this item. Otherwise look for the live item.
|
||||
boolean preview = false;
|
||||
if (remainingUrl.startsWith(PREVIEW)) {
|
||||
remainingUrl = remainingUrl.substring(PREVIEW.length());
|
||||
preview = true;
|
||||
}
|
||||
|
||||
// Check for published / previewable item.
|
||||
ContentItem item = null;
|
||||
|
||||
// Check if the user has access to view public pages
|
||||
final PermissionChecker permissionChecker = CdiUtil.createCdiUtil()
|
||||
.findBean(PermissionChecker.class);
|
||||
|
||||
if (permissionChecker.isPermitted(
|
||||
ItemPrivileges.VIEW_PUBLISHED, item)) {
|
||||
if (preview) {
|
||||
item = getContentItem(section,
|
||||
remainingUrl,
|
||||
CMSDispatcher.PREVIEW);
|
||||
} else {
|
||||
item = getContentItem(section,
|
||||
remainingUrl,
|
||||
"live");
|
||||
}
|
||||
if (item != null) {
|
||||
request.setAttribute(CONTENT_ITEM, item);
|
||||
}
|
||||
}
|
||||
|
||||
if (item != null) {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Found item " + item + "; serving it");
|
||||
}
|
||||
|
||||
DispatcherHelper.cacheDisable(response);
|
||||
preview(request, response, actx);
|
||||
} else {
|
||||
LOGGER.debug("No item to preview found; falling back to "
|
||||
+ "JSP dispatcher to look for some concrete "
|
||||
+ "resource in the file system");
|
||||
|
||||
// If no resource was found, look for a JSP page.
|
||||
JSPApplicationDispatcher jsp = JSPApplicationDispatcher
|
||||
.getInstance();
|
||||
//DispatcherHelper.cacheDisable(response);
|
||||
jsp.dispatch(request, response, actx);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int chainedDispatch(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
RequestContext actx)
|
||||
throws IOException, ServletException {
|
||||
if (m_adminPagesOnly) {
|
||||
String url = actx.getRemainingURLPart();
|
||||
|
||||
if (url.endsWith(ItemDispatcher.FILE_SUFFIX)) {
|
||||
url = url.substring(0, url.length() - ItemDispatcher.FILE_SUFFIX
|
||||
.length());
|
||||
} else if (url.endsWith("/")) {
|
||||
url = url.substring(0, url.length() - 1);
|
||||
}
|
||||
|
||||
if (url.equals(ADMIN_URL)) {
|
||||
if (LOGGER.isInfoEnabled()) {
|
||||
LOGGER.info("Resolving admin URL '" + url + "'");
|
||||
}
|
||||
|
||||
dispatch(request, response, actx);
|
||||
|
||||
return ChainedDispatcher.DISPATCH_BREAK;
|
||||
} else {
|
||||
return ChainedDispatcher.DISPATCH_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
dispatch(request, response, actx);
|
||||
return ChainedDispatcher.DISPATCH_BREAK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the user is logged in and is able to view the page.
|
||||
* Subclasses can override this method if they need to, but should always be
|
||||
* sure to call super.checkUserAccess(...)
|
||||
*
|
||||
* @param request The HTTP request
|
||||
* @param response The HTTP response
|
||||
* @param actx The request context
|
||||
*
|
||||
* @throws javax.servlet.ServletException
|
||||
*
|
||||
*/
|
||||
protected void checkUserAccess(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
RequestContext actx)
|
||||
throws ServletException, AuthorizationException {
|
||||
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final Shiro shiro = cdiUtil.findBean(Shiro.class);
|
||||
User user = shiro.getUser().get();
|
||||
final PermissionChecker permissionChecker = cdiUtil.findBean(
|
||||
PermissionChecker.class);
|
||||
|
||||
ContentSection section = getContentSection(request);
|
||||
|
||||
if (isAdminPage(actx.getRemainingURLPart())) {
|
||||
|
||||
// Handle admin page requests.
|
||||
// If the user is not logged in, redirect to the login page.
|
||||
// Otherwise, perform the Admin Pages access check.
|
||||
if (user == null) {
|
||||
redirectToLoginPage(request, response);
|
||||
return;
|
||||
}
|
||||
//if (!sm.canAccess(user, SecurityManager.ADMIN_PAGES)) {
|
||||
permissionChecker.checkPermission(ItemPrivileges.EDIT,
|
||||
section.getRootDocumentsFolder());
|
||||
} else {
|
||||
// For public page requests, use the SecurityManager to check access
|
||||
// SecurityManager.canAccess(user, SecurityManager.PUBLIC_PAGES) must
|
||||
permissionChecker.checkPermission(
|
||||
ItemPrivileges.VIEW_PUBLISHED,
|
||||
section.getRootDocumentsFolder());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the content section from the request attributes.
|
||||
*
|
||||
* @param request The HTTP request
|
||||
*
|
||||
* @return The content section
|
||||
*
|
||||
* @pre ( state != null )
|
||||
*/
|
||||
public static ContentSection getContentSection(HttpServletRequest request) {
|
||||
return (ContentSection) request.getAttribute(CONTENT_SECTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the content item from the request attributes.
|
||||
*
|
||||
* @param request The HTTP request
|
||||
*
|
||||
* @return The content item
|
||||
*
|
||||
* @pre ( state != null )
|
||||
*/
|
||||
public static ContentItem getContentItem(HttpServletRequest request) {
|
||||
return (ContentItem) request.getAttribute(CONTENT_ITEM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the current content section using the remaining URL stored in
|
||||
* the request context object and the SiteNode class.
|
||||
*
|
||||
* @param url The section URL stub
|
||||
*
|
||||
* @return The current Content Section
|
||||
*/
|
||||
protected ContentSection findContentSection(String url) {
|
||||
|
||||
// MP: This is a hack to get the debugging info in
|
||||
// SiteNodePresentationManager.servePage, but since it's
|
||||
// debugging info...
|
||||
// Remove /debug from the start of the URL if it exists.
|
||||
if (url.startsWith(DEBUG)) {
|
||||
url = url.substring(DEBUG.length());
|
||||
}
|
||||
|
||||
final String debugXMLString = "/xml";
|
||||
if (url.startsWith(debugXMLString)) {
|
||||
url = url.substring(debugXMLString.length());
|
||||
}
|
||||
|
||||
final String debugXSLString = "/xsl";
|
||||
if (url.startsWith(debugXSLString)) {
|
||||
url = url.substring(debugXSLString.length());
|
||||
}
|
||||
|
||||
final String sectionLabel = url;
|
||||
|
||||
// Fetch the current site node from the URL.
|
||||
final ContentSectionRepository sectionRepo = CdiUtil.createCdiUtil()
|
||||
.findBean(ContentSectionRepository.class);
|
||||
final ContentSection section = sectionRepo
|
||||
.findByLabel(url)
|
||||
.orElseThrow(() -> new UnexpectedErrorException(
|
||||
String.format("No ContentSection '%s' found.", sectionLabel)));
|
||||
return section;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a resource based on the URL stub.
|
||||
*
|
||||
* @param section The current content section
|
||||
* @param url The section-relative URL
|
||||
*
|
||||
* @return A ResourceHandler resource or null if none exists.
|
||||
*
|
||||
* @pre (url != null)
|
||||
*/
|
||||
protected ResourceHandler getResource(ContentSection section, String url)
|
||||
throws ServletException {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Searching for a resource for the URL fragment '" + url
|
||||
+ "' under " + section);
|
||||
}
|
||||
|
||||
final PageResolver pageResolver = CMSDispatcher.getPageResolver(section);
|
||||
|
||||
final ResourceHandler handler = pageResolver.getPage(url);
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup a content item by section and URL.
|
||||
*
|
||||
* @param section The content section
|
||||
* @param url The URL relative to the content section
|
||||
* @param context The use context
|
||||
*
|
||||
* @return The item associated with the URL, or null if no such item exists
|
||||
*
|
||||
* @throws javax.servlet.ServletException
|
||||
*/
|
||||
protected ContentItem getContentItem(ContentSection section, String url,
|
||||
String context)
|
||||
throws ServletException {
|
||||
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final ContentSectionManager sectionManager = cdiUtil.findBean(
|
||||
ContentSectionManager.class);
|
||||
final ItemResolver itemResolver = sectionManager
|
||||
.getItemResolver(section);
|
||||
|
||||
return itemResolver.getItem(section, url, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Preview the current content item.
|
||||
*
|
||||
* @param request The HTTP request
|
||||
* @param response The HTTP response
|
||||
* @param actx The request context
|
||||
*/
|
||||
protected void preview(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
RequestContext actx)
|
||||
throws IOException, ServletException {
|
||||
|
||||
ContentSection section = getContentSection(request);
|
||||
ContentItem item = getContentItem(request);
|
||||
|
||||
ItemResolver itemResolver = CMSDispatcher.getItemResolver(section);
|
||||
CMSPage page = itemResolver.getMasterPage(item, request);
|
||||
page.dispatch(request, response, actx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes the page resolver cache.
|
||||
*
|
||||
* @param section The current content section
|
||||
* @param url The section-relative URL
|
||||
*/
|
||||
public static void releaseResource(ContentSection section, String url) {
|
||||
final String pageResolverClassName = section.getPageResolverClass();
|
||||
final PageResolver pageResolver;
|
||||
try {
|
||||
pageResolver = (PageResolver) Class.forName(pageResolverClassName)
|
||||
.newInstance();
|
||||
} catch (ClassNotFoundException
|
||||
| IllegalAccessException
|
||||
| InstantiationException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
pageResolver.releasePage(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the PageResolver for a content section. Checks cache first.
|
||||
*
|
||||
* @param section The content section
|
||||
*
|
||||
* @return The PageResolver associated with the content section
|
||||
*/
|
||||
public static PageResolver getPageResolver(ContentSection section) {
|
||||
LOGGER.debug("Getting the page resolver");
|
||||
|
||||
final String name = section.getLabel();
|
||||
PageResolver pr = (PageResolver) s_pageResolverCache.get(name);
|
||||
|
||||
if (pr == null) {
|
||||
LOGGER.debug("The page resolver was not cached; fetching a new "
|
||||
+ "one and placing it in the cache");
|
||||
|
||||
final String pageResolverClassName = section.getPageResolverClass();
|
||||
final PageResolver pageResolver;
|
||||
try {
|
||||
pageResolver = (PageResolver) Class.forName(
|
||||
pageResolverClassName)
|
||||
.newInstance();
|
||||
} catch (ClassNotFoundException
|
||||
| IllegalAccessException
|
||||
| InstantiationException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
s_pageResolverCache.put(name, pageResolver);
|
||||
}
|
||||
|
||||
return pr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the ItemResolver for a content section. Checks cache first.
|
||||
*
|
||||
* @param section The content section
|
||||
*
|
||||
* @return The ItemResolver associated with the content section
|
||||
*/
|
||||
public static ItemResolver getItemResolver(ContentSection section) {
|
||||
|
||||
final Class<?> clazz;
|
||||
try {
|
||||
clazz = Class.forName(section.getItemResolverClass());
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new UncheckedWrapperException(ex);
|
||||
}
|
||||
|
||||
return (ItemResolver) CdiUtil.createCdiUtil().findBean(clazz);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the XMLGenerator for a content section. Checks cache first.
|
||||
*
|
||||
* @param section The content section
|
||||
*
|
||||
* @return The XMLGenerator associated with the content section
|
||||
*/
|
||||
public static XMLGenerator getXMLGenerator(ContentSection section) {
|
||||
String name = section.getLabel();
|
||||
XMLGenerator xmlGenerator = (XMLGenerator) s_xmlGeneratorCache.get(name);
|
||||
if (xmlGenerator == null) {
|
||||
final String xmlGeneratorClassName = section.getXmlGeneratorClass();
|
||||
try {
|
||||
xmlGenerator = (XMLGenerator) Class.forName(
|
||||
xmlGeneratorClassName).newInstance();
|
||||
} catch (ClassNotFoundException
|
||||
| IllegalAccessException
|
||||
| InstantiationException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
s_xmlGeneratorCache.put(name, xmlGenerator);
|
||||
}
|
||||
|
||||
return xmlGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this URL correspond to an admin page?
|
||||
*/
|
||||
protected boolean isAdminPage(String url) {
|
||||
|
||||
// MP: This is a hack to get the debugging info in
|
||||
// SiteNodePresentationManager.servePage, but since it's
|
||||
// debugging info...
|
||||
// Remove /debug from the start of the URL if it exists.
|
||||
if (url.startsWith(DEBUG)) {
|
||||
url = url.substring(DEBUG.length());
|
||||
}
|
||||
|
||||
return (url != null && (url.startsWith(ADMIN_SECTION) || url.startsWith(
|
||||
PREVIEW)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects the client to the login page, setting the return url to the
|
||||
* current request URI.
|
||||
*
|
||||
* @exception ServletException If there is an exception thrown while trying
|
||||
* to redirect, wrap that exception in a
|
||||
* ServletException
|
||||
*
|
||||
*/
|
||||
protected void redirectToLoginPage(HttpServletRequest req,
|
||||
HttpServletResponse resp)
|
||||
throws ServletException {
|
||||
throw new LoginSignal(req);
|
||||
}
|
||||
|
||||
// modified from JSPApplicationDispatcher
|
||||
private String getSiteNodeAsset(HttpServletRequest request,
|
||||
RequestContext actx)
|
||||
throws RedirectException {
|
||||
|
||||
String siteNodeAssetURL = null;
|
||||
|
||||
ServletContext sctx = actx.getServletContext();
|
||||
String processedURL = actx.getProcessedURLPart();
|
||||
String remainingURL = actx.getRemainingURLPart();
|
||||
// REMOVE THIS HACK ONCE we have working publish to file code in the build
|
||||
//String templateRoot = PublishToFile.getDefaultDestinationForType(Template.class);
|
||||
String templateRoot = null;
|
||||
|
||||
/* Allow a graceful early exit if publishToFile is not initialized */
|
||||
if (null == templateRoot) {
|
||||
return null;
|
||||
}
|
||||
|
||||
File siteNodeAssetRoot = new File(templateRoot, processedURL);
|
||||
File assetFile = new File(siteNodeAssetRoot, remainingURL);
|
||||
|
||||
String contextPath = request.getContextPath();
|
||||
|
||||
if (assetFile.isDirectory()) {
|
||||
|
||||
if (remainingURL.endsWith("/")) {
|
||||
throw new RedirectException(actx.getOriginalURL() + "/");
|
||||
}
|
||||
|
||||
for (int i = 0; i < INDEX_FILES.length; i++) {
|
||||
File indexFile = new File(assetFile, INDEX_FILES[i]);
|
||||
if (indexFile.exists()) {
|
||||
assetFile = indexFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (assetFile.exists()) {
|
||||
siteNodeAssetURL = contextPath + "/" + templateRoot
|
||||
+ processedURL + remainingURL;
|
||||
}
|
||||
|
||||
return siteNodeAssetURL;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,343 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.dispatcher;
|
||||
|
||||
import com.arsdigita.bebop.BebopConfig;
|
||||
import com.arsdigita.bebop.Container;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.Page;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.page.PageTransformer;
|
||||
import com.arsdigita.cms.CMS;
|
||||
import com.arsdigita.dispatcher.RequestContext;
|
||||
import com.arsdigita.templating.PresentationManager;
|
||||
import com.arsdigita.web.Web;
|
||||
import com.arsdigita.xml.Document;
|
||||
import com.arsdigita.xml.Element;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.security.PermissionChecker;
|
||||
import org.libreccm.security.Shiro;
|
||||
import org.libreccm.security.User;
|
||||
import org.libreccm.web.CcmApplication;
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contentsection.ContentItemRepository;
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
import org.librecms.contentsection.ContentSectionServlet;
|
||||
import org.librecms.contentsection.privileges.ItemPrivileges;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A <tt>CMSPage</tt> is a Bebop {@link com.arsdigita.bebop.Page} implementation
|
||||
* of the {@link com.arsdigita.cms.dispatcher.ResourceHandler} interface.</p>
|
||||
*
|
||||
* <p>
|
||||
* It stores the current {@link com.arsdigita.cms.ContentSection} and, if
|
||||
* applicable, the {@link com.arsdigita.cms.ContentItem} in the page state as
|
||||
* request local objects. Components that are part of the <tt>CMSPage</tt>
|
||||
* may access these objects by calling:</p>
|
||||
* <blockquote><code><pre>
|
||||
* getContentSection(PageState state);
|
||||
* </pre></code></blockquote>
|
||||
*
|
||||
* @author Michael Pih (pihman@arsdigita.com)
|
||||
* @author Uday Mathur (umathur@arsdigita.com)
|
||||
*/
|
||||
public class CMSPage extends Page implements ResourceHandler {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(CMSPage.class);
|
||||
|
||||
/**
|
||||
* The global assets URL stub XML parameter name.
|
||||
*/
|
||||
public final static String ASSETS = "ASSETS";
|
||||
|
||||
/**
|
||||
* The XML page class.
|
||||
*/
|
||||
public final static String PAGE_CLASS = "CMS";
|
||||
|
||||
/**
|
||||
* Map of XML parameters
|
||||
*/
|
||||
private HashMap m_params;
|
||||
|
||||
/**
|
||||
* */
|
||||
private PageTransformer m_transformer;
|
||||
|
||||
public CMSPage() {
|
||||
super();
|
||||
buildPage();
|
||||
}
|
||||
|
||||
public CMSPage(String title) {
|
||||
super(title);
|
||||
buildPage();
|
||||
}
|
||||
|
||||
public CMSPage(String title, Container panel) {
|
||||
super(title, panel);
|
||||
buildPage();
|
||||
}
|
||||
|
||||
public CMSPage(Label title) {
|
||||
super(title);
|
||||
buildPage();
|
||||
}
|
||||
|
||||
public CMSPage(Label title, Container panel) {
|
||||
super(title, panel);
|
||||
buildPage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the page.
|
||||
*/
|
||||
protected void buildPage() {
|
||||
// Set the class attribute value. May be overwritten by child class
|
||||
// to hold a more specific value
|
||||
setClassAttr(PAGE_CLASS);
|
||||
|
||||
// Global XML params.
|
||||
// MP: This only works with older versions of Xalan.
|
||||
m_params = new HashMap();
|
||||
setXMLParameter(ASSETS, Utilities.getGlobalAssetsURL());
|
||||
|
||||
// MP: This is a hack to so that the XML params work with the newer
|
||||
// version of Xalan.
|
||||
// Sets attribute in SimpleComponent, attributes of the same name will
|
||||
// be overweritten.
|
||||
setAttribute(ASSETS, Utilities.getGlobalAssetsURL());
|
||||
|
||||
// Make sure the error display gets rendered.
|
||||
getErrorDisplay().setIdAttr("page-body");
|
||||
|
||||
final Class<PresentationManager> presenterClass = BebopConfig
|
||||
.getConfig().getPresenterClass();
|
||||
final PresentationManager pm;
|
||||
try {
|
||||
pm = presenterClass.getDeclaredConstructor().newInstance();
|
||||
} catch (InstantiationException
|
||||
| IllegalAccessException
|
||||
| InvocationTargetException
|
||||
| NoSuchMethodException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
if (pm instanceof PageTransformer) {
|
||||
m_transformer = (PageTransformer) pm;
|
||||
} else {
|
||||
m_transformer = new PageTransformer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes and locks the page. If the page is already locked, does nothing.
|
||||
*
|
||||
* This method is called by the {@link com.arsdigita.dispatcher.Dispatcher}
|
||||
* that initializes this page.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void init() {
|
||||
LOGGER.debug("Initializing the page");
|
||||
|
||||
if (!isLocked()) {
|
||||
LOGGER.debug("The page hasn't been locked; locking it now");
|
||||
|
||||
lock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the value of the XML parameter.
|
||||
*
|
||||
* @param name The parameter name
|
||||
*
|
||||
* @return The parameter value
|
||||
*
|
||||
* @pre (name != null)
|
||||
*/
|
||||
public String getXMLParameter(String name) {
|
||||
return (String) m_params.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an XML parameter.
|
||||
*
|
||||
* @param name The parameter name
|
||||
* @param value The parameter value
|
||||
*
|
||||
* @pre (name != null)
|
||||
*/
|
||||
public void setXMLParameter(String name, String value) {
|
||||
m_params.put(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the request-local content section.
|
||||
*
|
||||
* @param request The HTTP request
|
||||
*
|
||||
* @return The current content section
|
||||
*
|
||||
* @deprecated use com.arsdigita.cms.CMS.getContext().getContentSection()
|
||||
* instead Despite of being deprecated it can not be removed because it is
|
||||
* required by the interface Resourcehandler which is implemented by this
|
||||
* class. On the other hand, if deprecated, implementing ResourceHandler may
|
||||
* not be required
|
||||
*/
|
||||
@Override
|
||||
public ContentSection getContentSection(HttpServletRequest request) {
|
||||
// Resets all content sections associations.
|
||||
// return ContentSectionDispatcher.getContentSection(request);
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the request-local content section.
|
||||
*
|
||||
* @param state The page state
|
||||
*
|
||||
* @return The current content section
|
||||
*
|
||||
* @deprecated use com.arsdigita.cms.CMS.getContext().getContentSection()
|
||||
* instead Despite of being deprecated it can not be removed because it is
|
||||
* required by ContentItemPage which extends CMSPage and uses this method.
|
||||
*/
|
||||
public ContentSection getContentSection(PageState state) {
|
||||
return getContentSection(state.getRequest());
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the request-local content item.
|
||||
*
|
||||
* @param request The HTTP request
|
||||
*
|
||||
* @return The current content item
|
||||
*
|
||||
* @deprecated use com.arsdigita.cms.CMS.getContext().getContentItem()
|
||||
* instead Despite of being deprecated it can not be removed because it is
|
||||
* required by the interface Resourcehandler which is implemented by this
|
||||
* class. On the other hand, if deprecated, implementing ResourceHandler may
|
||||
* not be required
|
||||
*/
|
||||
public ContentItem getContentItem(HttpServletRequest request) {
|
||||
// resets all content item associations
|
||||
return ContentSectionDispatcher.getContentItem(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the request-local content item.
|
||||
*
|
||||
* @param state The page state
|
||||
*
|
||||
* @return The current content item
|
||||
*
|
||||
* @deprecated use com.arsdigita.cms.CMS.getContext().getContentItem()
|
||||
* instead. Despite of being deprecated it can not be removed because it is
|
||||
* required by ContentItemPage which extends CMSPage and uses this method.
|
||||
*/
|
||||
public ContentItem getContentItem(PageState state) {
|
||||
return getContentItem(state.getRequest());
|
||||
}
|
||||
|
||||
/**
|
||||
* Services the Bebop page.
|
||||
*
|
||||
* @param request The servlet request object
|
||||
* @param response the servlet response object
|
||||
* @param actx The request context
|
||||
*
|
||||
* @pre m_transformer != null
|
||||
*/
|
||||
@Override
|
||||
public void dispatch(final HttpServletRequest request,
|
||||
final HttpServletResponse response,
|
||||
final RequestContext actx)
|
||||
throws IOException, ServletException {
|
||||
|
||||
final CcmApplication app = Web.getWebContext().getApplication();
|
||||
ContentSection section = null;
|
||||
|
||||
if (app == null) {
|
||||
//Nothing to do
|
||||
} else if (app instanceof ContentSection) {
|
||||
section = (ContentSection) app;
|
||||
}
|
||||
|
||||
if (section != null) {
|
||||
CMS.getContext().setContentSection(section);
|
||||
}
|
||||
|
||||
final String itemId = request.getParameter("item_id");
|
||||
|
||||
if (itemId != null) {
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final ContentItemRepository itemRepo = cdiUtil.findBean(
|
||||
ContentItemRepository.class);
|
||||
final ContentItem item = itemRepo
|
||||
.findById(Long.parseLong(itemId)).get();
|
||||
final PermissionChecker permissionChecker = cdiUtil.findBean(
|
||||
PermissionChecker.class);
|
||||
permissionChecker.checkPermission(ItemPrivileges.PREVIEW,
|
||||
item);
|
||||
CMS.getContext().setContentItem(item);
|
||||
}
|
||||
|
||||
final Document document = buildDocument(request, response);
|
||||
|
||||
m_transformer.servePage(document, request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrites bebop.Page#generateXMLHelper to add the name of the user
|
||||
* logged in to the page (displayed as part of the header).
|
||||
*
|
||||
* @param ps
|
||||
* @param parent
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected Element generateXMLHelper(PageState ps, Document parent) {
|
||||
Element page = super.generateXMLHelper(ps, parent);
|
||||
final Optional<User> user = CdiUtil.createCdiUtil()
|
||||
.findBean(Shiro.class).getUser();
|
||||
if (user.isPresent()) {
|
||||
page.addAttribute("name", user.get().getName());
|
||||
}
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,316 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.dispatcher;
|
||||
|
||||
import com.arsdigita.dispatcher.Dispatcher;
|
||||
import com.arsdigita.dispatcher.DispatcherHelper;
|
||||
import com.arsdigita.dispatcher.RequestContext;
|
||||
import com.arsdigita.util.Assert;
|
||||
import com.arsdigita.web.Web;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
|
||||
/**
|
||||
* This is the dispatcher for content-sections. It maintains a
|
||||
* ContentItem-to-Template cache Code that modifies a published ContentItem's
|
||||
* template must update the cache in this class by calling the appropriate cache
|
||||
* methods.
|
||||
*
|
||||
* @author bche@redhat.com
|
||||
*/
|
||||
public class ContentItemDispatcher implements Dispatcher {
|
||||
|
||||
/** cache for the template resolver */
|
||||
public static Map s_templateResolverCache = Collections
|
||||
.synchronizedMap(new HashMap());
|
||||
|
||||
/** */
|
||||
protected ItemXML m_itemXML;
|
||||
|
||||
/**
|
||||
* */
|
||||
public ContentItemDispatcher() {
|
||||
m_itemXML = new ItemXML();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see com.arsdigita.dispatcher.Dispatcher#dispatch (HttpServletRequest,
|
||||
* HttpServletResponse, RequestContext)
|
||||
*/
|
||||
public void dispatch(final HttpServletRequest request,
|
||||
final HttpServletResponse response,
|
||||
final RequestContext actx)
|
||||
throws IOException, ServletException {
|
||||
|
||||
Boolean bXMLMode = (Boolean) request
|
||||
.getAttribute("xmlMode");
|
||||
if (bXMLMode != null && bXMLMode.booleanValue()) {
|
||||
//if this is XML mode, then use itemXML
|
||||
m_itemXML.dispatch(request, response, actx);
|
||||
} else {
|
||||
//this is normal dispatching
|
||||
|
||||
//get the Content Item
|
||||
//final ContentItem item = (ContentItem) request.getAttribute
|
||||
// (ContentSectionServlet.CONTENT_ITEM);
|
||||
final ContentItem item = getContentItem(request);
|
||||
//get the Content Section
|
||||
final ContentSection section = (ContentSection) Web.getWebContext()
|
||||
.getApplication();
|
||||
|
||||
Assert.exists(item);
|
||||
|
||||
//get the item's template
|
||||
// final String sTemplateURL = getTemplatePath(item, request, actx);
|
||||
|
||||
//dispatch to the template
|
||||
DispatcherHelper.setRequestContext(request, actx);
|
||||
DispatcherHelper.forwardRequestByPath(null, request,
|
||||
response);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the content item from the request attributes.
|
||||
*
|
||||
* @param request The HTTP request
|
||||
*
|
||||
* @return The content item
|
||||
*
|
||||
* @pre ( request != null )
|
||||
*/
|
||||
public static ContentItem getContentItem(HttpServletRequest request) {
|
||||
return (ContentItem) request.getAttribute(
|
||||
"com.arsdigita.cms.dispatcher.item");
|
||||
}
|
||||
|
||||
// //synchronize access to the cache
|
||||
// private static synchronized void cachePut(BigDecimal contentItemID,
|
||||
// String sTemplatePath) {
|
||||
// s_cache.put(contentItemID, sTemplatePath);
|
||||
// }
|
||||
//
|
||||
// private static synchronized void cacheRemove(BigDecimal contentItemID) {
|
||||
// s_cache.remove(contentItemID);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Method cacheRemove. Removes the cached template path for the contentItem
|
||||
// * item
|
||||
// *
|
||||
// * @param item
|
||||
// */
|
||||
// public static void cacheRemove(ContentItem item) {
|
||||
// if (item == null) {
|
||||
// return;
|
||||
// }
|
||||
// if (s_log.isDebugEnabled()) {
|
||||
// s_log.debug("removing cached entry for item " + item.getName()
|
||||
// + " with ID " + item.getID());
|
||||
// }
|
||||
// s_cache.remove(item.getID());
|
||||
// }
|
||||
|
||||
/**
|
||||
* Method cachePut. Maps the ContentItem item to the template t in the cache
|
||||
*
|
||||
* @param item
|
||||
* @param t
|
||||
*/
|
||||
// public static void cachePut(ContentItem item, Template t) {
|
||||
// ContentSection section = item.getContentSection();
|
||||
// String sPath = getTemplatePath(section, t);
|
||||
//
|
||||
// //only cache live items
|
||||
// if (item == null || item.getVersion().compareTo(ContentItem.LIVE) != 0) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if (s_log.isDebugEnabled()) {
|
||||
// s_log.debug("updating mapping for item " + item.getName()
|
||||
// + " with ID " + item.getID() + " in section " + section
|
||||
// .getName() + " of type " + item.getContentType().getName()
|
||||
// + " to template " + sPath);
|
||||
// }
|
||||
//
|
||||
// cachePut(item.getID(), sPath);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Method cachePut. Maps all the content items of ContentType type and in
|
||||
* ContentSection section that don't have their own templates to the
|
||||
* template t in the cache
|
||||
*
|
||||
* @param section
|
||||
* @param type
|
||||
* @param t
|
||||
*/
|
||||
// public static void cachePut(ContentSection section,
|
||||
// ContentType type,
|
||||
// Template t) {
|
||||
// s_log.debug("updating cache for section " + section.getName()
|
||||
// + " and type " + type.getName());
|
||||
//
|
||||
// //get all the items in the section
|
||||
// ItemCollection items = section.getItems();
|
||||
//
|
||||
// //filter items by content type
|
||||
// BigDecimal typeID = type.getID();
|
||||
// Filter filter = items.addFilter("type.id = :typeID");
|
||||
// filter.set("typeID", typeID);
|
||||
//
|
||||
// //get only live items
|
||||
// Filter liveFilter = items.addFilter("version = '" + ContentItem.LIVE
|
||||
// + "'");
|
||||
//
|
||||
// //filter out content items in ContentSection section of
|
||||
// //ContentType type with a template for the "public" context
|
||||
// Filter itemsFilter = items.addNotInSubqueryFilter("id",
|
||||
// "com.arsdigita.cms.ItemsWithTemplateMapping");
|
||||
// itemsFilter.set("sectionId", section.getID());
|
||||
// itemsFilter.set("typeId", type.getID());
|
||||
//
|
||||
// //TODO: FILTER OUT CONTENT ITEMS IN THIS SECTION OF THIS TYPE
|
||||
// //WITH A TEMPLATE FOR THE "PUBLIC" CONTEXT
|
||||
// /*
|
||||
// * select items.item_id
|
||||
// * from cms_items items, cms_item_template_map map
|
||||
// * where items.item_id = map.item_id
|
||||
// * and use_context = 'public'
|
||||
// * and items.version = 'live'
|
||||
// * and items.section_id = :section_id
|
||||
// * and items.type_id = :type_id
|
||||
// */
|
||||
// synchronized (s_cache) {
|
||||
// //update the cache for all items
|
||||
// while (items.next()) {
|
||||
// cachePut(items.getContentItem(), t);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// private static String getTemplatePath(ContentSection section,
|
||||
// Template template) {
|
||||
// //the template path is
|
||||
// // TEMPLATE_ROOT/[content-section-name]/[template-path]
|
||||
// final String sep = java.io.File.separator;
|
||||
// String sPath = ContentSectionConfig.getConfig().getTemplateRoot() + sep
|
||||
// + section.getName() + sep + template.getPath();
|
||||
// return sPath;
|
||||
// }
|
||||
//
|
||||
// private static void updateTemplateCache(ContentSection section,
|
||||
// ContentItem item,
|
||||
// String sTemplatePath) {
|
||||
// //use the live version of the item for the cache
|
||||
// item = item.getLiveVersion();
|
||||
// s_log.debug("updating mapping for item " + item.getName() + " with ID "
|
||||
// + item.getID() + " in section " + item.getContentSection()
|
||||
// .getName() + " of type " + item.getContentType().getName()
|
||||
// + " to template " + sTemplatePath);
|
||||
// cachePut(item.getID(), sTemplatePath);
|
||||
// }
|
||||
//
|
||||
// private String cacheGet(BigDecimal key) {
|
||||
// return (String) s_cache.get(key);
|
||||
// }
|
||||
|
||||
// private String getTemplatePath(ContentItem item,
|
||||
// HttpServletRequest req,
|
||||
// RequestContext ctx) {
|
||||
//
|
||||
// //check if the template path is cached
|
||||
// //BigDecimal id = item.getID();
|
||||
// //String sPath = cacheGet(id);
|
||||
// //return from cache
|
||||
// // current cache scheme doesn't work when there are
|
||||
// //multiple templates per item, as would happen with
|
||||
// // multiple template contexts or in the case of
|
||||
// //category item resolution, more than one category for
|
||||
// //the item.
|
||||
// //if (sPath != null) {
|
||||
// //s_log.debug("returning template path from cache");
|
||||
// // return sPath;
|
||||
// //}
|
||||
// //s_log.debug("template path not in cache, so fecthing");
|
||||
// //template is not in the cache, so retrieve it and place it in
|
||||
// //the cache
|
||||
// String sPath = fetchTemplateURL(item, req, ctx);
|
||||
// //cachePut(id, sPath);
|
||||
//
|
||||
// return sPath;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Fetches the URL of a template for an item. The returned URL is relative
|
||||
* to the webapp context.
|
||||
*/
|
||||
// public String fetchTemplateURL(ContentItem item,
|
||||
// HttpServletRequest request,
|
||||
// RequestContext actx) {
|
||||
// if (s_log.isDebugEnabled()) {
|
||||
// s_log.debug("fetching URL for item " + item.getName() + " with ID "
|
||||
// + item.getID());
|
||||
// }
|
||||
//
|
||||
// ContentSection section = item.getContentSection();
|
||||
// String templateURL = getTemplateResolver(section).getTemplate(section,
|
||||
// item,
|
||||
// request);
|
||||
//
|
||||
// if (s_log.isDebugEnabled()) {
|
||||
// s_log.debug("templateURL is " + templateURL);
|
||||
// }
|
||||
// return templateURL;
|
||||
//
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Fetches the TemplateResolver for a content section. Checks cache first.
|
||||
// *
|
||||
// * @param section The content section
|
||||
// *
|
||||
// * @return The TemplateResolver associated with the content section
|
||||
// */
|
||||
// public TemplateResolver getTemplateResolver(ContentSection section) {
|
||||
//
|
||||
// String name = section.getName();
|
||||
// TemplateResolver ir = (TemplateResolver) s_templateResolverCache.get(
|
||||
// name);
|
||||
//
|
||||
// if (ir == null) {
|
||||
// ir = section.getTemplateResolver();
|
||||
// s_templateResolverCache.put(name, ir);
|
||||
// }
|
||||
//
|
||||
// return ir;
|
||||
// }
|
||||
|
||||
}
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.dispatcher;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.SimpleComponent;
|
||||
import com.arsdigita.cms.CMS;
|
||||
import com.arsdigita.dispatcher.DispatcherHelper;
|
||||
import com.arsdigita.util.Assert;
|
||||
import com.arsdigita.xml.Element;
|
||||
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
import org.librecms.dispatcher.ItemResolver;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This <code>ContentPanel</code> component fetches the
|
||||
* {@link com.arsdigita.cms.dispatcher.XMLGenerator} for the content
|
||||
* section.</p>
|
||||
*
|
||||
* @author Michael Pih (pihman@arsdigita.com)
|
||||
* @version $Revision$ $Date$
|
||||
* @version $Id$
|
||||
*/
|
||||
public class ContentPanel extends SimpleComponent {
|
||||
|
||||
public ContentPanel() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches an XML Generator. This method can be overridden to fetch any
|
||||
* {@link com.arsdigita.cms.dispatcher.XMLGenerator}, but by default, it
|
||||
* fetches the <code>XMLGenerator</code> registered to the current
|
||||
* {@link com.arsdigita.cms.ContentSection}.
|
||||
*
|
||||
* @param state The page state
|
||||
*
|
||||
* @return The XMLGenerator used by this Content Panel
|
||||
*/
|
||||
protected XMLGenerator getXMLGenerator(PageState state) {
|
||||
ContentSection section = CMS.getContext().getContentSection();
|
||||
Assert.exists(section);
|
||||
try {
|
||||
return (XMLGenerator) Class.forName(section.getXmlGeneratorClass())
|
||||
.newInstance();
|
||||
} catch (ClassNotFoundException |
|
||||
InstantiationException |
|
||||
IllegalAccessException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates XML that represents a content item.
|
||||
*
|
||||
* @param state The page state
|
||||
* @param parent The parent DOM element
|
||||
*
|
||||
* @see com.arsdigita.cms.dispatcher.XMLGenerator
|
||||
*/
|
||||
@Override
|
||||
public void generateXML(PageState state, Element parent) {
|
||||
if (isVisible(state)) {
|
||||
Element content = parent.newChildElement("cms:contentPanel",
|
||||
CMS.CMS_XML_NS);
|
||||
exportAttributes(content);
|
||||
|
||||
// Generate path information about the content item
|
||||
generatePathInfoXML(state, content);
|
||||
|
||||
// Take advantage of caching in the CMS Dispatcher.
|
||||
XMLGenerator xmlGenerator = getXMLGenerator(state);
|
||||
|
||||
xmlGenerator.generateXML(state, content, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate information about the path to this content item.
|
||||
*
|
||||
* @param state the page state
|
||||
* @param parent the element that will contain the path info
|
||||
*/
|
||||
protected void generatePathInfoXML(PageState state, Element parent) {
|
||||
Element pathInfo = parent
|
||||
.newChildElement("cms:pathInfo", CMS.CMS_XML_NS);
|
||||
|
||||
if (CMS.getContext().hasContentSection()) {
|
||||
pathInfo.newChildElement("cms:sectionPath", CMS.CMS_XML_NS).setText(
|
||||
CMS.getContext().getContentSection().getPrimaryUrl());
|
||||
}
|
||||
String url = DispatcherHelper.getRequestContext().getRemainingURLPart();
|
||||
if (url.startsWith(CMSDispatcher.PREVIEW)) {
|
||||
pathInfo.newChildElement("cms:previewPath", CMS.CMS_XML_NS).setText(
|
||||
"preview");
|
||||
}
|
||||
pathInfo.newChildElement("cms:templatePrefix", CMS.CMS_XML_NS).setText(
|
||||
"/" + ItemResolver.TEMPLATE_CONTEXT_PREFIX);
|
||||
|
||||
if (CMS.getContext().hasContentItem()) {
|
||||
ContentItem item = CMS.getContext().getContentItem();
|
||||
pathInfo.newChildElement("cms:itemPath", CMS.CMS_XML_NS).setText("/"
|
||||
+ item.getName());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.dispatcher;
|
||||
|
||||
import com.arsdigita.dispatcher.Dispatcher;
|
||||
import com.arsdigita.dispatcher.DispatcherChain;
|
||||
import com.arsdigita.dispatcher.RequestContext;
|
||||
import com.arsdigita.util.Assert;
|
||||
import com.arsdigita.web.Web;
|
||||
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.security.PermissionChecker;
|
||||
import org.libreccm.web.ApplicationManager;
|
||||
import org.librecms.CmsConstants;
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
import org.librecms.contentsection.privileges.ItemPrivileges;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* <b><font color="red">Unsupported</font></b> Refactored content section
|
||||
* dispatcher (under development).
|
||||
*
|
||||
* @author Karl Goldstein (karlg@arsdigita.com)
|
||||
* @version $Revision$ $DateTime: 2004/08/17 23:15:09 $
|
||||
* @version $Id$
|
||||
*/
|
||||
public class ContentSectionDispatcher implements Dispatcher {
|
||||
|
||||
public static final String CONTENT_ITEM
|
||||
= "com.arsdigita.cms.dispatcher.item";
|
||||
|
||||
static final String CONTENT_SECTION = "com.arsdigita.cms.dispatcher.section";
|
||||
|
||||
private DispatcherChain dispatcherChain = new DispatcherChain();
|
||||
|
||||
public ContentSectionDispatcher() {
|
||||
|
||||
// dispatcherChain.addChainedDispatcher(new CMSDispatcher(true));
|
||||
// dispatcherChain.addChainedDispatcher(new FileDispatcher());
|
||||
// dispatcherChain.addChainedDispatcher(new ItemDispatcher());
|
||||
// dispatcherChain.addChainedDispatcher(new CMSDispatcher());
|
||||
}
|
||||
|
||||
public void dispatch(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
RequestContext context)
|
||||
throws IOException, ServletException {
|
||||
|
||||
setContentSection(request, context);
|
||||
dispatcherChain.dispatch(request, response, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the content section from the request attributes.
|
||||
*
|
||||
* @param request The HTTP request
|
||||
*
|
||||
* @return The content section
|
||||
*
|
||||
* @pre ( request != null )
|
||||
*/
|
||||
public static ContentSection getContentSection(HttpServletRequest request) {
|
||||
return (ContentSection) request.getAttribute(CONTENT_SECTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the content item from the request attributes.
|
||||
*
|
||||
* @param request The HTTP request
|
||||
*
|
||||
* @return The content item
|
||||
*
|
||||
* @pre ( request != null )
|
||||
*/
|
||||
public static ContentItem getContentItem(HttpServletRequest request) {
|
||||
return (ContentItem) request.getAttribute(CONTENT_ITEM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the current content section using the remaining URL stored in
|
||||
* the request context object and the SiteNode class.
|
||||
*
|
||||
* @param url The section URL stub
|
||||
*
|
||||
* @return The current Content Section
|
||||
*/
|
||||
private void setContentSection(HttpServletRequest request,
|
||||
// SiteNodeRequestContext actx)
|
||||
RequestContext actx)
|
||||
throws ServletException {
|
||||
|
||||
final ContentSection section = (ContentSection) Web.getWebContext()
|
||||
.getApplication();
|
||||
request.setAttribute(CONTENT_SECTION, section);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the current user has permission to access the admin pages.
|
||||
*
|
||||
* @param request
|
||||
* @param section
|
||||
*/
|
||||
public static boolean checkAdminAccess(HttpServletRequest request,
|
||||
ContentSection section) {
|
||||
|
||||
return CdiUtil.createCdiUtil().findBean(PermissionChecker.class)
|
||||
.isPermitted(ItemPrivileges.EDIT, section
|
||||
.getRootDocumentsFolder());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,289 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.dispatcher;
|
||||
|
||||
import com.arsdigita.dispatcher.ChainedDispatcher;
|
||||
import com.arsdigita.dispatcher.DispatcherHelper;
|
||||
import com.arsdigita.dispatcher.RequestContext;
|
||||
import com.arsdigita.web.LoginSignal;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.security.PermissionChecker;
|
||||
import org.libreccm.security.Shiro;
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
import org.librecms.contentsection.ContentSectionManager;
|
||||
import org.librecms.contentsection.ContentSectionServlet;
|
||||
import org.librecms.contentsection.privileges.ItemPrivileges;
|
||||
import org.librecms.dispatcher.ItemResolver;
|
||||
|
||||
/**
|
||||
* Dispatches to the JSP or Servlet for rendering a content item.
|
||||
*
|
||||
* @author Karl Goldstein (karlg@arsdigita.com)
|
||||
*
|
||||
*/
|
||||
public class ItemDispatcher implements ChainedDispatcher {
|
||||
|
||||
private static Logger LOGGER = LogManager.getLogger(ItemDispatcher.class);
|
||||
|
||||
public static Map s_itemResolverCache = Collections.synchronizedMap(
|
||||
new HashMap());
|
||||
public static Map s_templateResolverCache = Collections.synchronizedMap(
|
||||
new HashMap());
|
||||
|
||||
public static final String FILE_SUFFIX = ".jsp";
|
||||
public static final String INDEX_FILE = "/index";
|
||||
// public static final String TEMPLATE_ROOT =
|
||||
// "/packages/content-section/templates";
|
||||
// public static final String DEFAULT_ITEM_TEMPLATE = "/default/item.jsp";
|
||||
// public static final String DEFAULT_FOLDER_TEMPLATE = "/default/folder.jsp";
|
||||
|
||||
public static final String XML_SUFFIX = ".xml";
|
||||
public static final String XML_MODE = "xmlMode";
|
||||
|
||||
private static boolean m_cacheItems = true;
|
||||
|
||||
/**
|
||||
* The context for previewing items
|
||||
*/
|
||||
public static final String PREVIEW = "/preview";
|
||||
|
||||
protected ItemXML m_itemXML;
|
||||
|
||||
public ItemDispatcher() {
|
||||
super();
|
||||
m_itemXML = new ItemXML();
|
||||
}
|
||||
|
||||
public static void setCacheItems(boolean value) {
|
||||
m_cacheItems = value;
|
||||
}
|
||||
|
||||
public int chainedDispatch(final HttpServletRequest request,
|
||||
final HttpServletResponse response,
|
||||
final RequestContext actx)
|
||||
throws IOException, ServletException {
|
||||
String queryString = request.getQueryString();
|
||||
String url = actx.getRemainingURLPart();
|
||||
|
||||
LOGGER.info("Resolving item URL " + url);
|
||||
|
||||
if (url.endsWith(XML_SUFFIX)) {
|
||||
request.setAttribute(XML_MODE, Boolean.TRUE);
|
||||
LOGGER.debug("StraightXML Requested");
|
||||
url = "/" + url.substring(0, url.length() - XML_SUFFIX.length());
|
||||
} else {
|
||||
request.setAttribute(XML_MODE, Boolean.FALSE);
|
||||
// it's neither a .jsp or a .xml, thus its an error
|
||||
if (url.endsWith(FILE_SUFFIX)) {
|
||||
url = "/" + url
|
||||
.substring(0, url.length() - FILE_SUFFIX.length());
|
||||
} else if (url.endsWith("/")) {
|
||||
url = "/" + url.substring(0, url.length() - 1);
|
||||
} else {
|
||||
LOGGER.warn("Fail: URL doesn't have right suffix.");
|
||||
return ChainedDispatcher.DISPATCH_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
final ContentSection section = ContentSectionServlet.getContentSection(
|
||||
request);
|
||||
// ContentSectionDispatcher.getContentSection(request);
|
||||
|
||||
final ContentItem item = getItem(section, url);
|
||||
if (item == null) {
|
||||
LOGGER.warn("Fail: No live item found matching " + url);
|
||||
return ChainedDispatcher.DISPATCH_CONTINUE;
|
||||
}
|
||||
|
||||
request.setAttribute(ContentSectionDispatcher.CONTENT_ITEM, item);
|
||||
|
||||
LOGGER.debug("MATCHED " + item.getObjectId());
|
||||
|
||||
// Work out how long to cache for....
|
||||
// We take minimum(default timeout, lifecycle expiry)
|
||||
//ToDo
|
||||
// Lifecycle cycle = item.getLifecycle();
|
||||
int expires = DispatcherHelper.getDefaultCacheExpiry();
|
||||
// if (cycle != null) {
|
||||
// Date endDate = cycle.getEndDate();
|
||||
//
|
||||
// if (endDate != null) {
|
||||
// int maxAge = (int) ( ( endDate.getTime() - System.currentTimeMillis() ) / 1000l );
|
||||
// if (maxAge < expires) {
|
||||
// expires = maxAge;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//ToDo end
|
||||
// NB, this is not the same as the security check previously
|
||||
// We are checking if anyone can access - ie can we allow
|
||||
// this page to be publically cached
|
||||
if (m_cacheItems && !url.startsWith(PREVIEW)) {
|
||||
// if (sm.canAccess((User)null, SecurityManager.PUBLIC_PAGES, item)) {
|
||||
if (CdiUtil.createCdiUtil().findBean(PermissionChecker.class)
|
||||
.isPermitted(
|
||||
ItemPrivileges.VIEW_PUBLISHED, item)) {
|
||||
DispatcherHelper.cacheForWorld(response, expires);
|
||||
} else {
|
||||
DispatcherHelper.cacheForUser(response, expires);
|
||||
}
|
||||
} else {
|
||||
DispatcherHelper.cacheDisable(response);
|
||||
}
|
||||
|
||||
if (((Boolean) request.getAttribute(XML_MODE)).booleanValue()) {
|
||||
m_itemXML.dispatch(request, response, actx);
|
||||
return ChainedDispatcher.DISPATCH_BREAK;
|
||||
} else {
|
||||
|
||||
// normal dispatching
|
||||
// This part assumes the template is JSP.
|
||||
// final String templateURL = getTemplateURL(section, item, request,
|
||||
// actx);
|
||||
// s_log.debug("TEMPLATE " + templateURL);
|
||||
DispatcherHelper.setRequestContext(request, actx);
|
||||
DispatcherHelper.forwardRequestByPath(null, request,
|
||||
response);
|
||||
return ChainedDispatcher.DISPATCH_BREAK;
|
||||
}
|
||||
}
|
||||
|
||||
public ContentItem getItem(ContentSection section, String url) {
|
||||
|
||||
ItemResolver itemResolver = getItemResolver(section);
|
||||
ContentItem item;
|
||||
// Check if the user has access to view public or preview pages
|
||||
boolean hasPermission = true;
|
||||
HttpServletRequest request = DispatcherHelper.getRequest();
|
||||
|
||||
// If the remaining URL starts with "preview/", then try and
|
||||
// preview this item. Otherwise look for the live item.
|
||||
boolean preview = false;
|
||||
if (url.startsWith(PREVIEW)) {
|
||||
url = url.substring(PREVIEW.length());
|
||||
preview = true;
|
||||
}
|
||||
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final PermissionChecker permissionChecker = cdiUtil.findBean(
|
||||
PermissionChecker.class);
|
||||
|
||||
if (preview) {
|
||||
item = itemResolver.getItem(section, url, "draft");
|
||||
if (item != null) {
|
||||
hasPermission = permissionChecker.isPermitted(
|
||||
ItemPrivileges.PREVIEW, item);
|
||||
}
|
||||
} else {
|
||||
item = itemResolver.getItem(section, url, "live");
|
||||
if (item != null) {
|
||||
hasPermission = permissionChecker.isPermitted(
|
||||
ItemPrivileges.VIEW_PUBLISHED, item);
|
||||
}
|
||||
}
|
||||
|
||||
if (item == null && url.endsWith(INDEX_FILE)) {
|
||||
|
||||
// look up folder if it's an index
|
||||
url = url.substring(0, url.length() - INDEX_FILE.length());
|
||||
LOGGER.info("Attempting to match folder " + url);
|
||||
item = itemResolver.getItem(section, url, "live");
|
||||
if (item != null) {
|
||||
hasPermission = permissionChecker.isPermitted(
|
||||
ItemPrivileges.VIEW_PUBLISHED, item);
|
||||
}
|
||||
}
|
||||
// chris.gilbert@westsussex.gov.uk - if user is not logged in, give them a chance to do that, else show them the door
|
||||
if (!hasPermission && !cdiUtil.findBean(Shiro.class).getSubject()
|
||||
.isAuthenticated()) {
|
||||
throw new LoginSignal(request);
|
||||
}
|
||||
if (!hasPermission) {
|
||||
throw new com.arsdigita.dispatcher.AccessDeniedException();
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the ItemResolver for a content section.
|
||||
*
|
||||
* @param section The content section
|
||||
*
|
||||
* @return The ItemResolver associated with the content section
|
||||
*/
|
||||
public ItemResolver getItemResolver(ContentSection section) {
|
||||
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final ContentSectionManager sectionManager = cdiUtil.findBean(
|
||||
ContentSectionManager.class);
|
||||
|
||||
return sectionManager.getItemResolver(section);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the ItemResolver for a content section. Checks cache first.
|
||||
*
|
||||
* @param section The content section
|
||||
*
|
||||
* @return The ItemResolver associated with the content section
|
||||
*/
|
||||
// public TemplateResolver getTemplateResolver(ContentSection section) {
|
||||
//
|
||||
// String name = section.getName();
|
||||
// TemplateResolver ir = (TemplateResolver) s_templateResolverCache.get(
|
||||
// name);
|
||||
//
|
||||
// if (ir == null) {
|
||||
// ir = section.getTemplateResolver();
|
||||
// s_templateResolverCache.put(name, ir);
|
||||
// }
|
||||
//
|
||||
// return ir;
|
||||
// }
|
||||
/**
|
||||
* Fetches the URL of a template for an item. The returned URL is relative
|
||||
* to the webapp context.
|
||||
*/
|
||||
// public String getTemplateURL(ContentSection section,
|
||||
// ContentItem item,
|
||||
// HttpServletRequest request,
|
||||
// RequestContext actx) {
|
||||
//
|
||||
// String templateURL = getTemplateResolver(section).getTemplate(section,
|
||||
// item,
|
||||
// request);
|
||||
//
|
||||
// return templateURL;
|
||||
// }
|
||||
}
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2002-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.dispatcher;
|
||||
|
||||
|
||||
import com.arsdigita.cms.CMS;
|
||||
import com.arsdigita.dispatcher.RequestContext;
|
||||
import com.arsdigita.xml.Document;
|
||||
import com.arsdigita.xml.Element;
|
||||
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
||||
/***
|
||||
*
|
||||
* XMLPage
|
||||
*
|
||||
* Designed to allow you to output straight XML directly from the ContentItem
|
||||
* that implements XMLGenerator, with none of the surrounding headers, footers, etc
|
||||
*
|
||||
* @author slater@arsdigita.com
|
||||
*
|
||||
***/
|
||||
|
||||
public class ItemXML extends ResourceHandlerImpl {
|
||||
|
||||
public ItemXML() {
|
||||
super();
|
||||
}
|
||||
|
||||
public void dispatch(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
RequestContext actx)
|
||||
throws IOException, ServletException {
|
||||
|
||||
ContentItem item = getContentItem(request);
|
||||
|
||||
Element content = new Element("cms:item", CMS.CMS_XML_NS);
|
||||
|
||||
// ContentItemXMLRenderer renderer =
|
||||
// new ContentItemXMLRenderer(content);
|
||||
//ToDo
|
||||
// renderer.setWrapAttributes(true);
|
||||
// renderer.setWrapRoot(false);
|
||||
// renderer.setWrapObjects(false);
|
||||
//
|
||||
// renderer.walk(item, SimpleXMLGenerator.ADAPTER_CONTEXT);
|
||||
//ToDo End
|
||||
|
||||
Document doc;
|
||||
try {
|
||||
doc = new Document(content);
|
||||
} catch (javax.xml.parsers.ParserConfigurationException e) {
|
||||
throw new javax.servlet.ServletException(e);
|
||||
}
|
||||
|
||||
OutputStream out = response.getOutputStream();
|
||||
try {
|
||||
out.write(doc.toString(true).getBytes());
|
||||
} catch (IOException e) {
|
||||
throw new ServletException(e);
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.dispatcher;
|
||||
|
||||
import com.arsdigita.bebop.SimpleContainer;
|
||||
import com.arsdigita.util.Assert;
|
||||
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
|
||||
/**
|
||||
* <p>A {@link com.arsdigita.cms.dispatcher.CMSPage} used for serving
|
||||
* content items.</p>
|
||||
*
|
||||
* <p>This page contains a <code>ContentPanel</code> component which fetches
|
||||
* the {@link com.arsdigita.cms.dispatcher.XMLGenerator} for the content
|
||||
* section.</p>
|
||||
*
|
||||
* @author Michael Pih (pihman@arsdigita.com)
|
||||
* @version $Revision$ $DateTime: 2004/08/17 23:15:09 $
|
||||
* @version $Id$
|
||||
*/
|
||||
public class MasterPage extends CMSPage {
|
||||
|
||||
public MasterPage() {
|
||||
super("Master", new SimpleContainer());
|
||||
setIdAttr("master_page");
|
||||
|
||||
add(new ContentPanel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the request-local content section.
|
||||
*
|
||||
* @param request The HTTP request
|
||||
* @return The current content section
|
||||
*/
|
||||
public ContentSection getContentSection(HttpServletRequest request) {
|
||||
// Resets all content sections associations.
|
||||
ContentSection section = super.getContentSection(request);
|
||||
Assert.exists(section);
|
||||
return section;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.dispatcher;
|
||||
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
|
||||
|
||||
/**
|
||||
* <p>This class contains methods for registering and resolving {@link
|
||||
* ResourceHandler CMS resources} in a specific content section.</p>
|
||||
*
|
||||
* <p>The <tt>PageResolver</tt> includes methods for caching resource
|
||||
* mappings.</p>
|
||||
*
|
||||
* @author Michael Pih (pihman@arsdigita.com)
|
||||
* @version $Revision$ $Date$
|
||||
* @version $Id$
|
||||
*/
|
||||
public abstract class PageResolver {
|
||||
|
||||
private BigDecimal m_sectionID;
|
||||
|
||||
// Used for caching pages
|
||||
private HashMap m_pages;
|
||||
|
||||
|
||||
public PageResolver() {
|
||||
m_pages = new HashMap();
|
||||
}
|
||||
|
||||
public void setContentSectionID(BigDecimal id) {
|
||||
m_sectionID = id;
|
||||
}
|
||||
|
||||
protected BigDecimal getContentSectionID() {
|
||||
return m_sectionID;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fetch the page associated with the request URL.
|
||||
*
|
||||
* @param url The content section-relative URL stub
|
||||
* @return The resource
|
||||
*/
|
||||
public ResourceHandler getPage(String url) {
|
||||
return (ResourceHandler) m_pages.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a page to the content section.
|
||||
*
|
||||
* @param page The master page
|
||||
* @param url The desired URL of the page
|
||||
*/
|
||||
public abstract void registerPage(ResourceHandler page, String url);
|
||||
|
||||
|
||||
/**
|
||||
* Register a page to the content section.
|
||||
*
|
||||
* @param page The master page
|
||||
* @param url The desired URL of the page
|
||||
*/
|
||||
public abstract void unregisterPage(ResourceHandler page, String url);
|
||||
|
||||
|
||||
/**
|
||||
* Loads a page into the page resolver cache.
|
||||
*
|
||||
* @param url The URL of the resource to load into the cache
|
||||
* @param page The resource
|
||||
*/
|
||||
public void loadPage(String url, ResourceHandler page) {
|
||||
m_pages.put(url, page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes a page from the page resolver cache.
|
||||
*
|
||||
* @param url The URL of the resource to remove from the cache
|
||||
*/
|
||||
public void releasePage(String url) {
|
||||
m_pages.remove(url);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.dispatcher;
|
||||
|
||||
import com.arsdigita.dispatcher.Dispatcher;
|
||||
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
|
||||
/**
|
||||
* An interface for resources that can be served.
|
||||
*
|
||||
* @author Michael Pih (pihman@arsdigita.com)
|
||||
* @version $Revision$ $DateTime: 2004/08/17 23:15:09 $
|
||||
* @version $Id$
|
||||
**/
|
||||
public interface ResourceHandler extends Dispatcher {
|
||||
|
||||
/**
|
||||
* This method is called by the {@link com.arsdigita.dispatcher.Dispatcher}
|
||||
* that initializes this page.
|
||||
*/
|
||||
public void init() throws ServletException;
|
||||
|
||||
/**
|
||||
* Fetches the content section context for this resource.
|
||||
*
|
||||
* @param request The HTTP request
|
||||
* @return A content section or null if there is none
|
||||
* @pre ( request != null )
|
||||
*/
|
||||
public ContentSection getContentSection(HttpServletRequest request);
|
||||
|
||||
/**
|
||||
* Fetches the content item context for this resource.
|
||||
*
|
||||
* @param request The HTTP request
|
||||
* @return A content item or null if there is none
|
||||
* @pre ( request != null )
|
||||
*/
|
||||
public ContentItem getContentItem(HttpServletRequest request);
|
||||
|
||||
}
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.dispatcher;
|
||||
|
||||
import com.arsdigita.dispatcher.RequestContext;
|
||||
import com.arsdigita.util.Assert;
|
||||
|
||||
import org.apache.shiro.authz.AuthorizationException;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.security.PermissionChecker;
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
import org.librecms.contentsection.privileges.ItemPrivileges;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* An interface for resources that can be served.
|
||||
*
|
||||
* @author Michael Pih (pihman@arsdigita.com)
|
||||
* @version $Revision$ $DateTime: 2004/08/17 23:15:09 $
|
||||
* @version $Id$
|
||||
*
|
||||
*/
|
||||
public abstract class ResourceHandlerImpl implements ResourceHandler {
|
||||
|
||||
/**
|
||||
* This method is called by the {@link com.arsdigita.dispatcher.Dispatcher}
|
||||
* that initializes this page.
|
||||
*/
|
||||
public void init() throws ServletException {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the request-local content section.
|
||||
*
|
||||
* @param request The HTTP request
|
||||
*
|
||||
* @return The current content section
|
||||
*/
|
||||
public ContentSection getContentSection(HttpServletRequest request) {
|
||||
// resets all content sections associations
|
||||
ContentSection section = CMSDispatcher.getContentSection(request);
|
||||
Assert.exists(section);
|
||||
return section;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the request-local content item.
|
||||
*
|
||||
* @param request The HTTP request
|
||||
*
|
||||
* @return The current content item
|
||||
*/
|
||||
public ContentItem getContentItem(HttpServletRequest request) {
|
||||
// resets all content item associations
|
||||
return CMSDispatcher.getContentItem(request);
|
||||
}
|
||||
|
||||
public void checkUserAccess(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
RequestContext actx,
|
||||
ContentItem item) {
|
||||
if (!CdiUtil.createCdiUtil().findBean(PermissionChecker.class)
|
||||
.isPermitted(ItemPrivileges.VIEW_PUBLISHED, item)) {
|
||||
throw new AuthorizationException(
|
||||
"cms.dispatcher.no_permission_to_access_resource");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Services this resource.
|
||||
*
|
||||
* @param request The servlet request object
|
||||
* @param response the servlet response object
|
||||
* @param actx The request context
|
||||
*/
|
||||
public abstract void dispatch(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
RequestContext actx)
|
||||
throws IOException, ServletException;
|
||||
|
||||
}
|
||||
|
|
@ -1,258 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.dispatcher;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.cms.CMS;
|
||||
import com.arsdigita.dispatcher.DispatcherHelper;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.librecms.CmsConstants;
|
||||
import org.librecms.assets.BinaryAsset;
|
||||
import org.librecms.assets.Image;
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This class provides many utility functions for the Content Management
|
||||
* System.</p>
|
||||
* Specifically used by various JSP templates.
|
||||
*
|
||||
* @author Michael Pih (pihman@arsdigita.com)
|
||||
*/
|
||||
public class Utilities {
|
||||
|
||||
public static final Logger LOGGER = LogManager.getLogger(Utilities.class);
|
||||
|
||||
// Used for caching util lookups
|
||||
private static HashMap m_cache = new HashMap();
|
||||
|
||||
private static Date s_lastSectionRefresh = null;
|
||||
private static Map s_sectionRefreshTimes = Collections.synchronizedMap(
|
||||
new HashMap());
|
||||
|
||||
/**
|
||||
* Fetch the location of the CMS ContentCenter package.
|
||||
*
|
||||
* @return The URL of the CMS ContentCenter package
|
||||
*
|
||||
* @deprecated use ContentCenter.getURL() instead
|
||||
*/
|
||||
public static String getWorkspaceURL() {
|
||||
|
||||
return CmsConstants.CONTENT_CENTER_URL;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the location (URL) of the CMS Services package. Caches the result.
|
||||
*
|
||||
* @return The URL of the CMS Services package
|
||||
*
|
||||
* @deprecated Use Service.getURL( instead
|
||||
*/
|
||||
public static String getServiceURL() {
|
||||
String url = (String) m_cache.get(CmsConstants.SERVICE_PACKAGE_KEY);
|
||||
if (url == null) {
|
||||
// chris.gilbert@westsussex.gov.uk
|
||||
// We don't want application context in this url, especially when
|
||||
// it gets cached in a static variable - if I have a
|
||||
// file that is maintained by a non cms application eg
|
||||
// forum, then I can end up with a url that doesn't work
|
||||
// and so breaks file links everywhere
|
||||
// url = getSingletonPackageURLSansContext(CMS.SERVICE_PACKAGE_KEY);
|
||||
url = CmsConstants.SERVICE_URL;
|
||||
m_cache.put(CmsConstants.SERVICE_PACKAGE_KEY, url);
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* The URL to log out.
|
||||
*
|
||||
* @return The logout URL
|
||||
*/
|
||||
public static String getLogoutURL() {
|
||||
//StringBuffer buf = new StringBuffer(getServiceURL());
|
||||
StringBuilder buf = new StringBuilder(CmsConstants.SERVICE_URL);
|
||||
buf.append("logout");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a URL which serves a binary asset.
|
||||
*
|
||||
* @param asset The binary asset
|
||||
*
|
||||
* @return the URL which will serve the specified binary asset
|
||||
*
|
||||
* @deprecated Use Service.getAssetURL(BinaryAsset asset) instead
|
||||
*/
|
||||
public static String getAssetURL(BinaryAsset asset) {
|
||||
return getAssetURL(asset.getObjectId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constuct a URL which serves a binary asset.
|
||||
*
|
||||
* @param assetId The asset ID
|
||||
*
|
||||
* @return the URL which will serve the specified binary asset
|
||||
*
|
||||
* @deprecated Use Service.getAssetURL(BigDecimal assetId) instead
|
||||
*/
|
||||
public static String getAssetURL(long assetId) {
|
||||
// StringBuffer buf = new StringBuffer(getServiceURL());
|
||||
StringBuilder buf = new StringBuilder(CmsConstants.SERVICE_URL);
|
||||
buf.append("stream/asset?");
|
||||
buf.append(CmsConstants.ASSET_ID).append("=").append(assetId);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a URL which serves an image.
|
||||
*
|
||||
* @param asset The image asset whose image is to be served
|
||||
*
|
||||
* @return the URL which will serve the specified image asset
|
||||
*
|
||||
* @deprecated Use Service.getImageURL(ImageAsset) instead!
|
||||
*/
|
||||
public static String getImageURL(Image asset) {
|
||||
// StringBuffer buf = new StringBuffer(getServiceURL());
|
||||
StringBuilder buf = new StringBuilder(CmsConstants.SERVICE_URL);
|
||||
buf.append("stream/image/?");
|
||||
buf.append(CmsConstants.IMAGE_ID).append("=")
|
||||
.append(asset.getObjectId());
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static String getGlobalAssetsURL() {
|
||||
return getWebappContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the context path of the request. This is typically "/".
|
||||
*
|
||||
* @return The webapp context path
|
||||
*/
|
||||
public static String getWebappContext() {
|
||||
return DispatcherHelper.getWebappContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for the last refresh on authoring kits or content types in a
|
||||
* section.
|
||||
*
|
||||
*/
|
||||
public static synchronized Date
|
||||
getLastSectionRefresh(ContentSection section) {
|
||||
|
||||
// cache by URL string instead of by section object to avoid
|
||||
// holding the reference.
|
||||
String sectionURL = section.getPrimaryUrl();
|
||||
|
||||
Date lastModified = (Date) s_sectionRefreshTimes.get(sectionURL);
|
||||
if (lastModified == null) {
|
||||
lastModified = new Date();
|
||||
s_lastSectionRefresh = lastModified;
|
||||
s_sectionRefreshTimes.put(sectionURL, lastModified);
|
||||
}
|
||||
|
||||
return lastModified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for the last refresh on authoring kits or content types in any
|
||||
* section.
|
||||
*
|
||||
*/
|
||||
public static Date getLastSectionRefresh() {
|
||||
|
||||
// instantiate last refresh lazily to ensure that first result is
|
||||
// predictable.
|
||||
if (s_lastSectionRefresh == null) {
|
||||
s_lastSectionRefresh = new Date();
|
||||
}
|
||||
return s_lastSectionRefresh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force the authoring UI to reload. This should be done every time an
|
||||
* authoring kit or a content type are updated.
|
||||
*/
|
||||
public static void refreshItemUI(PageState state) {
|
||||
// Drop the authoring kit UI to force it to refresh
|
||||
// THE URL SHOULD NOT BE HARDCODED !
|
||||
|
||||
ContentSection section = CMS.getContext().getContentSection();
|
||||
|
||||
// OLD APPROACH: used in conjunction with CMSDispatcher. This
|
||||
// shouldn't do any harm even if CMSDispatcher is not being used.
|
||||
CMSDispatcher.releaseResource(section, "admin/item");
|
||||
refreshAdminUI(state);
|
||||
|
||||
// NEW APPROACH: used in conjunction with
|
||||
// ContentSectionDispatcher. cache by URL string instead of by
|
||||
// section object to avoid holding the reference. This shouldn't
|
||||
// do any harm even if ContentSectionDispatcher is not being used.
|
||||
s_lastSectionRefresh = new Date();
|
||||
s_sectionRefreshTimes.put(section.getPrimaryUrl(),
|
||||
s_lastSectionRefresh);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force the authoring UI to reload. This should be done every time an
|
||||
* authoring kit or a content type are updated.
|
||||
*/
|
||||
public static void refreshAdminUI(PageState state) {
|
||||
// Drop the admin UI to force it to refresh
|
||||
// THE URL SHOULD NOT BE HARDCODED !
|
||||
|
||||
ContentSection section = CMS.getContext().getContentSection();
|
||||
|
||||
CMSDispatcher.releaseResource(section, "admin");
|
||||
CMSDispatcher.releaseResource(section, "admin/index");
|
||||
CMSDispatcher.releaseResource(section, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the "pragma: no-cache" header to the HTTP response to make sure the
|
||||
* browser does not cache tha page
|
||||
*
|
||||
* @param response The HTTP response
|
||||
*
|
||||
* @deprecated use
|
||||
* com.arsdigita.dispatcher.DispatcherHelper.cacheDisable(HttpServletResponse)
|
||||
*/
|
||||
public static void disableBrowserCache(HttpServletResponse response) {
|
||||
response.addHeader("pragma", "no-cache");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.dispatcher;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.xml.Element;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Generates XML representing a Content Item.</p>
|
||||
*
|
||||
* <p>As the last step of servicing a page, the
|
||||
* {@link com.arsdigita.cms.dispatcher.MasterPage} will go through the
|
||||
* hierarchy of its components and ask each of them to convert themselves
|
||||
* to XML. A MasterPage contains a special component that knows how to ask
|
||||
* its content section for the XML generator that should be applied. The
|
||||
* XML generator's <code>generateXML</code> method in turn asks the
|
||||
* containing page for the content item, the one that the
|
||||
* {@link com.arsdigita.cms.dispatcher.ItemResolver} found before, and
|
||||
* formats it as an XML document.</p>
|
||||
*
|
||||
* @author Michael Pih (pihman@arsdigita.com)
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface XMLGenerator {
|
||||
|
||||
/**
|
||||
* Generates the XML to render the content panel.
|
||||
*
|
||||
* @param state The page state
|
||||
* @param parent The parent DOM element
|
||||
* @param useContext The use context
|
||||
*/
|
||||
public void generateXML(PageState state, Element parent, String useContext);
|
||||
|
||||
}
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.lifecycle;
|
||||
|
||||
import com.arsdigita.util.Assert;
|
||||
|
||||
/**
|
||||
* Utility methods for lifecycle durations.
|
||||
*
|
||||
* @author <a href="mailto:pihman@arsdigita.com">Michael Pih</a>
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com>Jens Pelzetter</a>
|
||||
*/
|
||||
public class Duration {
|
||||
|
||||
/**
|
||||
* A convenience wrapper around {@link #formatDuration(long)}.
|
||||
*
|
||||
* @param minutes
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @see #formatDuration(long)
|
||||
* @pre minutes != null
|
||||
*/
|
||||
public static String formatDuration(final Long minutes) {
|
||||
Assert.exists(minutes, "minutes");
|
||||
return formatDuration(minutes.longValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a duration longo a user friendly format of the form "x days, h
|
||||
* hours, m minutes".
|
||||
*
|
||||
* @param minutes the duration in minutes
|
||||
* @return
|
||||
*/
|
||||
public static String formatDuration(final long minutes) {
|
||||
long[] dhm = formatDHM(minutes);
|
||||
final StringBuilder buffer = new StringBuilder();
|
||||
|
||||
if (dhm[0] > 0) {
|
||||
buffer.append(dhm[0]).append(" days");
|
||||
}
|
||||
|
||||
if (dhm[1] > 0) {
|
||||
if (dhm[0] > 0) {
|
||||
buffer.append(", ");
|
||||
}
|
||||
buffer.append(dhm[1]).append(" hours");
|
||||
}
|
||||
|
||||
if (dhm[0] > 0 || dhm[1] > 0) {
|
||||
buffer.append(", ");
|
||||
}
|
||||
buffer.append(dhm[2]).append(" minutes");
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats time in minutes longo a days/hours/minutes format.
|
||||
*
|
||||
* @param minutes
|
||||
* @return
|
||||
*/
|
||||
public static long[] formatDHM(final long minutes) {
|
||||
long[] dhm = new long[3];
|
||||
|
||||
long days = minutes / (60 * 24);
|
||||
long hours = minutes / 60; // no pun longended
|
||||
long mins = minutes;
|
||||
|
||||
if (days > 0) {
|
||||
hours -= (days * 24);
|
||||
mins -= (days * 24 * 60);
|
||||
}
|
||||
if (hours > 0) {
|
||||
mins -= (hours * 60);
|
||||
}
|
||||
|
||||
dhm[0] = days;
|
||||
dhm[1] = hours;
|
||||
dhm[2] = mins;
|
||||
return dhm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats time in minutes longo a days/hours/minutes format.
|
||||
*
|
||||
* @return
|
||||
* @see #formatDHM(long)
|
||||
* @param minutes timespan in minutes
|
||||
*/
|
||||
public static Long[] formatDHM(final Long minutes) {
|
||||
long dhm[] = formatDHM(minutes.longValue());
|
||||
return copyArray(dhm);
|
||||
}
|
||||
|
||||
private static Long[] copyArray(long[] from) {
|
||||
Assert.exists(from, "from");
|
||||
Long[] to = new Long[from.length];
|
||||
for (int ii = 0; ii < from.length; ii++) {
|
||||
to[ii] = from[ii];
|
||||
}
|
||||
return to;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui;
|
||||
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.event.FormProcessListener;
|
||||
import com.arsdigita.bebop.form.Submit;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
|
||||
/**
|
||||
* @author Justin Ross
|
||||
*/
|
||||
public abstract class BaseDeleteForm extends BaseForm
|
||||
implements FormProcessListener {
|
||||
|
||||
protected final Submit m_delete;
|
||||
protected final Submit m_cancel;
|
||||
|
||||
public BaseDeleteForm(final Component message) {
|
||||
super("delete", new Label(gz("cms.ui.attention")));
|
||||
|
||||
addComponent(message);
|
||||
|
||||
m_delete = new Submit("delete", gz("cms.ui.delete"));
|
||||
addAction(m_delete);
|
||||
|
||||
m_cancel = new Submit("cancel", gz("cms.ui.cancel"));
|
||||
addAction(m_cancel);
|
||||
|
||||
addProcessListener(this);
|
||||
}
|
||||
|
||||
public BaseDeleteForm(final GlobalizedMessage message) {
|
||||
this(new Label(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isCancelled(final PageState state) {
|
||||
return m_cancel.isSelected(state);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,190 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui;
|
||||
|
||||
import com.arsdigita.bebop.BoxPanel;
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.Form;
|
||||
import com.arsdigita.bebop.GridPanel;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.SimpleContainer;
|
||||
import com.arsdigita.bebop.form.FormErrorDisplay;
|
||||
import com.arsdigita.bebop.form.Submit;
|
||||
import com.arsdigita.bebop.form.TextArea;
|
||||
import com.arsdigita.bebop.form.TextField;
|
||||
import com.arsdigita.bebop.parameters.NotEmptyValidationListener;
|
||||
import com.arsdigita.bebop.parameters.NotNullValidationListener;
|
||||
import com.arsdigita.bebop.parameters.StringLengthValidationListener;
|
||||
import com.arsdigita.bebop.parameters.TrimmedStringParameter;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.toolbox.ui.Cancellable;
|
||||
import com.arsdigita.toolbox.ui.Section;
|
||||
import com.arsdigita.util.Assert;
|
||||
|
||||
import org.librecms.CmsConstants;
|
||||
|
||||
/**
|
||||
* A convenience class for CMS forms.
|
||||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
* @author <a href="mailto:jross@redhat.com">Justin Ross</a>
|
||||
*/
|
||||
public abstract class BaseForm extends Form implements Cancellable {
|
||||
|
||||
private final BodySection m_body;
|
||||
private final BoxPanel m_actions;
|
||||
private Cancel m_cancel;
|
||||
|
||||
protected BaseForm(final String name, final Label heading) {
|
||||
super(name, new GridPanel(1));
|
||||
|
||||
setRedirecting(true);
|
||||
|
||||
m_body = new BodySection(heading);
|
||||
m_actions = new BoxPanel(BoxPanel.HORIZONTAL);
|
||||
|
||||
add(m_body);
|
||||
add(m_actions);
|
||||
|
||||
addComponent(new FormErrorDisplay(this));
|
||||
}
|
||||
|
||||
protected BaseForm(final String name,
|
||||
final GlobalizedMessage heading) {
|
||||
this(name, new Label(heading));
|
||||
}
|
||||
|
||||
private class BodySection extends Section {
|
||||
|
||||
final SimpleContainer m_container;
|
||||
|
||||
BodySection(final Label heading) {
|
||||
setHeading(heading);
|
||||
|
||||
m_container = new GridPanel(2);
|
||||
setBody(m_container);
|
||||
}
|
||||
|
||||
final void add(final Component component) {
|
||||
m_container.add(component);
|
||||
}
|
||||
|
||||
final void add(final Component component, int hints) {
|
||||
m_container.add(component, hints);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected final void addComponent(final Component component) {
|
||||
m_body.add(component, GridPanel.FULL_WIDTH);
|
||||
}
|
||||
|
||||
protected final void addField(final Label name, final Component widget) {
|
||||
m_body.add(name);
|
||||
m_body.add(widget);
|
||||
}
|
||||
|
||||
protected final void addField(final GlobalizedMessage name,
|
||||
final Component widget) {
|
||||
addField(new Label(name), widget);
|
||||
}
|
||||
|
||||
protected final void addAction(final Submit button) {
|
||||
m_actions.add(button);
|
||||
}
|
||||
|
||||
protected final void addAction(final Cancel button) {
|
||||
m_cancel = button;
|
||||
m_actions.add(button);
|
||||
}
|
||||
|
||||
protected final void addSecurityListener(final String action) {
|
||||
addSubmissionListener(new FormSecurityListener(action));
|
||||
}
|
||||
|
||||
protected final void addSecurityListener(final String action,
|
||||
final ContentItemRequestLocal item) {
|
||||
addSubmissionListener(new FormSecurityListener(action, item));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled(final PageState state) {
|
||||
return m_cancel != null && m_cancel.isSelected(state);
|
||||
}
|
||||
|
||||
protected final class Name extends TextField {
|
||||
|
||||
public Name(final String key, final int max, final boolean required) {
|
||||
super(new TrimmedStringParameter(key));
|
||||
|
||||
if (required) {
|
||||
addValidationListener(new NotEmptyValidationListener());
|
||||
}
|
||||
|
||||
setSize(40);
|
||||
setMaxLength(max);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected final class Description extends TextArea {
|
||||
|
||||
public Description(final String key,
|
||||
final int maxLength,
|
||||
final boolean isRequired) {
|
||||
super(new TrimmedStringParameter(key));
|
||||
Assert.isTrue(maxLength > 0, "Max length cannot be negative");
|
||||
|
||||
if (isRequired) {
|
||||
addValidationListener(NotNullValidationListener.DEFAULT);
|
||||
}
|
||||
addValidationListener(new StringLengthValidationListener(maxLength));
|
||||
setCols(40);
|
||||
setRows(5);
|
||||
setWrap(TextArea.SOFT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected final class Finish extends Submit {
|
||||
|
||||
public Finish() {
|
||||
super("finish", gz("cms.ui.finish"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected final class Cancel extends Submit {
|
||||
|
||||
public Cancel() {
|
||||
super("cancel", gz("cms.ui.cancel"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected static final GlobalizedMessage gz(final String key) {
|
||||
return new GlobalizedMessage(key, CmsConstants.CMS_BUNDLE);
|
||||
}
|
||||
|
||||
protected static final String lz(final String key) {
|
||||
return (String) gz(key).localize();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui;
|
||||
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.toolbox.ui.ModalPanel;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.librecms.CmsConstants;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:jross@redhat.com">Justin Ross</a>
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
public abstract class BaseItemPane extends ModalPanel {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger
|
||||
(BaseItemPane.class);
|
||||
|
||||
protected BaseItemPane() {
|
||||
super();
|
||||
}
|
||||
|
||||
protected final static GlobalizedMessage gz(final String key) {
|
||||
return new GlobalizedMessage(key, CmsConstants.CMS_BUNDLE);
|
||||
}
|
||||
|
||||
protected final static String lz(final String key) {
|
||||
return (String) gz(key).localize();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui;
|
||||
|
||||
import com.arsdigita.bebop.SimpleContainer;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A simple container with XML wrapper tags.
|
||||
*
|
||||
* @author Michael Pih (pihman@arsdigita.com)
|
||||
* @version $Id$
|
||||
*/
|
||||
public class CMSContainer extends SimpleContainer {
|
||||
|
||||
public final static String CMS_XML_NS = "http://www.arsdigita.com/cms/1.0";
|
||||
|
||||
|
||||
public CMSContainer() {
|
||||
super("cms:container", CMS_XML_NS);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui;
|
||||
|
||||
import com.arsdigita.bebop.form.DHTMLEditor;
|
||||
import com.arsdigita.bebop.parameters.ParameterModel;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
import com.arsdigita.cms.CMS;
|
||||
|
||||
import org.librecms.CMSConfig;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.l10n.GlobalizationHelper;
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class CMSDHTMLEditor extends DHTMLEditor {
|
||||
|
||||
public CMSDHTMLEditor(final String name) {
|
||||
super(new StringParameter(name),
|
||||
CMSConfig.getConfig().getDHTMLEditorConfig());
|
||||
addPlugins();
|
||||
hideButtons();
|
||||
|
||||
final ContentSection section = CMS.getContext().getContentSection();
|
||||
final GlobalizationHelper globalizationHelper = CdiUtil
|
||||
.createCdiUtil()
|
||||
.findBean(GlobalizationHelper.class);
|
||||
setAttribute("current-contentsection-id",
|
||||
Long.toString(section.getObjectId()));
|
||||
setAttribute("current-contentsection-primaryurl",
|
||||
section.getPrimaryUrl());
|
||||
setAttribute("current-contentsection-title",
|
||||
globalizationHelper
|
||||
.getValueFromLocalizedString(section.getTitle()));
|
||||
|
||||
}
|
||||
|
||||
public CMSDHTMLEditor(final ParameterModel model) {
|
||||
super(model,
|
||||
CMSConfig.getConfig().getDHTMLEditorConfig());
|
||||
|
||||
addPlugins();
|
||||
hideButtons();
|
||||
}
|
||||
|
||||
private void addPlugins() {
|
||||
|
||||
CMSConfig
|
||||
.getConfig()
|
||||
.getDhtmlEditorPlugins()
|
||||
.forEach(plugin -> addPlugin(plugin));
|
||||
}
|
||||
|
||||
private void hideButtons() {
|
||||
|
||||
CMSConfig
|
||||
.getConfig()
|
||||
.getDhtmlEditorHiddenButtons()
|
||||
.forEach(hiddenButton -> hideButton(hiddenButton));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui;
|
||||
|
||||
import com.arsdigita.bebop.Container;
|
||||
import com.arsdigita.bebop.Form;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.toolbox.ui.Cancellable;
|
||||
|
||||
/**
|
||||
* A convenience class for CMS forms. The "CMS Admin" class eliminates
|
||||
* the nested tables created by the Bebop ColumnPanel. This is mainly
|
||||
* to increase form rendering.
|
||||
*
|
||||
* @author Michael Pih
|
||||
*/
|
||||
public class CMSForm extends Form implements Cancellable {
|
||||
|
||||
public static final String CLASS = "CMS Admin";
|
||||
|
||||
public CMSForm(final String name) {
|
||||
super(name);
|
||||
|
||||
setClassAttr(CLASS);
|
||||
getPanel().setClassAttr(CLASS);
|
||||
}
|
||||
|
||||
public CMSForm(final String name, final Container panel) {
|
||||
super(name, panel);
|
||||
|
||||
setClassAttr(CLASS);
|
||||
panel.setClassAttr(CLASS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the form has been cancelled.
|
||||
* Override this method if the form can be cancelled.
|
||||
*
|
||||
* @param state The page state
|
||||
* @return true if the form is cancelled, false otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean isCancelled(final PageState state) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,670 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui;
|
||||
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.FormData;
|
||||
import com.arsdigita.bebop.FormProcessException;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.Link;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.Resettable;
|
||||
import com.arsdigita.bebop.SimpleContainer;
|
||||
import com.arsdigita.bebop.TabbedPane;
|
||||
import com.arsdigita.bebop.event.ActionEvent;
|
||||
import com.arsdigita.bebop.event.ActionListener;
|
||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||
import com.arsdigita.bebop.event.FormValidationListener;
|
||||
import com.arsdigita.bebop.event.PrintEvent;
|
||||
import com.arsdigita.bebop.event.PrintListener;
|
||||
import com.arsdigita.bebop.parameters.LongParameter;
|
||||
import com.arsdigita.bebop.parameters.NotNullValidationListener;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
import com.arsdigita.cms.CMS;
|
||||
import com.arsdigita.cms.ItemSelectionModel;
|
||||
import com.arsdigita.cms.PageLocations;
|
||||
import com.arsdigita.cms.dispatcher.CMSPage;
|
||||
import com.arsdigita.cms.ui.authoring.WizardSelector;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.kernel.KernelConfig;
|
||||
import com.arsdigita.kernel.ui.ACSObjectSelectionModel;
|
||||
import com.arsdigita.util.Assert;
|
||||
import com.arsdigita.xml.Document;
|
||||
import com.arsdigita.xml.Element;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.librecms.CMSConfig;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.librecms.CmsConstants;
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contentsection.ContentItemL10NManager;
|
||||
import org.librecms.contentsection.ContentItemRepository;
|
||||
import org.librecms.contentsection.ContentItemVersion;
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
import org.librecms.contentsection.ContentType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* Page for administering a content item.
|
||||
*
|
||||
* @author Michael Pih
|
||||
* @author <a href="mailto:sfreidin@redhat.com">Stanislav Freidin</a>
|
||||
* @author Jack Chung
|
||||
* @author <a href="mailto:quasi@quasiweb.de">Sören Bernstein</a>
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*
|
||||
*/
|
||||
public class ContentItemPage extends CMSPage implements ActionListener {
|
||||
|
||||
/**
|
||||
* Private Logger instance for debugging purpose.
|
||||
*/
|
||||
private static final Logger LOGGER = LogManager.getLogger(
|
||||
ContentItemPage.class);
|
||||
|
||||
/**
|
||||
* The URL parameter that must be passed in in order to set the current tab.
|
||||
* This is a KLUDGE right now because the TabbedDialog's current tab is
|
||||
* selected with a local state parameter
|
||||
*/
|
||||
public static final String SET_TAB = "set_tab";
|
||||
|
||||
/**
|
||||
* The name of the global state parameter that holds the item id.
|
||||
*/
|
||||
public static final String ITEM_ID = "item_id";
|
||||
|
||||
/**
|
||||
* The name of th global state parameter that holds the selected language.
|
||||
*/
|
||||
public static final String SELECTED_LANGUAGE = "selected_language";
|
||||
|
||||
/**
|
||||
* The name of the global state parameter which holds the return URL.
|
||||
*/
|
||||
public static final String RETURN_URL = "return_url";
|
||||
|
||||
/**
|
||||
* The name of the global state parameter that determines whether or not to
|
||||
* use the streamlined authoring process (assuming the option is turned on).
|
||||
*
|
||||
*/
|
||||
public static final String STREAMLINED_CREATION = "streamlined_creation";
|
||||
|
||||
public static final String STREAMLINED_CREATION_ACTIVE = "active";
|
||||
|
||||
public static final String STREAMLINED_CREATION_INACTIVE = "active";
|
||||
|
||||
/**
|
||||
* Index of the summary tab
|
||||
*/
|
||||
public static final int SUMMARY_TAB = 0;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The name of the state parameter which indicates the content type of the
|
||||
* item the user wishes to create. or edit.</p>
|
||||
*
|
||||
* <p>
|
||||
* The parameter must be a BigDecimalParameter which encodes the id of the
|
||||
* content type.</p>
|
||||
*/
|
||||
public static final String CONTENT_TYPE = "content_type";
|
||||
|
||||
public static final int AUTHORING_TAB = 1;
|
||||
|
||||
public static final int LANGUAGE_TAB = 2;
|
||||
|
||||
public static final int WORKFLOW_TAB = 3;
|
||||
|
||||
public static final int PUBLISHING_TAB = 4;
|
||||
|
||||
public static final int HISTORY_TAB = 5;
|
||||
|
||||
public static final int TEMPLATES_TAB = 6;
|
||||
|
||||
private final TabbedPane tabbedPane;
|
||||
|
||||
private final StringParameter returnUrlParameter;
|
||||
|
||||
private final ItemSelectionModel itemSelectionModel;
|
||||
// private final SingleSelectionModel<String> selectedLanguageModel;
|
||||
|
||||
private final ACSObjectSelectionModel typeSelectionModel;
|
||||
|
||||
private final ContentItemRequestLocal itemRequestLocal;
|
||||
|
||||
|
||||
private final WizardSelector wizardPane;
|
||||
|
||||
private final Link previewLink;
|
||||
|
||||
private final GlobalNavigation globalNavigation;
|
||||
|
||||
private final StringParameter selectedLanguageParam;
|
||||
|
||||
private class ItemRequestLocal extends ContentItemRequestLocal {
|
||||
|
||||
@Override
|
||||
protected final Object initialValue(final PageState state) {
|
||||
return CMS.getContext().getContentItem();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class TitlePrinter implements PrintListener {
|
||||
|
||||
@Override
|
||||
public final void prepare(final PrintEvent event) {
|
||||
|
||||
final PageState state = event.getPageState();
|
||||
|
||||
final Label label = (Label) event.getTarget();
|
||||
final ContentItem item = itemRequestLocal.getContentItem(event.
|
||||
getPageState());
|
||||
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final ContentItemL10NManager l10nManager = cdiUtil
|
||||
.findBean(ContentItemL10NManager.class);
|
||||
final String selectedLanguage = (String) state
|
||||
.getValue(selectedLanguageParam);
|
||||
final Locale selectedLocale;
|
||||
if (selectedLanguage == null
|
||||
|| selectedLanguage.isEmpty()) {
|
||||
selectedLocale = KernelConfig.getConfig().getDefaultLocale();
|
||||
} else {
|
||||
selectedLocale = new Locale(selectedLanguage);
|
||||
}
|
||||
|
||||
final String language;
|
||||
if (l10nManager.hasLanguage(item, selectedLocale)) {
|
||||
language = selectedLanguage;
|
||||
} else {
|
||||
state.setValue(selectedLanguageParam,
|
||||
KernelConfig.getConfig().getDefaultLanguage());
|
||||
language = KernelConfig.getConfig().getDefaultLanguage();
|
||||
}
|
||||
|
||||
final StringBuffer title = new StringBuffer(item.getDisplayName());
|
||||
if (language != null) {
|
||||
title
|
||||
.append(" (")
|
||||
.append(language)
|
||||
.append(")");
|
||||
}
|
||||
|
||||
label.setLabel(title.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new ContentItemPage.
|
||||
*/
|
||||
public ContentItemPage() {
|
||||
super("", new SimpleContainer());
|
||||
|
||||
itemRequestLocal = new ItemRequestLocal();
|
||||
|
||||
setClassAttr("cms-admin");
|
||||
setTitle(new Label(new TitlePrinter()));
|
||||
|
||||
// Add the item id global state parameter
|
||||
final LongParameter itemId = new LongParameter(ITEM_ID);
|
||||
itemId.addParameterListener(new NotNullValidationListener(ITEM_ID));
|
||||
addGlobalStateParam(itemId);
|
||||
itemSelectionModel = new ItemSelectionModel(itemId);
|
||||
|
||||
// Add the selected item language as parameter
|
||||
selectedLanguageParam = new StringParameter(SELECTED_LANGUAGE);
|
||||
selectedLanguageParam.addParameterListener(
|
||||
new NotNullValidationListener(SELECTED_LANGUAGE));
|
||||
addGlobalStateParam(selectedLanguageParam);
|
||||
// selectedLanguageModel = new ParameterSingleSelectionModel<>(
|
||||
// selectedLanguageParam);
|
||||
// selectedLanguageParam
|
||||
// .setDefaultValue(KernelConfig.getConfig().getDefaultLanguage());
|
||||
|
||||
// Add the content type global state parameter
|
||||
final LongParameter contentType = new LongParameter(CONTENT_TYPE);
|
||||
addGlobalStateParam(contentType);
|
||||
|
||||
// Add the streamlined creation global state parameter
|
||||
final StringParameter streamlinedCreation = new StringParameter(
|
||||
STREAMLINED_CREATION);
|
||||
addGlobalStateParam(streamlinedCreation);
|
||||
|
||||
typeSelectionModel = new ACSObjectSelectionModel(ContentType.class
|
||||
.getName(),
|
||||
ContentType.class
|
||||
.getName(),
|
||||
contentType);
|
||||
|
||||
// Validate the item ID parameter (caches the validation).
|
||||
getStateModel().addValidationListener(
|
||||
event -> validateItemID(event.getPageState()));
|
||||
|
||||
// Add the return url global state parameter
|
||||
returnUrlParameter = new StringParameter(RETURN_URL);
|
||||
addGlobalStateParam(returnUrlParameter);
|
||||
|
||||
globalNavigation = new GlobalNavigation();
|
||||
add(globalNavigation);
|
||||
|
||||
// Create panels.
|
||||
wizardPane = new WizardSelector(itemSelectionModel, typeSelectionModel);
|
||||
|
||||
// Create tabbed pane.
|
||||
tabbedPane = new TabbedPane();
|
||||
add(tabbedPane);
|
||||
|
||||
tabbedPane.setIdAttr("page-body");
|
||||
|
||||
tabbedPane.
|
||||
addTab(new Label(gz("cms.ui.item.authoring")), wizardPane);
|
||||
|
||||
|
||||
tabbedPane.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public final void actionPerformed(final ActionEvent event) {
|
||||
|
||||
final PageState state = event.getPageState();
|
||||
final Component pane = tabbedPane.getCurrentPane(state);
|
||||
|
||||
if (pane instanceof Resettable) {
|
||||
((Resettable) pane).reset(state);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Build the preview link.
|
||||
previewLink = new Link(new Label(gz("cms.ui.preview")),
|
||||
new PrintListener() {
|
||||
|
||||
@Override
|
||||
public final void prepare(
|
||||
final PrintEvent event) {
|
||||
final Link link = (Link) event.getTarget();
|
||||
link.setTarget(getPreviewURL(event.
|
||||
getPageState()));
|
||||
link.setTargetFrame(Link.NEW_FRAME);
|
||||
}
|
||||
|
||||
});
|
||||
previewLink.setIdAttr("preview_link");
|
||||
add(previewLink);
|
||||
|
||||
addActionListener(this);
|
||||
|
||||
// Add validation to make sure we are not attempting to edit a live item
|
||||
getStateModel().addValidationListener(new FormValidationListener() {
|
||||
|
||||
@Override
|
||||
public void validate(final FormSectionEvent event)
|
||||
throws FormProcessException {
|
||||
|
||||
PageState s = event.getPageState();
|
||||
FormData data = event.getFormData();
|
||||
final ContentItem item = itemRequestLocal.getContentItem(s);
|
||||
if (item != null
|
||||
&& ContentItemVersion.LIVE == item.getVersion()) {
|
||||
LOGGER.error(String.format(
|
||||
"The item %d is live and cannot be edited.", item.
|
||||
getObjectId()));
|
||||
throw new FormProcessException(new GlobalizedMessage(
|
||||
"cms.ui.live_item_not_editable",
|
||||
CmsConstants.CMS_BUNDLE));
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the item_id parameter references a valid {@link
|
||||
* com.arsdigita.cms.ContentItem}.
|
||||
*
|
||||
* @param state The page state
|
||||
*
|
||||
* @pre state != null
|
||||
* @exception FormProcessException if the item_id is not valid
|
||||
*/
|
||||
protected void validateItemID(final PageState state) throws
|
||||
FormProcessException {
|
||||
final ContentItem item = itemRequestLocal.getContentItem(state);
|
||||
|
||||
if (item == null) {
|
||||
throw new FormProcessException(new GlobalizedMessage(
|
||||
"cms.ui.invalid_item_id", CmsConstants.CMS_BUNDLE));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the request-local content section.
|
||||
*
|
||||
* @deprecated use com.arsdigita.cms.CMS.getContext().getContentSection()
|
||||
* instead
|
||||
* @param request The HTTP request
|
||||
*
|
||||
* @return The current content section
|
||||
*/
|
||||
@Override
|
||||
public ContentSection getContentSection(final HttpServletRequest request) {
|
||||
// Resets all content sections associations.
|
||||
ContentSection section = super.getContentSection(request);
|
||||
Assert.exists(section);
|
||||
return section;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides CMSPage.getContentItem(PageState state) to get the current
|
||||
* content item from the page state.
|
||||
*
|
||||
* @deprecated Use the ItemSelectionModel
|
||||
* @param state The page state
|
||||
*
|
||||
* @return The current content item, null if there is none
|
||||
*/
|
||||
@Override
|
||||
public ContentItem getContentItem(final PageState state) {
|
||||
return (ContentItem) itemSelectionModel.getSelectedObject(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current tab, if necessary
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent event) {
|
||||
final PageState state = event.getPageState();
|
||||
final String setTab = state.getRequest().getParameter(SET_TAB);
|
||||
|
||||
// Hide the templates tab, the workflow tab, and the preview
|
||||
// link if the current item is a template.
|
||||
final ContentItem item = itemRequestLocal.getContentItem(state);
|
||||
|
||||
// ToDo: Reenable when Templates have been ported. Not clear yet if
|
||||
// Templates will be ContentItems in LibreCMS...
|
||||
// if (item instanceof Template) {
|
||||
// tabbedPane.setTabVisible(state, templatesPane, false);
|
||||
// tabbedPane.setTabVisible(state, workflowPane, false);
|
||||
// tabbedPane.setTabVisible(state, languagesPane, false);
|
||||
// m_previewLink.setVisible(state, false);
|
||||
// } else {
|
||||
// tabbedPane.setTabVisible(state,
|
||||
// templatesPane,
|
||||
// !ContentSectionConfig.getConfig().getHideTemplatesTab());
|
||||
// }
|
||||
// Set the current tab based on parameters
|
||||
if (setTab != null) {
|
||||
Integer tab;
|
||||
|
||||
try {
|
||||
tab = Integer.valueOf(setTab);
|
||||
} catch (NumberFormatException ex) {
|
||||
// Stop processing set_tab parameter.
|
||||
LOGGER.warn("Stopping processing of set_tab parameter.", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tab < tabbedPane.size()) {
|
||||
tabbedPane.setSelectedIndex(state, tab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a URL for displaying a certain item
|
||||
*
|
||||
* @param nodeURL The URL where this page is mounted
|
||||
* @param itemId The id of the item to display
|
||||
* @param tab The index of the tab to display
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static String getItemURL(final String nodeURL,
|
||||
final Long itemId,
|
||||
final int tab) {
|
||||
return getItemURL(nodeURL, itemId, tab, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a URL for displaying a certain item
|
||||
*
|
||||
* @param nodeURL The URL where this page is mounted
|
||||
* @param itemId The id of the item to display
|
||||
* @param tab The index of the tab to display
|
||||
* @param streamlinedCreation Whether to activate Streamlined item authoring
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static String getItemURL(final String nodeURL,
|
||||
final Long itemId,
|
||||
final int tab,
|
||||
final boolean streamlinedCreation) {
|
||||
final StringBuilder urlBuilder = new StringBuilder();
|
||||
|
||||
urlBuilder
|
||||
.append(nodeURL)
|
||||
.append(PageLocations.ITEM_PAGE)
|
||||
.append("?")
|
||||
.append(ITEM_ID)
|
||||
.append("=")
|
||||
.append(itemId.toString())
|
||||
.append("&")
|
||||
.append(SET_TAB)
|
||||
.append("=")
|
||||
.append(tab);
|
||||
|
||||
if (streamlinedCreation
|
||||
&& CMSConfig.getConfig().isUseStreamlinedCreation()) {
|
||||
|
||||
urlBuilder
|
||||
.append("&")
|
||||
.append(STREAMLINED_CREATION)
|
||||
.append("=")
|
||||
.append(STREAMLINED_CREATION_ACTIVE);
|
||||
}
|
||||
|
||||
return urlBuilder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param itemId
|
||||
* @param tab
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @deprecated Use getItemURL instead
|
||||
*/
|
||||
public static String getRelativeItemURL(final Long itemId, final int tab) {
|
||||
final StringBuilder url = new StringBuilder();
|
||||
url
|
||||
.append(PageLocations.ITEM_PAGE)
|
||||
.append("?")
|
||||
.append(ITEM_ID)
|
||||
.append("=")
|
||||
.append(itemId.toString())
|
||||
.append("&")
|
||||
.append(SET_TAB)
|
||||
.append("=")
|
||||
.append(tab);
|
||||
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a URL for displaying a certain item.
|
||||
*
|
||||
* @param item the ContentItem object to display
|
||||
* @param tab The index of the tab to display
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static String getItemURL(final ContentItem item,
|
||||
final int tab) {
|
||||
|
||||
final ContentSection section = item.getContentType().getContentSection();
|
||||
|
||||
if (section == null) {
|
||||
return null;
|
||||
} else {
|
||||
final String nodeURL = section.getPrimaryUrl() + "/";
|
||||
|
||||
return getItemURL(nodeURL, item.getObjectId(), tab);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a URL for displaying a certain item.
|
||||
*
|
||||
* @param itemId the id of the ContentItem object to display
|
||||
* @param tab The index of the tab to display
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static String getItemURL(final long itemId,
|
||||
final int tab) {
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final ContentItemRepository itemRepo = cdiUtil.findBean(
|
||||
ContentItemRepository.class);
|
||||
|
||||
final Optional<ContentItem> item = itemRepo.findById(itemId);
|
||||
|
||||
if (item.isPresent()) {
|
||||
return getItemURL(item.get(), tab);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect back to wherever the user came from, using the value of the
|
||||
* return_url parameter.
|
||||
*
|
||||
* @param state The current page state
|
||||
*/
|
||||
public void redirectBack(final PageState state) {
|
||||
try {
|
||||
final String returnUrl = (String) state.getValue(returnUrlParameter);
|
||||
state.getResponse().sendRedirect(returnUrl);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.error("IO Error redirecting back", ex);
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the preview URL.
|
||||
*/
|
||||
private String getPreviewURL(final PageState state) {
|
||||
final ContentItem item = itemRequestLocal.getContentItem(state);
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param state
|
||||
* @param item
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private String getDefaultPreviewLink(final PageState state,
|
||||
final ContentItem item) {
|
||||
final ContentSection section = CMS.getContext().getContentSection();
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
// final ContentSectionManager sectionManager = cdiUtil.findBean(
|
||||
// ContentSectionManager.class);
|
||||
// final ItemResolver itemResolver = sectionManager
|
||||
// .getItemResolver(section);
|
||||
|
||||
// Pass in the "Live" context since we need it for the preview
|
||||
// return itemResolver.generateItemURL(state,
|
||||
// item,
|
||||
// section,
|
||||
// CMSDispatcher.PREVIEW);
|
||||
final ContentItemPageController controller = cdiUtil
|
||||
.findBean(ContentItemPageController.class);
|
||||
|
||||
return controller.getDefaultPreviewLink(section, item, state);
|
||||
}
|
||||
|
||||
protected final static GlobalizedMessage gz(final String key) {
|
||||
return new GlobalizedMessage(key, CmsConstants.CMS_BUNDLE);
|
||||
}
|
||||
|
||||
protected final static String lz(final String key) {
|
||||
return (String) gz(key).localize();
|
||||
}
|
||||
|
||||
public static boolean isStreamlinedCreationActive(final PageState state) {
|
||||
return CMSConfig.getConfig().isUseStreamlinedCreation()
|
||||
&& STREAMLINED_CREATION_ACTIVE.equals(state.getRequest().
|
||||
getParameter(STREAMLINED_CREATION));
|
||||
}
|
||||
|
||||
protected TabbedPane getTabbedPane() {
|
||||
return tabbedPane;
|
||||
}
|
||||
|
||||
protected WizardSelector getWizardPane() {
|
||||
return wizardPane;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the content type to the output.
|
||||
*
|
||||
* @param state PageState
|
||||
* @param parent Parent document
|
||||
*
|
||||
* @return page
|
||||
*/
|
||||
@Override
|
||||
protected Element generateXMLHelper(final PageState state,
|
||||
final Document parent) {
|
||||
|
||||
Objects.requireNonNull(itemRequestLocal.getContentItem(state),
|
||||
"No ContentItem in current request.");
|
||||
|
||||
final Element page = super.generateXMLHelper(state, parent);
|
||||
final Element contenttype = page.newChildElement("bebop:contentType",
|
||||
BEBOP_XML_NS);
|
||||
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
|
||||
final ContentItemPageController controller = cdiUtil
|
||||
.findBean(ContentItemPageController.class);
|
||||
contenttype
|
||||
.setText(controller
|
||||
.getContentTypeLabel(itemRequestLocal.getContentItem(state)));
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2017 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 com.arsdigita.cms.ui;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.cms.dispatcher.CMSDispatcher;
|
||||
|
||||
import org.libreccm.l10n.GlobalizationHelper;
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contentsection.ContentItemRepository;
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
import org.librecms.contentsection.ContentSectionManager;
|
||||
import org.librecms.contentsection.ContentSectionRepository;
|
||||
import org.librecms.dispatcher.ItemResolver;
|
||||
|
||||
import javax.enterprise.context.RequestScoped;
|
||||
import javax.inject.Inject;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
@RequestScoped
|
||||
class ContentItemPageController {
|
||||
|
||||
@Inject
|
||||
private GlobalizationHelper globalizationHelper;
|
||||
|
||||
@Inject
|
||||
private ContentSectionRepository sectionRepo;
|
||||
|
||||
@Inject
|
||||
private ContentSectionManager sectionManager;
|
||||
@Inject
|
||||
private ContentItemRepository itemRepo;
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
protected String getContentTypeLabel(final ContentItem item) {
|
||||
|
||||
final ContentItem theItem = itemRepo
|
||||
.findById(item.getObjectId())
|
||||
.orElseThrow(() -> new IllegalArgumentException(String
|
||||
.format("No ContentItem with ID %d in the database.",
|
||||
item.getObjectId())));
|
||||
|
||||
return theItem
|
||||
.getContentType()
|
||||
.getLabel()
|
||||
.getValue(globalizationHelper.getNegotiatedLocale());
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
protected String getDefaultPreviewLink(final ContentSection section,
|
||||
final ContentItem item,
|
||||
final PageState state) {
|
||||
|
||||
final ContentSection contentSection = sectionRepo
|
||||
.findById(section.getObjectId())
|
||||
.orElseThrow(() -> new IllegalArgumentException(String
|
||||
.format("No ContentSectio with ID %d in the database.",
|
||||
section.getObjectId())));
|
||||
|
||||
final ContentItem contentItem = itemRepo
|
||||
.findById(item.getObjectId())
|
||||
.orElseThrow(() -> new IllegalArgumentException(String
|
||||
.format("No ContentItem with ID %d in the database.",
|
||||
item.getObjectId())));
|
||||
|
||||
final ItemResolver itemResolver = sectionManager
|
||||
.getItemResolver(contentSection);
|
||||
|
||||
return itemResolver.generateItemURL(state,
|
||||
contentItem,
|
||||
contentSection,
|
||||
CMSDispatcher.PREVIEW);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.RequestLocal;
|
||||
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
|
||||
import com.arsdigita.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link RequestLocal} storing a content item.
|
||||
*/
|
||||
public abstract class ContentItemRequestLocal extends RequestLocal {
|
||||
|
||||
public final ContentItem getContentItem(final PageState state) {
|
||||
final ContentItem item = (ContentItem) get(state);
|
||||
|
||||
Assert.exists(item, "ContentItem item");
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,488 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui;
|
||||
|
||||
import com.arsdigita.bebop.ColumnPanel;
|
||||
import com.arsdigita.bebop.Container;
|
||||
import com.arsdigita.bebop.FormData;
|
||||
import com.arsdigita.bebop.FormSection;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||
import com.arsdigita.bebop.form.FileUpload;
|
||||
import com.arsdigita.bebop.form.Option;
|
||||
import com.arsdigita.bebop.form.OptionGroup;
|
||||
import com.arsdigita.bebop.form.SingleSelect;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.dispatcher.MultipartHttpServletRequest;
|
||||
import java.io.File;
|
||||
import javax.activation.MimeType;
|
||||
import javax.activation.MimeTypeParseException;
|
||||
import javax.activation.MimetypesFileTypeMap;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import org.librecms.CmsConstants;
|
||||
|
||||
/**
|
||||
* A form section with two widgets: a mime-type selection widget and a file
|
||||
* upload widget. The section will attempt to automatically guess the mime type
|
||||
* from the filename (if necessary), and return the mime type.
|
||||
*
|
||||
* @author Stanislav Freidin (sfreidin@arsdigita.com)
|
||||
* @author <a href="jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
public class FileUploadSection extends FormSection {
|
||||
|
||||
private SingleSelect mimeWidget;
|
||||
private FileUpload fileWidget;
|
||||
private String mimePrefix;
|
||||
private String defaultMimeType;
|
||||
private String parameterPrefix;
|
||||
|
||||
/**
|
||||
* The mime type widget
|
||||
*/
|
||||
public static final String MIME_TYPE = "mime_type";
|
||||
|
||||
/**
|
||||
* The file upload widget
|
||||
*/
|
||||
public static final String FILE_UPLOAD = "file_upload";
|
||||
|
||||
/**
|
||||
* Automatically guess the mime type
|
||||
*/
|
||||
public static final String GUESS_MIME = "-guess-";
|
||||
|
||||
/**
|
||||
* Construct a new FileUploadSection
|
||||
*
|
||||
* @param mimeLabel The label for the mime type widget
|
||||
*
|
||||
* @param mimePrefix Populate the mime type widget with all mime types that
|
||||
* match the prefix. Some of the possible prefixes are "text", "image",
|
||||
* "binary", etc.
|
||||
*
|
||||
* @param defaultMimeType The default mime type that should be assumed if
|
||||
* the guessing fails
|
||||
*
|
||||
* @param panel The panel that is to be used to lay out the components
|
||||
*
|
||||
*/
|
||||
public FileUploadSection(final GlobalizedMessage mimeLabel,
|
||||
final String mimePrefix,
|
||||
final String defaultMimeType,
|
||||
final Container panel) {
|
||||
this(mimeLabel, mimePrefix, defaultMimeType, "", panel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new FileUploadSection
|
||||
*
|
||||
* @param mimeLabel The label for the mime type widget
|
||||
*
|
||||
* @param mimePrefix Populate the mime type widget with all mime types that
|
||||
* match the prefix. Some of the possible prefixes are "text", "image",
|
||||
* "binary", etc.
|
||||
*
|
||||
* @param defaultMimeType The default mime type that should be assumed if
|
||||
* the guessing fails
|
||||
*
|
||||
* @param panel The panel that is to be used to lay out the components
|
||||
*
|
||||
* @deprecated use the same constructor but with the GlobalizedMessage for
|
||||
* the mimeLabel
|
||||
*/
|
||||
public FileUploadSection(final String mimeLabel,
|
||||
final String mimePrefix,
|
||||
final String defaultMimeType,
|
||||
final Container panel) {
|
||||
// This takes advantage of the fact that the "key" is returned
|
||||
// when it is not present in the message bundle
|
||||
this(new GlobalizedMessage(mimeLabel),
|
||||
mimePrefix,
|
||||
defaultMimeType,
|
||||
panel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new FileUploadSection
|
||||
*
|
||||
* @param mimeLabel The label for the mime type widget
|
||||
*
|
||||
* @param mimePrefix Populate the mime type widget with all mime types that
|
||||
* match the prefix. Some of the possible prefixes are "text", "image",
|
||||
* "binary", etc.
|
||||
*
|
||||
* @param defaultMimeType The default mime type that should be assumed if
|
||||
* the guessing fails
|
||||
*
|
||||
* @param parameterPrefix Prepended to MIME_TYPE and FILE_UPLOAD for
|
||||
* parameter names so that more than 1 file upload widgets may be used per
|
||||
* form
|
||||
*
|
||||
* @param panel The panel that is to be used to lay out the components
|
||||
*
|
||||
* @deprecated use the same constructor but with the GlobalizedMessage for
|
||||
* the mimeLabel
|
||||
*/
|
||||
public FileUploadSection(final String mimeLabel,
|
||||
final String mimePrefix,
|
||||
final String defaultMimeType,
|
||||
final String parameterPrefix,
|
||||
final Container panel
|
||||
) {
|
||||
// This takes advantage of the fact that the "key" is returned
|
||||
// when it is not present in the message bundle
|
||||
this(new GlobalizedMessage(mimeLabel, CmsConstants.CMS_BUNDLE),
|
||||
mimePrefix,
|
||||
defaultMimeType,
|
||||
parameterPrefix,
|
||||
panel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new FileUploadSection
|
||||
*
|
||||
* @param mimeLabel The label for the mime type widget
|
||||
*
|
||||
* @param mimePrefix Populate the mime type widget with all mime types that
|
||||
* match the prefix. Some of the possible prefixes are "text", "image",
|
||||
* "binary", etc.
|
||||
*
|
||||
* @param defaultMimeType The default mime type that should be assumed if
|
||||
* the guessing fails
|
||||
*
|
||||
* @param parameterPrefix Prepended to MIME_TYPE and FILE_UPLOAD for
|
||||
* parameter names so that more than 1 file upload widgets may be used per
|
||||
* form
|
||||
*
|
||||
* @param panel The panel that is to be used to lay out the components
|
||||
*
|
||||
*/
|
||||
public FileUploadSection(final GlobalizedMessage mimeLabel,
|
||||
final String mimePrefix,
|
||||
final String defaultMimeType,
|
||||
final String parameterPrefix,
|
||||
final Container panel) {
|
||||
|
||||
super(panel);
|
||||
|
||||
this.mimePrefix = mimePrefix;
|
||||
this.defaultMimeType = defaultMimeType;
|
||||
if (parameterPrefix == null) {
|
||||
this.parameterPrefix = "";
|
||||
} else {
|
||||
this.parameterPrefix = parameterPrefix;
|
||||
}
|
||||
|
||||
add(new Label(mimeLabel, false));
|
||||
mimeWidget = new SingleSelect(getMimeTypeWidgetName());
|
||||
addMimeOptions(mimeWidget, mimePrefix);
|
||||
mimeWidget
|
||||
.addOption(new Option(GUESS_MIME,
|
||||
new Label(new GlobalizedMessage(
|
||||
"cms.ui.authoring.file_upload.auto_detect",
|
||||
CmsConstants.CMS_BUNDLE))));
|
||||
|
||||
mimeWidget.setDefaultValue(GUESS_MIME);
|
||||
add(mimeWidget);
|
||||
|
||||
add(new Label(new GlobalizedMessage("cms.ui.upload_new_content",
|
||||
CmsConstants.CMS_BUNDLE)));
|
||||
fileWidget = new FileUpload(getFileUploadWidgetName());
|
||||
add(fileWidget);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new FileUploadSection
|
||||
*
|
||||
* @param mimeLabel The label for the mime type widget
|
||||
*
|
||||
* @param mimePrefix Populate the mime type widget with all mime types that
|
||||
* match the prefix. Some of the possible prefixes are "text", "image",
|
||||
* "binary", etc.
|
||||
*
|
||||
* @param defaultMimeType The default mime type that should be assumed if
|
||||
* the guessing fails
|
||||
*
|
||||
* @param parameterPrefix Prepended to MIME_TYPE and FILE_UPLOAD for
|
||||
* parameter names so that more than 1 file upload widgets may be used per
|
||||
* form
|
||||
*
|
||||
*/
|
||||
public FileUploadSection(final GlobalizedMessage mimeLabel,
|
||||
final String mimePrefix,
|
||||
final String defaultMimeType,
|
||||
final String parameterPrefix) {
|
||||
this(mimeLabel,
|
||||
mimePrefix,
|
||||
defaultMimeType,
|
||||
parameterPrefix,
|
||||
new ColumnPanel(2, true));
|
||||
final ColumnPanel panel = (ColumnPanel) getPanel();
|
||||
panel.setBorder(false);
|
||||
panel.setPadColor("#FFFFFF");
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new FileUploadSection
|
||||
*
|
||||
* @param mimeLabel The label for the mime type widget
|
||||
*
|
||||
* @param mimePrefix Populate the mime type widget with all mime types that
|
||||
* match the prefix. Some of the possible prefixes are "text", "image",
|
||||
* "binary", etc.
|
||||
*
|
||||
* @param defaultMimeType The default mime type that should be assumed if
|
||||
* the guessing fails
|
||||
*
|
||||
* @param parameterPrefix Prepended to MIME_TYPE and FILE_UPLOAD for
|
||||
* parameter names so that more than 1 file upload widgets may be used per
|
||||
* form
|
||||
*
|
||||
* @deprecated use the same constructor but with the GlobalizedMessage for
|
||||
* the mimeLabel
|
||||
*/
|
||||
public FileUploadSection(final String mimeLabel,
|
||||
final String mimePrefix,
|
||||
final String defaultMimeType,
|
||||
final String parameterPrefix) {
|
||||
// This takes advantage of the fact that the "key" is returned
|
||||
// when it is not present in the message bundle
|
||||
this(new GlobalizedMessage(mimeLabel, CmsConstants.CMS_BUNDLE),
|
||||
mimePrefix,
|
||||
defaultMimeType,
|
||||
parameterPrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new FileUploadSection
|
||||
*
|
||||
* @param mimeLabel The label for the mime type widget
|
||||
*
|
||||
* @param mimePrefix Populate the mime type widget with all mime types that
|
||||
* match the prefix. Some of the possible prefixes are "text", "image",
|
||||
* "binary", etc.
|
||||
*
|
||||
* @param defaultMimeType The default mime type that should be assumed if
|
||||
* the guessing fails
|
||||
*
|
||||
* @deprecated use the same constructor but with the GlobalizedMessage for
|
||||
* the mimeLabel
|
||||
*/
|
||||
public FileUploadSection(final String mimeLabel,
|
||||
final String mimePrefix,
|
||||
final String defaultMimeType) {
|
||||
|
||||
// This takes advantage of the fact that the "key" is returned
|
||||
// when it is not present in the message bundle
|
||||
this(new GlobalizedMessage(mimeLabel, CmsConstants.CMS_BUNDLE),
|
||||
mimePrefix,
|
||||
defaultMimeType,
|
||||
"");
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new FileUploadSection
|
||||
*
|
||||
* @param mimeLabel The GlobalizedMessage for the label for the mime type
|
||||
* widget
|
||||
*
|
||||
* @param mimePrefix Populate the mime type widget with all mime types that
|
||||
* match the prefix. Some of the possible prefixes are "text", "image",
|
||||
* "binary", etc.
|
||||
*
|
||||
* @param defaultMimeType The default mime type that should be assumed if
|
||||
* the guessing fails
|
||||
*
|
||||
*/
|
||||
public FileUploadSection(GlobalizedMessage mimeLabel,
|
||||
String mimePrefix,
|
||||
String defaultMimeType) {
|
||||
this(mimeLabel, mimePrefix, defaultMimeType, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to guess the mime type from the filename, and return it. The parent
|
||||
* form should call this method in its process listener. Note that this
|
||||
* method may return null if the mime type could not be guessed.
|
||||
*
|
||||
* @param event The form section event
|
||||
* @return The mime type of the file.
|
||||
*/
|
||||
public MimeType getMimeType(final FormSectionEvent event) {
|
||||
|
||||
final FormData data = event.getFormData();
|
||||
|
||||
final String fileName = (String) data.get(getFileUploadWidgetName());
|
||||
final String mimeTypeName = (String) data.get(getMimeTypeWidgetName());
|
||||
|
||||
// Guess the mime type from the filename
|
||||
MimeType mimeType = null;
|
||||
if (fileName != null) {
|
||||
try {
|
||||
if (GUESS_MIME.equals(mimeTypeName)) {
|
||||
// Guess the mime type from the file extension
|
||||
mimeType = new MimeType(MimetypesFileTypeMap
|
||||
.getDefaultFileTypeMap()
|
||||
.getContentType(fileName));
|
||||
} else {
|
||||
mimeType = new MimeType(mimeTypeName);
|
||||
}
|
||||
} catch (MimeTypeParseException ex) {
|
||||
mimeType = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Failed to guess it, failed to load it, fall back on the default
|
||||
if (mimeType == null) {
|
||||
try {
|
||||
mimeType = new MimeType(defaultMimeType);
|
||||
} catch (MimeTypeParseException ex) {
|
||||
mimeType = null;
|
||||
}
|
||||
}
|
||||
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a File object from the file upload widget. The containing form
|
||||
* should call this method in its process listener.
|
||||
*
|
||||
* @param event The form section event
|
||||
* @return
|
||||
*/
|
||||
public File getFile(final FormSectionEvent event) {
|
||||
|
||||
final String fileName = getFileName(event);
|
||||
|
||||
if (fileName != null && fileName.length() > 0) {
|
||||
return ((MultipartHttpServletRequest) unwrapRequest(event
|
||||
.getPageState()
|
||||
.getRequest()))
|
||||
.getFile(getFileUploadWidgetName());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private ServletRequest unwrapRequest(final HttpServletRequest request) {
|
||||
|
||||
ServletRequest current = request;
|
||||
while (current instanceof HttpServletRequestWrapper) {
|
||||
current = ((HttpServletRequestWrapper) current).getRequest();
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a filename from the file upload widget. The containing form should
|
||||
* call this method in its process listener.
|
||||
*
|
||||
* @param event The form section event
|
||||
* @return
|
||||
*/
|
||||
public String getFileName(final FormSectionEvent event) {
|
||||
|
||||
return event
|
||||
.getFormData()
|
||||
.getString(getFileUploadWidgetName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for the mime type widget. The containing form should call
|
||||
* this method in its init listener
|
||||
*
|
||||
* @param event The form section event
|
||||
* @param mimeType The mime type to set, such as "text/html" or "img/jpeg"
|
||||
*
|
||||
*/
|
||||
public void setMimeType(final FormSectionEvent event,
|
||||
final String mimeType) {
|
||||
event
|
||||
.getFormData()
|
||||
.put(getMimeTypeWidgetName(), mimeType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the mime type widget
|
||||
*/
|
||||
public SingleSelect getMimeTypeWidget() {
|
||||
return mimeWidget;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the file upload widget
|
||||
*/
|
||||
public FileUpload getFileUploadWidget() {
|
||||
return fileWidget;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the parameter name prefix
|
||||
*/
|
||||
public String getParameterPrefix() {
|
||||
return parameterPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the file upload parameter name
|
||||
*/
|
||||
public String getFileUploadWidgetName() {
|
||||
return parameterPrefix + FILE_UPLOAD;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the mime typeparameter name
|
||||
*/
|
||||
public String getMimeTypeWidgetName() {
|
||||
return parameterPrefix + MIME_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add mime-type options to the option group by loading all mime types which
|
||||
* match a certain prefix from the database
|
||||
*
|
||||
* @param mimeTypeOptions The mime type widget to which options should be
|
||||
* added
|
||||
*
|
||||
* @param mimePrefix Populate the mime type widget with all mime types that
|
||||
* match the prefix. Some of the possible prefixes are "text", "image",
|
||||
* "binary", etc.
|
||||
*
|
||||
*/
|
||||
public static void addMimeOptions(final OptionGroup mimeTypeOptions,
|
||||
final String mimePrefix) {
|
||||
|
||||
// MimeTypeCollection types;
|
||||
// if (mimePrefix == null || mimePrefix.equals("")) {
|
||||
// types = MimeType.getAllMimeTypes();
|
||||
// } else {
|
||||
// types = MimeType.searchMimeTypes(mimePrefix + "/");
|
||||
// }
|
||||
// while (types.next()) {
|
||||
// MimeType type = types.getMimeType();
|
||||
// mimeTypeOptions.addOption(new Option(type.getMimeType(), type.getLabel()));
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui;
|
||||
|
||||
import com.arsdigita.bebop.FormProcessException;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||
import com.arsdigita.bebop.event.FormSubmissionListener;
|
||||
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
|
||||
import com.arsdigita.dispatcher.AccessDeniedException;
|
||||
|
||||
import com.arsdigita.util.Assert;
|
||||
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.security.PermissionChecker;
|
||||
|
||||
/**
|
||||
* @author Justin Ross <jross@redhat.com>
|
||||
*/
|
||||
public class FormSecurityListener implements FormSubmissionListener {
|
||||
|
||||
private final String m_action;
|
||||
private final ContentItemRequestLocal m_item;
|
||||
|
||||
public FormSecurityListener(final String action,
|
||||
final ContentItemRequestLocal item) {
|
||||
Assert.exists(action, String.class);
|
||||
|
||||
m_action = action;
|
||||
m_item = item;
|
||||
}
|
||||
|
||||
public FormSecurityListener(final String action) {
|
||||
this(action, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void submitted(final FormSectionEvent event)
|
||||
throws FormProcessException {
|
||||
|
||||
final PageState state = event.getPageState();
|
||||
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final PermissionChecker permissionChecker = cdiUtil.findBean(
|
||||
PermissionChecker.class);
|
||||
|
||||
if (m_item == null) {
|
||||
if (permissionChecker.isPermitted(m_action)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
final ContentItem item = m_item.getContentItem(state);
|
||||
|
||||
if (permissionChecker.isPermitted(m_action, item)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new AccessDeniedException();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.SimpleComponent;
|
||||
import com.arsdigita.cms.CMS;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.ui.UI;
|
||||
import com.arsdigita.ui.admin.AdminUiConstants;
|
||||
import com.arsdigita.ui.login.LoginServlet;
|
||||
import com.arsdigita.web.URL;
|
||||
import com.arsdigita.xml.Element;
|
||||
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.core.CoreConstants;
|
||||
import org.libreccm.security.PermissionChecker;
|
||||
import org.libreccm.web.ApplicationManager;
|
||||
import org.libreccm.web.ApplicationRepository;
|
||||
import org.libreccm.web.ApplicationType;
|
||||
import org.libreccm.web.CcmApplication;
|
||||
import org.librecms.CmsConstants;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Global navigation elements for the CMS admin UIs.</p>
|
||||
*
|
||||
* @author Justin Ross <jross@redhat.com>
|
||||
*/
|
||||
// Made public (instead of unspecified, resulting in protected) in 6.6.8
|
||||
public class GlobalNavigation extends SimpleComponent {
|
||||
|
||||
|
||||
private final String m_adminPath;
|
||||
private final String m_centerPath;
|
||||
private final String m_changePasswordPath;
|
||||
private final String m_helpPath;
|
||||
private final String m_signOutPath;
|
||||
private final String m_wspcPath;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public GlobalNavigation() {
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final ApplicationManager appManager = cdiUtil.findBean(
|
||||
ApplicationManager.class);
|
||||
final ApplicationRepository appRepo = cdiUtil.findBean(
|
||||
ApplicationRepository.class);
|
||||
final Map<String, ApplicationType> appTypes = appManager
|
||||
.getApplicationTypes();
|
||||
final ApplicationType adminAppType = appTypes.get(
|
||||
AdminUiConstants.ADMIN_APP_TYPE);
|
||||
final List<CcmApplication> adminApps = appRepo.findByType(adminAppType
|
||||
.name());
|
||||
final ApplicationType contentCenterAppType = appTypes.get(
|
||||
CmsConstants.CONTENT_CENTER_APP_TYPE);
|
||||
final List<CcmApplication> contentCenterApps = appRepo.findByType(
|
||||
contentCenterAppType.name());
|
||||
|
||||
m_adminPath = adminApps.get(0).getPrimaryUrl();
|
||||
m_centerPath = contentCenterApps.get(0).getPrimaryUrl();
|
||||
m_changePasswordPath = LoginServlet.getChangePasswordPageURL();
|
||||
m_helpPath = "/nowhere"; // We don't have this yet XXX.
|
||||
m_signOutPath = LoginServlet.getLogoutPageURL();
|
||||
m_wspcPath = UI.getWorkspaceURL();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param state
|
||||
* @param parent
|
||||
*/
|
||||
@Override
|
||||
public void generateXML(final PageState state, final Element parent) {
|
||||
if (isVisible(state)) {
|
||||
final HttpServletRequest sreq = state.getRequest();
|
||||
|
||||
final Element nav = parent.newChildElement("cms:globalNavigation",
|
||||
CMS.CMS_XML_NS);
|
||||
final String centerTitle = (String) new GlobalizedMessage(
|
||||
"cms.ui.content_center", CmsConstants.CMS_BUNDLE).localize();
|
||||
final String adminTitle = (String) new GlobalizedMessage(
|
||||
"cms.ui.admin_center", CmsConstants.CMS_BUNDLE).localize();
|
||||
final String wspcTitle = (String) new GlobalizedMessage(
|
||||
"cms.ui.my_workspace", CmsConstants.CMS_BUNDLE).localize();
|
||||
final String signOutTitle = (String) new GlobalizedMessage(
|
||||
"cms.ui.sign_out", CmsConstants.CMS_BUNDLE).localize();
|
||||
final String helpTitle = (String) new GlobalizedMessage(
|
||||
"cms.ui.help", CmsConstants.CMS_BUNDLE).localize();
|
||||
final String changePasswordTitle = (String) new GlobalizedMessage(
|
||||
"cms.ui.change_password", CmsConstants.CMS_BUNDLE).localize();
|
||||
|
||||
link(sreq, nav, "cms:contentCenter", m_centerPath, centerTitle);
|
||||
|
||||
/* If the current user has admin permissions, insert a link to the admin center */
|
||||
if (CdiUtil.createCdiUtil().findBean(PermissionChecker.class)
|
||||
.isPermitted(CoreConstants.PRIVILEGE_ADMIN)) {
|
||||
link(sreq, nav, "cms:adminCenter", m_adminPath, adminTitle);
|
||||
}
|
||||
|
||||
link(sreq, nav, "cms:workspace", m_wspcPath, wspcTitle);
|
||||
link(sreq, nav, "cms:changePassword", m_changePasswordPath,
|
||||
changePasswordTitle);
|
||||
link(sreq, nav, "cms:signOut", m_signOutPath, signOutTitle);
|
||||
link(sreq, nav, "cms:help", m_helpPath, helpTitle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param sreq
|
||||
* @param parent
|
||||
* @param name
|
||||
* @param path
|
||||
* @param title
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private static Element link(final HttpServletRequest sreq,
|
||||
final Element parent,
|
||||
final String name,
|
||||
final String path,
|
||||
final String title) {
|
||||
final Element link = parent.newChildElement(name, CMS.CMS_XML_NS);
|
||||
|
||||
link.addAttribute("href", URL.there(sreq, path).toString());
|
||||
link.addAttribute("title", title);
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.event.PrintEvent;
|
||||
import com.arsdigita.bebop.event.PrintListener;
|
||||
import com.arsdigita.bebop.form.Option;
|
||||
import com.arsdigita.bebop.form.OptionGroup;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Migrated from the {@code DataQueryOptionPrintListener} in the old system.
|
||||
* Renamed and refactored to operate on a list.
|
||||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*
|
||||
* @param <T> Type of the objects in the list.
|
||||
*/
|
||||
public abstract class ListOptionPrintListener<T> implements PrintListener {
|
||||
|
||||
public ListOptionPrintListener() {
|
||||
}
|
||||
|
||||
protected abstract List<T> getDataQuery(final PageState state);
|
||||
|
||||
@Override
|
||||
public void prepare(final PrintEvent event) {
|
||||
final PageState state = event.getPageState();
|
||||
final OptionGroup target = (OptionGroup) event.getTarget();
|
||||
final List<T> dataQuery = getDataQuery(state);
|
||||
|
||||
target.clearOptions();
|
||||
|
||||
dataQuery.forEach(item -> target.addOption(
|
||||
new Option(getKey(item),
|
||||
getValue(item))));
|
||||
}
|
||||
|
||||
public abstract String getKey(final T object);
|
||||
|
||||
public String getValue(final T object) {
|
||||
return getKey(object);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,392 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui;
|
||||
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.Form;
|
||||
import com.arsdigita.bebop.FormProcessException;
|
||||
import com.arsdigita.bebop.FormSection;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.PropertyEditor;
|
||||
import com.arsdigita.bebop.PropertyEditorModel;
|
||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||
import com.arsdigita.bebop.event.FormSubmissionListener;
|
||||
import com.arsdigita.bebop.form.Submit;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.toolbox.ui.ComponentAccess;
|
||||
import com.arsdigita.util.Assert;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.librecms.CmsConstants;
|
||||
|
||||
/**
|
||||
* Extends {@link com.arsdigita.bebop.PropertyEditor} to provide access control
|
||||
* features. Each link may be associated with a {@link
|
||||
* com.arsdigita.toolbox.ui.ComponentAccess} object; if the current does not
|
||||
* have sufficient privileges, the link will be hidden.
|
||||
* <p>
|
||||
* The simple use pattern for this component is as follows:
|
||||
*
|
||||
* <blockquote><pre><code>
|
||||
* SecurityPropertyEditor editor = new SecurityPropertyEditor();
|
||||
* editor.setDisplayComponent(new FooComponent());
|
||||
* NameEditForm n = new NameEditForm();
|
||||
* ComponentAccess ca1 = new ComponentAccess(n);
|
||||
* ca1.addAccessCheck(WORKFLOW_ADMIN);
|
||||
* ca1.addAccessCheck(CATEGORY_ADMIN);
|
||||
* editor.add("name", "Edit Name", ca, n.getCancelButton());
|
||||
* AddressEditForm a = new AddressEditForm();
|
||||
* ComponentAccess ca2 = new ComponentAccess(a);
|
||||
* editor.add("address", "Edit Address", ca2, a.getCancelButton());
|
||||
* </code></pre></blockquote>
|
||||
*
|
||||
* @author Michael Pih (pihman@arsdigita.com)
|
||||
* @author Stanislav Freidin (sfreidin@arsdigita.com)
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
public class SecurityPropertyEditor extends PropertyEditor {
|
||||
|
||||
private final Map<String, ComponentAccess> accessChecks;
|
||||
|
||||
/**
|
||||
* Construct a new, empty <code>PropertyEditor</code>. The {@link
|
||||
* #setDisplayComponent(Component)} method must be called before this
|
||||
* component is locked.
|
||||
*/
|
||||
public SecurityPropertyEditor() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new, <code>PropertyEditor</code> with the given display
|
||||
* component
|
||||
*
|
||||
* @param display The display component
|
||||
*/
|
||||
public SecurityPropertyEditor(final Component display) {
|
||||
super(display);
|
||||
accessChecks = new HashMap<>();
|
||||
setModelBuilder(new AccessListModelBuilder());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a component to the property editor. The component will be completely
|
||||
* invisible; it is up to the user to call {@link #showComponent(PageState,
|
||||
* String)} to display the component, and to call {@link
|
||||
* #showDisplayPane(PageState)} when the component needs to be hidden.
|
||||
*
|
||||
* @param key The symbolic key for the component; must be unique for this
|
||||
* <code>PropertyEditor</code>
|
||||
* @param componentAccess The {@link ComponentAccess} object which contains
|
||||
* the child component, along with security restrictions
|
||||
*/
|
||||
public void addComponent(final String key,
|
||||
final ComponentAccess componentAccess) {
|
||||
super.addComponent(key, componentAccess.getComponent());
|
||||
accessChecks.put(key, componentAccess);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a component to the list of links. It is up to the component to
|
||||
* correctly call showDisplayPane when it's done.
|
||||
*
|
||||
* @param key The symbolic key for the component; must be unique for this
|
||||
* <code>PropertyEditor</code>
|
||||
* @param label The label for the link
|
||||
* @param componentAccess The component access
|
||||
* @deprecated use addComponent(String,GlobalizedMessage,ComponentAccess)
|
||||
* instead.
|
||||
*/
|
||||
public void addComponent(final String key,
|
||||
final String label,
|
||||
final ComponentAccess componentAccess) {
|
||||
addComponent(key, componentAccess);
|
||||
getLabelsMap().put(key, label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a component to the list of links. It is up to the component to
|
||||
* correctly call showDisplayPane when it's done.
|
||||
*
|
||||
* @param key The symbolic key for the component; must be unique for this
|
||||
* <code>PropertyEditor</code>
|
||||
* @param label The label for the link
|
||||
* @param componentAccess The component access
|
||||
*/
|
||||
public void addComponent(final String key,
|
||||
final GlobalizedMessage label,
|
||||
final ComponentAccess componentAccess) {
|
||||
addComponent(key, componentAccess);
|
||||
getLabelsMap().put(key, label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a new {@link ComponentAccess} for a component which has already
|
||||
* been added to the <code>SecurityPropertyEditor</code>.
|
||||
*
|
||||
* @param key the key under which the component was added
|
||||
* @param componentAccess the <code>ComponentAccess</code> instance that
|
||||
* will determine when the link for the specified component should be
|
||||
* visible
|
||||
* @pre access.getComponent() == m_forms.get(key)
|
||||
*/
|
||||
public void setComponentAccess(final String key,
|
||||
final ComponentAccess componentAccess) {
|
||||
Assert.isUnlocked(this);
|
||||
final Component component = getComponent(key);
|
||||
Assert.exists(component, "the specified component");
|
||||
Assert.isTrue(componentAccess.getComponent().equals(component),
|
||||
"The specified component does not match the component that"
|
||||
+ " id already in the PropertyEditor");
|
||||
accessChecks.put(key, componentAccess);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a form to the set of forms which could be used to edit the
|
||||
* properties.
|
||||
*
|
||||
* @param key The symbolic key for the form; must be unique for this
|
||||
* <code>PropertyEditor</code>
|
||||
* @param label The label for the link to access the form
|
||||
* @param componentAccess The form ComponentAccess
|
||||
*
|
||||
* @deprecated use add(String,GlobalizedMessage,ComponentAccess)
|
||||
*/
|
||||
public void add(final String key,
|
||||
final String label,
|
||||
final ComponentAccess componentAccess) {
|
||||
final Component component = componentAccess.getComponent();
|
||||
if (component instanceof Form) {
|
||||
final Form form = (Form) component;
|
||||
accessChecks.put(key, componentAccess);
|
||||
add(key, label, form);
|
||||
addSecurityListener(form);
|
||||
} else if (component instanceof FormSection) {
|
||||
final FormSection section = (FormSection) componentAccess.
|
||||
getComponent();
|
||||
accessChecks.put(key, componentAccess);
|
||||
add(key, label, section);
|
||||
addSecurityListener(section);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"The ComponentAccess object does "
|
||||
+ "not contain a form section.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a form to the set of forms which could be used to edit the
|
||||
* properties.
|
||||
*
|
||||
* @param key The symbolic key for the form; must be unique for this
|
||||
* <code>PropertyEditor</code>
|
||||
* @param label The label for the link to access the form
|
||||
* @param componentAccess The form ComponentAccess
|
||||
*/
|
||||
public void add(final String key,
|
||||
final GlobalizedMessage label,
|
||||
final ComponentAccess componentAccess) {
|
||||
final Component component = componentAccess.getComponent();
|
||||
if (component instanceof Form) {
|
||||
final Form form = (Form) component;
|
||||
accessChecks.put(key, componentAccess);
|
||||
add(key, label, form);
|
||||
addSecurityListener(form);
|
||||
} else if (component instanceof FormSection) {
|
||||
final FormSection section = (FormSection) componentAccess.
|
||||
getComponent();
|
||||
accessChecks.put(key, componentAccess);
|
||||
add(key, label, section);
|
||||
addSecurityListener(section);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"The ComponentAccess object does "
|
||||
+ "not contain a form section.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a form to the set of forms which could be used to edit the properties
|
||||
*
|
||||
* @param key The symbolic key for the form; must be unique for this
|
||||
* <code>PropertyEditor</code>
|
||||
* @param label The label for the link to access the form.
|
||||
* @param componentAccess The form ComponentAccess
|
||||
* @param cancelButton The Cancel button on the form.
|
||||
*
|
||||
* @deprecated use add(String,GlobalizedMessage,ComponentAccess,Submit)
|
||||
* instead
|
||||
*/
|
||||
public void add(final String key,
|
||||
final String label,
|
||||
final ComponentAccess componentAccess,
|
||||
final Submit cancelButton) {
|
||||
add(key, label, componentAccess);
|
||||
addCancelListener((FormSection) componentAccess.getComponent(),
|
||||
cancelButton);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a form to the set of forms which could be used to edit the properties
|
||||
*
|
||||
* @param key The symbolic key for the form; must be unique for this
|
||||
* <code>PropertyEditor</code>
|
||||
* @param label The label for the link to access the form.
|
||||
* @param componentAccess The form ComponentAccess
|
||||
* @param cancelButton The Cancel button on the form.
|
||||
*/
|
||||
public void add(final String key,
|
||||
final GlobalizedMessage label,
|
||||
final ComponentAccess componentAccess,
|
||||
final Submit cancelButton) {
|
||||
add(key, label, componentAccess);
|
||||
addCancelListener((FormSection) componentAccess.getComponent(),
|
||||
cancelButton);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a submission listener to the form that will hide all components and
|
||||
* show the display pane. This method should be used to add submission
|
||||
* listeners to forms which are buried deep inside some component, and are
|
||||
* not members of this <code>PropertyEditor</code>.
|
||||
*
|
||||
* @param form The form
|
||||
*/
|
||||
public void addSecurityListener(final FormSection form) {
|
||||
form.addSubmissionListener(new FormSubmissionListener() {
|
||||
|
||||
@Override
|
||||
public void submitted(final FormSectionEvent event) throws
|
||||
FormProcessException {
|
||||
|
||||
final PageState state = event.getPageState();
|
||||
|
||||
// Cancel the form if the user does not pass the access checks.
|
||||
final String key = (String) getList().getSelectedKey(state);
|
||||
final ComponentAccess componentAccess
|
||||
= (ComponentAccess) accessChecks.get(key);
|
||||
|
||||
if (key == null || componentAccess == null) {
|
||||
// no components currently selected and therefore
|
||||
// no access checks to run for visibility
|
||||
// or
|
||||
// there are no access restrictions on the form
|
||||
return;
|
||||
}
|
||||
|
||||
if (!componentAccess.canAccess()) {
|
||||
showDisplayPane(state);
|
||||
throw new FormProcessException(new GlobalizedMessage(
|
||||
"cms.ui.insufficient_privileges",
|
||||
CmsConstants.CMS_BUNDLE));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all required listeners to the form to ensure that if the form is
|
||||
* submitted successfully or cancelled, the display pane will be shown. This
|
||||
* method should be used to add listeners to forms which are buried deep
|
||||
* inside some component, and are not members of this
|
||||
* <code>PropertyEditor</code>.
|
||||
*
|
||||
* @param form The form
|
||||
* @param cancelButton the "Cancel" button on the form
|
||||
*/
|
||||
@Override
|
||||
public void addListeners(final FormSection form,
|
||||
final Submit cancelButton) {
|
||||
addSecurityListener(form);
|
||||
super.addListeners(form, cancelButton);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the map of keys to access checks
|
||||
*
|
||||
* @return Map of keys to access check
|
||||
*/
|
||||
protected final Map<String, ComponentAccess> getAccessMap() {
|
||||
return accessChecks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link SecurityPropertyEditor.AccessListModel} during each
|
||||
* request
|
||||
*/
|
||||
protected static class AccessListModelBuilder extends DefaultModelBuilder {
|
||||
|
||||
public AccessListModelBuilder() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyEditorModel makeModel(
|
||||
final PropertyEditor propertyEditor, final PageState state) {
|
||||
|
||||
return new AccessListModel(
|
||||
getProperties(propertyEditor),
|
||||
((SecurityPropertyEditor) propertyEditor).getAccessMap(),
|
||||
state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs access checks for each property; skips the properties that the
|
||||
* user is not allowed to access
|
||||
*/
|
||||
protected static class AccessListModel extends DefaultModel {
|
||||
|
||||
private final Map<String, ComponentAccess> accessMap;
|
||||
private final PageState state;
|
||||
|
||||
public AccessListModel(final Iterator iter,
|
||||
final Map<String, ComponentAccess> accessMap,
|
||||
final PageState state) {
|
||||
super(iter);
|
||||
this.accessMap = accessMap;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean next() {
|
||||
|
||||
while (super.next()) {
|
||||
final Object key = getKey();
|
||||
final ComponentAccess ca = accessMap.get(key.toString());
|
||||
|
||||
if (ca == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ca.canAccess()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, skip the property
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,286 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui;
|
||||
|
||||
import com.arsdigita.bebop.ColumnPanel;
|
||||
import com.arsdigita.bebop.Form;
|
||||
import com.arsdigita.bebop.FormData;
|
||||
import com.arsdigita.bebop.FormProcessException;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.RequestLocal;
|
||||
import com.arsdigita.bebop.SimpleContainer;
|
||||
import com.arsdigita.bebop.event.FormProcessListener;
|
||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||
import com.arsdigita.bebop.event.PrintEvent;
|
||||
import com.arsdigita.bebop.event.PrintListener;
|
||||
import com.arsdigita.bebop.form.CheckboxGroup;
|
||||
import com.arsdigita.bebop.form.Hidden;
|
||||
import com.arsdigita.bebop.form.Option;
|
||||
import com.arsdigita.bebop.form.OptionGroup;
|
||||
import com.arsdigita.bebop.form.Submit;
|
||||
import com.arsdigita.bebop.form.Widget;
|
||||
import com.arsdigita.bebop.parameters.NotNullValidationListener;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.xml.Element;
|
||||
|
||||
import org.libreccm.security.User;
|
||||
import org.librecms.CmsConstants;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.TooManyListenersException;
|
||||
|
||||
/**
|
||||
* Form for adding multiple users to a role.
|
||||
*
|
||||
* @author <a href="mailto:pihman@arsdigita.com">Michael Pih</a>
|
||||
* @author <a href="mailto:umathur@arsdigita.com">Uday Mathur</a>
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
public abstract class UserAddForm extends SimpleContainer
|
||||
implements FormProcessListener {
|
||||
|
||||
private final static String SEARCH_QUERY = "searchQuery";
|
||||
private final static String USERS = "users";
|
||||
private final static String SUBMIT = "addSubmit";
|
||||
private final static String CANCEL = "addCancel";
|
||||
|
||||
private final static String DQ_USER_ID = "userId";
|
||||
private final static String DQ_NAME = "name";
|
||||
|
||||
private Widget m_search;
|
||||
private RequestLocal m_query;
|
||||
private String m_label;
|
||||
private String m_submitText;
|
||||
|
||||
private CMSContainer m_noMatches;
|
||||
private CMSContainer m_matches;
|
||||
|
||||
private Form m_form;
|
||||
private Hidden m_searchQuery;
|
||||
private CheckboxGroup m_users;
|
||||
private Submit m_submit;
|
||||
private Submit m_cancel;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param search The widget on the search form that contains the value of
|
||||
* the search string.
|
||||
*/
|
||||
public UserAddForm(final Widget search) {
|
||||
this(search, "AddUsers");
|
||||
}
|
||||
|
||||
public UserAddForm(final Widget search, final String name) {
|
||||
this(search, name,
|
||||
"Check the box next to the name of the person(s) to assign.",
|
||||
"Add Members");
|
||||
}
|
||||
|
||||
public UserAddForm(final Widget search,
|
||||
final String name,
|
||||
final String text,
|
||||
final String submitText) {
|
||||
m_label = text;
|
||||
m_submitText = submitText;
|
||||
m_search = search;
|
||||
|
||||
m_query = new RequestLocal() {
|
||||
|
||||
@Override
|
||||
protected Object initialValue(final PageState state) {
|
||||
return makeQuery(state);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
m_form = makeForm(name);
|
||||
|
||||
final Label title = new Label(new GlobalizedMessage("cms.ui.matches",
|
||||
CmsConstants.CMS_BUNDLE));
|
||||
title.setFontWeight(Label.BOLD);
|
||||
|
||||
final Label label = new Label(new GlobalizedMessage(
|
||||
"cms.ui.there_was_no_one_matching_the_search_criteria",
|
||||
CmsConstants.CMS_BUNDLE));
|
||||
label.setFontWeight("em");
|
||||
|
||||
m_noMatches = new CMSContainer();
|
||||
m_noMatches.add(title);
|
||||
m_noMatches.add(label);
|
||||
add(m_noMatches);
|
||||
|
||||
m_matches = new CMSContainer();
|
||||
m_matches.add(title);
|
||||
m_matches.add(m_form);
|
||||
add(m_matches);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the form used to add users.
|
||||
*
|
||||
* @param name
|
||||
*
|
||||
* @return The form
|
||||
*/
|
||||
protected Form makeForm(final String name) {
|
||||
final CMSForm form = new CMSForm(name) {
|
||||
|
||||
public final boolean isCancelled(final PageState state) {
|
||||
return m_cancel.isSelected(state);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// This hidden field will store the search query. A hidden widget is
|
||||
// used instead of a request local variable because the search query
|
||||
// should only be updated when the search form is submitted.
|
||||
m_searchQuery = new Hidden(SEARCH_QUERY);
|
||||
form.add(m_searchQuery, ColumnPanel.FULL_WIDTH);
|
||||
|
||||
Label l = new Label(m_label);
|
||||
form.add(l, ColumnPanel.FULL_WIDTH);
|
||||
|
||||
// Add the list of users that can be added.
|
||||
m_users = new CheckboxGroup(USERS);
|
||||
m_users.addValidationListener(new NotNullValidationListener());
|
||||
try {
|
||||
m_users.addPrintListener(new PrintListener() {
|
||||
|
||||
@Override
|
||||
public void prepare(PrintEvent event) {
|
||||
CheckboxGroup target = (CheckboxGroup) event.getTarget();
|
||||
PageState state = event.getPageState();
|
||||
// Ensures that the init listener gets fired before the
|
||||
// print listeners.
|
||||
FormData data = m_form.getFormData(state);
|
||||
addUsers(state, target);
|
||||
}
|
||||
|
||||
});
|
||||
} catch (TooManyListenersException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
form.add(m_users, ColumnPanel.FULL_WIDTH);
|
||||
|
||||
// Submit and Cancel buttons.
|
||||
SimpleContainer s = new SimpleContainer();
|
||||
m_submit = new Submit(SUBMIT, m_submitText);
|
||||
s.add(m_submit);
|
||||
m_cancel = new Submit(CANCEL, "Cancel");
|
||||
s.add(m_cancel);
|
||||
form.add(s, ColumnPanel.FULL_WIDTH | ColumnPanel.CENTER);
|
||||
|
||||
form.addProcessListener(this);
|
||||
|
||||
return form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the form for adding users.
|
||||
*
|
||||
* @return The "add user" form
|
||||
*/
|
||||
public Form getForm() {
|
||||
return m_form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the widget that contains the search string.
|
||||
*
|
||||
* @return The widget that contains the search string
|
||||
*/
|
||||
protected Widget getSearchWidget() {
|
||||
return m_searchQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the form is cancelled, false otherwise.
|
||||
*
|
||||
* @param state The page state
|
||||
*
|
||||
* @return true if the form is cancelled, false otherwise.
|
||||
*
|
||||
* @pre ( state != null )
|
||||
*/
|
||||
public boolean isCancelled(final PageState state) {
|
||||
return m_cancel.isSelected(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds users to the option group.
|
||||
*
|
||||
* @param state The page state
|
||||
* @param target The option group
|
||||
*
|
||||
* @pre ( state != null && target != null )
|
||||
*/
|
||||
protected void addUsers(final PageState state, final OptionGroup target) {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<User> users = (java.util.List<User>) m_query.get(state);
|
||||
|
||||
users.forEach(user -> target.addOption(
|
||||
new Option(Long.toString(user.getPartyId()),
|
||||
user.getName())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a {@link List} that encapsulates search results.
|
||||
*
|
||||
* @param state The page state
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected abstract List<User> makeQuery(final PageState state);
|
||||
|
||||
/**
|
||||
* Process listener for the "Add users" form.
|
||||
*
|
||||
* @param event The form event
|
||||
*
|
||||
* @throws com.arsdigita.bebop.FormProcessException
|
||||
*/
|
||||
@Override
|
||||
public abstract void process(final FormSectionEvent event)
|
||||
throws FormProcessException;
|
||||
|
||||
/**
|
||||
* Displays the appropriate frame.
|
||||
*
|
||||
* @param state The page state
|
||||
* @param parent The parent DOM element
|
||||
*/
|
||||
@Override
|
||||
public void generateXML(final PageState state,
|
||||
final Element parent) {
|
||||
|
||||
m_searchQuery.setValue(state, m_search.getValue(state));
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<User> searchResults = (List<User>) m_query.get(state);
|
||||
|
||||
if (searchResults.size() > 0) {
|
||||
m_matches.generateXML(state, parent);
|
||||
} else {
|
||||
m_noMatches.generateXML(state, parent);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui;
|
||||
|
||||
import com.arsdigita.bebop.ColumnPanel;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.form.Submit;
|
||||
import com.arsdigita.bebop.form.TextField;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
|
||||
import org.librecms.CmsConstants;
|
||||
|
||||
/**
|
||||
* Form to search for users to be added to a staff group.
|
||||
*
|
||||
*
|
||||
* @author <a href="mailto:pihman@arsdigita.com">Michael Pih</a>
|
||||
*/
|
||||
public class UserSearchForm extends CMSForm {
|
||||
|
||||
private final static String SEARCH_LABEL = "Search";
|
||||
|
||||
private TextField m_search;
|
||||
|
||||
public UserSearchForm(String name) {
|
||||
this(name,
|
||||
new Label(new GlobalizedMessage(
|
||||
"cms.ui.search_to_add_new_members",
|
||||
CmsConstants.CMS_BUNDLE)));
|
||||
|
||||
}
|
||||
|
||||
public UserSearchForm(String name, Label heading) {
|
||||
super(name, new ColumnPanel(3));
|
||||
heading.setFontWeight(Label.BOLD);
|
||||
add(heading, ColumnPanel.FULL_WIDTH);
|
||||
|
||||
add(new Label(new GlobalizedMessage(
|
||||
"cms.ui.enter_first_name_last_name_andor_email_address",
|
||||
CmsConstants.CMS_BUNDLE)));
|
||||
|
||||
m_search = new TextField(new StringParameter("query"));
|
||||
m_search.setSize(20);
|
||||
add(m_search, ColumnPanel.RIGHT);
|
||||
|
||||
Submit submit = new Submit("submit");
|
||||
submit.setButtonLabel(SEARCH_LABEL);
|
||||
add(submit, ColumnPanel.LEFT);
|
||||
}
|
||||
|
||||
public TextField getSearchWidget() {
|
||||
return m_search;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui;
|
||||
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.toolbox.ui.ProxyComponent;
|
||||
import com.arsdigita.util.Assert;
|
||||
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.security.PermissionChecker;
|
||||
|
||||
/**
|
||||
* @author Justin Ross
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
public class VisibilityComponent extends ProxyComponent {
|
||||
|
||||
private final String m_action;
|
||||
|
||||
public VisibilityComponent(final Component child, final String action) {
|
||||
super(child);
|
||||
|
||||
m_action = action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible(final PageState state) {
|
||||
return super.isVisible(state) && hasPermission(state);
|
||||
}
|
||||
|
||||
public boolean hasPermission(final PageState state) {
|
||||
Assert.exists(m_action, String.class);
|
||||
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final PermissionChecker permissionChecker = cdiUtil.findBean(
|
||||
PermissionChecker.class);
|
||||
|
||||
return permissionChecker.isPermitted(m_action);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2007 Chris Gilbert All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui.authoring;
|
||||
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.cms.ItemSelectionModel;
|
||||
|
||||
/**
|
||||
* class used for decoupled display components that caters for a callback to
|
||||
* provide them with a handle on the ItemSelectionModel
|
||||
*
|
||||
* @author chris.gilbert@westsussex.gov.uk
|
||||
*
|
||||
*/
|
||||
public interface AdditionalDisplayComponent extends Component {
|
||||
|
||||
public void setItemSelectionModel(ItemSelectionModel model);
|
||||
|
||||
}
|
||||
|
|
@ -1,153 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2017 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 com.arsdigita.cms.ui.authoring;
|
||||
|
||||
import org.libreccm.security.PermissionChecker;
|
||||
import org.libreccm.workflow.AssignableTask;
|
||||
import org.libreccm.workflow.AssignableTaskManager;
|
||||
import org.libreccm.workflow.Workflow;
|
||||
import org.libreccm.workflow.WorkflowManager;
|
||||
import org.libreccm.workflow.WorkflowRepository;
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
import org.librecms.contentsection.ContentSectionRepository;
|
||||
import org.librecms.contentsection.ContentType;
|
||||
import org.librecms.contentsection.ContentTypeRepository;
|
||||
import org.librecms.contentsection.Folder;
|
||||
import org.librecms.contentsection.privileges.ItemPrivileges;
|
||||
|
||||
import java.nio.charset.IllegalCharsetNameException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.enterprise.context.RequestScoped;
|
||||
import javax.inject.Inject;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
@RequestScoped
|
||||
class ApplyWorkflowController {
|
||||
|
||||
@Inject
|
||||
private ContentTypeRepository typeRepo;
|
||||
|
||||
@Inject
|
||||
private ContentSectionRepository sectionRepo;
|
||||
|
||||
@Inject
|
||||
private WorkflowRepository templateRepo;
|
||||
|
||||
@Inject
|
||||
private WorkflowManager workflowManager;
|
||||
|
||||
@Inject
|
||||
private AssignableTaskManager assignableTaskManager;
|
||||
|
||||
@Inject
|
||||
private PermissionChecker permissionChecker;
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
protected Workflow getDefaultWorkflow(final ContentType contentType) {
|
||||
|
||||
Objects.requireNonNull(contentType);
|
||||
|
||||
final ContentType type = typeRepo
|
||||
.findById(contentType.getObjectId())
|
||||
.orElseThrow(() -> new IllegalCharsetNameException(String.format(
|
||||
"No ContentType with ID %d in the database. Where did that ID come from?",
|
||||
contentType.getObjectId())));
|
||||
|
||||
return type.getDefaultWorkflow();
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
Long getDefaultWorkflowId(final ContentType contentType) {
|
||||
final Workflow workflowTemplate
|
||||
= getDefaultWorkflow(contentType);
|
||||
if (workflowTemplate == null) {
|
||||
return null;
|
||||
} else {
|
||||
return workflowTemplate.getWorkflowId();
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
protected List<Workflow> getWorkflowTemplates(
|
||||
final ContentSection section) {
|
||||
|
||||
final ContentSection contentSection = sectionRepo
|
||||
.findById(section.getObjectId())
|
||||
.orElseThrow(() -> new IllegalArgumentException(String.format(
|
||||
"No ContentSection with ID %d in the database. "
|
||||
+ "Where did that ID come from?",
|
||||
section.getObjectId())));
|
||||
|
||||
return new ArrayList<>(contentSection.getWorkflowTemplates());
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
protected void applyWorkflow(final ContentItem item,
|
||||
final Folder folder,
|
||||
final Long workflowTemplateId) {
|
||||
|
||||
Objects.requireNonNull(item);
|
||||
Objects.requireNonNull(folder);
|
||||
Objects.requireNonNull(workflowTemplateId);
|
||||
|
||||
final Workflow workflowTemplate;
|
||||
if (workflowTemplateId == null
|
||||
&& permissionChecker
|
||||
.isPermitted(ItemPrivileges.APPLY_ALTERNATE_WORKFLOW, folder)) {
|
||||
|
||||
workflowTemplate = templateRepo
|
||||
.findById(workflowTemplateId)
|
||||
.orElseThrow(() -> new IllegalArgumentException(String.format(
|
||||
"No WorkflowTemplate with ID %d in database. "
|
||||
+ "Where did that ID come from?",
|
||||
workflowTemplateId)));
|
||||
} else {
|
||||
workflowTemplate = item.getContentType().getDefaultWorkflow();
|
||||
}
|
||||
|
||||
if (workflowTemplate != null) {
|
||||
|
||||
final Workflow workflow = workflowManager
|
||||
.createWorkflow(workflowTemplate, item);
|
||||
workflowManager.start(workflow);
|
||||
|
||||
if (!workflow.getTasks().isEmpty()) {
|
||||
|
||||
if (workflow.getTasks().get(0) instanceof AssignableTask) {
|
||||
|
||||
final AssignableTask task = (AssignableTask) workflow
|
||||
.getTasks()
|
||||
.get(0);
|
||||
assignableTaskManager.lockTask(task);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,162 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui.authoring;
|
||||
|
||||
import com.arsdigita.bebop.Component;
|
||||
|
||||
import com.arsdigita.bebop.MapComponentSelectionModel;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.SimpleContainer;
|
||||
import com.arsdigita.bebop.SingleSelectionModel;
|
||||
|
||||
import com.arsdigita.cms.ItemSelectionModel;
|
||||
import com.arsdigita.xml.Element;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.librecms.contenttypes.AuthoringKitInfo;
|
||||
import org.librecms.contenttypes.ContentTypeInfo;
|
||||
import org.librecms.contenttypes.ContentTypesManager;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Selects a component based on content type. Helper class for {@link
|
||||
* com.arsdigita.cms.ui.authoring.WizardSelector}.
|
||||
*
|
||||
* @author unknown
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
public abstract class AuthoringKitSelector extends SimpleContainer {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(
|
||||
AuthoringKitSelector.class);
|
||||
private final Map<String, Component> components;
|
||||
private final MapComponentSelectionModel<String> selectionModel;
|
||||
private final List<ContentTypeInfo> types;
|
||||
|
||||
/**
|
||||
* Construct a new AuthoringKitSelector. Load all the possible authoring
|
||||
* kits from the database and construct components for them.
|
||||
*
|
||||
* @param model the {@link ItemSelectionModel} which will supply the
|
||||
* selector with the id of a content type
|
||||
*
|
||||
* @pre itemModel != null
|
||||
*/
|
||||
public AuthoringKitSelector(final SingleSelectionModel<String> model) {
|
||||
super();
|
||||
|
||||
components = new HashMap<>();
|
||||
selectionModel = new MapComponentSelectionModel<>(model, components);
|
||||
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final ContentTypesManager typesManager = cdiUtil.findBean(
|
||||
ContentTypesManager.class);
|
||||
types = typesManager.getAvailableContentTypes();
|
||||
|
||||
if (types.isEmpty()) {
|
||||
throw new RuntimeException("No Content Types were found.");
|
||||
}
|
||||
}
|
||||
|
||||
// Overloaded add methods
|
||||
@Override
|
||||
public void add(final Component component) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
// Overloaded add methods
|
||||
@Override
|
||||
public void add(final Component component, final int constraints) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate all the authoring kit wizards. The child class should call
|
||||
* this method after it is done with initialisation.
|
||||
*/
|
||||
protected void processKit() {
|
||||
for (final ContentTypeInfo type : types) {
|
||||
final AuthoringKitInfo kit = type.getAuthoringKit();
|
||||
if (kit != null) {
|
||||
final Component component = instantiateKitComponent(kit, type);
|
||||
if (component != null) {
|
||||
super.add(component);
|
||||
components.put(type.getContentItemClass().getName(),
|
||||
component);
|
||||
LOGGER.info("Added component {} for {}",
|
||||
Objects.toString(component),
|
||||
type.getContentItemClass().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate an authoring kit component. Child classes should override
|
||||
* this to do the right thing. It is permissible for this method to return
|
||||
* null.
|
||||
*
|
||||
* @param kit for this kit
|
||||
* @param type for this type
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected abstract Component instantiateKitComponent(
|
||||
final AuthoringKitInfo kit, final ContentTypeInfo type);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param typeClass
|
||||
*
|
||||
* @return The component the given type id
|
||||
*/
|
||||
public Component getComponent(final String typeClass) {
|
||||
return components.get(typeClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The selection model used by this wizard
|
||||
*/
|
||||
public MapComponentSelectionModel<String> getComponentSelectionModel() {
|
||||
return selectionModel;
|
||||
}
|
||||
|
||||
// Choose the right component and run it
|
||||
@Override
|
||||
public void generateXML(final PageState state, final Element parent) {
|
||||
if (isVisible(state)) {
|
||||
final Component component = selectionModel.getComponent(state);
|
||||
if (component == null) {
|
||||
throw new IllegalStateException("No component for "
|
||||
+ selectionModel
|
||||
.getSelectedKey(state));
|
||||
}
|
||||
component.generateXML(state, parent);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,564 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui.authoring;
|
||||
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.ControlLink;
|
||||
import com.arsdigita.bebop.GridPanel;
|
||||
import com.arsdigita.bebop.List;
|
||||
import com.arsdigita.bebop.Page;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.Resettable;
|
||||
import com.arsdigita.bebop.SimpleContainer;
|
||||
import com.arsdigita.bebop.SingleSelectionModel;
|
||||
import com.arsdigita.bebop.event.ActionEvent;
|
||||
import com.arsdigita.bebop.event.ActionListener;
|
||||
import com.arsdigita.bebop.event.ChangeEvent;
|
||||
import com.arsdigita.bebop.event.ChangeListener;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.list.ListCellRenderer;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
|
||||
import org.librecms.contentsection.ContentType;
|
||||
|
||||
import com.arsdigita.cms.ItemSelectionModel;
|
||||
import com.arsdigita.cms.ui.ContentItemPage;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.toolbox.ui.LayoutPanel;
|
||||
import com.arsdigita.toolbox.ui.ModalPanel;
|
||||
import com.arsdigita.toolbox.ui.Section;
|
||||
import com.arsdigita.util.Assert;
|
||||
import com.arsdigita.util.SequentialMap;
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.librecms.CMSConfig;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.configuration.ConfigurationManager;
|
||||
import org.libreccm.core.UnexpectedErrorException;
|
||||
import org.libreccm.l10n.GlobalizationHelper;
|
||||
import org.libreccm.workflow.Task;
|
||||
import org.libreccm.workflow.TaskRepository;
|
||||
import org.librecms.CmsConstants;
|
||||
import org.librecms.contenttypes.AuthoringKit;
|
||||
import org.librecms.contenttypes.AuthoringKitInfo;
|
||||
import org.librecms.contenttypes.AuthoringStepInfo;
|
||||
import org.librecms.contenttypes.ContentTypeInfo;
|
||||
import org.librecms.ui.authoring.ContentItemAuthoringStepInfo;
|
||||
import org.librecms.ui.authoring.ContentItemAuthoringStepManager;
|
||||
|
||||
/**
|
||||
* This class represents a single authoring kit. The wizard accepts a
|
||||
* {@link ContentType} in the constructor; it then extracts the
|
||||
* {@link AuthoringKit} for the content type, and creates the components for all
|
||||
* the steps in the kit.
|
||||
*
|
||||
* Note that the individual authoring kit steps must provide the following
|
||||
* constructor:
|
||||
*
|
||||
* <blockquote><pre><code>
|
||||
* public TheClass(ItemSelectionModel model, AuthoringKitWizard parent) { ... }
|
||||
* </code></pre></blockquote>
|
||||
*
|
||||
* This constructor will be called when the component is automatically
|
||||
* instantiated by the <code>AuthoringKitWizard</code>.
|
||||
*
|
||||
*/
|
||||
public class AuthoringKitWizard extends LayoutPanel implements Resettable {
|
||||
|
||||
/**
|
||||
* Private Logger instance for this class
|
||||
*/
|
||||
private static final Logger LOGGER = LogManager
|
||||
.getLogger(AuthoringKitWizard.class);
|
||||
|
||||
private final static Class<?>[] ARGUMENTS = new Class<?>[]{
|
||||
ItemSelectionModel.class,
|
||||
AuthoringKitWizard.class,
|
||||
StringParameter.class
|
||||
};
|
||||
|
||||
private static final Class<?>[] USER_DEFINED_ARGS = new Class<?>[]{
|
||||
ItemSelectionModel.class,
|
||||
AuthoringKitWizard.class,
|
||||
ContentType.class
|
||||
};
|
||||
|
||||
private final Object[] values;
|
||||
|
||||
private final ContentTypeInfo typeInfo;
|
||||
|
||||
private final AuthoringKitInfo kitInfo;
|
||||
|
||||
private final ItemSelectionModel selectionModel;
|
||||
|
||||
|
||||
|
||||
private final SequentialMap labels;
|
||||
|
||||
private final List list;
|
||||
|
||||
private String defaultKey;
|
||||
|
||||
private final GridPanel leftPanel;
|
||||
|
||||
private final ModalPanel bodyPanel;
|
||||
|
||||
private final SimpleContainer stepsContainer;
|
||||
|
||||
|
||||
private final StringParameter selectedLanguageParam;
|
||||
|
||||
/**
|
||||
* The name of the state parameter that determines whether the wizard is in
|
||||
* item creation mode or item editing mode.
|
||||
*/
|
||||
public static final String IS_EDITING = "is_edit";
|
||||
|
||||
/**
|
||||
* The key for the item creation step.
|
||||
*/
|
||||
public static final String CREATION = "_creation_";
|
||||
|
||||
private final static String SEC_PAGE_EDIT_DYN
|
||||
= "com.arsdigita.cms.ui.authoring.SecondaryPageEditDynamic";
|
||||
|
||||
private final static String PAGE_EDIT_DYN
|
||||
= "com.arsdigita.cms.ui.authoring.PageEditDynamic";
|
||||
|
||||
/**
|
||||
* Construct a new AuthoringKitWizard. Add all the steps in the authoring
|
||||
* kit to the wizard.
|
||||
*
|
||||
* @param typeInfo The content type of the items that this wizard will
|
||||
* handle
|
||||
* @param selectionModel
|
||||
*/
|
||||
public AuthoringKitWizard(final ContentTypeInfo typeInfo,
|
||||
final ItemSelectionModel selectionModel) {
|
||||
LOGGER.debug("Authoring kit wizard for type {} undergoing creation...",
|
||||
Objects.toString(typeInfo));
|
||||
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final ConfigurationManager confManager = cdiUtil.findBean(
|
||||
ConfigurationManager.class);
|
||||
|
||||
selectedLanguageParam = new StringParameter(
|
||||
ContentItemPage.SELECTED_LANGUAGE);
|
||||
final GlobalizationHelper globalizationHelper = cdiUtil
|
||||
.findBean(GlobalizationHelper.class);
|
||||
selectedLanguageParam.setDefaultValue(globalizationHelper
|
||||
.getNegotiatedLocale()
|
||||
.toString());
|
||||
|
||||
this.typeInfo = typeInfo;
|
||||
kitInfo = typeInfo.getAuthoringKit();
|
||||
this.selectionModel = selectionModel;
|
||||
values = new Object[]{selectionModel, this, selectedLanguageParam};
|
||||
labels = new SequentialMap();
|
||||
|
||||
leftPanel = new GridPanel(1);
|
||||
setLeft(leftPanel);
|
||||
|
||||
final Section stepSection = new Section(
|
||||
new GlobalizedMessage("cms.ui.authoring.steps",
|
||||
CmsConstants.CMS_BUNDLE));
|
||||
leftPanel.add(stepSection);
|
||||
|
||||
list = new List();
|
||||
stepSection.setBody(list);
|
||||
|
||||
list.setListData(labels);
|
||||
list.setCellRenderer(new ListCellRenderer() {
|
||||
|
||||
@Override
|
||||
public Component getComponent(final List list,
|
||||
final PageState state,
|
||||
final Object value,
|
||||
final String key,
|
||||
final int index,
|
||||
final boolean isSelected) {
|
||||
final Label label;
|
||||
if (value instanceof GlobalizedMessage) {
|
||||
label = new Label((GlobalizedMessage) value);
|
||||
} else {
|
||||
label = new Label((String) value);
|
||||
}
|
||||
if (isSelected) {
|
||||
label.setFontWeight(Label.BOLD);
|
||||
return label;
|
||||
}
|
||||
return new ControlLink(label);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
bodyPanel = new ModalPanel();
|
||||
setBody(bodyPanel);
|
||||
|
||||
stepsContainer = new SimpleContainer();
|
||||
bodyPanel.add(stepsContainer);
|
||||
bodyPanel.setDefault(stepsContainer);
|
||||
|
||||
final java.util.List<AuthoringStepInfo> steps = kitInfo.
|
||||
getAuthoringSteps();
|
||||
|
||||
if (Assert.isEnabled()) {
|
||||
Assert.isTrue(!steps.isEmpty(),
|
||||
String.format("The authoring kit for content type "
|
||||
+ "s\"%s\" has no steps.",
|
||||
typeInfo.getContentItemClass().getName()));
|
||||
}
|
||||
|
||||
final CMSConfig cmsConfig = confManager.findConfiguration(
|
||||
CMSConfig.class);
|
||||
|
||||
StepComponent panel = null;
|
||||
for (final AuthoringStepInfo step : steps) {
|
||||
final String key = step.getComponent().getName();
|
||||
|
||||
if (defaultKey == null) {
|
||||
defaultKey = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* The "label" and "description" are only here for backwards
|
||||
* compatibility
|
||||
*/
|
||||
final ResourceBundle labelBundle = ResourceBundle
|
||||
.getBundle(step.getLabelBundle());
|
||||
final ResourceBundle descBundle = ResourceBundle
|
||||
.getBundle(step.getDescriptionBundle());
|
||||
final String labelKey = step.getLabelKey();
|
||||
final String label = labelBundle.getString(labelKey);
|
||||
final String descriptionKey = step.getDescriptionKey();
|
||||
|
||||
final Class<? extends Component> componentClass = step.
|
||||
getComponent();
|
||||
final String compClassName = componentClass.getName();
|
||||
|
||||
if (panel != null) {
|
||||
panel.setNextStepKey(key);
|
||||
}
|
||||
panel = new StepComponent(compClassName);
|
||||
stepsContainer.add(panel);
|
||||
final Component component;
|
||||
|
||||
if (compClassName.equals(SEC_PAGE_EDIT_DYN)
|
||||
|| compClassName.equals(PAGE_EDIT_DYN)) {
|
||||
component = instantiateUserDefinedStep(compClassName, typeInfo);
|
||||
} else {
|
||||
component = instantiateStep(compClassName);
|
||||
}
|
||||
panel.add(component);
|
||||
if (component instanceof AuthoringStepComponent) {
|
||||
((AuthoringStepComponent) component).addCompletionListener(
|
||||
new StepCompletionListener());
|
||||
}
|
||||
|
||||
final GlobalizedMessage gzLabel;
|
||||
if (labelKey != null) {
|
||||
if (step.getLabelBundle() == null) {
|
||||
gzLabel = new GlobalizedMessage(labelKey,
|
||||
CmsConstants.CMS_BUNDLE);
|
||||
} else {
|
||||
gzLabel = new GlobalizedMessage(labelKey,
|
||||
step.getLabelBundle());
|
||||
}
|
||||
} else {
|
||||
gzLabel = null;
|
||||
}
|
||||
if (gzLabel == null) {
|
||||
labels.put(key, label);
|
||||
} else {
|
||||
labels.put(key, gzLabel);
|
||||
}
|
||||
}
|
||||
|
||||
final java.util.List<String> skipSteps = cmsConfig.getSkipAssetSteps();
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
for (final String step : skipSteps) {
|
||||
LOGGER.debug("skip step \"{}\"...", step);
|
||||
}
|
||||
}
|
||||
|
||||
for (final ContentItemAuthoringStepInfo stepInfo
|
||||
: getContentItemAuthoringSteps()) {
|
||||
|
||||
if (panel != null) {
|
||||
panel.setNextStepKey(stepInfo.getStep());
|
||||
}
|
||||
|
||||
panel = new StepComponent(stepInfo.getStep());
|
||||
stepsContainer.add(panel);
|
||||
|
||||
final Component component = instantiateStep(stepInfo
|
||||
.getStep().getName());
|
||||
if (component instanceof AuthoringStepComponent) {
|
||||
((AuthoringStepComponent) component)
|
||||
.addCompletionListener(new StepCompletionListener());
|
||||
}
|
||||
panel.add(component);
|
||||
|
||||
labels.put(stepInfo.getStep(),
|
||||
new GlobalizedMessage(stepInfo.getLabelKey(),
|
||||
stepInfo.getLabelBundle()));
|
||||
}
|
||||
|
||||
list.addChangeListener(new StepListener());
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private final class StepListener implements ChangeListener {
|
||||
|
||||
@Override
|
||||
public final void stateChanged(final ChangeEvent event) {
|
||||
final PageState state = event.getPageState();
|
||||
final String key = list.getSelectedKey(state).toString();
|
||||
|
||||
final Iterator<?> iter = stepsContainer.children();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
final StepComponent step = (StepComponent) iter.next();
|
||||
|
||||
if (step.getStepKey().toString().equals(key)) {
|
||||
step.setVisible(state, true);
|
||||
} else {
|
||||
step.setVisible(state, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private final class StepCompletionListener implements ActionListener {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public final void actionPerformed(final ActionEvent event) {
|
||||
final PageState state = event.getPageState();
|
||||
if (ContentItemPage.isStreamlinedCreationActive(state)) {
|
||||
final String key = list.getSelectedKey(state).toString();
|
||||
|
||||
final Iterator<?> iter = stepsContainer.children();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
final StepComponent step = (StepComponent) iter.next();
|
||||
if (step.getStepKey().toString().equals(key)) {
|
||||
Object nextStep = step.getNextStepKey();
|
||||
if (nextStep != null) {
|
||||
list
|
||||
.getSelectionModel()
|
||||
.setSelectedKey(state, nextStep.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void register(final Page page) {
|
||||
super.register(page);
|
||||
|
||||
final Iterator<?> iter = stepsContainer.children();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
final StepComponent child = (StepComponent) iter.next();
|
||||
|
||||
page.setVisibleDefault(child, false);
|
||||
}
|
||||
|
||||
page.addGlobalStateParam(selectedLanguageParam);
|
||||
|
||||
page.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public final void actionPerformed(final ActionEvent event) {
|
||||
final PageState state = event.getPageState();
|
||||
|
||||
if (state.isVisibleOnPage(AuthoringKitWizard.this)) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final SingleSelectionModel<Object> model = list
|
||||
.getSelectionModel();
|
||||
|
||||
if (!model.isSelected(state)) {
|
||||
model.setSelectedKey(state, defaultKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private java.util.List<ContentItemAuthoringStepInfo> getContentItemAuthoringSteps() {
|
||||
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final ContentItemAuthoringStepManager manager = cdiUtil
|
||||
.findBean(ContentItemAuthoringStepManager.class);
|
||||
|
||||
return manager.getContentItemAuthoringStepInfos();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The content type handled by this wizard
|
||||
*/
|
||||
public ContentTypeInfo getContentType() {
|
||||
return typeInfo;
|
||||
}
|
||||
|
||||
public List getList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The authoring kit which is represented by this wizard
|
||||
*/
|
||||
public AuthoringKitInfo getAuthoringKit() {
|
||||
return kitInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The ItemSelectionModel used by the steps in this wizard
|
||||
*/
|
||||
public ItemSelectionModel getItemSelectionModel() {
|
||||
return selectionModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate the specified authoring kit step. Will throw a
|
||||
* RuntimeException on failure.
|
||||
*
|
||||
* @param className The Java class name of the step
|
||||
*
|
||||
* @return The instance of the component.
|
||||
*/
|
||||
protected Component instantiateStep(final String className) {
|
||||
|
||||
LOGGER.debug("Instantiating kit wizard \"{}\" with arguments {}...",
|
||||
className,
|
||||
ARGUMENTS);
|
||||
|
||||
try {
|
||||
// Get the creation component
|
||||
final Class<?> createClass = Class.forName(className);
|
||||
final Constructor<?> constr = createClass.getConstructor(ARGUMENTS);
|
||||
final Component component = (Component) constr.newInstance(values);
|
||||
|
||||
return component;
|
||||
} catch (ClassNotFoundException
|
||||
| IllegalAccessException
|
||||
| IllegalArgumentException
|
||||
| InstantiationException
|
||||
| InvocationTargetException
|
||||
| NoSuchMethodException
|
||||
| SecurityException ex) {
|
||||
LOGGER.error(
|
||||
"Failed to instantiate authoring kit component \"{}\"...",
|
||||
className);
|
||||
LOGGER.error("Exception is: ", ex);
|
||||
throw new UncheckedWrapperException(String.format(
|
||||
"Failed to instantiate authoring kit component \"%s\".",
|
||||
className),
|
||||
ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate the specified authoring kit step for a user defined content
|
||||
* type. Will throw a RuntimeException on failure.
|
||||
*
|
||||
* @param className The Java class name of the step
|
||||
* @param originatingType
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected Component instantiateUserDefinedStep(
|
||||
final String className, final ContentTypeInfo originatingType) {
|
||||
|
||||
try {
|
||||
// Get the creation component
|
||||
final Class<?> createClass = Class.forName(className);
|
||||
final Constructor<?> constr = createClass.getConstructor(
|
||||
USER_DEFINED_ARGS);
|
||||
final Object[] userDefinedVals = new Object[]{selectionModel,
|
||||
this,
|
||||
originatingType};
|
||||
final Component component = (Component) constr.newInstance(
|
||||
userDefinedVals);
|
||||
|
||||
return component;
|
||||
} catch (ClassNotFoundException
|
||||
| NoSuchMethodException
|
||||
| InstantiationException
|
||||
| IllegalAccessException
|
||||
| InvocationTargetException ex) {
|
||||
throw new UncheckedWrapperException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the state of this wizard
|
||||
*/
|
||||
@Override
|
||||
public final void reset(final PageState state) {
|
||||
list.setSelectedKey(state, defaultKey);
|
||||
}
|
||||
|
||||
private final class StepComponent extends SimpleContainer {
|
||||
|
||||
private final Object key;
|
||||
|
||||
private Object nextKey;
|
||||
|
||||
public StepComponent(final Object key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public Object getStepKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public Object getNextStepKey() {
|
||||
return nextKey;
|
||||
}
|
||||
|
||||
public void setNextStepKey(final Object nextKey) {
|
||||
this.nextKey = nextKey;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui.authoring;
|
||||
|
||||
import com.arsdigita.bebop.event.ActionListener;
|
||||
|
||||
/**
|
||||
* Interface which authoring step components should implement. It's
|
||||
* currently an optional interface.
|
||||
*
|
||||
* @author Scott Seago (sseago@redhat.com)
|
||||
*/
|
||||
public interface AuthoringStepComponent {
|
||||
|
||||
/**
|
||||
* Add a completion listener to this component
|
||||
*/
|
||||
void addCompletionListener(ActionListener listener);
|
||||
|
||||
}
|
||||
|
|
@ -1,429 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2002-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui.authoring;
|
||||
|
||||
import com.arsdigita.bebop.ColumnPanel;
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.FormData;
|
||||
import com.arsdigita.bebop.FormProcessException;
|
||||
import com.arsdigita.bebop.FormSection;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.SaveCancelSection;
|
||||
import com.arsdigita.bebop.event.FormInitListener;
|
||||
import com.arsdigita.bebop.event.FormProcessListener;
|
||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||
import com.arsdigita.bebop.event.FormValidationListener;
|
||||
import com.arsdigita.bebop.form.Hidden;
|
||||
import com.arsdigita.bebop.form.TextField;
|
||||
import com.arsdigita.bebop.parameters.NotNullValidationListener;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
import com.arsdigita.bebop.parameters.TrimmedStringParameter;
|
||||
import com.arsdigita.bebop.parameters.URLTokenValidationListener;
|
||||
import com.arsdigita.cms.ItemSelectionModel;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.web.Web;
|
||||
import com.arsdigita.xml.Element;
|
||||
|
||||
import org.libreccm.categorization.Category;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.librecms.CmsConstants;
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contentsection.ContentItemRepository;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A form for editing subclasses of ContentItem. This is just a convenience
|
||||
* class.
|
||||
*
|
||||
* @author <a href="mailto:stas@arsdigita.com">Stanislav Freidin</a>
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
public abstract class BasicItemForm extends FormSection
|
||||
implements FormInitListener,
|
||||
FormProcessListener,
|
||||
FormValidationListener {
|
||||
|
||||
public static final String CONTENT_ITEM_ID = "ContentItemId";
|
||||
public static final String NAME = "ContentItemName";
|
||||
public static final String TITLE = "ContentPageTitle";
|
||||
public static final String LANGUAGE = "ContentItemLanguage";
|
||||
|
||||
private final ItemSelectionModel itemSelectionModel;
|
||||
private final StringParameter selectedLanguageParam;
|
||||
|
||||
private SaveCancelSection saveCancelSection;
|
||||
private final FormSection widgetSection;
|
||||
/**
|
||||
* Currently, to insert JavaScript code the Label Widget is "abused".
|
||||
*/
|
||||
private final Label script = new Label(String
|
||||
.format("<script language=\"javascript\" "
|
||||
+ "src=\"%s/javascript/manipulate-input.js\"></script>",
|
||||
Web.getWebappContextPath()),
|
||||
false);
|
||||
|
||||
/**
|
||||
* Construct a new BasicItemForm with 2 ColumnPanels and add basic content.
|
||||
* The left Panel is used for Labels, the right Panel for values.
|
||||
*
|
||||
* @param formName the name of this form
|
||||
* @param itemSelectionModel The {@link ItemSelectionModel} which will be
|
||||
* responsible for loading the current item
|
||||
* @param selectedLanguageParam
|
||||
*/
|
||||
public BasicItemForm(final String formName,
|
||||
final ItemSelectionModel itemSelectionModel,
|
||||
final StringParameter selectedLanguageParam) {
|
||||
|
||||
super(new ColumnPanel(2));
|
||||
|
||||
Objects.requireNonNull(selectedLanguageParam);
|
||||
|
||||
widgetSection = new FormSection(new ColumnPanel(2, true));
|
||||
|
||||
super.add(widgetSection, ColumnPanel.INSERT);
|
||||
this.itemSelectionModel = itemSelectionModel;
|
||||
this.selectedLanguageParam = selectedLanguageParam;
|
||||
|
||||
/* Prepare Panel design */
|
||||
final ColumnPanel panel = (ColumnPanel) getPanel();
|
||||
panel.setBorder(false);
|
||||
panel.setPadColor("#FFFFFF");
|
||||
panel.setColumnWidth(1, "20%");
|
||||
panel.setColumnWidth(2, "80%");
|
||||
panel.setWidth("100%");
|
||||
|
||||
/* Add basic contents */
|
||||
addWidgets();
|
||||
|
||||
saveCancelSection = new SaveCancelSection();
|
||||
super.add(saveCancelSection,
|
||||
ColumnPanel.FULL_WIDTH | ColumnPanel.LEFT);
|
||||
|
||||
addInitListener(this);
|
||||
addProcessListener(this);
|
||||
addValidationListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new BasicItemForm with a specified number of ColumnPanels and
|
||||
* without any content.
|
||||
*
|
||||
* @param formName the name of this form
|
||||
* @param columnPanel the column panel of the form
|
||||
* @param itemSelectionModel The {@link ItemSelectionModel} which will be
|
||||
* responsible for loading the current item
|
||||
* @param selectedLanguageParam
|
||||
*/
|
||||
public BasicItemForm(final String formName,
|
||||
final ColumnPanel columnPanel,
|
||||
final ItemSelectionModel itemSelectionModel,
|
||||
final StringParameter selectedLanguageParam) {
|
||||
|
||||
super(columnPanel);
|
||||
|
||||
Objects.requireNonNull(selectedLanguageParam);
|
||||
|
||||
widgetSection = new FormSection(new ColumnPanel(columnPanel.
|
||||
getNumCols(),
|
||||
true));
|
||||
super.add(widgetSection, ColumnPanel.INSERT);
|
||||
this.itemSelectionModel = itemSelectionModel;
|
||||
this.selectedLanguageParam = selectedLanguageParam;
|
||||
}
|
||||
|
||||
/**
|
||||
* create and add the save/cancel section for this form
|
||||
*/
|
||||
public void addSaveCancelSection() {
|
||||
saveCancelSection = new SaveCancelSection();
|
||||
super.add(saveCancelSection,
|
||||
ColumnPanel.FULL_WIDTH | ColumnPanel.LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add basic widgets to the form.
|
||||
*
|
||||
* Widgets added are 'title' and 'name (url)' which are part of any content
|
||||
* item. Child classes will override this method to perform all their
|
||||
* widget-adding needs but are supposed to use super() to add the basic
|
||||
* widgets.
|
||||
*/
|
||||
protected void addWidgets() {
|
||||
//add(new FormErrorDisplay(this), ColumnPanel.FULL_WIDTH | ColumnPanel.LEFT);
|
||||
|
||||
final Hidden id = new Hidden(CONTENT_ITEM_ID);
|
||||
add(id);
|
||||
|
||||
// JavaScript auto-name generation is off by default.
|
||||
// It is turned on under the following circumstances
|
||||
//
|
||||
// * If the name is null, upon starting edit of the title
|
||||
// * If the name is null, upon finishing edit of name
|
||||
//
|
||||
// The rationale is that, auto-name generation is useful
|
||||
// if the name is currently null, but once a name has been
|
||||
// created you don't want to subsequently change it since
|
||||
// it breaks URLs & potentially overwrites the user's
|
||||
// customizations.
|
||||
final TextField titleWidget = new TextField(new TrimmedStringParameter(
|
||||
TITLE));
|
||||
titleWidget.setLabel(getTitleLabel());
|
||||
titleWidget.setHint(getTitleHint());
|
||||
titleWidget.addValidationListener(new NotNullValidationListener());
|
||||
titleWidget.setOnFocus("if (this.form." + NAME + ".value == '') { "
|
||||
+ " defaulting = true; this.form." + NAME
|
||||
+ ".value = urlize(this.value); }");
|
||||
titleWidget.setOnKeyUp(
|
||||
"if (defaulting) { this.form." + NAME
|
||||
+ ".value = urlize(this.value) }");
|
||||
add(titleWidget);
|
||||
|
||||
// For some content types it may be useful to change the label of
|
||||
// the name (or URL) field to something different than 'name (url)'.
|
||||
// This can now be accomplished by overwriting the getNameLabel() method.
|
||||
// (jensp 2011-01-28)
|
||||
// add(new Label(getNameLabel()));
|
||||
final TextField nameWidget = new TextField(new TrimmedStringParameter(
|
||||
NAME));
|
||||
nameWidget.setLabel(getNameLabel());
|
||||
nameWidget.setHint(getNameHint());
|
||||
// We just check parameter specific properties here! Additionally,
|
||||
// context properties as uniqueness in folder must be validated
|
||||
// for the form es the whole (using the validate method required by
|
||||
// implementing FormValidationListener in this form.
|
||||
nameWidget.addValidationListener(new NotNullValidationListener());
|
||||
nameWidget.addValidationListener(new URLTokenValidationListener());
|
||||
nameWidget.setMaxLength(190);
|
||||
nameWidget.setOnFocus("defaulting = false");
|
||||
nameWidget.setOnBlur(
|
||||
"if (this.value == '') "
|
||||
+ "{ defaulting = true; this.value = urlize(this.form."
|
||||
+ TITLE
|
||||
+ ".value) } "
|
||||
+ " else { this.value = urlize(this.value); }");
|
||||
add(nameWidget);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateXML(final PageState state,
|
||||
final Element parent) {
|
||||
script.generateXML(state, parent);
|
||||
super.generateXML(state, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the item selection model used in this form
|
||||
*/
|
||||
public ItemSelectionModel getItemSelectionModel() {
|
||||
return itemSelectionModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the save/cancel section for this form
|
||||
*/
|
||||
public SaveCancelSection getSaveCancelSection() {
|
||||
return saveCancelSection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform form initialisation. Children should override this this method to
|
||||
* pre-fill the widgets with data, instantiate the content item, etc.
|
||||
*
|
||||
* @param event
|
||||
*
|
||||
* @throws FormProcessException
|
||||
*/
|
||||
@Override
|
||||
public abstract void init(final FormSectionEvent event) throws FormProcessException;
|
||||
|
||||
/**
|
||||
* Process the form. Children have to override this method to save the
|
||||
* user's changes to the database.
|
||||
*
|
||||
* @param event
|
||||
*
|
||||
* @throws FormProcessException
|
||||
*/
|
||||
@Override
|
||||
public abstract void process(final FormSectionEvent event) throws FormProcessException;
|
||||
|
||||
/**
|
||||
* Validate the form. Children have to override this method to provide
|
||||
* context form validation, specifically name (url) uniqueness in a folder!
|
||||
*
|
||||
* @param event
|
||||
*
|
||||
* @throws com.arsdigita.bebop.FormProcessException
|
||||
*/
|
||||
@Override
|
||||
public void validate(final FormSectionEvent event) throws FormProcessException {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a component to this container.
|
||||
*
|
||||
* @param component the component to add to this BasicPageForm
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public void add(final Component component) {
|
||||
widgetSection.add(component);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a component with the specified layout constraints to this container.
|
||||
* Layout constraints are defined in each layout container as static ints.
|
||||
* Use a bitwise OR to specify multiple constraints.
|
||||
*
|
||||
* @param component the component to add to this container
|
||||
* @param constraints layout constraints (a bitwise OR of static ints in the
|
||||
* particular layout)
|
||||
*/
|
||||
@Override
|
||||
public void add(final Component component,
|
||||
final int constraints) {
|
||||
widgetSection.add(component, constraints);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method can be overridden to change the label of the title field. To
|
||||
* change to label of the title field can be useful for some content types.
|
||||
* For example, for an organisation the label "Title" for the field may be
|
||||
* confusing for the normal user. For such a content type, the label would
|
||||
* be changed to something like "Name of the organisation".
|
||||
*
|
||||
* @return (Content for the) Label for the title field as string
|
||||
*/
|
||||
protected GlobalizedMessage getTitleLabel() {
|
||||
return new GlobalizedMessage("cms.contenttypes.ui.title",
|
||||
CmsConstants.CMS_BUNDLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the text for the user hint providing some detailed information
|
||||
* how to use this widget. This method can be overwritten to adjust the text
|
||||
* for some content types. {@link #getTitleLabel()}
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected GlobalizedMessage getTitleHint() {
|
||||
return new GlobalizedMessage("cms.contenttypes.ui.title_hint",
|
||||
CmsConstants.CMS_BUNDLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method does the same as {@link #getTitleLabel() } for the labe l of
|
||||
* the name (URL) field.
|
||||
*
|
||||
* @return (Content for the) Label for the name field as string
|
||||
*/
|
||||
protected GlobalizedMessage getNameLabel() {
|
||||
return new GlobalizedMessage("cms.contenttypes.ui.name",
|
||||
CmsConstants.CMS_BUNDLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the text for the user hint providing some detailed information
|
||||
* how to use this widget. This method can be overwritten to adjust the text
|
||||
* for some content types. {@link #getNameLabel()}
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected GlobalizedMessage getNameHint() {
|
||||
return new GlobalizedMessage("cms.contenttypes.ui.name_hint",
|
||||
CmsConstants.CMS_BUNDLE);
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// VALIDATION helper methods
|
||||
//
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Ensure that the name of an item is unique within a folder. A "New item"
|
||||
* form should call this method in the validation listener.
|
||||
*
|
||||
* @param parent the folder in which to check
|
||||
* @param event the {@link FormSectionEvent} which was passed to the
|
||||
* validation listener
|
||||
*/
|
||||
public void validateNameUniqueness(final Category parent,
|
||||
final FormSectionEvent event) {
|
||||
|
||||
final FormData data = event.getFormData();
|
||||
final String newName = (String) data.get(NAME);
|
||||
|
||||
validateNameUniqueness(parent, event, newName);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param parent
|
||||
* @param event
|
||||
* @param newName
|
||||
*/
|
||||
public void validateNameUniqueness(final Category parent,
|
||||
final FormSectionEvent event,
|
||||
final String newName) {
|
||||
|
||||
final String ERR_MSG = "cms.ui.authoring.an_item_with_this_name_exists";
|
||||
|
||||
if (newName != null) {
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final ContentItemRepository itemRepo = cdiUtil
|
||||
.findBean(ContentItemRepository.class);
|
||||
|
||||
final long result = itemRepo.countByNameInFolder(parent, newName);
|
||||
|
||||
if (result > 0) {
|
||||
// Try to get a currently selected content item
|
||||
final ContentItem item;
|
||||
if (getItemSelectionModel() == null) {
|
||||
item = null;
|
||||
} else {
|
||||
item = getItemSelectionModel()
|
||||
.getSelectedObject(event.getPageState());
|
||||
}
|
||||
if (item == null) { // The content item being null
|
||||
// means it is a creation form.
|
||||
// Therefore finding any item of the same name is a fault.
|
||||
event.getFormData()
|
||||
.addError(new GlobalizedMessage(ERR_MSG,
|
||||
CmsConstants.CMS_BUNDLE));
|
||||
} else {
|
||||
// means we are in a edit form.
|
||||
// We need to add all of the items that are different
|
||||
// versions of this item to the list so that we do not mark
|
||||
// an error if those are the only problems.
|
||||
event.getFormData()
|
||||
.addError(new GlobalizedMessage(
|
||||
ERR_MSG,
|
||||
CmsConstants.CMS_BUNDLE,
|
||||
new Object[]{item.getUuid()}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,360 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui.authoring;
|
||||
|
||||
import com.arsdigita.bebop.ColumnPanel;
|
||||
import com.arsdigita.bebop.FormData;
|
||||
import com.arsdigita.bebop.FormProcessException;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||
import com.arsdigita.bebop.event.ParameterEvent;
|
||||
import com.arsdigita.bebop.event.ParameterListener;
|
||||
import com.arsdigita.bebop.parameters.DateParameter;
|
||||
import com.arsdigita.bebop.parameters.ParameterData;
|
||||
import com.arsdigita.bebop.parameters.ParameterModel;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
import org.librecms.contentsection.Folder;
|
||||
|
||||
import com.arsdigita.cms.ItemSelectionModel;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.util.Assert;
|
||||
|
||||
import org.librecms.CMSConfig;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.workflow.Workflow;
|
||||
import org.librecms.CmsConstants;
|
||||
import org.librecms.contentsection.ContentItemInitializer;
|
||||
import org.librecms.contentsection.ContentType;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* A form for editing basic properties of documents (that is subclasses of class
|
||||
* ContentPage).
|
||||
*
|
||||
* Document specific classes inherit from this class which provides the basic
|
||||
* widgets for title, name launch date to use by those classes.
|
||||
*
|
||||
* This is just a convenience class. It uses parent class to construct the form
|
||||
* including basic widgets (i.e. title and name/URL as well as save/cancel
|
||||
* buttons) and adds optional launch date.
|
||||
*
|
||||
* Note: It is for editing existing content (specifically due to its validation
|
||||
* method).
|
||||
*
|
||||
* @author Stanislav Freidin (stas@arsdigita.com)
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
public abstract class BasicPageForm extends BasicItemForm {
|
||||
|
||||
private static final String LAUNCH_DATE = "launch_date";
|
||||
|
||||
private final StringParameter selectedLanguageParam;
|
||||
|
||||
/**
|
||||
* Construct a new BasicPageForm
|
||||
*
|
||||
* @param formName the name of this form
|
||||
* @param itemModel The {@link ItemSelectionModel} which will be
|
||||
* responsible for loading the current item
|
||||
* @param selectedLanguageParam
|
||||
*/
|
||||
public BasicPageForm(final String formName,
|
||||
final ItemSelectionModel itemModel,
|
||||
final StringParameter selectedLanguageParam) {
|
||||
|
||||
super(formName, itemModel, selectedLanguageParam);
|
||||
Objects.requireNonNull(selectedLanguageParam);
|
||||
this.selectedLanguageParam = selectedLanguageParam;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new BasicPageForm with nothing on it
|
||||
*
|
||||
* @param formName the name of this form
|
||||
* @param columnPanel the column panel of the form
|
||||
* @param itemModel The {@link ItemSelectionModel} which will be
|
||||
* responsible for loading the current item
|
||||
* @param selectedLanguageParam
|
||||
*/
|
||||
public BasicPageForm(final String formName,
|
||||
final ColumnPanel columnPanel,
|
||||
final ItemSelectionModel itemModel,
|
||||
final StringParameter selectedLanguageParam) {
|
||||
|
||||
super(formName, columnPanel, itemModel, selectedLanguageParam);
|
||||
this.selectedLanguageParam = selectedLanguageParam;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add various widgets to the form. Child classes should override this
|
||||
* method to perform all their widget-adding needs
|
||||
*/
|
||||
@Override
|
||||
protected void addWidgets() {
|
||||
|
||||
/* Add basic widgets title/name which are part of any content item */
|
||||
super.addWidgets();
|
||||
|
||||
final CMSConfig cmsConfig = CMSConfig.getConfig();
|
||||
|
||||
/* Optionally add Lunchdate */
|
||||
if (!cmsConfig.isHideLaunchDate()) {
|
||||
add(new Label(new GlobalizedMessage(
|
||||
"cms.ui.authoring.page_launch_date",
|
||||
CmsConstants.CMS_BUNDLE)));
|
||||
final ParameterModel launchDateParam
|
||||
= new DateParameter(LAUNCH_DATE);
|
||||
com.arsdigita.bebop.form.Date launchDate
|
||||
= new com.arsdigita.bebop.form.Date(
|
||||
launchDateParam);
|
||||
if (CMSConfig.getConfig().isRequireLaunchDate()) {
|
||||
launchDate.addValidationListener(
|
||||
new LaunchDateValidationListener());
|
||||
// if launch date is required, help user by suggesting today's date
|
||||
launchDateParam.setDefaultValue(new Date());
|
||||
}
|
||||
add(launchDate);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to initialise the name/title widgets. Child classes may
|
||||
* call this method from the init listener
|
||||
*
|
||||
* @param event the {@link FormSectionEvent} which was passed to the init
|
||||
* listener
|
||||
*
|
||||
* @return the ContentPage instance which was extracted from the
|
||||
* ItemSelectionModel
|
||||
*/
|
||||
public ContentItem initBasicWidgets(final FormSectionEvent event) {
|
||||
Assert.exists(getItemSelectionModel());
|
||||
|
||||
final FormData data = event.getFormData();
|
||||
final PageState state = event.getPageState();
|
||||
final ContentItem item = getItemSelectionModel()
|
||||
.getSelectedObject(state);
|
||||
|
||||
final Locale selectedLocale = SelectedLanguageUtil
|
||||
.selectedLocale(state, selectedLanguageParam);
|
||||
|
||||
if (item != null) {
|
||||
// Preset fields
|
||||
data.put(CONTENT_ITEM_ID, Long.toString(item.getObjectId()));
|
||||
data.put(NAME, item.getName().getValue(selectedLocale));
|
||||
data.put(TITLE, item.getTitle().getValue(selectedLocale));
|
||||
final CMSConfig cmsConfig = CMSConfig.getConfig();
|
||||
if (!cmsConfig.isHideLaunchDate()) {
|
||||
data.put(LAUNCH_DATE, item.getLaunchDate());
|
||||
// if launch date is required, help user by suggesting today's date
|
||||
if (cmsConfig.isRequireLaunchDate()
|
||||
&& item.getLaunchDate() == null) {
|
||||
data.put(LAUNCH_DATE, new Date());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class specific implementation of FormValidationListener interface
|
||||
* (inherited from BasicItemForm).
|
||||
*
|
||||
* @param event
|
||||
*
|
||||
* @throws FormProcessException
|
||||
*/
|
||||
@Override
|
||||
public void validate(final FormSectionEvent event)
|
||||
throws FormProcessException {
|
||||
|
||||
super.validate(event);
|
||||
|
||||
final PageState state = event.getPageState();
|
||||
|
||||
final ContentItem item = getItemSelectionModel()
|
||||
.getSelectedItem(event.getPageState());
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final BasicPageFormController controller = cdiUtil
|
||||
.findBean(BasicPageFormController.class);
|
||||
|
||||
final Optional<Folder> folder = controller.getItemFolder(item);
|
||||
if (folder.isPresent()) {
|
||||
final String name = event.getFormData().getString(NAME);
|
||||
final String selectedLang = (String) state
|
||||
.getValue(selectedLanguageParam);
|
||||
final Locale selectedLocale = new Locale(selectedLang);
|
||||
if (!item.getName().hasValue(selectedLocale)
|
||||
|| !item.getName().getValue(selectedLocale).equals(name)) {
|
||||
validateNameUniqueness(folder.get(), event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to process the name/title widgets. Child classes may call
|
||||
* this method from the process listener.
|
||||
*
|
||||
* @param event the {@link FormSectionEvent} which was passed to the process
|
||||
* listener
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ContentItem processBasicWidgets(final FormSectionEvent event) {
|
||||
Assert.exists(getItemSelectionModel());
|
||||
|
||||
final FormData data = event.getFormData();
|
||||
final PageState state = event.getPageState();
|
||||
final ContentItem item = getItemSelectionModel()
|
||||
.getSelectedObject(state);
|
||||
|
||||
if (item != null) {
|
||||
|
||||
final Locale selectedLocale = SelectedLanguageUtil
|
||||
.selectedLocale(state, selectedLanguageParam);
|
||||
|
||||
item.getName().putValue(selectedLocale, (String) data.get(NAME));
|
||||
item.getTitle().putValue(selectedLocale, (String) data.get(TITLE));
|
||||
if (!CMSConfig.getConfig().isHideLaunchDate()) {
|
||||
item.setLaunchDate((Date) data.get(LAUNCH_DATE));
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility method that will create a new item and tell the selection model
|
||||
* to select the new item.
|
||||
*
|
||||
* Creation components may call this method in the process listener of their
|
||||
* form. See {@link PageCreate} for an example.
|
||||
*
|
||||
* @param <T>
|
||||
* @param state
|
||||
* @param name
|
||||
* @param section
|
||||
* @param folder
|
||||
* @param initializer
|
||||
* @param locale
|
||||
*
|
||||
* @return the new content item (or a proper subclass thereof)
|
||||
*
|
||||
* @throws com.arsdigita.bebop.FormProcessException
|
||||
*/
|
||||
public <T extends ContentItem> T createContentPage(
|
||||
final PageState state,
|
||||
final String name,
|
||||
final ContentSection section,
|
||||
final Folder folder,
|
||||
final ContentItemInitializer<T> initializer,
|
||||
final Locale locale) throws FormProcessException {
|
||||
|
||||
return createContentItemPage(state,
|
||||
name,
|
||||
section,
|
||||
folder,
|
||||
null,
|
||||
initializer,
|
||||
locale);
|
||||
}
|
||||
|
||||
public <T extends ContentItem> T createContentItemPage(
|
||||
final PageState state,
|
||||
final String name,
|
||||
final ContentSection section,
|
||||
final Folder folder,
|
||||
final Workflow workflowTemplate,
|
||||
final ContentItemInitializer<T> initializer,
|
||||
final Locale locale) throws FormProcessException {
|
||||
|
||||
final ItemSelectionModel selectionModel = getItemSelectionModel();
|
||||
final ContentType contentType = selectionModel.getContentType();
|
||||
|
||||
// Create new item
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final BasicPageFormController controller = cdiUtil
|
||||
.findBean(BasicPageFormController.class);
|
||||
|
||||
final T item;
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
final Class<T> clazz = (Class<T>) Class
|
||||
.forName(contentType.getContentItemClass());
|
||||
|
||||
if (workflowTemplate == null) {
|
||||
item = controller
|
||||
.createContentItem(name,
|
||||
section,
|
||||
folder,
|
||||
clazz,
|
||||
initializer,
|
||||
locale);
|
||||
} else {
|
||||
item = controller.createContentItem(name,
|
||||
section,
|
||||
folder,
|
||||
workflowTemplate,
|
||||
clazz,
|
||||
initializer,
|
||||
locale);
|
||||
}
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new FormProcessException(
|
||||
"Couldn't create contentpage",
|
||||
new GlobalizedMessage(
|
||||
"cms.ui.authoring.couldnt_create_contentpage",
|
||||
CmsConstants.CMS_BUNDLE),
|
||||
ex);
|
||||
}
|
||||
|
||||
// Make sure the item will be remembered across requests
|
||||
selectionModel.setSelectedKey(state, item.getObjectId());
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>LaunchDateValidationListener</code>.
|
||||
*/
|
||||
private class LaunchDateValidationListener implements ParameterListener {
|
||||
|
||||
@Override
|
||||
public void validate(final ParameterEvent event) {
|
||||
|
||||
final ParameterData data = event.getParameterData();
|
||||
final Object value = data.getValue();
|
||||
|
||||
if (value == null) {
|
||||
data.addError("launch date is required");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,143 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2017 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 com.arsdigita.cms.ui.authoring;
|
||||
|
||||
import org.libreccm.workflow.Workflow;
|
||||
import org.libreccm.workflow.WorkflowRepository;
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contentsection.ContentItemInitializer;
|
||||
import org.librecms.contentsection.ContentItemManager;
|
||||
import org.librecms.contentsection.ContentItemRepository;
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
import org.librecms.contentsection.ContentSectionRepository;
|
||||
import org.librecms.contentsection.Folder;
|
||||
import org.librecms.contentsection.FolderRepository;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.enterprise.context.RequestScoped;
|
||||
import javax.inject.Inject;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
@RequestScoped
|
||||
class BasicPageFormController {
|
||||
|
||||
@Inject
|
||||
private ContentSectionRepository sectionRepo;
|
||||
|
||||
@Inject
|
||||
private ContentItemRepository itemRepo;
|
||||
|
||||
@Inject
|
||||
private ContentItemManager itemManager;
|
||||
|
||||
@Inject
|
||||
private FolderRepository folderRepo;
|
||||
|
||||
@Inject
|
||||
private WorkflowRepository workflowRepo;
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
protected <T extends ContentItem> T createContentItem(
|
||||
final String name,
|
||||
final ContentSection section,
|
||||
final Folder folder,
|
||||
final Class<T> clazz,
|
||||
final ContentItemInitializer<T> initializer,
|
||||
final Locale locale) {
|
||||
|
||||
return createContentItem(name,
|
||||
section,
|
||||
folder,
|
||||
null,
|
||||
clazz,
|
||||
initializer,
|
||||
locale);
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
protected <T extends ContentItem> T createContentItem(
|
||||
final String name,
|
||||
final ContentSection section,
|
||||
final Folder folder,
|
||||
final Workflow workflowTemplate,
|
||||
final Class<T> clazz,
|
||||
final ContentItemInitializer<T> initializer,
|
||||
final Locale locale) {
|
||||
|
||||
final ContentSection contentSection = sectionRepo
|
||||
.findById(section.getObjectId())
|
||||
.orElseThrow(() -> new IllegalArgumentException(String
|
||||
.format("No ContentSection with ID %d in the database.",
|
||||
section.getObjectId())));
|
||||
|
||||
final Folder itemFolder = folderRepo
|
||||
.findById(folder.getObjectId())
|
||||
.orElseThrow(() -> new IllegalArgumentException(String
|
||||
.format("No Folder with ID %d in the database.",
|
||||
folder.getObjectId())));
|
||||
|
||||
final T item;
|
||||
if (workflowTemplate == null) {
|
||||
|
||||
item = itemManager.createContentItem(name,
|
||||
contentSection,
|
||||
itemFolder,
|
||||
clazz,
|
||||
initializer,
|
||||
locale);
|
||||
|
||||
} else {
|
||||
final Workflow itemWorkflowTemplate = workflowRepo
|
||||
.findById(workflowTemplate.getWorkflowId())
|
||||
.orElseThrow(() -> new IllegalArgumentException(String
|
||||
.format("No WorkflowTemplate with ID %d in the database.",
|
||||
workflowTemplate.getWorkflowId())));
|
||||
|
||||
item = itemManager.createContentItem(name,
|
||||
contentSection,
|
||||
itemFolder,
|
||||
itemWorkflowTemplate,
|
||||
clazz,
|
||||
initializer,
|
||||
locale);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
protected Optional<Folder> getItemFolder(final ContentItem item) {
|
||||
|
||||
final Optional<ContentItem> contentItem = itemRepo
|
||||
.findById(item.getObjectId());
|
||||
|
||||
if (contentItem.isPresent()) {
|
||||
return itemManager.getItemFolder(contentItem.get());
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,220 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui.authoring;
|
||||
|
||||
import com.arsdigita.bebop.form.Widget;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.parameters.ArrayParameter;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
import com.arsdigita.bebop.parameters.BigDecimalParameter;
|
||||
import com.arsdigita.bebop.parameters.LongParameter;
|
||||
import com.arsdigita.xml.Element;
|
||||
import com.arsdigita.xml.XML;
|
||||
|
||||
import org.libreccm.categorization.Category;
|
||||
|
||||
import com.arsdigita.cms.CMS;
|
||||
import com.arsdigita.kernel.KernelConfig;
|
||||
|
||||
import org.librecms.CMSConfig;
|
||||
import org.libreccm.categorization.CategoryRepository;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import static javax.naming.ldap.SortControl.*;
|
||||
|
||||
public class CategoryWidget extends Widget {
|
||||
|
||||
private LongParameter rootParameter;
|
||||
private StringParameter modeParameter;
|
||||
|
||||
public CategoryWidget(final String name,
|
||||
final LongParameter rootParameter,
|
||||
final StringParameter modeParameter) {
|
||||
|
||||
super(new ArrayParameter(new BigDecimalParameter(name)));
|
||||
|
||||
this.rootParameter = rootParameter;
|
||||
this.modeParameter = modeParameter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getType() {
|
||||
return "category";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCompound() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateWidget(final PageState state,
|
||||
final Element parent) {
|
||||
|
||||
Element widget = parent.newChildElement("cms:categoryWidget",
|
||||
CMS.CMS_XML_NS);
|
||||
exportAttributes(widget);
|
||||
|
||||
widget.addAttribute("mode", (String) state.getValue(modeParameter));
|
||||
widget.addAttribute("name", getName());
|
||||
|
||||
final Set<Long> selectedCategories = new HashSet<>();
|
||||
|
||||
final Long[] values = (Long[]) getValue(state);
|
||||
if (values != null) {
|
||||
selectedCategories.addAll(Arrays.asList(values));
|
||||
}
|
||||
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final CategoryRepository categoryRepo = cdiUtil
|
||||
.findBean(CategoryRepository.class);
|
||||
final Category rootCategory = categoryRepo
|
||||
.findById((Long) state.getValue(rootParameter))
|
||||
.orElseThrow(() -> new IllegalArgumentException(
|
||||
String.format(
|
||||
"No Category with ID %d in the database. "
|
||||
+ "Where did that ID come from?",
|
||||
state.getValue(rootParameter))));
|
||||
|
||||
final List<Category> categories = rootCategory.getSubCategories();
|
||||
|
||||
final Map children = new HashMap();
|
||||
// ToDo, I don't understand was is done here...
|
||||
// while (categories.next()) {
|
||||
// final Category cat = categories.getCategory();
|
||||
// final BigDecimal parentID = (BigDecimal) categories
|
||||
// .get("parents.id");
|
||||
//
|
||||
// List childList = (List) children.get(parentID);
|
||||
// if (childList == null) {
|
||||
// childList = new ArrayList();
|
||||
// children.put(parentID, childList);
|
||||
// }
|
||||
//
|
||||
// childList.add(
|
||||
// new CategorySortKeyPair(cat, (BigDecimal) categories.get(
|
||||
// "parents.link.sortKey")));
|
||||
// }
|
||||
|
||||
generateCategory(widget, null, rootCategory, null, selectedCategories,
|
||||
children);
|
||||
}
|
||||
|
||||
public void generateCategory(final Element parent,
|
||||
final String path,
|
||||
final Category category,
|
||||
final Long sortKey,
|
||||
final Set selected,
|
||||
final Map children) {
|
||||
|
||||
final Element element = new Element("cms:category",
|
||||
CMS.CMS_XML_NS);
|
||||
|
||||
element.addAttribute("id", XML.format(category.getObjectId()));
|
||||
element.addAttribute("name", category.getName());
|
||||
element.addAttribute("description",
|
||||
category
|
||||
.getDescription()
|
||||
.getValue(KernelConfig
|
||||
.getConfig()
|
||||
.getDefaultLocale()));
|
||||
if (selected.contains(category.getObjectId())) {
|
||||
element.addAttribute("isSelected", "1");
|
||||
} else {
|
||||
element.addAttribute("isSelected", "0");
|
||||
}
|
||||
if (category.isAbstractCategory()) {
|
||||
element.addAttribute("isAbstract", "1");
|
||||
} else {
|
||||
element.addAttribute("isAbstract", "0");
|
||||
}
|
||||
if (category.isEnabled()) {
|
||||
element.addAttribute("isEnabled", "1");
|
||||
} else {
|
||||
element.addAttribute("isEnabled", "0");
|
||||
}
|
||||
if (sortKey != null) {
|
||||
element.addAttribute("sortKey", sortKey.toString());
|
||||
}
|
||||
// sort order attribute added to every node in order that same xsl may
|
||||
// be used to transform xml fragments returned by ajax in the Aplaws
|
||||
// extension
|
||||
// element.addAttribute("order",
|
||||
// CMSConfig.getConfig().getCategoryTreeOrder());
|
||||
|
||||
String fullname = path == null ? "/" : path + " > " + category.getName();
|
||||
element.addAttribute("fullname", fullname);
|
||||
StringBuilder nodeID = new StringBuilder(parent.getAttribute("node-id"));
|
||||
if (nodeID.length() > 0) {
|
||||
nodeID.append("-");
|
||||
}
|
||||
nodeID.append(category.getObjectId());
|
||||
element.addAttribute("node-id", nodeID.toString());
|
||||
parent.addContent(element);
|
||||
|
||||
List c = (List) children.get(category.getObjectId());
|
||||
if (c != null) {
|
||||
Iterator i = c.iterator();
|
||||
while (i.hasNext()) {
|
||||
CategorySortKeyPair pair = (CategorySortKeyPair) i.next();
|
||||
Category child = pair.getCategory();
|
||||
Long childSortKey = pair.getSortKey();
|
||||
generateCategory(element,
|
||||
fullname,
|
||||
child,
|
||||
childSortKey,
|
||||
selected,
|
||||
children);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class CategorySortKeyPair {
|
||||
|
||||
private Category category;
|
||||
private Long sortKey;
|
||||
|
||||
public CategorySortKeyPair(final Category category,
|
||||
final Long sortKey) {
|
||||
this.category = category;
|
||||
this.sortKey = sortKey;
|
||||
}
|
||||
|
||||
public Category getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
public Long getSortKey() {
|
||||
return sortKey;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2017 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 com.arsdigita.cms.ui.authoring;
|
||||
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
import org.librecms.contentsection.ContentSectionRepository;
|
||||
import org.librecms.contentsection.Folder;
|
||||
import org.librecms.contentsection.FolderRepository;
|
||||
|
||||
import javax.enterprise.context.RequestScoped;
|
||||
import javax.inject.Inject;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
@RequestScoped
|
||||
class CreationSelectorController {
|
||||
|
||||
@Inject
|
||||
private FolderRepository folderRepo;
|
||||
|
||||
@Inject
|
||||
private ContentSectionRepository sectionRepo;
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
protected ContentSection getContentSectionForFolder(final Folder folder) {
|
||||
|
||||
final Folder theFolder = folderRepo
|
||||
.findById(folder.getObjectId())
|
||||
.orElseThrow(() -> new IllegalArgumentException(String.format(
|
||||
"No Folder with ID %d in the database. Where did that ID come from?",
|
||||
folder.getObjectId())));
|
||||
|
||||
final ContentSection section = theFolder.getSection();
|
||||
|
||||
return sectionRepo
|
||||
.findById(section.getObjectId())
|
||||
.orElseThrow(() -> new IllegalArgumentException(String.format(
|
||||
"No ContentSection with ID %d in the database.",
|
||||
section.getObjectId())));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2017 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 com.arsdigita.cms.ui.authoring;
|
||||
|
||||
import com.arsdigita.bebop.SimpleComponent;
|
||||
|
||||
/**
|
||||
* NOOP base implementation of category authoring step extension.
|
||||
* Summary component returned by #getSummary() is show on category summary page,
|
||||
* usually an ActionLink which activates the Form component returned by #getForm().
|
||||
*
|
||||
* @author Alan Pevec
|
||||
*/public class ItemCategoryExtension {
|
||||
|
||||
public SimpleComponent[] getSummary() {
|
||||
return new SimpleComponent[0];
|
||||
}
|
||||
|
||||
public SimpleComponent[] getForm() {
|
||||
return new SimpleComponent[0];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui.authoring;
|
||||
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.form.Option;
|
||||
import com.arsdigita.bebop.form.SingleSelect;
|
||||
import com.arsdigita.bebop.parameters.ParameterModel;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
import org.librecms.util.LanguageUtil;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.util.Pair;
|
||||
|
||||
import java.util.List;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
|
||||
/**
|
||||
* Language picker for the multilingual content items.
|
||||
*/
|
||||
public class LanguageWidget extends SingleSelect {
|
||||
|
||||
public LanguageWidget(String name) {
|
||||
this(new StringParameter(name));
|
||||
}
|
||||
|
||||
public LanguageWidget(ParameterModel model) {
|
||||
super(model);
|
||||
setupOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds list of languages. Default version shows all supported languages for
|
||||
* this CMS installation, as defined in the enterprise.init:
|
||||
* com.arsdigita.cms.installer.Initializer: languages
|
||||
*/
|
||||
protected void setupOptions() {
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final LanguageUtil languageUtil = cdiUtil.findBean(LanguageUtil.class);
|
||||
final List<Pair> languages = languageUtil.convertToG11N(languageUtil.
|
||||
getSupportedLanguages2LA());
|
||||
for(final Pair pair : languages) {
|
||||
final String langCode = (String) pair.getKey();
|
||||
final GlobalizedMessage langName = (GlobalizedMessage) pair.getValue();
|
||||
|
||||
addOption(new Option(langCode, new Label(langName)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,282 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2021 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 com.arsdigita.cms.ui.authoring;
|
||||
|
||||
import com.arsdigita.bebop.BoxPanel;
|
||||
import com.arsdigita.bebop.Form;
|
||||
import com.arsdigita.bebop.FormData;
|
||||
import com.arsdigita.bebop.FormProcessException;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.RequestLocal;
|
||||
import com.arsdigita.bebop.SaveCancelSection;
|
||||
import com.arsdigita.bebop.event.FormProcessListener;
|
||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||
import com.arsdigita.bebop.event.FormValidationListener;
|
||||
import com.arsdigita.bebop.form.FormErrorDisplay;
|
||||
import com.arsdigita.bebop.parameters.NotNullValidationListener;
|
||||
import com.arsdigita.cms.ItemSelectionModel;
|
||||
import com.arsdigita.cms.ui.FileUploadSection;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
|
||||
import org.libreccm.l10n.LocalizedString;
|
||||
import org.librecms.CmsConstants;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import javax.activation.MimeType;
|
||||
|
||||
/**
|
||||
* A form for editing TextAsset items. Displays a "file upload" widget,
|
||||
* auto-guesses mime type
|
||||
*/
|
||||
class PageFileForm extends Form implements FormProcessListener,
|
||||
FormValidationListener {
|
||||
|
||||
private final TextBody textBody;
|
||||
|
||||
private SaveCancelSection saveCancelSection;
|
||||
private FileUploadSection fileUploadSection;
|
||||
// Variables saved by validate for processing
|
||||
private RequestLocal fileUploadContent;
|
||||
private RequestLocal fileUploadUsedINSO;
|
||||
/**
|
||||
* The text entry widget
|
||||
*/
|
||||
public static final String TEXT_ENTRY = "text_entry";
|
||||
|
||||
/**
|
||||
* Construct a new PageFileForm
|
||||
*
|
||||
* @param itemSelectionModel
|
||||
*/
|
||||
public PageFileForm(final TextBody textBody) {
|
||||
|
||||
super("PageFileUpload", new BoxPanel(BoxPanel.VERTICAL));
|
||||
|
||||
this.textBody = textBody;
|
||||
|
||||
setMethod(Form.POST);
|
||||
setEncType("multipart/form-data");
|
||||
|
||||
addWidgets();
|
||||
}
|
||||
|
||||
private void addWidgets() {
|
||||
|
||||
fileUploadSection = new FileUploadSection(
|
||||
new GlobalizedMessage("cms.ui.authoring.text.mime_type"),
|
||||
"text",
|
||||
textBody.getDefaultMimeType());
|
||||
|
||||
fileUploadSection
|
||||
.getFileUploadWidget()
|
||||
.addValidationListener(new NotNullValidationListener());
|
||||
fileUploadSection
|
||||
.getMimeTypeWidget()
|
||||
.setDefaultValue(FileUploadSection.GUESS_MIME);
|
||||
add(fileUploadSection);
|
||||
|
||||
saveCancelSection = new SaveCancelSection();
|
||||
add(saveCancelSection);
|
||||
|
||||
final FormErrorDisplay errorDisplay = new FormErrorDisplay(this);
|
||||
add(errorDisplay);
|
||||
|
||||
addValidationListener(this);
|
||||
addProcessListener(this);
|
||||
|
||||
fileUploadContent = new RequestLocal();
|
||||
fileUploadUsedINSO = new RequestLocal();
|
||||
|
||||
}
|
||||
|
||||
protected String getFileUploadContent(PageState state) {
|
||||
return (String) fileUploadContent.get(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that files of this type can be uploaded
|
||||
*/
|
||||
private void validateFileType(final MimeType mime, final boolean textType)
|
||||
throws FormProcessException {
|
||||
// boolean validType = textType || ((mime instanceof TextMimeType)
|
||||
// && ((TextMimeType) mime).
|
||||
// allowINSOConvert().booleanValue());
|
||||
boolean validType = true; //ToDo
|
||||
if (!validType) {
|
||||
throw new FormProcessException(new GlobalizedMessage(
|
||||
"cms.ui.authoring.invalid_file_type",
|
||||
CmsConstants.CMS_BUNDLE));
|
||||
}
|
||||
// boolean insoWorks = MimeTypeStatus.getMimeTypeStatus().
|
||||
// getInsoFilterWorks().intValue() == 1;
|
||||
boolean insoWorks = true; //ToDo
|
||||
if (!textType && !insoWorks) {
|
||||
// Can't convert. inso filter is not working. Give message.
|
||||
throw new FormProcessException(new GlobalizedMessage(
|
||||
"cms.ui.authoring.couldnt_convert_missing_inso",
|
||||
CmsConstants.CMS_BUNDLE));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read in the content of the file (in bytes).
|
||||
*/
|
||||
private byte[] readFileBytes(final File file) throws FormProcessException {
|
||||
byte[] fileBytes;
|
||||
try (final FileInputStream fs = new FileInputStream(file)) {
|
||||
fileBytes = new byte[fs.available()];
|
||||
fs.read(fileBytes);
|
||||
} catch (IOException ex) {
|
||||
throw new FormProcessException(new GlobalizedMessage(
|
||||
"cms.ui.authoring.unable_to_load_file",
|
||||
CmsConstants.CMS_BUNDLE));
|
||||
}
|
||||
return fileBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert bytes to String, possibly using INSO filter to convert to HTML
|
||||
* type
|
||||
*/
|
||||
private String convertBytes(final byte[] fileBytes, final boolean textType,
|
||||
final boolean[] usedInso) throws
|
||||
FormProcessException {
|
||||
String fileContent;
|
||||
// If mime type is not text type, try to convert to html
|
||||
if (!textType) {
|
||||
fileContent = new String(fileBytes);
|
||||
if (fileContent != null) {
|
||||
// Converted successfully, flag type should be html
|
||||
usedInso[0] = true;
|
||||
} else {
|
||||
throw new FormProcessException(new GlobalizedMessage(
|
||||
"cms.ui.authoring.couldnt_convert_inso_failed",
|
||||
CmsConstants.CMS_BUNDLE));
|
||||
}
|
||||
} else {
|
||||
// Text type, no need to convert
|
||||
final String enc = "UTF-8";
|
||||
try {
|
||||
fileContent = new String(fileBytes, enc);
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
throw new UncheckedWrapperException(
|
||||
"cannot convert to encoding " + enc, ex);
|
||||
}
|
||||
usedInso[0] = false;
|
||||
}
|
||||
return fileContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the contents of the HTML Body tag. (Done to prevent base and
|
||||
* other header tags from interfering with page display).
|
||||
*/
|
||||
private String extractHTMLBody(final String htmlText) throws
|
||||
FormProcessException {
|
||||
final String lowerCase = htmlText.toLowerCase();
|
||||
int bodyStart = lowerCase.indexOf("<body");
|
||||
int bodyStart_v = lowerCase.indexOf(">", bodyStart);
|
||||
int bodyEnd = lowerCase.indexOf("</body>", bodyStart_v);
|
||||
if (bodyStart == -1 || bodyEnd == -1) {
|
||||
throw new FormProcessException(new GlobalizedMessage(
|
||||
"cms.ui.authoring.html_file_missing_body_tags",
|
||||
CmsConstants.CMS_BUNDLE));
|
||||
}
|
||||
return htmlText.substring(bodyStart_v + 1, bodyEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate file upload
|
||||
*
|
||||
* @throws com.arsdigita.bebop.FormProcessException
|
||||
*/
|
||||
@Override
|
||||
public void validate(final FormSectionEvent event) throws
|
||||
FormProcessException {
|
||||
MimeType mime = fileUploadSection.getMimeType(event);
|
||||
// boolean textType = mime.getPrefix().equals(TextMimeType.TEXT_PREFIX);
|
||||
final boolean textType = true; //ToDo
|
||||
validateFileType(mime, textType);
|
||||
// Convert the file to HTML, if possible
|
||||
File file = fileUploadSection.getFile(event);
|
||||
byte[] file_bytes = readFileBytes(file);
|
||||
boolean[] usedInso = new boolean[1];
|
||||
String file_content = convertBytes(file_bytes, textType, usedInso);
|
||||
// ToDo if (TextMimeType.MIME_TEXT_HTML.equals(mime.getMimeType())) {
|
||||
file_content = extractHTMLBody(file_content);
|
||||
// }
|
||||
final PageState state = event.getPageState();
|
||||
fileUploadContent.set(state, file_content);
|
||||
fileUploadUsedINSO.set(state, usedInso[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process file upload. Must be validated first.
|
||||
*/
|
||||
@Override
|
||||
public void process(final FormSectionEvent event)
|
||||
throws FormProcessException {
|
||||
|
||||
final FormData data = event.getFormData();
|
||||
final PageState state = event.getPageState();
|
||||
// Get the text asset or create a new one
|
||||
final String text = textBody.getText(state);
|
||||
final File file = fileUploadSection.getFile(event);
|
||||
// Get info created during validation
|
||||
final String uploadContent = (String) fileUploadContent.get(state);
|
||||
boolean usedINSO = (Boolean) fileUploadUsedINSO.get(state);
|
||||
// Set the mime type
|
||||
// final MimeType mime = fileUploadSection.getMimeType(event);
|
||||
// if (usedINSO) {
|
||||
// mime = MimeType.loadMimeType("text/html");
|
||||
// }
|
||||
// if (mime != null) {
|
||||
// text.setMimeType(mime);
|
||||
// }
|
||||
// Save the uploaded content
|
||||
//ToDo text.setText(uploadContent);
|
||||
//t.setName(fileName); // ???
|
||||
// file = null;
|
||||
// Save everything
|
||||
textBody.updateText(state, text);
|
||||
// if (text.isNew() || text.isModified()) {
|
||||
// text.save();
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the save/cancel section for this form
|
||||
*/
|
||||
public SaveCancelSection getSaveCancelSection() {
|
||||
return saveCancelSection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the save/cancel section for this form
|
||||
*/
|
||||
public FileUploadSection getFileUploadSection() {
|
||||
return fileUploadSection;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,190 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2021 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 com.arsdigita.cms.ui.authoring;
|
||||
|
||||
import com.arsdigita.bebop.ColumnPanel;
|
||||
import com.arsdigita.bebop.Form;
|
||||
import com.arsdigita.bebop.FormData;
|
||||
import com.arsdigita.bebop.FormProcessException;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.SaveCancelSection;
|
||||
import com.arsdigita.bebop.event.FormInitListener;
|
||||
import com.arsdigita.bebop.event.FormProcessListener;
|
||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||
import com.arsdigita.bebop.event.FormSubmissionListener;
|
||||
import com.arsdigita.bebop.form.TextArea;
|
||||
import com.arsdigita.cms.ui.CMSDHTMLEditor;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
|
||||
import org.librecms.CMSConfig;
|
||||
import org.libreccm.l10n.LocalizedString;
|
||||
import org.librecms.CmsConstants;
|
||||
|
||||
/**
|
||||
* A form for editing the body of the text.
|
||||
*/
|
||||
public class PageTextForm
|
||||
extends Form
|
||||
implements FormInitListener,
|
||||
FormProcessListener,
|
||||
FormSubmissionListener {
|
||||
|
||||
private final TextBody textBody;
|
||||
|
||||
// private SingleSelect mimeWidget;
|
||||
// private Label mimeLabel;
|
||||
private TextArea textWidget;
|
||||
private SaveCancelSection saveCancelSection;
|
||||
/**
|
||||
* The text entry widget
|
||||
*/
|
||||
public static final String TEXT_ENTRY = "text_entry";
|
||||
/**
|
||||
* The mime type widget
|
||||
*/
|
||||
public static final String MIME_TYPE = "mime_type";
|
||||
|
||||
/**
|
||||
* Construct a new PageTextForm
|
||||
*
|
||||
*/
|
||||
public PageTextForm(final TextBody textBody) {
|
||||
|
||||
super("PageTextForm", new ColumnPanel(2));
|
||||
|
||||
this.textBody = textBody;
|
||||
|
||||
setMethod(Form.POST);
|
||||
setEncType("multipart/form-data");
|
||||
|
||||
addWidgets();
|
||||
}
|
||||
|
||||
private void addWidgets() {
|
||||
|
||||
final ColumnPanel panel = (ColumnPanel) getPanel();
|
||||
panel.setBorder(false);
|
||||
panel.setPadColor("#FFFFFF");
|
||||
panel.setColumnWidth(1, "20%");
|
||||
panel.setColumnWidth(2, "80%");
|
||||
panel.setWidth("100%");
|
||||
|
||||
add(new Label(new GlobalizedMessage(
|
||||
"cms.ui.authoring.edit_body_text",
|
||||
CmsConstants.CMS_BUNDLE)),
|
||||
ColumnPanel.LEFT | ColumnPanel.FULL_WIDTH);
|
||||
|
||||
textWidget = new CMSDHTMLEditor(PageTextForm.TEXT_ENTRY);
|
||||
textWidget.setRows(25);
|
||||
textWidget.setCols(40);
|
||||
// cg - sets editor size - closer to actual published page
|
||||
// width, and similar size as htmlarea.
|
||||
// could be configurable - unset means default 100% x 400px
|
||||
textWidget.setMetaDataAttribute("width", "575");
|
||||
textWidget.setMetaDataAttribute("height", "500");
|
||||
textWidget.setWrap(CMSDHTMLEditor.SOFT);
|
||||
add(textWidget, ColumnPanel.LEFT
|
||||
| ColumnPanel.FULL_WIDTH);
|
||||
|
||||
saveCancelSection = new SaveCancelSection();
|
||||
add(saveCancelSection, ColumnPanel.FULL_WIDTH);
|
||||
|
||||
// optionally, we clear the text of MSWord tags every time
|
||||
// the text is submitted/saved
|
||||
if (CMSConfig.getConfig().isSaveTextCleansWordTags()) {
|
||||
saveCancelSection.getSaveButton().setOnClick(
|
||||
"wordClean_"
|
||||
+ PageTextForm.TEXT_ENTRY
|
||||
+ "();");
|
||||
}
|
||||
|
||||
addInitListener(this);
|
||||
addProcessListener(this);
|
||||
|
||||
}
|
||||
|
||||
// These are here so that TemplateBody can set them.
|
||||
// public final void setMimeWidget(final SingleSelect widget) {
|
||||
// mimeWidget = widget;
|
||||
// }
|
||||
public final void setTextWidget(final TextArea widget) {
|
||||
textWidget = widget;
|
||||
}
|
||||
|
||||
public final void setSaveCancel(final SaveCancelSection widget) {
|
||||
saveCancelSection = widget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the text area with the current value.
|
||||
*
|
||||
* @param event
|
||||
*
|
||||
* @throws FormProcessException
|
||||
*/
|
||||
public void init(final FormSectionEvent event) throws FormProcessException {
|
||||
|
||||
final FormData data = event.getFormData();
|
||||
final PageState state = event.getPageState();
|
||||
|
||||
final String text = textBody.getText(state);
|
||||
|
||||
if (text != null) {
|
||||
data.put(TEXT_ENTRY, text);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels streamlined editing.
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
@Override
|
||||
public void submitted(final FormSectionEvent event) {
|
||||
|
||||
if (getSaveCancelSection()
|
||||
.getCancelButton()
|
||||
.isSelected(event.getPageState())) {
|
||||
|
||||
textBody.cancelStreamlinedCreation(event.getPageState());
|
||||
}
|
||||
}
|
||||
|
||||
// process: update the mime type and content
|
||||
@Override
|
||||
public void process(final FormSectionEvent event) throws
|
||||
FormProcessException {
|
||||
|
||||
final FormData data = event.getFormData();
|
||||
final PageState state = event.getPageState();
|
||||
final String text = (String) data.get(TEXT_ENTRY);
|
||||
textBody.updateText(state, text);
|
||||
|
||||
textBody.maybeForwardToNextStep(event.getPageState());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the save/cancel section for this form
|
||||
*/
|
||||
public SaveCancelSection getSaveCancelSection() {
|
||||
return saveCancelSection;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2017 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 com.arsdigita.cms.ui.authoring;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
import com.arsdigita.kernel.KernelConfig;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
public class SelectedLanguageUtil {
|
||||
|
||||
private SelectedLanguageUtil() {
|
||||
//Nothing
|
||||
}
|
||||
|
||||
public static final Locale selectedLocale(
|
||||
final PageState state,
|
||||
final StringParameter selectedLanguageParam) {
|
||||
|
||||
final String selectedLanguage = (String) state
|
||||
.getValue(selectedLanguageParam);
|
||||
if (selectedLanguage == null) {
|
||||
return KernelConfig.getConfig().getDefaultLocale();
|
||||
} else {
|
||||
return new Locale(selectedLanguage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui.authoring;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
|
||||
|
||||
import com.arsdigita.bebop.table.TableCellRenderer;
|
||||
import com.arsdigita.bebop.Table;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.Component;
|
||||
|
||||
import org.libreccm.l10n.LocalizedString;
|
||||
|
||||
// Renders strings as labels
|
||||
public class TextAssetBodyLabelCellRenderer implements TableCellRenderer {
|
||||
|
||||
@Override
|
||||
public Component getComponent(final Table table,
|
||||
final PageState state,
|
||||
final Object value,
|
||||
final boolean isSelected,
|
||||
final Object key,
|
||||
final int row,
|
||||
final int column) {
|
||||
|
||||
throw new UnsupportedOperationException("ToDo");
|
||||
|
||||
// final Label label;
|
||||
// if ("content".equals(key) && value instanceof LocalizedString) {
|
||||
// // We have different styles for different mime types
|
||||
// final LocalizedString asset = (LocalizedString )value;
|
||||
// label = new Label(asset.getText());
|
||||
// label.setIdAttr("webPage");
|
||||
// String type = asset.getMimeType().getMimeType()
|
||||
// .toLowerCase();
|
||||
// if (type.indexOf("text/xml") > -1 ||
|
||||
// type.indexOf("text/xsl") > -1 ||
|
||||
// type.indexOf("text/x-jsp") > -1) {
|
||||
// label.setClassAttr("preformatted");
|
||||
// label.setOutputEscaping(true);
|
||||
// } else {
|
||||
// label.setOutputEscaping(false);
|
||||
// }
|
||||
// } else if (MIME_TYPE_KEY.equals(key) && value instanceof TextAsset) {
|
||||
// label = new Label(((TextAsset)value).getMimeType().getLabel(),
|
||||
// false);
|
||||
// } else {
|
||||
// label = new Label(value.toString());
|
||||
// label.setOutputEscaping(false);
|
||||
// }
|
||||
//
|
||||
// return label;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,291 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui.authoring;
|
||||
|
||||
import com.arsdigita.bebop.Page;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.Resettable;
|
||||
import com.arsdigita.bebop.event.RequestEvent;
|
||||
import com.arsdigita.bebop.event.RequestListener;
|
||||
import com.arsdigita.bebop.form.SingleSelect;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
|
||||
import com.arsdigita.cms.ItemSelectionModel;
|
||||
import com.arsdigita.cms.ui.ContentItemPage;
|
||||
import com.arsdigita.cms.ui.FileUploadSection;
|
||||
import com.arsdigita.cms.ui.SecurityPropertyEditor;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.toolbox.ui.DomainObjectPropertySheet;
|
||||
|
||||
import org.librecms.CMSConfig;
|
||||
import org.libreccm.l10n.LocalizedString;
|
||||
import org.librecms.CmsConstants;
|
||||
|
||||
/**
|
||||
* Displays the mime-type and the body of a single {@code TextAsset}. Maintains
|
||||
* a form or uploading files into the text body of the asset, and a form for
|
||||
* editing the text of the asset.
|
||||
* <p>
|
||||
* Unlike most other authoring components, this component does not require the
|
||||
* asset to exist. If the asset does not exist (i.e., if
|
||||
* <code>!m_assetModel.isSelected(state)</code>), the upload and editing forms
|
||||
* will create a new asset and set it in the model by calling
|
||||
* <code>setSelectedObject</code> on the asset selection model. Child classes
|
||||
* should override the {@link #createTextAsset(PageState)} method in to create a
|
||||
* valid text asset.
|
||||
* <p>
|
||||
* This component is used primarily in {@link GenericArticleBody} and
|
||||
* {@link com.arsdigita.cms.ui.templates.TemplateBody}
|
||||
*
|
||||
* <b>Note: </b> In CCM NG (version 7 and newer) {@code TextAsset} does not
|
||||
* longer exist. Instead fields of type {@link LocalizedString} are used. This
|
||||
* class has been adapted to use {@link LocalizedString}. The name of the class
|
||||
* etc. has been kept to make the migration easier.
|
||||
*
|
||||
* @author Stanislav Freidin (sfreidin@arsdigita.com)
|
||||
* @version <a href="jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
public abstract class TextBody
|
||||
extends SecurityPropertyEditor
|
||||
implements Resettable, AuthoringStepComponent, RequestListener {
|
||||
|
||||
public static final String FILE_UPLOAD = "file";
|
||||
public static final String TEXT_ENTRY = "text";
|
||||
|
||||
private static final String STREAMLINED_DONE = "1";
|
||||
private static final CMSConfig CMS_CONFIG = CMSConfig.getConfig();
|
||||
|
||||
private final StringParameter streamlinedCreationParam;
|
||||
private final StringParameter selectedLanguageParam;
|
||||
private final ItemSelectionModel itemSelectionModel;
|
||||
|
||||
/**
|
||||
* Construct a new GenericArticleBody component
|
||||
*
|
||||
* @param assetModel The {@link ItemSelectionModel} which will be
|
||||
* responsible for maintaining the current
|
||||
* asset
|
||||
* @param selectedLanguageParam Parameter for the currently selected locale.
|
||||
*/
|
||||
public TextBody(final ItemSelectionModel assetModel,
|
||||
final StringParameter selectedLanguageParam) {
|
||||
|
||||
this(assetModel, null, selectedLanguageParam);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new GenericArticleBody component
|
||||
*
|
||||
* @param itemSelectionModel The {@link ItemSelectionModel} which will be
|
||||
* responsible for maintaining the current asset
|
||||
* @param authoringKitWizard The parent wizard which contains the form.
|
||||
* The form may use the wizard's methods, such
|
||||
* as stepForward and stepBack, in its process
|
||||
* listener.
|
||||
* @param selectedLangugeParam Parameter for the currently selected locale.
|
||||
*/
|
||||
public TextBody(final ItemSelectionModel itemSelectionModel,
|
||||
final AuthoringKitWizard authoringKitWizard,
|
||||
final StringParameter selectedLangugeParam) {
|
||||
|
||||
super();
|
||||
this.itemSelectionModel = itemSelectionModel;
|
||||
|
||||
if (authoringKitWizard == null) {
|
||||
streamlinedCreationParam = new StringParameter("item_body_done");
|
||||
} else {
|
||||
streamlinedCreationParam = new StringParameter(
|
||||
String.format("%s_body_done",
|
||||
authoringKitWizard
|
||||
.getContentType()
|
||||
.getContentItemClass()
|
||||
.getName()));
|
||||
}
|
||||
|
||||
this.selectedLanguageParam = selectedLangugeParam;
|
||||
|
||||
if (!CMS_CONFIG.isHideTextAssetUploadFile()) {
|
||||
final PageFileForm pageFileForm = getPageFileForm();
|
||||
add(FILE_UPLOAD,
|
||||
new GlobalizedMessage("cms.ui.upload", CmsConstants.CMS_BUNDLE),
|
||||
pageFileForm,
|
||||
pageFileForm.getSaveCancelSection().getCancelButton());
|
||||
}
|
||||
|
||||
final PageTextForm pageTextForm = new PageTextForm(this);
|
||||
add(TEXT_ENTRY,
|
||||
new GlobalizedMessage("cms.ui.edit", CmsConstants.CMS_BUNDLE),
|
||||
pageTextForm,
|
||||
pageTextForm.getSaveCancelSection().getCancelButton());
|
||||
|
||||
// Specify full path to properties of the text asset
|
||||
final DomainObjectPropertySheet sheet = getTextBodyPropertySheet(
|
||||
itemSelectionModel);
|
||||
sheet.add(new GlobalizedMessage("cms.ui.article.text",
|
||||
CmsConstants.CMS_BUNDLE),
|
||||
getTextPropertyName());
|
||||
|
||||
setDisplayComponent(sheet);
|
||||
|
||||
getDisplayPane().setClassAttr("invertedPropertyDisplay");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the name of the property holding the text.
|
||||
*
|
||||
* @return The name of the property holding the text.
|
||||
*/
|
||||
protected abstract String getTextPropertyName();
|
||||
|
||||
protected DomainObjectPropertySheet getTextBodyPropertySheet(
|
||||
final ItemSelectionModel itemSelectionModel) {
|
||||
|
||||
final DomainObjectPropertySheet sheet = new DomainObjectPropertySheet(
|
||||
itemSelectionModel);
|
||||
|
||||
return sheet;
|
||||
|
||||
// return new TextBodyPropertySheet(itemSelectionModel,
|
||||
// selectedLanguageParam);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the options for the mime type select widget of
|
||||
* <code>GenericArticleForm</code> and sets the default mime type.
|
||||
*
|
||||
* @param mimeSelect
|
||||
*/
|
||||
protected void setMimeTypeOptions(final SingleSelect mimeSelect) {
|
||||
FileUploadSection.addMimeOptions(mimeSelect, "text");
|
||||
mimeSelect.setOptionSelected("text/html");
|
||||
}
|
||||
|
||||
/**
|
||||
* To be overwritten by subclasses, should return the text for the currently
|
||||
* selected locale.
|
||||
*
|
||||
* @param state The current page state
|
||||
*
|
||||
* @return The text of the currently selected locale.
|
||||
*/
|
||||
public abstract String getText(final PageState state);
|
||||
|
||||
/**
|
||||
* Reset this component to its original state
|
||||
*
|
||||
* @param state the current page state
|
||||
*/
|
||||
@Override
|
||||
public void reset(final PageState state) {
|
||||
showDisplayPane(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the text for the currently selected locale.
|
||||
*
|
||||
* @param state the current page state
|
||||
* @param text the new next text for the currently selected locale.
|
||||
*/
|
||||
protected abstract void updateText(PageState state, String text);
|
||||
|
||||
/**
|
||||
* Return the <code>ItemSelectionModel</code> which will be used to maintain
|
||||
* the current text asset
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ItemSelectionModel getItemSelectionModel() {
|
||||
return itemSelectionModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward to the next step if the streamlined creation parameter is turned
|
||||
* on _and_ the streamlined_creation global state parameter is set to
|
||||
* 'active'
|
||||
*
|
||||
* @param state the PageState
|
||||
*/
|
||||
protected void maybeForwardToNextStep(final PageState state) {
|
||||
if (ContentItemPage.isStreamlinedCreationActive(state)
|
||||
&& !STREAMLINED_DONE.
|
||||
equals(state.getValue(streamlinedCreationParam))) {
|
||||
state.setValue(streamlinedCreationParam, STREAMLINED_DONE);
|
||||
fireCompletionEvent(state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel streamlined creation for this step if the streamlined creation
|
||||
* parameter is turned on _and_ the streamlined_creation global state param
|
||||
* is set to 'active'
|
||||
*
|
||||
* @param state the PageState
|
||||
*/
|
||||
protected void cancelStreamlinedCreation(final PageState state) {
|
||||
if (ContentItemPage.isStreamlinedCreationActive(state)) {
|
||||
state.setValue(streamlinedCreationParam, STREAMLINED_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the edit component if the streamlined creation parameter is turned
|
||||
* on _and_ the streamlined_creation global state param is set to 'active'
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
@Override
|
||||
public void pageRequested(final RequestEvent event) {
|
||||
|
||||
final PageState state = event.getPageState();
|
||||
|
||||
if (ContentItemPage.isStreamlinedCreationActive(state)
|
||||
&& !STREAMLINED_DONE.
|
||||
equals(state.getValue(streamlinedCreationParam))) {
|
||||
showComponent(state, TEXT_ENTRY);
|
||||
}
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the form that is used to upload files. This method can be used so
|
||||
* that a subclass can use their own subclass of PageFileForm.
|
||||
*
|
||||
* @return The form for uploading a text.
|
||||
*/
|
||||
protected PageFileForm getPageFileForm() {
|
||||
return new PageFileForm(this);
|
||||
}
|
||||
|
||||
protected String getDefaultMimeType() {
|
||||
return "text/plain";
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers global state parameter for cancelling streamlined creation
|
||||
*/
|
||||
@Override
|
||||
public void register(final Page page) {
|
||||
super.register(page);
|
||||
page.addGlobalStateParam(streamlinedCreationParam);
|
||||
page.addRequestListener(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,160 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui.authoring;
|
||||
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.Resettable;
|
||||
import com.arsdigita.bebop.SingleSelectionModel;
|
||||
import com.arsdigita.bebop.parameters.LongParameter;
|
||||
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contentsection.ContentType;
|
||||
|
||||
import com.arsdigita.cms.ItemSelectionModel;
|
||||
import com.arsdigita.kernel.ui.ACSObjectSelectionModel;
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
import com.arsdigita.xml.Element;
|
||||
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.librecms.contenttypes.AuthoringKitInfo;
|
||||
import org.librecms.contenttypes.ContentTypeInfo;
|
||||
|
||||
|
||||
/**
|
||||
* An invisible component which contains all the possible authoring kits. The
|
||||
* kits are loaded from the database at construction time. The selector chooses
|
||||
* which kit to display at page rendering time based on the value of the
|
||||
* content_type state parameter.
|
||||
*
|
||||
* Essentially, this component is a hack which is used to get around the fact
|
||||
* that we cannot instantiate stateful components dynamically.
|
||||
*
|
||||
* @author unknown
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
public class WizardSelector extends AuthoringKitSelector
|
||||
implements Resettable {
|
||||
|
||||
private final ItemSelectionModel itemSelectionModel;
|
||||
|
||||
/**
|
||||
* Construct a new WizardSelector. Load all the possible authoring kits from
|
||||
* the database and construct wizards for them.
|
||||
*
|
||||
* @param model the {@link ItemSelectionModel} which will supply the
|
||||
* wizard with its item
|
||||
*
|
||||
* @param typeModel the {@link ACSObjectSelectionModel} which will supply
|
||||
* the default content type
|
||||
*
|
||||
* @pre itemModel != null
|
||||
*/
|
||||
public WizardSelector(final ItemSelectionModel model,
|
||||
final SingleSelectionModel<String> typeModel) {
|
||||
super(typeModel);
|
||||
itemSelectionModel = model;
|
||||
super.processKit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the wizard for the given kit.
|
||||
*
|
||||
* @param kit
|
||||
* @param type
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Component instantiateKitComponent(final AuthoringKitInfo kit,
|
||||
final ContentTypeInfo type) {
|
||||
|
||||
final ItemSelectionModel itemModel = new ItemSelectionModel(
|
||||
type, (LongParameter) itemSelectionModel.getStateParameter());
|
||||
|
||||
final AuthoringKitWizard wizard
|
||||
= new AuthoringKitWizard(type, itemModel);
|
||||
return wizard;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The item selection model used by this wizard
|
||||
*/
|
||||
public ItemSelectionModel getSelectionModel() {
|
||||
return itemSelectionModel;
|
||||
}
|
||||
|
||||
// Determine the current wizard
|
||||
private Component getCurrentWizard(PageState state) {
|
||||
|
||||
// Get the current item and extract its content type
|
||||
if (!itemSelectionModel.isSelected(state)) {
|
||||
throw new UncheckedWrapperException("No item selected.");
|
||||
}
|
||||
|
||||
final ContentItem item = itemSelectionModel.getSelectedObject(state);
|
||||
|
||||
// final ContentType type = item.getContentType();
|
||||
// final String typeClass;
|
||||
//
|
||||
// if (type == null) {
|
||||
// // Try to get the default content type
|
||||
// typeClass = getComponentSelectionModel().getSelectedKey(state);
|
||||
// if (typeClass == null || typeClass.isEmpty()) {
|
||||
// throw new UncheckedWrapperException("Content type is missing");
|
||||
// }
|
||||
// } else {
|
||||
// typeClass = type.getContentItemClass();
|
||||
// }
|
||||
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final WizardSelectorController controller = cdiUtil
|
||||
.findBean(WizardSelectorController.class);
|
||||
|
||||
final String typeClass = controller.getTypeClass(item);
|
||||
|
||||
// Return the selected wizard
|
||||
return getComponent(typeClass);
|
||||
}
|
||||
|
||||
// Choose the right wizard and run it
|
||||
@Override
|
||||
public void generateXML(final PageState state, final Element parent) {
|
||||
|
||||
final Component component = getCurrentWizard(state);
|
||||
|
||||
if (component == null) {
|
||||
throw new UncheckedWrapperException("No Wizard.");
|
||||
}
|
||||
|
||||
component.generateXML(state, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the state of the current wizard
|
||||
*/
|
||||
@Override
|
||||
public void reset(final PageState state) {
|
||||
final Resettable resettable = (Resettable) getCurrentWizard(state);
|
||||
if (resettable != null) {
|
||||
resettable.reset(state);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2017 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 com.arsdigita.cms.ui.authoring;
|
||||
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contentsection.ContentItemRepository;
|
||||
import org.librecms.contentsection.ContentType;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.enterprise.context.RequestScoped;
|
||||
import javax.inject.Inject;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
@RequestScoped
|
||||
public class WizardSelectorController {
|
||||
|
||||
@Inject
|
||||
private ContentItemRepository itemRepo;
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public String getTypeClass(final ContentItem item) {
|
||||
|
||||
Objects.requireNonNull(item);
|
||||
|
||||
final ContentItem contentItem = itemRepo
|
||||
.findById(item.getObjectId())
|
||||
.orElseThrow(() -> new IllegalArgumentException(String
|
||||
.format("No ContentItem with ID %d in the database.",
|
||||
item.getObjectId())));
|
||||
|
||||
final ContentType type = contentItem.getContentType();
|
||||
|
||||
return type.getContentItemClass();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -19,15 +19,12 @@
|
|||
package org.librecms;
|
||||
|
||||
import com.arsdigita.bebop.form.DHTMLEditor;
|
||||
import com.arsdigita.cms.ui.authoring.ItemCategoryExtension;
|
||||
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.configuration.Configuration;
|
||||
import org.libreccm.configuration.ConfigurationManager;
|
||||
import org.libreccm.configuration.Setting;
|
||||
import org.libreccm.core.UnexpectedErrorException;
|
||||
import org.librecms.dispatcher.ItemResolver;
|
||||
import org.librecms.dispatcher.SimpleItemResolver;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
|
@ -406,21 +403,6 @@ public class CMSConfig {
|
|||
private String contentCenterMap
|
||||
= "/WEB-INF/resources/content-center-map.xml";
|
||||
|
||||
@Setting(
|
||||
descKey = "defaultItemResolverClassNames.desc",
|
||||
labelKey = "defaultItemResolverClassNames.label"
|
||||
)
|
||||
private List<String> defaultItemResolverClassNames = Arrays.asList(
|
||||
new String[]{
|
||||
SimpleItemResolver.class.getName()
|
||||
});
|
||||
|
||||
// @Setting
|
||||
// private List<String> defaultTemplateResolverClassNames = Arrays.asList(
|
||||
// new String[]{
|
||||
// DefaultTemplateResolver.class.getName(),
|
||||
// TemplateResolver.class.getName()
|
||||
// });
|
||||
@Setting(
|
||||
descKey = "itemSearchDefaultTab.desc",
|
||||
labelKey = "itemSearchDefaultTab.label"
|
||||
|
|
@ -553,13 +535,6 @@ public class CMSConfig {
|
|||
)
|
||||
private int xmlCacheAge = 60 * 60 * 24;
|
||||
|
||||
@Setting(
|
||||
descKey = "categoryAuthoringExtension.desc",
|
||||
labelKey = "categoryAuthoringExtension.label"
|
||||
)
|
||||
private String categoryAuthoringExtension = ItemCategoryExtension.class
|
||||
.getName();
|
||||
|
||||
@Setting(
|
||||
descKey = "categoryPickerAjaxExpandAll.desc",
|
||||
labelKey = "categoryPickerAjaxExpandAll.label"
|
||||
|
|
@ -887,55 +862,6 @@ public class CMSConfig {
|
|||
this.contentCenterMap = contentCenterMap;
|
||||
}
|
||||
|
||||
public List<String> getDefaultItemResolverClassNames() {
|
||||
return new ArrayList<>(defaultItemResolverClassNames);
|
||||
}
|
||||
|
||||
public void setDefaultItemResolverClassNames(
|
||||
final List<String> defaultItemResolverClassNames) {
|
||||
this.defaultItemResolverClassNames
|
||||
= new ArrayList<>(defaultItemResolverClassNames);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Class<ItemResolver>> getDefaultItemResolverClasses() {
|
||||
final List<Class<ItemResolver>> resolverClasses = new ArrayList<>();
|
||||
for (final String className : getDefaultItemResolverClassNames()) {
|
||||
try {
|
||||
resolverClasses.add((Class<ItemResolver>) Class.forName(
|
||||
className));
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new UnexpectedErrorException(String.format(
|
||||
"ItemResolver class \"%s\" not found.", className), ex);
|
||||
}
|
||||
}
|
||||
return resolverClasses;
|
||||
}
|
||||
|
||||
// public List<String> getDefaultTemplateResolverClassNames() {
|
||||
// return new ArrayList<>(defaultTemplateResolverClassNames);
|
||||
// }
|
||||
//
|
||||
// public void setDefaultTemplateResolverClassNames(
|
||||
// List<String> defaultTemplateResolverClassNames) {
|
||||
// this.defaultTemplateResolverClassNames = new ArrayList<>(
|
||||
// defaultTemplateResolverClassNames);
|
||||
// }
|
||||
//
|
||||
// @SuppressWarnings("unchecked")
|
||||
// public List<Class<TemplateResolver>> getDefaultTemplateResolverClasses() {
|
||||
// final List<Class<TemplateResolver>> resolverClasses = new ArrayList<>();
|
||||
// for (final String className : getDefaultTemplateResolverClassNames()) {
|
||||
// try {
|
||||
// resolverClasses.add((Class<TemplateResolver>) Class.forName(
|
||||
// className));
|
||||
// } catch (ClassNotFoundException ex) {
|
||||
// throw new UnexpectedErrorException(String.format(
|
||||
// "ItemResolver class \"%s\" not found.", className), ex);
|
||||
// }
|
||||
// }
|
||||
// return resolverClasses;
|
||||
// }
|
||||
public String getItemSearchDefaultTab() {
|
||||
return itemSearchDefaultTab;
|
||||
}
|
||||
|
|
@ -1129,15 +1055,6 @@ public class CMSConfig {
|
|||
this.linkDescMaxLength = linkDescMaxLength;
|
||||
}
|
||||
|
||||
public String getCategoryAuthoringExtension() {
|
||||
return categoryAuthoringExtension;
|
||||
}
|
||||
|
||||
public void setCategoryAuthoringExtension(
|
||||
final String categoryAuthoringExtension) {
|
||||
this.categoryAuthoringExtension = categoryAuthoringExtension;
|
||||
}
|
||||
|
||||
public boolean isCategoryPickerAjaxExpandAll() {
|
||||
return categoryPickerAjaxExpandAll;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ import org.librecms.lifecycle.LifecycleDefinition;
|
|||
import java.util.Optional;
|
||||
|
||||
import org.librecms.contentsection.privileges.TypePrivileges;
|
||||
import org.librecms.dispatcher.ItemResolver;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
|
|
@ -97,9 +96,6 @@ public class ContentSectionManager {
|
|||
@Inject
|
||||
private ConfigurationManager confManager;
|
||||
|
||||
@Inject
|
||||
private Instance<ItemResolver> itemResolvers;
|
||||
|
||||
/**
|
||||
* Creates a new content section including the default roles. This operation
|
||||
* requries {@code admin} privileges.
|
||||
|
|
@ -458,36 +454,6 @@ public class ContentSectionManager {
|
|||
sectionRepo.save(section);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the {@link ItemResolver} for the provided content section.
|
||||
*
|
||||
* @param section The section for which the {@link ItemResolver} is
|
||||
* retrieved.
|
||||
*
|
||||
* @return The {@link ItemResolver} for the provided content section.
|
||||
*/
|
||||
public ItemResolver getItemResolver(final ContentSection section) {
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
final Class<ItemResolver> itemResolverClazz
|
||||
= (Class<ItemResolver>) Class.
|
||||
forName(section.getItemResolverClass());
|
||||
|
||||
final Instance<ItemResolver> instance = itemResolvers.select(
|
||||
itemResolverClazz);
|
||||
|
||||
if (instance.isUnsatisfied()) {
|
||||
throw new UnexpectedErrorException(String.format(
|
||||
"No ItemResolver \"{}\" found.",
|
||||
itemResolverClazz.getName()));
|
||||
} else {
|
||||
return instance.get();
|
||||
}
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new UnexpectedErrorException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new {@link ContentType} to a content section, making items of that
|
||||
* type available in the content section. This operation requires
|
||||
|
|
|
|||
|
|
@ -1,660 +0,0 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import com.arsdigita.bebop.Page;
|
||||
import com.arsdigita.cms.dispatcher.CMSPage;
|
||||
import com.arsdigita.cms.dispatcher.ContentItemDispatcher;
|
||||
import com.arsdigita.dispatcher.AccessDeniedException;
|
||||
import com.arsdigita.dispatcher.DispatcherHelper;
|
||||
import com.arsdigita.dispatcher.RequestContext;
|
||||
import com.arsdigita.templating.PresentationManager;
|
||||
import com.arsdigita.templating.Templating;
|
||||
import com.arsdigita.util.Assert;
|
||||
import com.arsdigita.util.Classes;
|
||||
import com.arsdigita.web.ApplicationFileResolver;
|
||||
import com.arsdigita.web.BaseApplicationServlet;
|
||||
import com.arsdigita.web.LoginSignal;
|
||||
import com.arsdigita.web.Web;
|
||||
import com.arsdigita.web.WebConfig;
|
||||
import com.arsdigita.xml.Document;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.librecms.CMSConfig;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.l10n.GlobalizationHelper;
|
||||
import org.libreccm.security.PermissionChecker;
|
||||
import org.libreccm.security.Shiro;
|
||||
import org.libreccm.web.CcmApplication;
|
||||
import org.librecms.CmsConstants;
|
||||
import org.librecms.contentsection.privileges.ItemPrivileges;
|
||||
import org.librecms.dispatcher.ItemResolver;
|
||||
import org.librecms.lifecycle.Lifecycle;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.servlet.RequestDispatcher;
|
||||
|
||||
/*
|
||||
* This servlet will maybe removed. Our current plan is to integrate the navigation
|
||||
* application into ccm-cms, and to deliver all content using that app. Then
|
||||
* this servlet becomes useless.
|
||||
*/
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
* Repaired ItemURLCache to save multilingual items with automatic
|
||||
* language negotiation. The cache now uses the remaining url part
|
||||
* and the language concatinated as a hash table key. The delimiter
|
||||
* is CACHE_KEY_DELIMITER.
|
||||
*/
|
||||
|
||||
/*
|
||||
* NOTE 2:
|
||||
* In a process of refactoring from legacy compatible to legacy free applications.
|
||||
* TODO:
|
||||
* - replace url check using RequestContext which resolves to SiteNodeRequest
|
||||
* implementation (due to SiteNodeRequest used in BaseApplicationServlet).
|
||||
* - Refactor content item UI bebop ApplicationPage or PageFactory instead of
|
||||
* legacy infected sitenode / package dispatchers.
|
||||
*/
|
||||
/**
|
||||
* Content Section's Application Servlet according CCM core web application
|
||||
* structure {
|
||||
*
|
||||
* @see com.arsdigita.web.Application} implements the content section UI.
|
||||
*
|
||||
* It handles the UI for content items and delegates the UI for sections and
|
||||
* folders to jsp templates.
|
||||
*
|
||||
* @author unknown
|
||||
* @author <a href="mailto:pboy@barkhof.uni-bremen.de">Peter Boy</a>
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
@WebServlet(urlPatterns = {CmsConstants.CONTENT_SECTION_SERVLET_PATH,
|
||||
"/templates/servlet/content-section/",
|
||||
"/templates/servlet/content-section",
|
||||
CmsConstants.CMS_SERVICE_SERVLET_PATH,
|
||||
CmsConstants.CONTENT_ITEM_SERVLET_PATH})
|
||||
public class ContentSectionServlet extends BaseApplicationServlet {
|
||||
|
||||
private static final long serialVersionUID = 8061725145564728637L;
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(
|
||||
ContentSectionServlet.class);
|
||||
|
||||
/**
|
||||
* Literal for the prefix (in url) for previewing items
|
||||
*/
|
||||
public static final String PREVIEW = "/preview";
|
||||
/**
|
||||
* Literal Template files suffix
|
||||
*/
|
||||
public static final String FILE_SUFFIX = ".jsp";
|
||||
/**
|
||||
* Literal of URL Stub for index file name (includes leading slash)
|
||||
*/
|
||||
public static final String INDEX_FILE = "/index";
|
||||
public static final String XML_SUFFIX = ".xml";
|
||||
public static final String XML_MODE = "xmlMode";
|
||||
public static final String MEDIA_TYPE = "templateContext";
|
||||
private static final String CACHE_KEY_DELIMITER = "%";
|
||||
|
||||
public static final String CONTENT_ITEM
|
||||
= "com.arsdigita.cms.dispatcher.item";
|
||||
public static final String CONTENT_SECTION
|
||||
= "com.arsdigita.cms.dispatcher.section";
|
||||
|
||||
private final ContentItemDispatcher m_disp = new ContentItemDispatcher();
|
||||
// private static Map<String, ItemResolver> itemResolverCache = Collections
|
||||
// .synchronizedMap(new HashMap<>());
|
||||
private static Map s_itemURLCacheMap = null;
|
||||
/**
|
||||
* Whether to cache the content items
|
||||
*/
|
||||
// private static final boolean s_cacheItems = true;
|
||||
// NEW STUFF here used to process the pages in this servlet
|
||||
/**
|
||||
* URL (pathinfo) -> Page object mapping. Based on it (and the http request
|
||||
* url) the doService method selects a page to display
|
||||
*/
|
||||
private final Map m_pages = new HashMap();
|
||||
/**
|
||||
* Path to directory containg ccm-cms template (jsp) files
|
||||
*/
|
||||
private String m_templatePath;
|
||||
|
||||
/**
|
||||
* Resolver to actually use to find templates (JSP). JSP may be stored in
|
||||
* file system or otherwise, depends on resolver. Resolver is retrieved from
|
||||
* configuration. (probably used for other stuff as JSP's as well)
|
||||
*/
|
||||
private ApplicationFileResolver m_resolver;
|
||||
|
||||
@Inject
|
||||
private ContentSectionManager sectionManager;
|
||||
|
||||
/**
|
||||
* Init method overwrites parents init to pass in optional parameters
|
||||
* {@link com.arsdigita.web.BaseServlet}. If not specified system wide
|
||||
* defaults are used.
|
||||
*
|
||||
* @param config
|
||||
*
|
||||
* @throws javax.servlet.ServletException
|
||||
*/
|
||||
@Override
|
||||
public void init(ServletConfig config) throws ServletException {
|
||||
|
||||
super.init(config);
|
||||
|
||||
// optional init-param named template-path from ~/WEB-INF/web.xml
|
||||
// may overwrite configuration parameters
|
||||
String templatePath = config.getInitParameter("template-path");
|
||||
if (templatePath == null) {
|
||||
m_templatePath = CMSConfig.getConfig().getTemplateRootPath();
|
||||
} else {
|
||||
m_templatePath = config.getInitParameter("template-path");
|
||||
}
|
||||
|
||||
// optional init-param named file-resolver from ~/WEB-INF/web.xml
|
||||
String resolverName = config.getInitParameter("file-resolver");
|
||||
|
||||
if (resolverName == null) {
|
||||
m_resolver = WebConfig.getConfig().getResolver();
|
||||
} else {
|
||||
m_resolver = (ApplicationFileResolver) Classes.newInstance(
|
||||
resolverName);
|
||||
}
|
||||
LOGGER.debug("Template path is {} with resolver {}",
|
||||
m_templatePath,
|
||||
m_resolver.getClass().getName());
|
||||
|
||||
// NEW STUFF here will be used to process the pages in this servlet
|
||||
// Currently NOT working
|
||||
// addPage("/admin", new MainPage()); // index page at address ~/cs
|
||||
// addPage("/admin/index.jsp", new MainPage());
|
||||
// addPage("/admin/item.jsp", new MainPage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal service method, adds one pair of Url - Page to the internal hash
|
||||
* map, used as a cache.
|
||||
*
|
||||
* @param pathInfo url stub for a page to display
|
||||
* @param page Page object to display
|
||||
*/
|
||||
private void addPage(final String pathInfo, final Page page) {
|
||||
m_pages.put(pathInfo, page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of parent's (abstract) doService method checks HTTP
|
||||
* request to determine whether to handle a content item or other stuff
|
||||
* which is delegated to jsp templates. {
|
||||
*
|
||||
* @see com.arsdigita.web.BaseApplicationServlet#doService
|
||||
* (HttpServletRequest, HttpServletResponse, Application)}
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param app
|
||||
*
|
||||
* @throws javax.servlet.ServletException
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Override
|
||||
protected void doService(final HttpServletRequest request,
|
||||
final HttpServletResponse response,
|
||||
final CcmApplication app)
|
||||
throws ServletException, IOException {
|
||||
|
||||
if (!(app instanceof ContentSection)) {
|
||||
throw new IllegalArgumentException(
|
||||
"The provided application instance is not a content section.");
|
||||
}
|
||||
|
||||
final ContentSection section = (ContentSection) app;
|
||||
|
||||
final RequestContext ctx = DispatcherHelper.getRequestContext();
|
||||
final String url = ctx.getRemainingURLPart();
|
||||
|
||||
//Only for testing PageModel
|
||||
if (url != null && url.endsWith("page-model/")) {
|
||||
getServletContext()
|
||||
.getRequestDispatcher("/page-model.bebop")
|
||||
.include(request, response);
|
||||
return;
|
||||
}
|
||||
//End Test PageModel
|
||||
|
||||
LOGGER.info("Resolving URL {} and trying as item first.", url);
|
||||
final ItemResolver itemResolver = getItemResolver(section);
|
||||
|
||||
String pathInfo = request.getPathInfo();
|
||||
if (pathInfo == null) {
|
||||
pathInfo = "/";
|
||||
}
|
||||
|
||||
final ContentItem item = getItem(section, pathInfo, itemResolver);
|
||||
|
||||
Assert.exists(pathInfo, "String pathInfo");
|
||||
if (pathInfo.length() > 1 && pathInfo.endsWith("/")) {
|
||||
/* NOTE: ServletAPI specifies, pathInfo may be empty or will
|
||||
* start with a '/' character. It currently carries a
|
||||
* trailing '/' if a "virtual" page, i.e. not a real jsp, but
|
||||
* result of a servlet mapping. But Application requires url
|
||||
* NOT to end with a trailing '/' for legacy free applications. */
|
||||
pathInfo = pathInfo.substring(0, pathInfo.length() - 1);
|
||||
}
|
||||
final Page page = (Page) m_pages.get(pathInfo);
|
||||
// ////////////////////////////////////////////////////////////////////
|
||||
// Serve the page
|
||||
// ////////////////////////////////////////////////////////////////////
|
||||
/* FIRST try new style servlet based service */
|
||||
if (page != null) {
|
||||
|
||||
// Check user access.
|
||||
// checkUserAccess(request, response); // done in individual pages ??
|
||||
if (page instanceof CMSPage) {
|
||||
// backwards compatibility fix until migration completed
|
||||
final CMSPage cmsPage = (CMSPage) page;
|
||||
// final RequestContext ctx = DispatcherHelper.getRequestContext();
|
||||
cmsPage.init();
|
||||
cmsPage.dispatch(request, response, ctx);
|
||||
}
|
||||
|
||||
/* SECONDLY try if we have to serve an item (old style dispatcher based */
|
||||
} else if (item != null) {
|
||||
|
||||
/* We have to serve an item here */
|
||||
String param = request.getParameter("transID");
|
||||
|
||||
serveItem(request, response, section, item);
|
||||
|
||||
/* OTHERWISE delegate to a JSP in file system */
|
||||
} else {
|
||||
/* We have to deal with a content-section, folder or another bit */
|
||||
if (LOGGER.isInfoEnabled()) {
|
||||
LOGGER.info("NOT serving content item");
|
||||
}
|
||||
|
||||
/* Store content section in http request to make it available
|
||||
* for admin/index.jsp */
|
||||
request.setAttribute(CONTENT_SECTION, section);
|
||||
|
||||
RequestDispatcher rd = m_resolver.resolve(m_templatePath,
|
||||
request,
|
||||
response,
|
||||
app);
|
||||
if (rd != null) {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Got dispatcher " + rd);
|
||||
}
|
||||
rd.forward(DispatcherHelper.restoreOriginalRequest(request),
|
||||
response);
|
||||
} else {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("No dispatcher found for " + rd);
|
||||
}
|
||||
String requestUri = request.getRequestURI(); // same as ctx.getRemainingURLPart()
|
||||
response.sendError(404, requestUri
|
||||
+ " not found on this server.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void serveItem(final HttpServletRequest request,
|
||||
final HttpServletResponse response,
|
||||
final ContentSection section,
|
||||
final ContentItem item)
|
||||
throws ServletException, IOException {
|
||||
|
||||
if (LOGGER.isInfoEnabled()) {
|
||||
LOGGER.info("serving content item");
|
||||
}
|
||||
|
||||
RequestContext ctx = DispatcherHelper.getRequestContext();
|
||||
String url = ctx.getRemainingURLPart();
|
||||
|
||||
final ItemResolver itemResolver = getItemResolver(section);
|
||||
|
||||
//set the content item in the request
|
||||
request.setAttribute(CONTENT_ITEM, item);
|
||||
|
||||
//set the template context
|
||||
// ToDo
|
||||
// final TemplateResolver templateResolver = m_disp.getTemplateResolver(
|
||||
// section);
|
||||
//
|
||||
// String templateURL = url;
|
||||
// if (!templateURL.startsWith("/")) {
|
||||
// templateURL = "/" + templateURL;
|
||||
// }
|
||||
// if (templateURL.startsWith(PREVIEW)) {
|
||||
// templateURL = templateURL.substring(PREVIEW.length());
|
||||
// }
|
||||
//
|
||||
// final String sTemplateContext = itemResolver.getTemplateFromURL(
|
||||
// templateURL);
|
||||
// LOGGER.debug("setting template context to {}", sTemplateContext);
|
||||
//
|
||||
// templateResolver.setTemplateContext(sTemplateContext, request);
|
||||
// ToDo End
|
||||
// Work out how long to cache for....
|
||||
// We take minimum(default timeout, lifecycle expiry)
|
||||
Lifecycle cycle = item.getLifecycle();
|
||||
int expires = DispatcherHelper.getDefaultCacheExpiry();
|
||||
if (cycle != null) {
|
||||
Date endDate = cycle.getEndDateTime();
|
||||
|
||||
if (endDate != null) {
|
||||
int maxAge = (int) ((endDate.getTime() - System
|
||||
.currentTimeMillis()) / 1000l);
|
||||
if (maxAge < expires) {
|
||||
expires = maxAge;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//use ContentItemDispatcher
|
||||
m_disp.dispatch(request, response, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the content section from the request attributes.
|
||||
*
|
||||
* @param request The HTTP request
|
||||
*
|
||||
* @return The content section
|
||||
*
|
||||
* @pre ( request != null )
|
||||
*/
|
||||
public static ContentSection getContentSection(HttpServletRequest request) {
|
||||
return (ContentSection) request.getAttribute(CONTENT_SECTION);
|
||||
}
|
||||
|
||||
public static boolean checkAdminAccess(final HttpServletRequest request,
|
||||
final ContentSection section) {
|
||||
final PermissionChecker permissionChecker = CdiUtil.createCdiUtil()
|
||||
.findBean(PermissionChecker.class);
|
||||
|
||||
return permissionChecker.isPermitted(ItemPrivileges.PREVIEW,
|
||||
section)
|
||||
|| permissionChecker.isPermitted(ItemPrivileges.EDIT,
|
||||
section)
|
||||
|| permissionChecker.isPermitted(ItemPrivileges.APPROVE,
|
||||
section);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public ItemResolver getItemResolver(final ContentSection section) {
|
||||
|
||||
return sectionManager.getItemResolver(section);
|
||||
}
|
||||
|
||||
public ContentItem getItem(final ContentSection section,
|
||||
final String url,
|
||||
final ItemResolver itemResolver) {
|
||||
|
||||
LOGGER.debug("getting item at url {}", url);
|
||||
final HttpServletRequest request = Web.getRequest();
|
||||
|
||||
//first sanitize the url
|
||||
String itemUrl = url;
|
||||
if (url.endsWith(XML_SUFFIX)) {
|
||||
request.setAttribute(XML_MODE, Boolean.TRUE);
|
||||
LOGGER.debug("StraightXML Requested");
|
||||
itemUrl = "/" + url.substring(1, url.length() - XML_SUFFIX.length());
|
||||
} else {
|
||||
request.setAttribute(XML_MODE, Boolean.FALSE);
|
||||
if (url.endsWith(FILE_SUFFIX)) {
|
||||
itemUrl = String.format(
|
||||
"/%s",
|
||||
url.substring(1, url.length() - FILE_SUFFIX.length()));
|
||||
} else if (url.endsWith("/")) {
|
||||
itemUrl = String.format("/%s",
|
||||
url.substring(0, url.length() - 1));
|
||||
}
|
||||
}
|
||||
|
||||
if (!itemUrl.startsWith("/")) {
|
||||
itemUrl = String.format("/%s", itemUrl);
|
||||
}
|
||||
|
||||
ContentItem item;
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final PermissionChecker permissionChecker = cdiUtil.findBean(
|
||||
PermissionChecker.class);
|
||||
final ContentItemManager itemManager = cdiUtil.findBean(
|
||||
ContentItemManager.class);
|
||||
// Check if the user has access to view public or preview pages
|
||||
boolean hasPermission = true;
|
||||
|
||||
// If the remaining URL starts with "preview/", then try and
|
||||
// preview this item. Otherwise look for the live item.
|
||||
boolean preview = false;
|
||||
if (itemUrl.startsWith(PREVIEW)) {
|
||||
itemUrl = itemUrl.substring(PREVIEW.length());
|
||||
preview = true;
|
||||
}
|
||||
|
||||
if (preview) {
|
||||
LOGGER.info("Trying to get item for PREVIEW");
|
||||
|
||||
item = itemResolver.getItem(section,
|
||||
itemUrl,
|
||||
ContentItemVersion.DRAFT.toString());
|
||||
if (item != null) {
|
||||
hasPermission = permissionChecker.isPermitted(
|
||||
ItemPrivileges.PREVIEW, item);
|
||||
}
|
||||
} else {
|
||||
LOGGER.info("Trying to get LIVE item");
|
||||
|
||||
//check if this item is in the cache
|
||||
//we only cache live items
|
||||
LOGGER.debug("Trying to get content item for URL {}from cache",
|
||||
itemUrl);
|
||||
|
||||
// Get the negotiated locale
|
||||
final GlobalizationHelper globalizationHelper = cdiUtil.findBean(
|
||||
GlobalizationHelper.class);
|
||||
final String lang = globalizationHelper.getNegotiatedLocale()
|
||||
.getLanguage();
|
||||
|
||||
// XXX why assign a value and afterwards null??
|
||||
// Effectively it just ignores the cache and forces a fallback to
|
||||
// itemResover in any case. Maybe otherwise language selection /
|
||||
// negotiation doesn't work correctly?
|
||||
item = null;
|
||||
|
||||
if (item == null) {
|
||||
LOGGER.debug("Did not find content item in cache, so trying "
|
||||
+ "to retrieve and cache...");
|
||||
//item not cached, so retreive it and cache it
|
||||
item = itemResolver.getItem(section,
|
||||
itemUrl,
|
||||
ContentItemVersion.LIVE.toString());
|
||||
|
||||
if (LOGGER.isDebugEnabled() && item != null) {
|
||||
LOGGER.debug("Sanity check: item.getPath() is {}",
|
||||
itemManager.getItemPath(item));
|
||||
}
|
||||
|
||||
if (item != null) {
|
||||
LOGGER.debug("Content Item is not null");
|
||||
|
||||
hasPermission = permissionChecker.isPermitted(
|
||||
ItemPrivileges.VIEW_PUBLISHED, item);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (item == null && itemUrl.endsWith(INDEX_FILE)) {
|
||||
|
||||
if (item == null) {
|
||||
LOGGER.info("no item found");
|
||||
}
|
||||
|
||||
// look up folder if it's an index
|
||||
itemUrl = itemUrl.substring(0, itemUrl.length() - INDEX_FILE
|
||||
.length());
|
||||
LOGGER.info("Attempting to match folder " + itemUrl);
|
||||
|
||||
item = itemResolver.getItem(section,
|
||||
itemUrl,
|
||||
ContentItemVersion.LIVE.toString());
|
||||
if (item != null) {
|
||||
hasPermission = permissionChecker.isPermitted(
|
||||
ItemPrivileges.VIEW_PUBLISHED, item);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasPermission) {
|
||||
|
||||
// first, check if the user is logged-in
|
||||
// if he isn't, give him a chance to do so...
|
||||
final Shiro shiro = cdiUtil.findBean(Shiro.class);
|
||||
|
||||
if (shiro.getSubject().isAuthenticated()) {
|
||||
throw new LoginSignal(request);
|
||||
}
|
||||
|
||||
throw new AccessDeniedException();
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public ContentItem getItem(final ContentSection section, final String url) {
|
||||
final ItemResolver itemResolver = getItemResolver(section);
|
||||
|
||||
return getItem(section, url, itemResolver);
|
||||
}
|
||||
|
||||
// synchronize access to the item-url cache
|
||||
// private static synchronized void itemURLCachePut(
|
||||
// final ContentSection section,
|
||||
// final String sURL,
|
||||
// final String lang,
|
||||
// final Long itemID) {
|
||||
//
|
||||
// getItemURLCache(section).put(String.format(
|
||||
// "%s" + CACHE_KEY_DELIMITER + "%s", sURL, lang), itemID);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Maps the content item to the URL in a cache
|
||||
// *
|
||||
// * @param section the content section in which the content item is published
|
||||
// * @param url the URL at which the content item s published
|
||||
// * @param lang
|
||||
// * @param item the content item at the URL
|
||||
// */
|
||||
// public static synchronized void itemURLCachePut(
|
||||
// final ContentSection section,
|
||||
// final String url,
|
||||
// final String lang,
|
||||
// final ContentItem item) {
|
||||
//
|
||||
// if (url == null || item == null) {
|
||||
// return;
|
||||
// }
|
||||
// LOGGER.debug("adding cached entry for url {} and language {}",
|
||||
// url,
|
||||
// lang);
|
||||
//
|
||||
// itemURLCachePut(section, url, lang, item.getObjectId());
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Removes the cache entry for the URL, sURL
|
||||
// *
|
||||
// * @param section the content section in which to remove the key
|
||||
// * @param url the cache entry key to remove
|
||||
// * @param lang
|
||||
// */
|
||||
// public static synchronized void itemURLCacheRemove(
|
||||
// final ContentSection section,
|
||||
// final String url,
|
||||
// final String lang) {
|
||||
//
|
||||
// LOGGER.debug("removing cached entry for url {} and language {} ",
|
||||
// url,
|
||||
// lang);
|
||||
//
|
||||
// getItemURLCache(section).remove(url + CACHE_KEY_DELIMITER + lang);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Fetches the ContentItem published at that URL from the cache.
|
||||
// *
|
||||
// * @param section the content section in which the content item is published
|
||||
// * @param url the URL for the item to fetch
|
||||
// * @param lang
|
||||
// * @return the ContentItem in the cache, or null
|
||||
// */
|
||||
// public static ContentItem itemURLCacheGet(final ContentSection section,
|
||||
// final String url,
|
||||
// final String lang) {
|
||||
// final Long itemID = (Long) getItemURLCache(section).get(
|
||||
// url + CACHE_KEY_DELIMITER + lang);
|
||||
//
|
||||
// if (itemID == null) {
|
||||
// return null;
|
||||
// } else {
|
||||
// final ContentItemRepository itemRepo = CdiUtil.createCdiUtil().findBean(ContentItemRepository.class);
|
||||
// try {
|
||||
// return itemRepo.findById(itemID);
|
||||
// } catch(NoResultException ex) {
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private static synchronized CacheTable getItemURLCache(ContentSection section) {
|
||||
// Assert.exists(section, ContentSection.class);
|
||||
// if (s_itemURLCacheMap == null) {
|
||||
// initializeItemURLCache();
|
||||
// }
|
||||
//
|
||||
// if (s_itemURLCacheMap.get(section.getPath()) == null) {
|
||||
// final CacheTable cache = new CacheTable("ContentSectionServletItemURLCache" +
|
||||
// section.getID().toString());
|
||||
// s_itemURLCacheMap.put(section.getPath(), cache);
|
||||
// }
|
||||
//
|
||||
// return (CacheTable) s_itemURLCacheMap.get(section.getPath());
|
||||
// }
|
||||
}
|
||||
|
|
@ -39,7 +39,6 @@ import org.librecms.contenttypes.Article;
|
|||
import org.librecms.contenttypes.Event;
|
||||
import org.librecms.contenttypes.MultiPartArticle;
|
||||
import org.librecms.contenttypes.News;
|
||||
import org.librecms.dispatcher.MultilingualItemResolver;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
|
@ -102,16 +101,6 @@ public class ContentSectionSetup extends AbstractCcmApplicationSetup {
|
|||
section.setDisplayName(sectionName);
|
||||
section.setLabel(sectionName);
|
||||
|
||||
if (getIntegrationProps().getProperty(DEFAULT_ITEM_RESOLVER) == null
|
||||
|| getIntegrationProps().getProperty(DEFAULT_ITEM_RESOLVER)
|
||||
.trim().isEmpty()) {
|
||||
section.setItemResolverClass(getIntegrationProps().getProperty(
|
||||
DEFAULT_ITEM_RESOLVER));
|
||||
} else {
|
||||
section.setItemResolverClass(MultilingualItemResolver.class
|
||||
.getName());
|
||||
}
|
||||
|
||||
LOGGER.debug("New content section properties: "
|
||||
+ "uuid = {}; "
|
||||
+ "applicationType = \"{}\"; "
|
||||
|
|
@ -283,34 +272,6 @@ public class ContentSectionSetup extends AbstractCcmApplicationSetup {
|
|||
getEntityManager().persist(lifecycleDefinition);
|
||||
getEntityManager().persist(workflow);
|
||||
|
||||
LOGGER.debug("Setting ItemResolver for content section '{}'...",
|
||||
sectionName);
|
||||
final String itemResolverClassName;
|
||||
if (getIntegrationProps().containsKey(String.format("%s.item_resolver",
|
||||
sectionName))) {
|
||||
|
||||
itemResolverClassName = getIntegrationProps().getProperty(
|
||||
String.format("%s.item_resolver",
|
||||
sectionName));
|
||||
LOGGER.debug("integration.properties contains setting for the item "
|
||||
+ "resolver of content section '{}'. Using "
|
||||
+ "item resolver '{}'.",
|
||||
sectionName, itemResolverClassName);
|
||||
} else if (getIntegrationProps().containsKey("default_item_resolver")) {
|
||||
itemResolverClassName = getIntegrationProps().getProperty(
|
||||
"default_item_resolver_name");
|
||||
LOGGER.debug("integration.properties contains setting for the "
|
||||
+ "default item resolver. Using item "
|
||||
+ "resolver '{}'.",
|
||||
itemResolverClassName);
|
||||
} else {
|
||||
itemResolverClassName = MultilingualItemResolver.class.getName();
|
||||
LOGGER.debug("integration.properties contains *no* setting for item "
|
||||
+ "resolver. Using default item resolver '{}'.",
|
||||
itemResolverClassName);
|
||||
}
|
||||
section.setItemResolverClass(itemResolverClassName);
|
||||
|
||||
LOGGER.debug("Adding default content types to content section '{}'...",
|
||||
sectionName);
|
||||
final String[] types;
|
||||
|
|
|
|||
|
|
@ -1,243 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2017 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.dispatcher;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.cms.dispatcher.CMSPage;
|
||||
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contentsection.ContentItemVersion;
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* The {@code ItemResolver} is responsible for mapping a URL in a particular
|
||||
* content section to a content item.
|
||||
*
|
||||
*
|
||||
* As an example, here is the item resolution process for a request to
|
||||
* {@code http://yourserver/cms/cheese}:
|
||||
*
|
||||
* The item resolver would be asked to map the URL stub {@code /cheese} in the
|
||||
* content section mounted at {@code /cms} to a content item. To this end, the
|
||||
* dispatcher calls the {@link #getItem} method, passing in the
|
||||
* {@link ContentSection} and the URL stub for the item within
|
||||
* the section, {@code /cheese} in our example. As a final argument, the
|
||||
* dispatcher passes either {@link ContentItemVersion#DRAFT} or
|
||||
* {@link ContentItemVersion#LIVE} to the {@code ItemResolver}, depending on
|
||||
* whether the returned item should be the live version (for pages) or the draft
|
||||
* version (for previewing).
|
||||
*
|
||||
* Originally these interface was located in the
|
||||
* {@code org.arsdigita.cms.dispatcher} package but has been moved here when its
|
||||
* implementations had been refactored to CDI beans. Also the default
|
||||
* implementations of the {@link #getTemplateFromURL(java.lang.String)} and
|
||||
* {@link #stripTemplateFromURL(java.lang.String)} from the old
|
||||
* {@code AbstractItemResolver} class have been moved here which is now possible
|
||||
* thanks to the default methods in interfaces introduced in Java 8. The
|
||||
* class {@code AbstractItemResolver} has been removed completely.
|
||||
*
|
||||
* @author Michael Pih (pihman@arsdigita.com)
|
||||
* @author Stanislav Freidin (sfreidin@arsdigita.com)
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
* @version $Revision$ $DateTime: 2004/08/17 23:15:09 $
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface ItemResolver {
|
||||
|
||||
public static final String TEMPLATE_CONTEXT_PREFIX = "tem_";
|
||||
|
||||
/**
|
||||
* Return a content item based on section, url, and use context.
|
||||
*
|
||||
* @param section The current content section
|
||||
* @param url The section-relative URL
|
||||
* @param context The use context
|
||||
*
|
||||
* @return The content item, or null if no such item exists
|
||||
*/
|
||||
ContentItem getItem(ContentSection section,
|
||||
String url,
|
||||
String context);
|
||||
|
||||
/**
|
||||
* Fetches the current context based on the page state.
|
||||
*
|
||||
* @param state the current page state
|
||||
*
|
||||
* @return the context of the current URL, such as "live" or "admin"
|
||||
*/
|
||||
String getCurrentContext(PageState state);
|
||||
|
||||
/**
|
||||
* Generates a URL for a content item.
|
||||
*
|
||||
* @param state The page state
|
||||
* @param itemId The item ID
|
||||
* @param name The name of the content page
|
||||
* @param section the content section to which the item belongs
|
||||
* @param context the context of the URL, such as "live" or "admin"
|
||||
*
|
||||
* @return The URL of the item
|
||||
*
|
||||
* @see #getCurrentContext
|
||||
*/
|
||||
String generateItemURL(PageState state,
|
||||
Long itemId,
|
||||
String name,
|
||||
ContentSection section,
|
||||
String context);
|
||||
|
||||
/**
|
||||
* Generates a URL for a content item.
|
||||
*
|
||||
* @param itemId The item ID
|
||||
* @param name The name of the content page
|
||||
* @param state The page state
|
||||
* @param section the content section to which the item belongs
|
||||
* @param context the context of the URL, such as "live" or "admin"
|
||||
* @param templateContext the context for the URL, such as "public"
|
||||
*
|
||||
* @return The URL of the item
|
||||
*
|
||||
* @see #getCurrentContext
|
||||
*/
|
||||
String generateItemURL(PageState state,
|
||||
Long itemId,
|
||||
String name,
|
||||
ContentSection section,
|
||||
String context,
|
||||
String templateContext
|
||||
);
|
||||
|
||||
/**
|
||||
* Generates a URL for a content item.
|
||||
*
|
||||
* @param item The item
|
||||
* @param state The page state
|
||||
* @param section the content section to which the item belongs
|
||||
* @param context the context of the URL, such as "live" or "admin"
|
||||
*
|
||||
* @return The URL of the item
|
||||
*
|
||||
* @see #getCurrentContext
|
||||
*/
|
||||
String generateItemURL(PageState state,
|
||||
ContentItem item,
|
||||
ContentSection section,
|
||||
String context);
|
||||
|
||||
/**
|
||||
* Generates a URL for a content item.
|
||||
*
|
||||
* @param item The item
|
||||
* @param state The page state
|
||||
* @param section the content section to which the item belongs
|
||||
* @param context the context of the URL, such as "live" or "admin"
|
||||
* @param templateContext the context for the URL, such as "public"
|
||||
*
|
||||
* @return The URL of the item
|
||||
*
|
||||
* @see #getCurrentContext
|
||||
*/
|
||||
String generateItemURL(PageState state,
|
||||
ContentItem item,
|
||||
ContentSection section,
|
||||
String context,
|
||||
String templateContext);
|
||||
|
||||
/**
|
||||
* Return a master page based on page state (and content section).
|
||||
*
|
||||
* @param item The content item
|
||||
* @param request The HTTP request
|
||||
*
|
||||
* @return The master page
|
||||
*
|
||||
* @throws javax.servlet.ServletException
|
||||
*/
|
||||
CMSPage getMasterPage(ContentItem item, HttpServletRequest request)
|
||||
throws ServletException;
|
||||
|
||||
|
||||
/*
|
||||
* Having to stick the following methods, getTemplateFromURL, and
|
||||
* stripTemplateFromURL in the ItemResolver interface is somewhat ugly.
|
||||
* But, the relationship between ItemResolver and TemplateResolver needs
|
||||
* to be cleaned up to fix this. As it is, ItemResolver parses URL's for
|
||||
* template contexts, and TemplateResolver sets the actual template contexts
|
||||
* in the request.
|
||||
*/
|
||||
/**
|
||||
* Finds the template context from the URL and returns it, if it is there.
|
||||
* Otherwise, returns null.
|
||||
*
|
||||
* @param inUrl the URL from which to get the template context
|
||||
*
|
||||
* @return the template context, or null if there is no template context
|
||||
*/
|
||||
default String getTemplateFromURL(final String inUrl) {
|
||||
final String tempUrl;
|
||||
if (inUrl.startsWith("/")) {
|
||||
tempUrl = inUrl.substring(1);
|
||||
} else {
|
||||
tempUrl = inUrl;
|
||||
}
|
||||
|
||||
final StringTokenizer tokenizer = new StringTokenizer(tempUrl, "/");
|
||||
final String templateContext;
|
||||
if (tokenizer.hasMoreTokens()) {
|
||||
templateContext = tokenizer.nextToken();
|
||||
} else {
|
||||
templateContext = null;
|
||||
}
|
||||
|
||||
if (templateContext != null && templateContext.startsWith(
|
||||
TEMPLATE_CONTEXT_PREFIX)) {
|
||||
return templateContext.substring(TEMPLATE_CONTEXT_PREFIX.length());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the template context from the <code>inUrl</code>.
|
||||
*
|
||||
* @param inUrl URL, possibly including the template context.
|
||||
*
|
||||
* @return <code>inUrl</code> with the template context removed
|
||||
*/
|
||||
default String stripTemplateFromURL(final String inUrl) {
|
||||
final String sTemplateContext = getTemplateFromURL(inUrl);
|
||||
|
||||
if (sTemplateContext != null) {
|
||||
//there is a template context, so strip it
|
||||
final int iTemplateLength = TEMPLATE_CONTEXT_PREFIX.length()
|
||||
+ sTemplateContext.length() + 1;
|
||||
return inUrl.substring(iTemplateLength, inUrl.length());
|
||||
} else {
|
||||
return inUrl;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,805 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2017 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.dispatcher;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.cms.CMS;
|
||||
import com.arsdigita.cms.dispatcher.CMSDispatcher;
|
||||
import com.arsdigita.cms.dispatcher.CMSPage;
|
||||
import com.arsdigita.cms.dispatcher.MasterPage;
|
||||
import com.arsdigita.cms.ui.ContentItemPage;
|
||||
import com.arsdigita.kernel.KernelConfig;
|
||||
import com.arsdigita.util.Assert;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.libreccm.core.CcmObject;
|
||||
import org.librecms.CmsConstants;
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contentsection.ContentItemManager;
|
||||
import org.librecms.contentsection.ContentItemRepository;
|
||||
import org.librecms.contentsection.ContentItemVersion;
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
import org.librecms.contentsection.Folder;
|
||||
import org.librecms.contentsection.FolderManager;
|
||||
import org.librecms.contentsection.FolderRepository;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import javax.enterprise.context.RequestScoped;
|
||||
import javax.inject.Inject;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
/**
|
||||
* Resolves items to URLs and URLs to items for multiple language variants.
|
||||
*
|
||||
* For version 7.0.0 this call has been moved from the
|
||||
* {@code com.arsdigita.cms.dispatcher} package to the
|
||||
* {@code org.librecms.dispatcher} package and refactored to an CDI bean. This
|
||||
* was necessary to avoid several problems when accessing the entity beans for
|
||||
* {@link Category} and {@link ContentItem}, primarily the infamous
|
||||
* {@code LazyInitializationException}. Also several checks for null parameters
|
||||
* were added to avoid {@code NullPointerExcpetions}.
|
||||
*
|
||||
* <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:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
@RequestScoped
|
||||
public class MultilingualItemResolver implements ItemResolver {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(
|
||||
MultilingualItemResolver.class);
|
||||
|
||||
private static final String ADMIN_PREFIX = "admin";
|
||||
|
||||
/**
|
||||
* The string identifying an item's ID in the query string of a URL.
|
||||
*/
|
||||
protected static final String ITEM_ID = "item_id";
|
||||
|
||||
/**
|
||||
* The separator used in URL query strings; should be either "&" or ";".
|
||||
*/
|
||||
protected static final String SEPARATOR = "&";
|
||||
|
||||
@Inject
|
||||
private FolderRepository folderRepo;
|
||||
|
||||
@Inject
|
||||
private FolderManager folderManager;
|
||||
|
||||
@Inject
|
||||
private ContentItemRepository itemRepo;
|
||||
|
||||
@Inject
|
||||
private ContentItemManager itemManager;
|
||||
|
||||
/**
|
||||
* Returns a content item based on section, url, and use context.
|
||||
*
|
||||
* @param section The current content section
|
||||
* @param itemUrl The section-relative URL
|
||||
* @param context The use context, e.g. <code>ContentItem.LIVE</code>,
|
||||
* <code>CMSDispatcher.PREVIEW</code> or
|
||||
* <code>ContentItem.DRAFT</code>. See {@link
|
||||
* #getCurrentContext}.
|
||||
*
|
||||
* @return The content item, or null if no such item exists
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
@Override
|
||||
public ContentItem getItem(final ContentSection section,
|
||||
final String itemUrl,
|
||||
final String context) {
|
||||
if (section == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't get item from section null.");
|
||||
}
|
||||
if (itemUrl == null) {
|
||||
throw new IllegalArgumentException("Can't get item for URL null.");
|
||||
}
|
||||
if (context == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't get item for context null.");
|
||||
}
|
||||
|
||||
LOGGER.debug("Resolving the item in content section \"{}\" at URL "
|
||||
+ "\"{}\" for context \"{}\"...",
|
||||
section.getLabel(),
|
||||
itemUrl,
|
||||
context);
|
||||
|
||||
final Folder rootFolder = section.getRootDocumentsFolder();
|
||||
String url = stripTemplateFromURL(itemUrl);
|
||||
|
||||
if (rootFolder == null) {
|
||||
// nothing to do, if root folder is null
|
||||
LOGGER.debug("The root folder is null; returning no item");
|
||||
} else {
|
||||
LOGGER.debug("Using root folder {}...", rootFolder.getName());
|
||||
|
||||
if (ContentItemVersion.LIVE.toString().equals(context)) {
|
||||
LOGGER.debug("The use context is 'live'");
|
||||
|
||||
LOGGER.debug("The root folder has a live version; recursing");
|
||||
|
||||
final String prefix = String.join(
|
||||
"",
|
||||
section.getPrimaryUrl(),
|
||||
folderManager.getFolderPath(rootFolder));
|
||||
|
||||
if (url.startsWith(prefix)) {
|
||||
LOGGER.
|
||||
debug("The starts with prefix \"{}\"; removing it...",
|
||||
prefix);
|
||||
|
||||
url = url.substring(prefix.length());
|
||||
}
|
||||
|
||||
final ContentItem item = getItemFromLiveURL(url, rootFolder);
|
||||
|
||||
LOGGER.debug("Resolved URL \"{}\" to item {}...",
|
||||
url,
|
||||
Objects.toString(item));
|
||||
|
||||
return item;
|
||||
|
||||
} else if (ContentItemVersion.DRAFT.toString().equals(context)) {
|
||||
LOGGER.debug("The use context is 'draft'");
|
||||
|
||||
// For 'draft' items, 'generateUrl()' method returns
|
||||
// URL like this
|
||||
// '/acs/wcms/admin/item.jsp?item_id=10201&set_tab=1'
|
||||
// Check if URL contains any match of string
|
||||
// 'item_id', then try to instanciate item_id value
|
||||
// and return FIXME: Please hack this if there is
|
||||
// more graceful solution. [aavetyan]
|
||||
if (Assert.isEnabled()) {
|
||||
Assert.isTrue(url.contains(ITEM_ID),
|
||||
String.format("url must contain parameter %s",
|
||||
ITEM_ID));
|
||||
}
|
||||
|
||||
final ContentItem item = getItemFromDraftURL(url);
|
||||
|
||||
LOGGER.debug("Resolved URL \"{}\" to item {}.",
|
||||
url,
|
||||
Objects.toString(item));
|
||||
|
||||
return item;
|
||||
} else if (CMSDispatcher.PREVIEW.equals(context)) {
|
||||
LOGGER.debug("The use context is 'preview'");
|
||||
|
||||
final String prefix = CMSDispatcher.PREVIEW + "/";
|
||||
|
||||
if (url.startsWith(prefix)) {
|
||||
LOGGER.debug(
|
||||
"The URL starts with prefix \"{}\"; removing it",
|
||||
prefix);
|
||||
|
||||
url = url.substring(prefix.length());
|
||||
}
|
||||
|
||||
final ContentItem item = getItemFromLiveURL(url, rootFolder);
|
||||
|
||||
LOGGER.debug("Resolved URL \"{}\" to item {}.",
|
||||
url,
|
||||
Objects.toString(item));
|
||||
|
||||
return item;
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Invalid item resolver context \"%s\".", context));
|
||||
}
|
||||
}
|
||||
|
||||
LOGGER.debug("No item resolved; returning null");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the current context based on the page state.
|
||||
*
|
||||
* @param state the current page state
|
||||
*
|
||||
* @return the context of the current URL, such as
|
||||
* <code>ContentItem.LIVE</code> or <code>ContentItem.DRAFT</code>
|
||||
*
|
||||
* @see ContentItem#LIVE
|
||||
* @see ContentItem#DRAFT
|
||||
*
|
||||
* ToDo: Refactor to use the {@link ContentItemVersion} directly.
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
@Override
|
||||
public String getCurrentContext(final PageState state) {
|
||||
LOGGER.debug("Getting the current context");
|
||||
|
||||
// XXX need to use Web.getWebContext().getRequestURL() here.
|
||||
String url = state.getRequest().getRequestURI();
|
||||
|
||||
final ContentSection section = CMS.getContext().getContentSection();
|
||||
|
||||
// If this page is associated with a content section,
|
||||
// transform the URL so that it is relative to the content
|
||||
// section site node.
|
||||
if (section != null) {
|
||||
final String sectionURL = section.getPrimaryUrl();
|
||||
|
||||
if (url.startsWith(sectionURL)) {
|
||||
url = url.substring(sectionURL.length());
|
||||
}
|
||||
}
|
||||
|
||||
// Remove any template-specific URL components (will only work
|
||||
// if they're first in the URL at this point; verify). XXX but
|
||||
// we don't actually verify?
|
||||
url = stripTemplateFromURL(url);
|
||||
|
||||
// Determine if we are under the admin UI.
|
||||
if (url.startsWith(ADMIN_PREFIX)
|
||||
|| url.startsWith(CmsConstants.CONTENT_CENTER_URL)) {
|
||||
return ContentItemVersion.DRAFT.toString();
|
||||
} else {
|
||||
return ContentItemVersion.LIVE.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a URL for a content item.
|
||||
*
|
||||
* @param itemId The item ID
|
||||
* @param name The name of the content page
|
||||
* @param state The page state
|
||||
* @param section the content section to which the item belongs
|
||||
* @param context the context of the URL, such as "live" or "admin"
|
||||
*
|
||||
* @return The URL of the item
|
||||
*
|
||||
* @see #getCurrentContext
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
@Override
|
||||
public String generateItemURL(final PageState state,
|
||||
final Long itemId,
|
||||
final String name,
|
||||
final ContentSection section,
|
||||
final String context) {
|
||||
return generateItemURL(state, itemId, name, section, context, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a URL for a content item.
|
||||
*
|
||||
* @param itemId The item ID
|
||||
* @param name The name of the content page
|
||||
* @param state The page state
|
||||
* @param section the content section to which the item belongs
|
||||
* @param context the context of the URL, such as "live" or "admin"
|
||||
* @param templateContext the context for the URL, such as "public"
|
||||
*
|
||||
* @return The URL of the item
|
||||
*
|
||||
* @see #getCurrentContext
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
@Override
|
||||
public String generateItemURL(final PageState state,
|
||||
final Long itemId,
|
||||
final String name,
|
||||
final ContentSection section,
|
||||
final String context,
|
||||
final String templateContext) {
|
||||
if (itemId == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't generate item URL for item id null.");
|
||||
}
|
||||
if (context == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't generate item URL for context null.");
|
||||
}
|
||||
if (section == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't generate item URL for section null.");
|
||||
}
|
||||
|
||||
LOGGER.debug("Generating an item URL for item id {}, section \"{}\" "
|
||||
+ "and context \"{}\" with name \"{}\"...",
|
||||
itemId,
|
||||
section.getLabel(),
|
||||
context,
|
||||
name);
|
||||
|
||||
if (ContentItemVersion.DRAFT.toString().equals(context)) {
|
||||
// No template context here.
|
||||
return generateDraftURL(section, itemId);
|
||||
} else if (CMSDispatcher.PREVIEW.equals(context)) {
|
||||
final ContentItem item = itemRepo.findById(itemId).get();
|
||||
return generatePreviewURL(section, item, templateContext);
|
||||
} else if (ContentItemVersion.LIVE.toString().equals(context)) {
|
||||
final ContentItem item = itemRepo.findById(itemId).get();
|
||||
|
||||
return generateLiveURL(section, item, templateContext);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown context '" + context
|
||||
+ "'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a URL for a content item.
|
||||
*
|
||||
* @param item The item
|
||||
* @param state The page state
|
||||
* @param section the content section to which the item belongs
|
||||
* @param context the context of the URL, such as "live" or "admin"
|
||||
*
|
||||
* @return The URL of the item
|
||||
*
|
||||
* @see #getCurrentContext
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
@Override
|
||||
public String generateItemURL(final PageState state,
|
||||
final ContentItem item,
|
||||
final ContentSection section,
|
||||
final String context) {
|
||||
return generateItemURL(state, item, section, context, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a URL for a content item.
|
||||
*
|
||||
* @param item The item
|
||||
* @param state The page state
|
||||
* @param section the content section to which the item belongs
|
||||
* @param context the context of the URL, such as "live" or "admin"
|
||||
* @param templateContext the context for the URL, such as "public"
|
||||
*
|
||||
* @return The URL of the item
|
||||
*
|
||||
* @see #getCurrentContext
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
@Override
|
||||
public String generateItemURL(final PageState state,
|
||||
final ContentItem item,
|
||||
final ContentSection section,
|
||||
final String context,
|
||||
final String templateContext) {
|
||||
if (item == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't generate URL for item null.");
|
||||
}
|
||||
if (context == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't generate URL for context null.");
|
||||
}
|
||||
|
||||
final ContentSection contentSection;
|
||||
if (section == null) {
|
||||
contentSection = item.getContentType().getContentSection();
|
||||
} else {
|
||||
contentSection = section;
|
||||
}
|
||||
|
||||
LOGGER.debug("Generating an item URL for item \"{}\", section \"{}\" "
|
||||
+ "and context \"{}\".",
|
||||
item.getDisplayName(),
|
||||
contentSection.getLabel(),
|
||||
context);
|
||||
|
||||
if (ContentItemVersion.DRAFT.toString().equals(context)) {
|
||||
return generateDraftURL(section, item.getObjectId());
|
||||
} else if (CMSDispatcher.PREVIEW.equals(context)) {
|
||||
return generatePreviewURL(section, item, templateContext);
|
||||
} else if (ContentItemVersion.LIVE.toString().equals(context)) {
|
||||
return generateLiveURL(contentSection, item, templateContext);
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Unknown context \"%s\".", context));
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
@Override
|
||||
public CMSPage getMasterPage(final ContentItem item,
|
||||
final HttpServletRequest request)
|
||||
throws ServletException {
|
||||
|
||||
LOGGER.debug("Getting the master page for item {}",
|
||||
item.getDisplayName());
|
||||
|
||||
final MasterPage masterPage = new MasterPage();
|
||||
masterPage.init();
|
||||
|
||||
return masterPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns content item's draft version URL
|
||||
*
|
||||
* @param section The content section to which the item belongs
|
||||
* @param itemId The content item's ID
|
||||
*
|
||||
* @return generated URL string
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
protected String generateDraftURL(final ContentSection section,
|
||||
final Long itemId) {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Generating draft URL for item ID " + itemId
|
||||
+ " and section " + section);
|
||||
}
|
||||
|
||||
if (Assert.isEnabled()) {
|
||||
Assert.isTrue(section != null && itemId != null,
|
||||
"get draft url: neither secion nor item "
|
||||
+ "can be null");
|
||||
}
|
||||
|
||||
final String url = ContentItemPage.getItemURL(
|
||||
String.format("%s/", section.getPrimaryUrl()),
|
||||
itemId,
|
||||
ContentItemPage.AUTHORING_TAB);
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Generated draft URL " + url);
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a <em>language-independent</em> URL to the <code>item</code> in
|
||||
* the given section.<p>
|
||||
* When a client retrieves this URL, the URL is resolved to point to a
|
||||
* specific language instance of the item referenced here, i.e. this URL
|
||||
* will be resolved to a <em>language-specific</em> URL internally.
|
||||
*
|
||||
* @param section the <code>ContentSection</code> that contains this
|
||||
* item
|
||||
* @param item <code>ContentItem</code> for which a URL should be
|
||||
* constructed.
|
||||
* @param templateContext template context; will be ignored if
|
||||
* <code>null</code>
|
||||
*
|
||||
* @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 <code>templateContext</code>
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
protected String generateLiveURL(final ContentSection section,
|
||||
final ContentItem item,
|
||||
final String templateContext) {
|
||||
LOGGER.debug("Generating live URL for item {} in section {}",
|
||||
Objects.toString(item),
|
||||
Objects.toString(section));
|
||||
|
||||
/*
|
||||
* URL = URL of section + templateContext + path to the ContentBundle
|
||||
* which contains the item
|
||||
*/
|
||||
final StringBuffer url = new StringBuffer(400);
|
||||
//url.append(section.getURL());
|
||||
url
|
||||
.append(section.getPrimaryUrl())
|
||||
.append("/");
|
||||
|
||||
/*
|
||||
* add template context, if one is given
|
||||
*/
|
||||
// This is breaking URL's...not sure why it's here. XXX
|
||||
// this should work with the appropriate logic. trying again.
|
||||
if (!(templateContext == null || templateContext.length() == 0)) {
|
||||
url
|
||||
.append(TEMPLATE_CONTEXT_PREFIX)
|
||||
.append(templateContext)
|
||||
.append("/");
|
||||
}
|
||||
|
||||
url.append(itemManager.getItemPath(item));
|
||||
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a URL which can be used to preview the <code>item</code>, using
|
||||
* the given <code>templateContext</code>.<p>
|
||||
* Only a specific language instance can be previewed, meaning there
|
||||
* <em>no</em> language negotiation is involved when a request is made to a
|
||||
* URL that has been generated by this method.
|
||||
*
|
||||
* @param section The <code>ContentSection</code> which contains the
|
||||
* <code>item</code>
|
||||
* @param item The <code>ContentItem</code> for which a URL
|
||||
* should be generated.
|
||||
* @param templateContext the context that determines which template should
|
||||
* render the item when it is previewed; ignored if
|
||||
* the argument given here is <code>null</code>
|
||||
*
|
||||
* @return a URL which can be used to preview the given <code>item</code>
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
protected String generatePreviewURL(final ContentSection section,
|
||||
final ContentItem item,
|
||||
final String templateContext) {
|
||||
Assert.exists(section, "ContentSection section");
|
||||
Assert.exists(item, "ContentItem item");
|
||||
|
||||
final StringBuffer url = new StringBuffer(100);
|
||||
url
|
||||
.append(section.getPrimaryUrl())
|
||||
.append("/")
|
||||
.append(CMSDispatcher.PREVIEW)
|
||||
.append("/");
|
||||
/*
|
||||
* add template context, if one is given
|
||||
*/
|
||||
// This is breaking URL's...not sure why it's here. XXX
|
||||
// this should work with the appropriate logic. trying again.
|
||||
if (!(templateContext == null || templateContext.length() == 0)) {
|
||||
url
|
||||
.append(TEMPLATE_CONTEXT_PREFIX)
|
||||
.append(templateContext)
|
||||
.append("/");
|
||||
}
|
||||
|
||||
url.append(itemManager.getItemPath(item));
|
||||
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves <code>ITEM_ID</code> parameter from URL and instantiates item
|
||||
* according to this ID.
|
||||
*
|
||||
* @param url URL that indicates which item should be retrieved; must
|
||||
* contain the <code>ITEM_ID</code> parameter
|
||||
*
|
||||
* @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>
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
protected ContentItem getItemFromDraftURL(final String url) {
|
||||
LOGGER.debug("Looking up the item from draft URL ", url);
|
||||
|
||||
int pos = url.indexOf(ITEM_ID);
|
||||
|
||||
String item_id = url.substring(pos); // item_id == ITEM_ID=.... ?
|
||||
|
||||
pos = item_id.indexOf("="); // should be exactly after the ITEM_ID string
|
||||
|
||||
if (pos != ITEM_ID.length()) {
|
||||
// item_id seems to be something like ITEM_IDFOO=
|
||||
|
||||
LOGGER.debug("No suitable item_id parameter found; returning null");
|
||||
|
||||
return null; // no ID found
|
||||
}
|
||||
|
||||
pos++; // skip the "="
|
||||
|
||||
// ID is the string between the equal (at pos) and the next separator
|
||||
int i = item_id.indexOf(SEPARATOR);
|
||||
item_id = item_id.substring(pos, Math.min(i, item_id.length() - 1));
|
||||
|
||||
LOGGER.debug("Looking up item using item ID {}", item_id);
|
||||
|
||||
final Optional<ContentItem> item = itemRepo.findById(Long.parseLong(
|
||||
item_id));
|
||||
|
||||
if (item.isPresent()) {
|
||||
LOGGER.debug("Returning item {}", Objects.toString(item));
|
||||
return item.get();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a content item based on URL relative to the root folder.
|
||||
*
|
||||
* @param url The content item url
|
||||
* @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
|
||||
* objects, depending on URL and file language extension
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
protected ContentItem getItemFromLiveURL(final String url,
|
||||
final Folder parentFolder) {
|
||||
|
||||
if (parentFolder == null || url == null || url.equals("")) {
|
||||
LOGGER.debug("The url is null or parent folder was null "
|
||||
+ "or something else is wrong, so just return "
|
||||
+ "null.");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
LOGGER.debug("Resolving the item for live URL {}"
|
||||
+ " and parent folder {}...",
|
||||
url,
|
||||
parentFolder.getName());
|
||||
|
||||
int len = url.length();
|
||||
int index = url.indexOf('/');
|
||||
|
||||
if (index >= 0) {
|
||||
LOGGER.debug("The URL starts with a slash; paring off the first "
|
||||
+ "URL element and recursing");
|
||||
|
||||
final String liveUrl = index + 1 < len ? url.substring(index + 1)
|
||||
: "";
|
||||
|
||||
return getItemFromLiveURL(liveUrl, parentFolder);
|
||||
} else {
|
||||
LOGGER.debug("Found a file element in the URL");
|
||||
|
||||
final String[] nameAndLang = getNameAndLangFromURLFrag(url);
|
||||
final String name = nameAndLang[0];
|
||||
|
||||
final Optional<ContentItem> item = itemRepo.findByNameInFolder(
|
||||
parentFolder, name);
|
||||
|
||||
if (item.isPresent()) {
|
||||
return item.get();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing the the item's name and lang based on the URL
|
||||
* fragment.
|
||||
*
|
||||
* @param url
|
||||
*
|
||||
* @return a two-element string array, the first element containing the
|
||||
* bundle name, and the second element containing the lang string
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
protected String[] getNameAndLangFromURLFrag(final String url) {
|
||||
String name;
|
||||
String lang = null;
|
||||
|
||||
/*
|
||||
* Try to find out if there's an extension with the language code
|
||||
* 1 Get a list of all "extensions", i.e. parts of the url
|
||||
* which are separated by colons
|
||||
* 2 If one or more extensions have been found, compare them against
|
||||
* the list of known language codes
|
||||
* 2a if a match is found, this language is used to retrieve an instance
|
||||
* from a bundle
|
||||
* 2b if no match is found
|
||||
*/
|
||||
final List<String> exts = new ArrayList<>(5);
|
||||
final StringTokenizer tok = new StringTokenizer(url, ".");
|
||||
|
||||
while (tok.hasMoreTokens()) {
|
||||
exts.add(tok.nextToken());
|
||||
}
|
||||
|
||||
if (exts.size() > 0) {
|
||||
LOGGER.debug("Found some file extensions to look at; they "
|
||||
+ "are {}",
|
||||
exts);
|
||||
|
||||
/*
|
||||
* We have found at least one extension, so we can
|
||||
* proceed. Now try to find out if one of the
|
||||
* extensions looks like a language code (we only
|
||||
* support 2-letter language codes!).
|
||||
* If so, use this as the language to look for.
|
||||
*/
|
||||
/*
|
||||
* First element is the NAME of the item, not an extension!
|
||||
*/
|
||||
name = exts.get(0);
|
||||
String ext;
|
||||
final Collection<String> supportedLangs = KernelConfig.getConfig()
|
||||
.getSupportedLanguages();
|
||||
Iterator<String> supportedLangIt;
|
||||
|
||||
for (int i = 1; i < exts.size(); i++) {
|
||||
ext = exts.get(i);
|
||||
|
||||
LOGGER.debug("Examining extension {}", ext);
|
||||
|
||||
/*
|
||||
* Loop through all extensions, but discard the
|
||||
* first one, which is the name of the item.
|
||||
*/
|
||||
if (ext != null && ext.length() == 2) {
|
||||
/* Only check extensions consisting of 2
|
||||
* characters.
|
||||
*
|
||||
* Compare current extension with known
|
||||
* languages; if it matches, we've found the
|
||||
* language we should use!
|
||||
*/
|
||||
supportedLangIt = supportedLangs.iterator();
|
||||
while (supportedLangIt.hasNext()) {
|
||||
if (ext.equals(supportedLangIt.next())) {
|
||||
lang = ext;
|
||||
LOGGER.debug("Found a match; using "
|
||||
+ "language {}", lang);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOGGER.debug("Discarding extension {}; it is too short",
|
||||
ext);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOGGER.debug("The file has no extensions; no language was encoded");
|
||||
name = url; // no extension, so we just have a name here
|
||||
lang = null; // no extension, so we cannot guess the language
|
||||
}
|
||||
|
||||
LOGGER.debug("File name resolved to {}", name);
|
||||
LOGGER.debug("File language resolved to {}", lang);
|
||||
|
||||
final String[] returnArray = new String[2];
|
||||
returnArray[0] = name;
|
||||
returnArray[1] = lang;
|
||||
return returnArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a language instance of a content item given the bundle, name, and
|
||||
* lang string. Note: Because there not ContentBundles anymore this method
|
||||
* simply returns the provided item.
|
||||
*
|
||||
* @param lang The lang string from the URL
|
||||
* @param item The content bundle
|
||||
*
|
||||
* @return The negotiated lang instance for the current request.
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
protected ContentItem getItemFromLangAndBundle(final String lang,
|
||||
final ContentItem item) {
|
||||
return item;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,475 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2017 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.dispatcher;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.cms.CMS;
|
||||
import com.arsdigita.cms.dispatcher.CMSDispatcher;
|
||||
import com.arsdigita.cms.dispatcher.CMSPage;
|
||||
import com.arsdigita.cms.dispatcher.MasterPage;
|
||||
import com.arsdigita.cms.ui.ContentItemPage;
|
||||
import com.arsdigita.dispatcher.DispatcherHelper;
|
||||
import com.arsdigita.web.URL;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.libreccm.categorization.Category;
|
||||
import org.libreccm.core.CcmObject;
|
||||
import org.librecms.CmsConstants;
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contentsection.ContentItemManager;
|
||||
import org.librecms.contentsection.ContentItemRepository;
|
||||
import org.librecms.contentsection.ContentItemVersion;
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
import org.librecms.contentsection.Folder;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.enterprise.context.RequestScoped;
|
||||
import javax.inject.Inject;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
/**
|
||||
* This is the default implementation of
|
||||
* {@link com.arsdigita.cms.dispatcher.ItemResolver}.
|
||||
*
|
||||
* The {@link #getItem(java.lang.String, org.librecms.contentsection.Folder) }
|
||||
* method of the default implementation of null {@link ItemResolver},
|
||||
* {@link com.arsdigita.cms.dispatcher.SimpleItemResolver} runs a simple query
|
||||
* using the passed in information to retrieve the content item with a name that
|
||||
* matches the URL stub, in our example it looks for a content item with name
|
||||
* {@code cheese}. If no such item exists, or if there is such an item, but
|
||||
* without a live version, even though one has been requested, {@code getItem}
|
||||
* returns {@code null}.
|
||||
*
|
||||
* After the CMS Dispatcher received the content item from the
|
||||
* {@link ItemResolver}, it also asks it for the
|
||||
* {@link com.arsdigita.cms.dispatcher.MasterPage} for that item in the current
|
||||
* request. With the content item and the master page in hand, the dispatcher
|
||||
* calls {@code service} on the page.
|
||||
*
|
||||
* For version 7.0.0 this call has been moved from the
|
||||
* {@code com.arsdigita.cms.dispatcher} package to the
|
||||
* {@code org.librecms.dispatcher} package and refactored to an CDI bean. This
|
||||
* was necessary to avoid several problems when accessing the entity beans for
|
||||
* {@link Category} and {@link ContentItem}, primarily the infamous
|
||||
* {@code LazyInitializationException}. Also several checks for null parameters
|
||||
* were added to avoid {@code NullPointerExcpetions}.
|
||||
*
|
||||
* <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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
@RequestScoped
|
||||
public class SimpleItemResolver implements ItemResolver {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(
|
||||
SimpleItemResolver.class);
|
||||
|
||||
private static final String ADMIN_PREFIX = "admin";
|
||||
private static final String WORKSPACE_PREFIX
|
||||
= CmsConstants.CONTENT_CENTER_URL;
|
||||
|
||||
@Inject
|
||||
private ContentItemRepository itemRepo;
|
||||
@Inject
|
||||
private ContentItemManager itemManager;
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
@Override
|
||||
public ContentItem getItem(final ContentSection section,
|
||||
final String url,
|
||||
final String context) {
|
||||
if (section == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't get an item for ContentSection null.");
|
||||
}
|
||||
if (url == null) {
|
||||
throw new IllegalArgumentException("Can't get an item for URL null.");
|
||||
}
|
||||
if (context == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't get an item for context null.");
|
||||
}
|
||||
|
||||
LOGGER.debug(
|
||||
"Trying to get {} item for url \"{}\" from content section \"{}\"...",
|
||||
context,
|
||||
url,
|
||||
section.getLabel());
|
||||
|
||||
final String itemUrl = stripTemplateFromURL(url);
|
||||
|
||||
// getItem fails if called from a JSP template, because the request URL
|
||||
// gets replaced with the filesystem path to the JSP (when
|
||||
// DispatcherHelper.forwardRequestByPath is called). To fix this, we check
|
||||
// if the item had already been put into the request by the CMSDispatcher
|
||||
// (which it usually has) and return it.
|
||||
ContentItem reqItem = (ContentItem) DispatcherHelper.getRequest().
|
||||
getAttribute("com.arsdigita.cms.dispatcher.item");
|
||||
if (reqItem != null) {
|
||||
LOGGER.info("Found item in the request, returning it.");
|
||||
return reqItem;
|
||||
}
|
||||
|
||||
final Folder rootFolder = section.getRootDocumentsFolder();
|
||||
if (rootFolder == null) {
|
||||
LOGGER.info("No root folder found, returning null.");
|
||||
return null;
|
||||
}
|
||||
|
||||
return getItem(itemUrl, rootFolder);
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
@Override
|
||||
public String getCurrentContext(final PageState state) {
|
||||
|
||||
if (state == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't get current context from PageState null.");
|
||||
}
|
||||
|
||||
String url = state.getRequest().getRequestURI();
|
||||
|
||||
final ContentSection section = CMS.getContext().getContentSection();
|
||||
|
||||
// If this page is associated with a content section, transform
|
||||
// the URL so that it is relative to the content section site node.
|
||||
if (section != null) {
|
||||
final String sectionURL = section.getPrimaryUrl();
|
||||
if (url.startsWith(sectionURL)) {
|
||||
url = url.substring(sectionURL.length());
|
||||
}
|
||||
}
|
||||
|
||||
// remove any template-specific URL components
|
||||
// (will only work if they're first in the URL at this point: verify
|
||||
url = stripTemplateFromURL(url);
|
||||
|
||||
// Determine if we are under the admin UI.
|
||||
if (url.startsWith(ADMIN_PREFIX) || url.startsWith(WORKSPACE_PREFIX)) {
|
||||
return ContentItemVersion.DRAFT.toString();
|
||||
} else {
|
||||
return ContentItemVersion.LIVE.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the content item at the specified path, or null if no such item
|
||||
* exists.
|
||||
*
|
||||
* The path is interpreted as a series of folders; for example,
|
||||
* {@code /foo/bar/baz} will look for an item named @code{baz} in a folder
|
||||
* named * @code{bar} * in a folder named {@code foo} under the specified
|
||||
* root folder.
|
||||
*
|
||||
* @param url the URL to the item
|
||||
* @param rootFolder The root folder where the item search will start
|
||||
*
|
||||
* @return the item on success, null if no such item exists
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public ContentItem getItem(final String url, final Folder rootFolder) {
|
||||
|
||||
if (url == null) {
|
||||
throw new IllegalArgumentException("Can't get item for URL null.");
|
||||
}
|
||||
if (rootFolder == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't get item from rootFolder null.");
|
||||
}
|
||||
|
||||
final String[] tokens = url.split("/");
|
||||
|
||||
Folder currentFolder = rootFolder;
|
||||
int i;
|
||||
for (i = 0; i < tokens.length; i++) {
|
||||
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 (i >= tokens.length - 1) {
|
||||
// failure
|
||||
LOGGER.debug("no more tokens found, returning null");
|
||||
return null;
|
||||
} else {
|
||||
//Get the content item which is the last token
|
||||
final String name = tokens[tokens.length - 1];
|
||||
final Optional<CcmObject> item = currentFolder.getObjects()
|
||||
.stream()
|
||||
.map(categorization -> categorization.getCategorizedObject())
|
||||
.filter(object -> object.getDisplayName().equals(name))
|
||||
.findFirst();
|
||||
if (item.isPresent() && item.get() instanceof ContentItem) {
|
||||
return (ContentItem) item.get();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the URL for an item in the DRAFT context
|
||||
*
|
||||
* @param itemId
|
||||
* @param section
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private String generateDraftURL(final Long itemId,
|
||||
final ContentSection section) {
|
||||
if (itemId == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't generat draft URL for itemId null.");
|
||||
}
|
||||
if (itemId == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't generat draft URL for content section null.");
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
if (item == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't generate live URL for item null.");
|
||||
}
|
||||
if (section == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't generate live URL for content section null.");
|
||||
}
|
||||
|
||||
final String templateUrlFrag;
|
||||
if (templateContext == null || templateContext.isEmpty()) {
|
||||
templateUrlFrag = "";
|
||||
} else {
|
||||
templateUrlFrag = String.format(TEMPLATE_CONTEXT_PREFIX + "%s/",
|
||||
templateContext);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (item == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't generate draft URL for item null.");
|
||||
}
|
||||
if (section == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't generate draft URL for content section null.");
|
||||
}
|
||||
|
||||
final String templateUrlFrag;
|
||||
if (templateContext == null || templateContext.isEmpty()) {
|
||||
templateUrlFrag = "";
|
||||
} else {
|
||||
templateUrlFrag = String.format(TEMPLATE_CONTEXT_PREFIX + "%s/",
|
||||
templateContext);
|
||||
}
|
||||
|
||||
final StringBuilder url = new StringBuilder();
|
||||
url
|
||||
.append(section.getPrimaryUrl())
|
||||
.append("/")
|
||||
.append(CMSDispatcher.PREVIEW)
|
||||
.append("/")
|
||||
.append(templateUrlFrag)
|
||||
.append(itemManager.getItemPath(item));
|
||||
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a URL for a content item.
|
||||
*
|
||||
* @param itemId The item ID
|
||||
* @param name The name of the content page
|
||||
* @param state The page state
|
||||
* @param section the content section to which the item belongs
|
||||
* @param context the context of the URL, such as "LIVE" or "DRAFT"
|
||||
*
|
||||
* @return The URL of the item
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
@Override
|
||||
public String generateItemURL(final PageState state,
|
||||
final Long itemId,
|
||||
final String name,
|
||||
final ContentSection section,
|
||||
final String context) {
|
||||
return generateItemURL(state, itemId, name, section, context, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a URL for a content item.
|
||||
*
|
||||
* @param itemId The item ID
|
||||
* @param name The name of the content page
|
||||
* @param state The page state
|
||||
* @param section the content section to which the item belongs
|
||||
* @param context the context of the URL, such as "live" or "admin"
|
||||
* @param templateContext the context for the URL, such as "public"
|
||||
*
|
||||
* @return The URL of the item
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
@Override
|
||||
public String generateItemURL(final PageState state,
|
||||
final Long itemId,
|
||||
final String name,
|
||||
final ContentSection section,
|
||||
final String context,
|
||||
final String templateContext) {
|
||||
|
||||
if (ContentItemVersion.DRAFT.toString().equals(context)) {
|
||||
return generateDraftURL(itemId, section);
|
||||
} else if (ContentItemVersion.LIVE.toString().equals(context)) {
|
||||
final ContentItem item = itemRepo.findById(itemId).get();
|
||||
return generateLiveURL(item, section, templateContext);
|
||||
} else if (CMSDispatcher.PREVIEW.equals(context)) {
|
||||
final ContentItem item = itemRepo.findById(itemId).get();
|
||||
return generatePreviewURL(item, section, templateContext);
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Unknown context \"%s\".", context));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a URL for a content item.
|
||||
*
|
||||
* @param item The item
|
||||
* @param state The page state
|
||||
* @param section the content section to which the item belongs
|
||||
* @param context the context of the URL, such as "LIVE" or "DRAFT"
|
||||
*
|
||||
* @return The URL of the item
|
||||
*
|
||||
* @see #getCurrentContext
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
@Override
|
||||
public String generateItemURL(final PageState state,
|
||||
final ContentItem item,
|
||||
final ContentSection section,
|
||||
final String context) {
|
||||
return generateItemURL(state, item, section, context, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a URL for a content item.
|
||||
*
|
||||
* @param item The item
|
||||
* @param state The page state
|
||||
* @param section the content section to which the item belongs
|
||||
* @param context the context of the URL, such as "live" or "admin"
|
||||
* @param templateContext the context for the URL, such as "public"
|
||||
*
|
||||
* @return The URL of the item
|
||||
*
|
||||
* @see #getCurrentContext
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
@Override
|
||||
public String generateItemURL(final PageState state,
|
||||
final ContentItem item,
|
||||
final ContentSection section,
|
||||
final String context,
|
||||
final String templateContext) {
|
||||
|
||||
if (ContentItemVersion.LIVE.toString().equals(context)) {
|
||||
return generateLiveURL(item, section, templateContext);
|
||||
} else if (ContentItemVersion.DRAFT.toString().equals(context)) {
|
||||
return generateDraftURL(item.getObjectId(), section);
|
||||
} else if (CMSDispatcher.PREVIEW.equals(context)) {
|
||||
return generatePreviewURL(item, section, templateContext);
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Unknown context \"%s\".", context));
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
@Override
|
||||
public CMSPage getMasterPage(final ContentItem item,
|
||||
final HttpServletRequest request)
|
||||
throws ServletException {
|
||||
|
||||
final MasterPage masterPage = new MasterPage();
|
||||
masterPage.init();
|
||||
|
||||
return masterPage;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue