From 04b1f4f28d19bd58b86ed24410585691ab4d782d Mon Sep 17 00:00:00 2001 From: pb Date: Fri, 26 Apr 2013 00:59:09 +0000 Subject: [PATCH] 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 --- .../src/WEB-INF/resources/cms-service-map.xml | 14 +- .../arsdigita/cms/ContentCenterServlet.java | 2 +- .../src/com/arsdigita/cms/ServiceServlet.java | 147 ++++++++---------- .../arsdigita/cms/dispatcher/BaseAsset.java | 33 ++-- .../arsdigita/cms/dispatcher/BaseImage.java | 2 +- .../arsdigita/cms/dispatcher/SimpleCache.java | 3 + 6 files changed, 100 insertions(+), 101 deletions(-) diff --git a/ccm-cms/src/WEB-INF/resources/cms-service-map.xml b/ccm-cms/src/WEB-INF/resources/cms-service-map.xml index 9f814dd2d..050ccd719 100755 --- a/ccm-cms/src/WEB-INF/resources/cms-service-map.xml +++ b/ccm-cms/src/WEB-INF/resources/cms-service-map.xml @@ -1,22 +1,34 @@ - logout/ + /logout/ com.arsdigita.cms.ui.Logout + + /stream/image/ com.arsdigita.cms.dispatcher.StreamImage + + /download/image/ com.arsdigita.cms.dispatcher.DownloadImage + + /stream/asset/ com.arsdigita.cms.dispatcher.StreamAsset + + /download/asset/ com.arsdigita.cms.dispatcher.DownloadAsset diff --git a/ccm-cms/src/com/arsdigita/cms/ContentCenterServlet.java b/ccm-cms/src/com/arsdigita/cms/ContentCenterServlet.java index 085ae6d8f..09e1342fb 100644 --- a/ccm-cms/src/com/arsdigita/cms/ContentCenterServlet.java +++ b/ccm-cms/src/com/arsdigita/cms/ContentCenterServlet.java @@ -229,7 +229,7 @@ public class ContentCenterServlet extends BaseApplicationServlet { sreq = DispatcherHelper.restoreOriginalRequest(sreq); rd.forward(sreq, sresp); } else { - // String requestUri = sreq.getRequestURI(); + sresp.sendError(404, sreq.getRequestURI() + " not found on this server."); } diff --git a/ccm-cms/src/com/arsdigita/cms/ServiceServlet.java b/ccm-cms/src/com/arsdigita/cms/ServiceServlet.java index 8f819c609..a684a3f3f 100644 --- a/ccm-cms/src/com/arsdigita/cms/ServiceServlet.java +++ b/ccm-cms/src/com/arsdigita/cms/ServiceServlet.java @@ -33,7 +33,6 @@ import com.arsdigita.web.Web; import com.arsdigita.xml.XML; import java.io.IOException; -import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import javax.servlet.RequestDispatcher; @@ -44,10 +43,23 @@ import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; 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 * 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 * 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. * * The CMS Service determines whether a Page 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 Page is registered to the URL, then the CMS Service hands * the request to the TemplateResolver to find an appropriate JSP file. @@ -74,18 +86,15 @@ public class ServiceServlet extends BaseApplicationServlet { * class names). */ 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.*/ - private static HashMap s_pageClasses = new HashMap(); + /** Mapping between a relative URL and the class name of a service. */ + private static HashMap s_serviceClasses = new HashMap(); - /** Instantiated ResourceHandler cache. This allows for lazy loading. */ - private static SimpleCache s_pages = new SimpleCache(); + /** Instantiated services cache. This allows for lazy loading of the class + * (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 - * creating virtual directories, so that relative URLs and redirects - * work. */ - private ArrayList m_trailingSlashList = new ArrayList(); - - /** Path to directory containg ccm-cms template files */ + /** Path to directory containg ccm-cms template files, used in case of fall + * back, when no service class is found in s_serviceClasses rsp. MAP_FILE */ private String m_templatePath; /** 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"); } - /* Initialize List with an empty URL. Later URL's are added which are - * provided w/o trailing slash rsp. file extension. */ - requireTrailingSlash(""); - - /* Process mapping file. */ + /* Process mapping file and fill up s_serviceClasses. */ readFromFile(MAP_FILE); /** Set Template base path for JSP's */ @@ -141,42 +146,38 @@ public class ServiceServlet extends BaseApplicationServlet { } 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(); - 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: - // probably want to redirect. - if ( m_trailingSlashList.contains(url) && !originalUrl.endsWith("/") ) { - DispatcherHelper.sendRedirect(sreq, sresp, originalUrl + "/"); - return; + /* Get the service being requested, i.e. the remaining URL following + * the servlet address ( ccm/cms-service by default) */ + String url = sreq.getPathInfo(); + if (url.length() > 1 && url.endsWith("/")) { + /* 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. - // Deprecated and here implemented as a No-OP method! - /* checkUserAccess(request, response, actx); */ + // User access can not be checked here, but has to be checked by each + // service! - ResourceHandler page = getResource(url); + /* Determine the service requested by url */ + ResourceHandler serviceResource = getResource(url); - if (page == null) { - //Retry without last part - final String[] tokens = url.split("/"); - - 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); + if ( serviceResource != null ) { + // Serve the serviceResource. + serviceResource.init(); + serviceResource.dispatch(sreq, sresp, ctx); } else { // Fall back on the JSP application dispatcher. if (s_log.isInfoEnabled()) { @@ -192,7 +193,7 @@ public class ServiceServlet extends BaseApplicationServlet { sreq = DispatcherHelper.restoreOriginalRequest(sreq); rd.forward(sreq,sresp); } 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 * @return A ResourceHandler or null if none exists. * @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. - ResourceHandler page = (ResourceHandler) s_pages.get(url); + ResourceHandler page = (ResourceHandler) s_services.get(url); if ( page == null ) { - // Next check if the URL maps to a page class. - String pageClassName = (String) s_pageClasses.get(url); + // Next check if the URL maps to a serviceResource class. + String pageClassName = (String) s_serviceClasses.get(url); if ( pageClassName != null ) { Class pageClass; @@ -230,7 +235,7 @@ public class ServiceServlet extends BaseApplicationServlet { throw new ServletException(e); } - // Try and instantiate the page. + // Try and instantiate the serviceResource. try { page = (ResourceHandler) pageClass.newInstance(); } catch (InstantiationException e) { @@ -242,7 +247,7 @@ public class ServiceServlet extends BaseApplicationServlet { } page.init(); - s_pages.put(url, page); + s_services.put(url, 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: *
      * <dispatcher-configuration>
      *   <url-mapping
-     *     <url>my-page</url>
-     *     OR <page-class>com.arsdigita.Page.class</page-class>
+     *     <url>my-serviceResource</url>
+     *     OR <serviceResource-class>com.arsdigita.Page</page-class>
      *   <url-mapping
      * </dispatcher-configuration>
      * 
*/ private void readFromFile(final String file) { - // XML.parseResource(file, newParseConfigHandler(s_pageClasses)); - XML.parseResource(file, new PageClassConfigHandler(s_pageClasses)); + XML.parseResource(file, new PageClassConfigHandler(s_serviceClasses)); } - /** - * 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); -// } /** diff --git a/ccm-cms/src/com/arsdigita/cms/dispatcher/BaseAsset.java b/ccm-cms/src/com/arsdigita/cms/dispatcher/BaseAsset.java index bfd443133..08cde7bb7 100755 --- a/ccm-cms/src/com/arsdigita/cms/dispatcher/BaseAsset.java +++ b/ccm-cms/src/com/arsdigita/cms/dispatcher/BaseAsset.java @@ -52,15 +52,6 @@ class BaseAsset extends ResourceHandlerImpl { private static final BigDecimalParameter s_assetId = new BigDecimalParameter(ASSET_ID); 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 String m_disposition; @@ -79,7 +70,7 @@ class BaseAsset extends ResourceHandlerImpl { * Content-Disposition in HTTP. */ protected void setFilenameHeader(HttpServletResponse response, - BinaryAsset asset) { + BinaryAsset asset) { String filename = asset.getName(); if (filename == null) { filename = s_defaultName; @@ -95,7 +86,7 @@ class BaseAsset extends ResourceHandlerImpl { } private void setHeaders(HttpServletResponse response, - BinaryAsset asset) { + BinaryAsset asset) { setFilenameHeader(response, asset); Long contentLength = new Long(asset.getSize()); @@ -121,7 +112,8 @@ class BaseAsset extends ResourceHandlerImpl { } private void send(HttpServletResponse response, - BinaryAsset asset) throws IOException { + BinaryAsset asset) + throws IOException { // Stream the blob. OutputStream out = response.getOutputStream(); 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 public final void dispatch(HttpServletRequest request, - HttpServletResponse response, - RequestContext actx) - throws IOException, ServletException { + HttpServletResponse response, + RequestContext actx) + throws IOException, ServletException { // Fetch and validate the asset ID OID oid = null; diff --git a/ccm-cms/src/com/arsdigita/cms/dispatcher/BaseImage.java b/ccm-cms/src/com/arsdigita/cms/dispatcher/BaseImage.java index abbf3788d..94970c533 100755 --- a/ccm-cms/src/com/arsdigita/cms/dispatcher/BaseImage.java +++ b/ccm-cms/src/com/arsdigita/cms/dispatcher/BaseImage.java @@ -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 * Content-Disposition in HTTP. */ diff --git a/ccm-cms/src/com/arsdigita/cms/dispatcher/SimpleCache.java b/ccm-cms/src/com/arsdigita/cms/dispatcher/SimpleCache.java index 2a75fe5e8..ad4dbfd89 100755 --- a/ccm-cms/src/com/arsdigita/cms/dispatcher/SimpleCache.java +++ b/ccm-cms/src/com/arsdigita/cms/dispatcher/SimpleCache.java @@ -53,6 +53,7 @@ public class SimpleCache extends Hashtable{ * @param key The object key * @return The cached object, null if there is none */ + @Override public Object get(Object key) { return super.get(key); } @@ -64,6 +65,7 @@ public class SimpleCache extends Hashtable{ * @param value The object to be cached * @return The cached object */ + @Override public Object put(Object key, Object value) { return super.put(key, value); } @@ -74,6 +76,7 @@ public class SimpleCache extends Hashtable{ * @param key The object key * @return The formerly-cached object */ + @Override public Object remove(Object key) { return super.remove(key); }