Prototypes implementation of the JSR286 compatible portlet for serving content items

git-svn-id: https://svn.libreccm.org/ccm/trunk@2739 8810af33-2d31-482b-a856-94f89814c4df
master
jensp 2014-07-07 10:01:19 +00:00
parent ea1128367c
commit 435f024233
5 changed files with 323 additions and 19 deletions

View File

@ -18,24 +18,35 @@
*/
package com.arsdigita.cms.portlet;
import com.arsdigita.bebop.Page;
import com.arsdigita.bebop.PageFactory;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.SimpleComponent;
import com.arsdigita.cms.CMS;
import com.arsdigita.cms.ContentBundle;
import com.arsdigita.cms.ContentItem;
import com.arsdigita.cms.ContentPage;
import com.arsdigita.cms.ContentSection;
import com.arsdigita.cms.ContentSectionCollection;
import com.arsdigita.cms.ItemCollection;
import com.arsdigita.cms.dispatcher.SimpleXMLGenerator;
import com.arsdigita.cms.portlet.utils.HttpServletRequestAdapter;
import com.arsdigita.cms.portlet.utils.HttpServletResponseAdapter;
import com.arsdigita.domain.DataObjectNotFoundException;
import com.arsdigita.domain.DomainObjectFactory;
import com.arsdigita.globalization.GlobalizationHelper;
import com.arsdigita.persistence.OID;
import com.arsdigita.portal.JSRPortlet;
import com.arsdigita.templating.PresentationManager;
import com.arsdigita.templating.Templating;
import com.arsdigita.xml.Document;
import com.arsdigita.xml.Element;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletException;
@ -43,6 +54,9 @@ import javax.portlet.PortletPreferences;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
@ -195,9 +209,37 @@ public class ContentItemJSRPortlet extends JSRPortlet {
@Override
protected void doView(final RenderRequest request, final RenderResponse response)
throws PortletException, IOException {
response.setContentType("text/html");
final PrintWriter writer = new PrintWriter(response.getWriter());
writer.println("Hello world! You're in View mode.");
// response.setContentType("text/html");
// final PrintWriter writer = new PrintWriter(response.getWriter());
// writer.println("Hello world! You're in View mode.");
final String itemOID = request.getPreferences().getValue(response.getNamespace().concat(
PREFS_SELECTED_ITEM), "");
if (itemOID.isEmpty()) {
final PrintWriter writer = response.getWriter();
writer.append("<div>");
writer.append(getResourceBundle(request.getLocale()).getString(
"contentItemJSRPortlet.no_item_configured"));
writer.append("</div>");
} else {
try {
final OID oid = OID.valueOf(itemOID);
final BigDecimal itemId = (BigDecimal) oid.get("id");
final PortletRequestDispatcher dispatcher = getPortletContext().
getRequestDispatcher(String.format(
"/portlets/content-item-portlet-servlet/items/%s",
itemId.toString()));
dispatcher.include(request, response);
} catch (IllegalArgumentException ex) {
writeMessage(request,
response,
"contentItemJSRPortlet.errors.parameters.illegal_oid",
itemOID);
}
}
}
@Override
@ -245,4 +287,54 @@ public class ContentItemJSRPortlet extends JSRPortlet {
}
}
private void writeMessage(final RenderRequest request,
final RenderResponse response,
final String msgKey,
final Object... args) throws IOException {
final PrintWriter writer = response.getWriter();
writer.append("<div>");
writer.append(MessageFormat.format(getResourceBundle(request.getLocale()).
getString(msgKey), args));
writer.append("</div>");
}
/**
* Special component to make it possible to use special XSL for the data served by the
* PortletDataProvider
*
*/
private class PortletDataItemPanel extends SimpleComponent {
private final XMLGenerator xmlGenerator;
public PortletDataItemPanel(final ContentItem item) {
super();
this.xmlGenerator = new XMLGenerator(item);
}
@Override
public void generateXML(final PageState state, final Element parent) {
final Element content = parent.newChildElement("cms:contentPanel",
CMS.CMS_XML_NS);
xmlGenerator.generateXML(state, content, "");
}
}
private class XMLGenerator extends SimpleXMLGenerator {
private final ContentItem item;
public XMLGenerator(final ContentItem item) {
super();
this.item = item;
}
@Override
protected ContentItem getContentItem(final PageState state) {
return item;
}
}
}

