Permanent fix for ticket #1693. CMS service works with the original urls again.

git-svn-id: https://svn.libreccm.org/ccm/trunk@2143 8810af33-2d31-482b-a856-94f89814c4df
master
pb 2013-04-26 00:59:09 +00:00
parent 50bb1a275b
commit 04b1f4f28d
6 changed files with 100 additions and 101 deletions

View File

@ -1,22 +1,34 @@
<dispatcher-configuration> <dispatcher-configuration>
<url-mapping> <url-mapping>
<url>logout/</url> <url>/logout/</url>
<page-class>com.arsdigita.cms.ui.Logout</page-class> <page-class>com.arsdigita.cms.ui.Logout</page-class>
</url-mapping> </url-mapping>
<url-mapping> <url-mapping>
<!--
<url>/templates/servlet/cms-service/stream/image/</url> <url>/templates/servlet/cms-service/stream/image/</url>
-->
<url>/stream/image/</url>
<page-class>com.arsdigita.cms.dispatcher.StreamImage</page-class> <page-class>com.arsdigita.cms.dispatcher.StreamImage</page-class>
</url-mapping> </url-mapping>
<url-mapping> <url-mapping>
<!--
<url>/templates/servlet/cms-service/download/image/</url> <url>/templates/servlet/cms-service/download/image/</url>
-->
<url>/download/image/</url>
<page-class>com.arsdigita.cms.dispatcher.DownloadImage</page-class> <page-class>com.arsdigita.cms.dispatcher.DownloadImage</page-class>
</url-mapping> </url-mapping>
<url-mapping> <url-mapping>
<!--
<url>/templates/servlet/cms-service/stream/asset/</url> <url>/templates/servlet/cms-service/stream/asset/</url>
-->
<url>/stream/asset/</url>
<page-class>com.arsdigita.cms.dispatcher.StreamAsset</page-class> <page-class>com.arsdigita.cms.dispatcher.StreamAsset</page-class>
</url-mapping> </url-mapping>
<url-mapping> <url-mapping>
<!--
<url>/templates/servlet/cms-service/download/asset/</url> <url>/templates/servlet/cms-service/download/asset/</url>
-->
<url>/download/asset/</url>
<page-class>com.arsdigita.cms.dispatcher.DownloadAsset</page-class> <page-class>com.arsdigita.cms.dispatcher.DownloadAsset</page-class>
</url-mapping> </url-mapping>
</dispatcher-configuration> </dispatcher-configuration>

View File

@ -229,7 +229,7 @@ public class ContentCenterServlet extends BaseApplicationServlet {
sreq = DispatcherHelper.restoreOriginalRequest(sreq); sreq = DispatcherHelper.restoreOriginalRequest(sreq);
rd.forward(sreq, sresp); rd.forward(sreq, sresp);
} else { } else {
// String requestUri = sreq.getRequestURI();
sresp.sendError(404, sreq.getRequestURI() + " not found on this server."); sresp.sendError(404, sreq.getRequestURI() + " not found on this server.");
} }

View File