View File

@ -10,3 +10,5 @@ contentItemJSRPortlet.edit.contentSectionSelect.label=Content section
contentitemJSRPortlet.edit.search.label=Title of the content item
contentItemJSRPortlet.edit.fieldset.label=Please choose the content item to display
contentItemJSRPortlet.no_item_configured=No item to show configured
contentItemJSRPortlet.errors.item_is_not_live=The configured is not published yet

View File

@ -7,3 +7,5 @@ contentItemJSRPortlet.errors.parameters.item_does_not_exist=Es gibt kein Item mi
contentItemJSRPortlet.edit.contentSectionSelect.label=Content Section
contentitemJSRPortlet.edit.search.label=Titel des Content Items
contentItemJSRPortlet.edit.fieldset.label=Bitte w\u00e4hlen Sie das anzuzeigende Content Item
contentItemJSRPortlet.no_item_configured=Es wurde noch Content Item zum Anzeigen festgelegt.
contentItemJSRPortlet.errors.item_is_not_live=Das konfigurierte Content Item ist (noch) nicht publiziert.

View File

@ -0,0 +1,195 @@
package com.arsdigita.cms.portlet;
import com.arsdigita.bebop.Page;
import com.arsdigita.bebop.PageFactory;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.SimpleComponent;
import com.arsdigita.bebop.page.PageTransformer;
import com.arsdigita.cms.CMS;
import com.arsdigita.cms.ContentItem;
import com.arsdigita.cms.dispatcher.SimpleXMLGenerator;
import com.arsdigita.domain.DataObjectNotFoundException;
import com.arsdigita.persistence.OID;
import com.arsdigita.templating.PresentationManager;
import com.arsdigita.templating.Templating;
import com.arsdigita.web.Application;
import com.arsdigita.web.BaseServlet;
import com.arsdigita.xml.Document;
import com.arsdigita.xml.Element;
import java.io.IOException;
import java.math.BigDecimal;
import javax.portlet.PortletRequest;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* This servlet is the backend for the the {@link ContentItemJSRPortlet} and provides the view of a
* content item. Using a servlet is necessary to include the transformed HTML of the content item.
* The {@link PageTransformer} requires a HTTP request but in the Portlet only a
* {@link PortletRequest} is available. And a {@link PortletRequest} can't be converted into a
* {@link ServletHttpRequest}.
*
* @author Jens Pelzetter <jens.pelzetter@scientificcms.org>
*/
public class ContentItemPortletItemProviderServlet extends BaseServlet{ //BaseApplicationServlet {
private static final String ITEMS = "items";
private static final String CATEGORIES = "categories";
/**
* This method is the entry point to the logic of this class. The method analyses the path (from
* {@link HttpServletRequest#getPathInfo()}) and delegates to the responsible method of this
* class.
*
* @param request
* @param response
* @param app
* @throws ServletException
* @throws IOException
*/
@Override
// protected void doService(final HttpServletRequest request,
// final HttpServletResponse response,
// final Application app)
protected void doService(final HttpServletRequest request,
final HttpServletResponse response)
throws ServletException, IOException {
String path = request.getPathInfo();
if (path.charAt(0) == '/') {
path = path.substring(1);
}
final String[] pathTokens = path.split("/");
if (pathTokens.length == 0) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
//Check the first token of the path and delegate the clal
if (ITEMS.equals(pathTokens[0])) {
serveContentItem(pathTokens, request, response);
} else if (CATEGORIES.equals(pathTokens[0])) {
throw new UnsupportedOperationException("Not implemtend yet");
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
/**
* Serves an HTML fragment showing the detail view of a specific content item. Will create a
* BAD_REQUEST HTTP error if the provided ID/OID is invalid and a NOT_FOUND HTTP error if no
* content item with the provided ID/OID is found.
*
* @param pathTokens The tokens of the path
* @param request
* @param response
* @throws IOException
* @throws ServletException
*/
protected void serveContentItem(final String[] pathTokens,
final HttpServletRequest request,
final HttpServletResponse response) throws IOException,
ServletException {
//Retrieve the content item and ensure that we work with the live version of the item.
ContentItem item = null;
try {
final ContentItem tmpItem = retrieveContentItem(pathTokens[1]);
if (tmpItem.isLiveVersion()) {
item = tmpItem;
} else {
if (tmpItem.isLive()) {
item = tmpItem.getLiveVersion();
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND,
String.format("Item with ID %d is not published.",
pathTokens[1]));
}
}
} catch (DataObjectNotFoundException ex) {
//No item with the provided ID/OID found, respond with NOT_FOUND (404).
response.sendError(HttpServletResponse.SC_NOT_FOUND,
String.format("Item with ID/PID %d not found.", pathTokens[1]));
return;
} catch (NumberFormatException ex) {
//The provided ID was not a number, respond with bad request error.
response.sendError(HttpServletResponse.SC_BAD_REQUEST,
String.format("'%s' is not a valid item id", pathTokens[1]));
return;
} catch (IllegalArgumentException ex) {
//The provided OID is was invalid, respond with bad request error.
response.sendError(HttpServletResponse.SC_BAD_REQUEST,
String.format("'%s' is not a valid item OID", pathTokens[1]));
return;
}
//Create the XML output
final Page page = PageFactory.buildPage(
"PortletDataProvider",
String.format("ContentItem %s", item.getOID().toString()));
final PortletDataItemPanel panel = new PortletDataItemPanel(item);
page.add(panel);
page.lock();
//Delegate to theming enging
final Document document = page.buildDocument(request, response);
final PresentationManager presenter = Templating.getPresentationManager();
presenter.servePage(document, request, response);
}
/**
* Helper method encapsulating the logic for retrieving a content item. If the first character
* of the provided item id is a digit the method assumes that the numeric ID of the item was
* provided. Otherwise the method assumes that the OID of the item to serve was provided.
*
* @param itemId
* @return
*/
private ContentItem retrieveContentItem(final String itemId) {
if (Character.isDigit(itemId.charAt(0))) {
return new ContentItem(new BigDecimal(itemId));
} else {
return new ContentItem(OID.valueOf(itemId));
}
}
/**
* Special component to make it possible to use special XSL for the data served by the
* PortletDataProvider
*
*/
private class PortletDataItemPanel extends SimpleComponent {
private final XMLGenerator xmlGenerator;
public PortletDataItemPanel(final ContentItem item) {
super();
this.xmlGenerator = new XMLGenerator(item);
}
@Override
public void generateXML(final PageState state, final Element parent) {
final Element content = parent.newChildElement("cms:contentPanel",
CMS.CMS_XML_NS);
xmlGenerator.generateXML(state, content, "");
}
}
private class XMLGenerator extends SimpleXMLGenerator {
private final ContentItem item;
public XMLGenerator(final ContentItem item) {
super();
this.item = item;
}
@Override
protected ContentItem getContentItem(final PageState state) {
return item;
}
}
}

View File

@ -32,6 +32,11 @@
<servlet-class>com.arsdigita.cms.dispatcher.TemplateXSLServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>content-item-portlet-servlet</servlet-name>
<servlet-class>com.arsdigita.cms.portlet.ContentItemPortletItemProviderServlet</servlet-class>
</servlet>
<!--
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SERVLET MAPPINGS SECTION basically requirred by ccm-cms
@ -58,4 +63,12 @@
<url-pattern>/themes/servlet/template/*</url-pattern>
</servlet-mapping>
<!--
Servlets used as backend for Portlets
-->
<servlet-mapping>
<servlet-name>content-item-portlet-servlet</servlet-name>
<url-pattern>/portlets/content-item-portlet-servlet/*</url-pattern>
</servlet-mapping>
</web-app>