@ -33,7 +33,6 @@ import com.arsdigita.web.Web;
import com.arsdigita.xml.XML; import com.arsdigita.xml.XML;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.servlet.RequestDispatcher; import javax.servlet.RequestDispatcher;
@ -44,10 +43,23 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.DefaultHandler;
// Developer's Note:
// Class is currently in a transistory state. ServiceServlet itself does process
// the request following the new legacy free web application model (i.e. as a
// servlet based on BaseApplicationSerevlet / HTTPServlet).
// The methods used to invoke the service classes follow the legacy dispatcher
// model as set up by BaseApplicationServlet (see #makeLegacyContext). They
// should be refactored to work without LegacyContext, probably as a servlet
// as well or a legacy free dispatcher / ResourceHandler.
/** /**
* CMS Service application servlet serves all request made for the CMS * CMS Service application servlet serves all request made for the CMS
* service application. * service application.
* *
* In many cases a service will open a (Web) page, e.g. the download page for
* files of a page to provide details or feedback/results of the service. But
* a service may also work without any visual output.
*
* URLs of the available services are stored in a XML file which is processed * URLs of the available services are stored in a XML file which is processed
* into a cache of services on a request by request basis (lazy loading). * into a cache of services on a request by request basis (lazy loading).
* *
@ -55,7 +67,7 @@ import org.xml.sax.helpers.DefaultHandler;
* ServiceServlet is associated with a request URL. * ServiceServlet is associated with a request URL.
* *
* The CMS Service determines whether a <tt>Page</tt> has been registered to * The CMS Service determines whether a <tt>Page</tt> has been registered to
* the URL and if so passes the request to that page. * the URL and if so passes the request to that serviceResource.
* *
* If no <tt>Page</tt> is registered to the URL, then the CMS Service hands * If no <tt>Page</tt> is registered to the URL, then the CMS Service hands
* the request to the TemplateResolver to find an appropriate JSP file. * the request to the TemplateResolver to find an appropriate JSP file.
@ -74,18 +86,15 @@ public class ServiceServlet extends BaseApplicationServlet {
* class names). */ * class names). */
private final static String MAP_FILE = "WEB-INF/resources/cms-service-map.xml"; private final static String MAP_FILE = "WEB-INF/resources/cms-service-map.xml";
/** Mapping between a relative URL and the class name of a ResourceHandler.*/ /** Mapping between a relative URL and the class name of a service. */
private static HashMap s_pageClasses = new HashMap(); private static HashMap s_serviceClasses = new HashMap();
/** Instantiated ResourceHandler cache. This allows for lazy loading. */ /** Instantiated services cache. This allows for lazy loading of the class
private static SimpleCache s_pages = new SimpleCache(); * (i.e. irs ResourceHandler) for each service. */
private static SimpleCache s_services = new SimpleCache();
/** List of URLs which require a trailing slash. These are required for /** Path to directory containg ccm-cms template files, used in case of fall
* creating virtual directories, so that relative URLs and redirects * back, when no service class is found in s_serviceClasses rsp. MAP_FILE */
* work. */
private ArrayList m_trailingSlashList = new ArrayList();
/** Path to directory containg ccm-cms template files */
private String m_templatePath; private String m_templatePath;
/** Resolvers to find templages (JSP) and other stuff stored in file system.*/ /** Resolvers to find templages (JSP) and other stuff stored in file system.*/
@ -102,11 +111,7 @@ public class ServiceServlet extends BaseApplicationServlet {
s_log.info("starting doInit method"); s_log.info("starting doInit method");
} }
/* Initialize List with an empty URL. Later URL's are added which are /* Process mapping file and fill up s_serviceClasses. */
* provided w/o trailing slash rsp. file extension. */
requireTrailingSlash("");
/* Process mapping file. */
readFromFile(MAP_FILE); readFromFile(MAP_FILE);
/** Set Template base path for JSP's */ /** Set Template base path for JSP's */
@ -141,42 +146,38 @@ public class ServiceServlet extends BaseApplicationServlet {
} }
DeveloperSupport.startStage("ServiceServlet.doService"); DeveloperSupport.startStage("ServiceServlet.doService");
Service service = (Service) app; /* Developer's Note:
* Legacy context, established by BaseApplicationServlet, currently
* KernelContext. Not used in ServiceServlet, but required to invoke
* the Resource to provide the service by interface definition.
* Cuurently (version 6.6.8) not used in any service class.
*/
RequestContext ctx = DispatcherHelper.getRequestContext(); RequestContext ctx = DispatcherHelper.getRequestContext();
String url = ctx.getRemainingURLPart(); // here SiteNodeRequestContext
String originalUrl = ctx.getOriginalURL();
String requestUri = sreq.getRequestURI();
// An empty remaining URL or a URL which doesn't end in trailing slash: /* Get the service being requested, i.e. the remaining URL following
// probably want to redirect. * the servlet address ( ccm/cms-service by default) */
if ( m_trailingSlashList.contains(url) && !originalUrl.endsWith("/") ) { String url = sreq.getPathInfo();
DispatcherHelper.sendRedirect(sreq, sresp, originalUrl + "/"); if (url.length() > 1 && url.endsWith("/")) {
return; /* NOTE: ServletAPI specifies, pathInfo may be empty or will
* start with a '/' character. It currently carries a
* trailing '/' if a "virtual" serviceResource, 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.
* The service classes are currently not real applications, so no
* adaptation required here. */
// url = url.substring(0, url.length() - 1);
} }
// Check user access. // User access can not be checked here, but has to be checked by each
// Deprecated and here implemented as a No-OP method! // service!
/* checkUserAccess(request, response, actx); */
ResourceHandler page = getResource(url); /* Determine the service requested by url */
ResourceHandler serviceResource = getResource(url);
if (page == null) { if ( serviceResource != null ) {
//Retry without last part // Serve the serviceResource.
final String[] tokens = url.split("/"); serviceResource.init();
serviceResource.dispatch(sreq, sresp, ctx);
final StringBuilder altUrlBuilder = new StringBuilder('/');
for(int i = 0; i < tokens.length - 1; i++) {
altUrlBuilder.append(tokens[i]);
altUrlBuilder.append('/');
}
page = getResource(altUrlBuilder.toString());
}
if ( page != null ) {
// Serve the page.
page.init();
page.dispatch(sreq, sresp, ctx);
} else { } else {
// Fall back on the JSP application dispatcher. // Fall back on the JSP application dispatcher.
if (s_log.isInfoEnabled()) { if (s_log.isInfoEnabled()) {
@ -192,7 +193,7 @@ public class ServiceServlet extends BaseApplicationServlet {
sreq = DispatcherHelper.restoreOriginalRequest(sreq); sreq = DispatcherHelper.restoreOriginalRequest(sreq);
rd.forward(sreq,sresp); rd.forward(sreq,sresp);
} else { } else {
sresp.sendError(404, requestUri + " not found on this server."); sresp.sendError(404, sreq.getRequestURI() + " not found on this server.");
} }
} }
@ -206,20 +207,24 @@ public class ServiceServlet extends BaseApplicationServlet {
/** /**
* Fetch a page based on the URL stub. * Determines the Resource (ie class) to serve a requested service based
* on its url.
*
* Returns a RecourceHandler for the requested service if it could be found,
* i.e. a dispatcher class whose dispatch method invokes the service.
* *
* @param url The URL stub following the site-node URL * @param url The URL stub following the site-node URL
* @return A ResourceHandler or null if none exists. * @return A ResourceHandler or null if none exists.
* @pre (url != null) * @pre (url != null)
*/ */
protected ResourceHandler getResource(String url) throws ServletException { private ResourceHandler getResource(String url) throws ServletException {
// First check the pages cache for existing pages. // First check the pages cache for existing pages.
ResourceHandler page = (ResourceHandler) s_pages.get(url); ResourceHandler page = (ResourceHandler) s_services.get(url);
if ( page == null ) { if ( page == null ) {
// Next check if the URL maps to a page class. // Next check if the URL maps to a serviceResource class.
String pageClassName = (String) s_pageClasses.get(url); String pageClassName = (String) s_serviceClasses.get(url);
if ( pageClassName != null ) { if ( pageClassName != null ) {
Class pageClass; Class pageClass;
@ -230,7 +235,7 @@ public class ServiceServlet extends BaseApplicationServlet {
throw new ServletException(e); throw new ServletException(e);
} }
// Try and instantiate the page. // Try and instantiate the serviceResource.
try { try {
page = (ResourceHandler) pageClass.newInstance(); page = (ResourceHandler) pageClass.newInstance();
} catch (InstantiationException e) { } catch (InstantiationException e) {
@ -242,7 +247,7 @@ public class ServiceServlet extends BaseApplicationServlet {
} }
page.init(); page.init();
s_pages.put(url, page); s_services.put(url, page);
} }
} }
return page; return page;
@ -251,48 +256,24 @@ public class ServiceServlet extends BaseApplicationServlet {
/** /**
* *
* Initializes URL-to-Page/Dispatcher/Servlet mappings from a file. * Initializes URL-to-Page (class) mappings from a file.
* *
* Format of the file is XML: * Format of the file is XML:
* <pre> * <pre>
* &lt;dispatcher-configuration> * &lt;dispatcher-configuration>
* &lt;url-mapping * &lt;url-mapping
* &lt;url>my-page&lt;/url> * &lt;url>my-serviceResource&lt;/url>
* OR &lt;page-class>com.arsdigita.Page.class&lt;/page-class> * OR &lt;serviceResource-class>com.arsdigita.Page&lt;/page-class>
* &lt;url-mapping * &lt;url-mapping
* &lt;/dispatcher-configuration> * &lt;/dispatcher-configuration>
* </pre> * </pre>
*/ */
private void readFromFile(final String file) { private void readFromFile(final String file) {
// XML.parseResource(file, newParseConfigHandler(s_pageClasses)); XML.parseResource(file, new PageClassConfigHandler(s_serviceClasses));
XML.parseResource(file, new PageClassConfigHandler(s_pageClasses));
} }
/**
* Adds a URL to the list of URLs that are required to have trailing
* slashes. A request for url will be redirected to url + "/"
* if the original URL request (what you see in your browser)
* doesn't include a trailing slash. This is required for
* creating virtual directories, so that relative URLs and redirects
* work.
*/
public void requireTrailingSlash(String url) {
m_trailingSlashList.add(url);
}
/**
* Returns a SAX event handler object for setting up a MapDispatcher
* using an XML config file.
* @param map A map to configure
* @return a SAX DefaultHandler object for handling SAX events
* @pre md.m_map != null
*/
// protected DefaultHandler newParseConfigHandler(Map map) {
// return new PageClassConfigHandler(map);
// }
/** /**

View File

@ -52,15 +52,6 @@ class BaseAsset extends ResourceHandlerImpl {
private static final BigDecimalParameter s_assetId = new BigDecimalParameter(ASSET_ID); private static final BigDecimalParameter s_assetId = new BigDecimalParameter(ASSET_ID);
private static final OIDParameter s_oid = new OIDParameter(OID_PARAM); private static final OIDParameter s_oid = new OIDParameter(OID_PARAM);
/*
* jensp 2011-02-11: No need for static initalizer block here. Moved
* to variable declaration (see above).
*/
/*static {
s_assetId = new BigDecimalParameter(ASSET_ID);
s_oid = new OIDParameter(OID_PARAM);
//s_assetId.addParameterListener(new NotNullValidationListener());
}*/
private final boolean m_download; private final boolean m_download;
private String m_disposition; private String m_disposition;
@ -79,7 +70,7 @@ class BaseAsset extends ResourceHandlerImpl {
* Content-Disposition in HTTP. * Content-Disposition in HTTP.
*/ */
protected void setFilenameHeader(HttpServletResponse response, protected void setFilenameHeader(HttpServletResponse response,
BinaryAsset asset) { BinaryAsset asset) {
String filename = asset.getName(); String filename = asset.getName();
if (filename == null) { if (filename == null) {
filename = s_defaultName; filename = s_defaultName;
@ -95,7 +86,7 @@ class BaseAsset extends ResourceHandlerImpl {
} }
private void setHeaders(HttpServletResponse response, private void setHeaders(HttpServletResponse response,
BinaryAsset asset) { BinaryAsset asset) {
setFilenameHeader(response, asset); setFilenameHeader(response, asset);
Long contentLength = new Long(asset.getSize()); Long contentLength = new Long(asset.getSize());
@ -121,7 +112,8 @@ class BaseAsset extends ResourceHandlerImpl {
} }
private void send(HttpServletResponse response, private void send(HttpServletResponse response,
BinaryAsset asset) throws IOException { BinaryAsset asset)
throws IOException {
// Stream the blob. // Stream the blob.
OutputStream out = response.getOutputStream(); OutputStream out = response.getOutputStream();
try { try {
@ -131,11 +123,22 @@ class BaseAsset extends ResourceHandlerImpl {
} }
} }
/**
*
* @param request HTTP request
* @param response HTTP response
* @param actx (legacy) context, not used in this method but required by
* parent implementation's interface
* maybe required in future when access privilege is checked.
* @throws IOException
* @throws ServletException
*/
@Override @Override
public final void dispatch(HttpServletRequest request, public final void dispatch(HttpServletRequest request,
HttpServletResponse response, HttpServletResponse response,
RequestContext actx) RequestContext actx)
throws IOException, ServletException { throws IOException, ServletException {
// Fetch and validate the asset ID // Fetch and validate the asset ID
OID oid = null; OID oid = null;

View File

@ -90,7 +90,7 @@ public class BaseImage extends ResourceHandlerImpl {
} }
/** /**
* Sets RFC2183 governed Contnet-Disposition header to supply filename to * Sets RFC2183 governed Content-Disposition header to supply filename to
* client. See section 19.5.1 of RFC2616 for interpretation of * client. See section 19.5.1 of RFC2616 for interpretation of
* Content-Disposition in HTTP. * Content-Disposition in HTTP.
*/ */

View File

@ -53,6 +53,7 @@ public class SimpleCache extends Hashtable{
* @param key The object key * @param key The object key
* @return The cached object, null if there is none * @return The cached object, null if there is none
*/ */
@Override
public Object get(Object key) { public Object get(Object key) {
return super.get(key); return super.get(key);
} }
@ -64,6 +65,7 @@ public class SimpleCache extends Hashtable{
* @param value The object to be cached * @param value The object to be cached
* @return The cached object * @return The cached object
*/ */
@Override
public Object put(Object key, Object value) { public Object put(Object key, Object value) {
return super.put(key, value); return super.put(key, value);
} }
@ -74,6 +76,7 @@ public class SimpleCache extends Hashtable{
* @param key The object key * @param key The object key
* @return The formerly-cached object * @return The formerly-cached object
*/ */
@Override
public Object remove(Object key) { public Object remove(Object key) {
return super.remove(key); return super.remove(key);
} }