Set some additional headers to improve cache handling for multi lingual sites
git-svn-id: https://svn.libreccm.org/ccm/trunk@4911 8810af33-2d31-482b-a856-94f89814c4dfmaster
parent
3aea3f4425
commit
c3a9839ae5
|
|
@ -27,12 +27,15 @@ import com.arsdigita.bebop.parameters.ParameterModel;
|
|||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
import com.arsdigita.bebop.util.Traversal;
|
||||
import com.arsdigita.developersupport.DeveloperSupport;
|
||||
import com.arsdigita.globalization.GlobalizationHelper;
|
||||
import com.arsdigita.kernel.Kernel;
|
||||
import com.arsdigita.profiler.Profiler;
|
||||
import com.arsdigita.util.Assert;
|
||||
import com.arsdigita.util.SystemInformation;
|
||||
import com.arsdigita.web.WebConfig;
|
||||
import com.arsdigita.xml.Document;
|
||||
import com.arsdigita.xml.Element;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.Collection;
|
||||
|
|
@ -45,21 +48,27 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
/**
|
||||
* The top-level container for all Bebop components and containers.
|
||||
*
|
||||
* <UL>
|
||||
* <LI>Holds references to the components of a page.</LI>
|
||||
* <LI>Provides methods for servicing requests and for notifying other components that a request for
|
||||
* this page has been received through {@link ActionListener ActionListeners}.</LI>
|
||||
* <LI>Tracks request parameters for stateful components, such as tabbed panes and sortable
|
||||
* tables.</LI>
|
||||
* <LI>Provides methods for servicing requests and for notifying other
|
||||
* components that a request for this page has been received through
|
||||
* {@link ActionListener ActionListeners}.</LI>
|
||||
* <LI>Tracks request parameters for stateful components, such as tabbed panes
|
||||
* and sortable tables.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* A typical <code>Page</code> may be created as follows: null <blockquote><pre><code>
|
||||
|
|
@ -85,14 +94,16 @@ public class Page extends SimpleComponent implements Container {
|
|||
*/
|
||||
private static final String DELIMITER = ".";
|
||||
/**
|
||||
* The prefix that gets prepended to all state variables. Components must not use variables
|
||||
* starting with this prefix. This guarantees that the page state and variables individual
|
||||
* components wish to pass do not interfere with each other.
|
||||
* The prefix that gets prepended to all state variables. Components must
|
||||
* not use variables starting with this prefix. This guarantees that the
|
||||
* page state and variables individual components wish to pass do not
|
||||
* interfere with each other.
|
||||
*/
|
||||
private static final String COMPONENT_PREFIX = "bbp" + DELIMITER;
|
||||
private static final String INTERNAL = COMPONENT_PREFIX;
|
||||
/**
|
||||
* The name of the special parameter that indicates which component has been selected.
|
||||
* The name of the special parameter that indicates which component has been
|
||||
* selected.
|
||||
*/
|
||||
static final String SELECTED = INTERNAL + "s";
|
||||
static final String CONTROL_EVENT = INTERNAL + "e";
|
||||
|
|
@ -109,14 +120,15 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* The name of the request parameter used for the visibility state of components stored in
|
||||
* m_invisible.
|
||||
* The name of the request parameter used for the visibility state of
|
||||
* components stored in m_invisible.
|
||||
*/
|
||||
static final String INVISIBLE = INTERNAL + "i";
|
||||
/**
|
||||
* Map of stateful components (id --> Component) SortedMap used because component based hash for
|
||||
* page is based on concatenation of component ids, and so need to guarantee that they are
|
||||
* returned in the same order for the same page - cg.
|
||||
* Map of stateful components (id --> Component) SortedMap used because
|
||||
* component based hash for page is based on concatenation of component ids,
|
||||
* and so need to guarantee that they are returned in the same order for the
|
||||
* same page - cg.
|
||||
*/
|
||||
private SortedMap m_componentMap;
|
||||
private List m_components;
|
||||
|
|
@ -132,32 +144,35 @@ public class Page extends SimpleComponent implements Container {
|
|||
private List m_actionListeners;
|
||||
private List m_requestListeners;
|
||||
/**
|
||||
* The title of the page to be added in the head of HTML output. The title is wrapped in a Label
|
||||
* to allow developers to add PrintListeners to dynamically change the value of the title.
|
||||
* The title of the page to be added in the head of HTML output. The title
|
||||
* is wrapped in a Label to allow developers to add PrintListeners to
|
||||
* dynamically change the value of the title.
|
||||
*/
|
||||
private Label m_title;
|
||||
/**
|
||||
* Stores the actual title for the current request. The title may be generated with a
|
||||
* PrintListener of the m_title Label.
|
||||
* Stores the actual title for the current request. The title may be
|
||||
* generated with a PrintListener of the m_title Label.
|
||||
*/
|
||||
private RequestLocal m_currentTitle;
|
||||
/**
|
||||
* A list of all the client-side stylesheets. The elements of the list are of type
|
||||
* Page.Stylesheet, defined at the end of this file.
|
||||
* A list of all the client-side stylesheets. The elements of the list are
|
||||
* of type Page.Stylesheet, defined at the end of this file.
|
||||
*/
|
||||
private List m_clientStylesheets;
|
||||
private StringParameter m_selected;
|
||||
private StringParameter m_controlEvent;
|
||||
private StringParameter m_controlValue;
|
||||
/**
|
||||
* The default (initial) visibility of components. The encoding is identical to that for
|
||||
* PageState.m_invisible.
|
||||
* The default (initial) visibility of components. The encoding is identical
|
||||
* to that for PageState.m_invisible.
|
||||
*
|
||||
* This variable is package-friendly since it needs to be accessed by PageState.
|
||||
* This variable is package-friendly since it needs to be accessed by
|
||||
* PageState.
|
||||
*/
|
||||
protected BitSet m_invisible;
|
||||
/**
|
||||
* The PageErrorDisplay component that will display page state validation errors on this page
|
||||
* The PageErrorDisplay component that will display page state validation
|
||||
* errors on this page
|
||||
*/
|
||||
private Component m_errorDisplay;
|
||||
/**
|
||||
|
|
@ -165,39 +180,41 @@ public class Page extends SimpleComponent implements Container {
|
|||
*/
|
||||
private boolean m_finished = false;
|
||||
/**
|
||||
* indicates whether pageState.stateAsURL() should export the entire state for this page, or
|
||||
* whether it should only export the control event as a URL and use the HttpSession for the rest
|
||||
* of the page state.
|
||||
* indicates whether pageState.stateAsURL() should export the entire state
|
||||
* for this page, or whether it should only export the control event as a
|
||||
* URL and use the HttpSession for the rest of the page state.
|
||||
*/
|
||||
private boolean m_useHttpSession = false;
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if this page should export state through the HttpSession instead of
|
||||
* the URL query string.
|
||||
* Returns <code>true</code> if this page should export state through the
|
||||
* HttpSession instead of the URL query string.
|
||||
* <P>
|
||||
* If this returns <code>true</code>, then PageState.stateAsURL() will only export the control
|
||||
* event as a URL query string. If this returns <code>false</code>, then stateAsURL() will
|
||||
* export the entire page state.
|
||||
* If this returns <code>true</code>, then PageState.stateAsURL() will only
|
||||
* export the control event as a URL query string. If this returns
|
||||
* <code>false</code>, then stateAsURL() will export the entire page state.
|
||||
*
|
||||
* @see PageState#stateAsURL
|
||||
*
|
||||
* @return <code>true</code> if this page should export state through the HttpSession;
|
||||
* <code>false</code> if it should export using the URL query string.
|
||||
* @return <code>true</code> if this page should export state through the
|
||||
* HttpSession; <code>false</code> if it should export using the URL
|
||||
* query string.
|
||||
*/
|
||||
public boolean isUsingHttpSession() {
|
||||
return m_useHttpSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates to this page whether it should export its entire state to subsequent requests
|
||||
* through the URL query string, or if it should use the HttpSession instead and only use the
|
||||
* URL query string for the control event.
|
||||
* Indicates to this page whether it should export its entire state to
|
||||
* subsequent requests through the URL query string, or if it should use the
|
||||
* HttpSession instead and only use the URL query string for the control
|
||||
* event.
|
||||
*
|
||||
* @see PageState#stateAsURL
|
||||
*
|
||||
* @param b <code>true</code> if PageState.stateAsURL() will export only the control event as a
|
||||
* URL query string. <code>false</code> if stateAsURL() will export the entire page
|
||||
* state.
|
||||
* @param b <code>true</code> if PageState.stateAsURL() will export only the
|
||||
* control event as a URL query string. <code>false</code> if
|
||||
* stateAsURL() will export the entire page state.
|
||||
*/
|
||||
public void setUsingHttpSession(boolean b) {
|
||||
m_useHttpSession = b;
|
||||
|
|
@ -273,7 +290,8 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates an empty page with the specified title and implicit BoxPanel container.
|
||||
* Creates an empty page with the specified title and implicit BoxPanel
|
||||
* container.
|
||||
*
|
||||
* @param title title for this page
|
||||
*/
|
||||
|
|
@ -284,7 +302,8 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates an empty page with the specified title and implicit BoxPanel container.
|
||||
* Creates an empty page with the specified title and implicit BoxPanel
|
||||
* container.
|
||||
*
|
||||
* @param title title for this page
|
||||
*/
|
||||
|
|
@ -304,12 +323,13 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Adds a component with the specified layout constraints to this container. Layout constraints
|
||||
* are defined in each layout container as static ints. To specify multiple constraints, use
|
||||
* bitwise OR.
|
||||
* Adds a component with the specified layout constraints to this container.
|
||||
* Layout constraints are defined in each layout container as static ints.
|
||||
* To specify multiple constraints, use bitwise OR.
|
||||
*
|
||||
* @param c component to add to this container
|
||||
* @param constraints layout constraints (a bitwise OR of static ints in the particular layout)
|
||||
* @param constraints layout constraints (a bitwise OR of static ints in the
|
||||
* particular layout)
|
||||
*/
|
||||
@Override
|
||||
public void add(Component c, int constraints) {
|
||||
|
|
@ -317,18 +337,20 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if this list contains the specified element. More formally, returns
|
||||
* <code>true</code> if and only if this list contains at least one element e such that (o==null
|
||||
* ? e==null : o.equals(e)).
|
||||
* Returns <code>true</code> if this list contains the specified element.
|
||||
* More formally, returns <code>true</code> if and only if this list
|
||||
* contains at least one element e such that (o==null ? e==null :
|
||||
* o.equals(e)).
|
||||
* <P>
|
||||
* This method returns <code>true</code> only if the component has been directly added to this
|
||||
* container. If this container contains another container that contains this component, this
|
||||
* method returns <code>false</code>.
|
||||
* This method returns <code>true</code> only if the component has been
|
||||
* directly added to this container. If this container contains another
|
||||
* container that contains this component, this method returns
|
||||
* <code>false</code>.
|
||||
*
|
||||
* @param o element whose presence in this container is to be tested
|
||||
*
|
||||
* @return <code>true</code> if this Container contains the specified component directly;
|
||||
* <code>false</code> otherwise.
|
||||
* @return <code>true</code> if this Container contains the specified
|
||||
* component directly; <code>false</code> otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
|
|
@ -336,9 +358,10 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the component at the specified position. Each call to the add method increments the
|
||||
* index. Since the user has no control over the index of added components (other than counting
|
||||
* each call to add), this method should be used in conjunction with indexOf.
|
||||
* Returns the component at the specified position. Each call to the add
|
||||
* method increments the index. Since the user has no control over the index
|
||||
* of added components (other than counting each call to add), this method
|
||||
* should be used in conjunction with indexOf.
|
||||
*
|
||||
* @param index the index of the item to be retrieved from this Container
|
||||
*
|
||||
|
|
@ -354,12 +377,11 @@ public class Page extends SimpleComponent implements Container {
|
|||
*
|
||||
* @param c component to search for
|
||||
*
|
||||
* @return the index in this list of the first occurrence of the specified element, or -1 if
|
||||
* this list does not contain this element.
|
||||
* @return the index in this list of the first occurrence of the specified
|
||||
* element, or -1 if this list does not contain this element.
|
||||
*
|
||||
* @pre c != null
|
||||
* @post contains(c) implies (return >= 0) && (return < size())
|
||||
* @pos
|
||||
* @post contains(c) implies (return >= 0) && (return < size()) @pos
|
||||
* t !contains(c) implies return == -1
|
||||
*/
|
||||
@Override
|
||||
|
|
@ -370,8 +392,8 @@ public class Page extends SimpleComponent implements Container {
|
|||
/**
|
||||
* Returns <code>true</code> if the container contains no components.
|
||||
*
|
||||
* @return <code>true</code> if this container contains no components; <code>false</code>
|
||||
* otherwise.
|
||||
* @return <code>true</code> if this container contains no components;
|
||||
* <code>false</code> otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
|
|
@ -379,8 +401,9 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the number of elements in this container. This does not recursively count the
|
||||
* components that are indirectly contained in this container.
|
||||
* Returns the number of elements in this container. This does not
|
||||
* recursively count the components that are indirectly contained in this
|
||||
* container.
|
||||
*
|
||||
* @return the number of components directly in this container.
|
||||
*/
|
||||
|
|
@ -395,7 +418,8 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the panel that the <code>Page</code> uses for rendering its components.
|
||||
* Returns the panel that the <code>Page</code> uses for rendering its
|
||||
* components.
|
||||
*
|
||||
* @return the panel.
|
||||
*/
|
||||
|
|
@ -404,8 +428,9 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Set the Container used for rendering components on this page. Caution should be used with
|
||||
* this function, as the existing container is simply overwritten.
|
||||
* Set the Container used for rendering components on this page. Caution
|
||||
* should be used with this function, as the existing container is simply
|
||||
* overwritten.
|
||||
*
|
||||
* @param c
|
||||
*
|
||||
|
|
@ -456,15 +481,16 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link Component} that will display the validation errors in the current
|
||||
* {@link PageState}. Any validation error in the <code>PageState</code> will cause the
|
||||
* <code>Page</code> to completely ignore all other components and render only the error display
|
||||
* component.
|
||||
* Sets the {@link Component} that will display the validation errors in the
|
||||
* current {@link PageState}. Any validation error in the
|
||||
* <code>PageState</code> will cause the <code>Page</code> to completely
|
||||
* ignore all other components and render only the error display component.
|
||||
* <p>
|
||||
* By default, a {@link PageErrorDisplay} component is used to display the validation errors.
|
||||
* By default, a {@link PageErrorDisplay} component is used to display the
|
||||
* validation errors.
|
||||
*
|
||||
* @param c the component that will display the validation errors in the current
|
||||
* <code>PageState</code>
|
||||
* @param c the component that will display the validation errors in the
|
||||
* current <code>PageState</code>
|
||||
*/
|
||||
public final void setErrorDisplay(Component c) {
|
||||
Assert.isUnlocked(this);
|
||||
|
|
@ -472,32 +498,35 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link Component} that will display the validation errors in the current
|
||||
* {@link PageState}. Any validation error in the <code>PageState</code> will cause the
|
||||
* <code>Page</code> to completely ignore all other components and render only the error display
|
||||
* component.
|
||||
* Gets the {@link Component} that will display the validation errors in the
|
||||
* current {@link PageState}. Any validation error in the
|
||||
* <code>PageState</code> will cause the <code>Page</code> to completely
|
||||
* ignore all other components and render only the error display component.
|
||||
* <p>
|
||||
* By default, a {@link PageErrorDisplay} component is used to display the validation errors.
|
||||
* By default, a {@link PageErrorDisplay} component is used to display the
|
||||
* validation errors.
|
||||
*
|
||||
* @return the component that will display the validation errors in the current
|
||||
* <code>PageState</code>.
|
||||
* @return the component that will display the validation errors in the
|
||||
* current <code>PageState</code>.
|
||||
*/
|
||||
public final Component getErrorDisplay() {
|
||||
return m_errorDisplay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a client-side stylesheet that should be used in HTML output. Arbitrarily many
|
||||
* client-side stylesheets can be added with this method. To use a CSS stylesheet, call
|
||||
* something like <code>setStyleSheet("style.css", "text/css")</code>.
|
||||
* Adds a client-side stylesheet that should be used in HTML output.
|
||||
* Arbitrarily many client-side stylesheets can be added with this method.
|
||||
* To use a CSS stylesheet, call something like
|
||||
* <code>setStyleSheet("style.css", "text/css")</code>.
|
||||
*
|
||||
* <p>
|
||||
* These values will ultimately wind up in a <tt><link></tt>
|
||||
* tag in the head of the HTML page.
|
||||
*
|
||||
* <p>
|
||||
* Note that the stylesheet set with this call has nothing to do with the XSLT stylesheet
|
||||
* (transformer) that is applied to the XML generated from this page!
|
||||
* Note that the stylesheet set with this call has nothing to do with the
|
||||
* XSLT stylesheet (transformer) that is applied to the XML generated from
|
||||
* this page!
|
||||
*
|
||||
* @param styleSheetURI the location of the stylesheet
|
||||
* @param mimeType the MIME type of the stylesheet, usually
|
||||
|
|
@ -510,13 +539,14 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Adds a global state parameter to this page. Global parameters are values that need to be
|
||||
* preserved between requests, but that have no special connection to any of the components on
|
||||
* the page. For a page that displays details about an item, a global parameter would be used to
|
||||
* identify the item.
|
||||
* Adds a global state parameter to this page. Global parameters are values
|
||||
* that need to be preserved between requests, but that have no special
|
||||
* connection to any of the components on the page. For a page that displays
|
||||
* details about an item, a global parameter would be used to identify the
|
||||
* item.
|
||||
*
|
||||
* If the parameter was previously added as a component state parameter, its name is unmangled
|
||||
* and stays unmangled.
|
||||
* If the parameter was previously added as a component state parameter, its
|
||||
* name is unmangled and stays unmangled.
|
||||
*
|
||||
* @see #addComponentStateParam
|
||||
*
|
||||
|
|
@ -532,8 +562,8 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Constructs the top nodes of the DOM or JDOM tree. Used by generateXML(PageState, Document)
|
||||
* below.
|
||||
* Constructs the top nodes of the DOM or JDOM tree. Used by
|
||||
* generateXML(PageState, Document) below.
|
||||
* <p>
|
||||
* Generates DOM fragment:
|
||||
* <pre>
|
||||
|
|
@ -543,7 +573,8 @@ public class Page extends SimpleComponent implements Container {
|
|||
* ... page content gnerated by children ...
|
||||
* </bebop:page></pre> The content of the <tt><title></tt>
|
||||
* element can be set by calling {@link #setTitle setTitle}. The
|
||||
* <tt><stylesheet></tt> element will only be present if a stylesheet has been set with {@link
|
||||
* <tt><stylesheet></tt> element will only be present if a stylesheet
|
||||
* has been set with {@link
|
||||
* #setStyleSheet setStyleSheet}.
|
||||
*
|
||||
* @param ps the page state for the current page
|
||||
|
|
@ -573,8 +604,9 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Constructs a DOM or JDOM tree with all components on the page. The tree represents the page
|
||||
* that results from the {@link javax.servlet.http.HttpServletRequest} kept in the
|
||||
* Constructs a DOM or JDOM tree with all components on the page. The tree
|
||||
* represents the page that results from the
|
||||
* {@link javax.servlet.http.HttpServletRequest} kept in the
|
||||
* <code>state</code>.
|
||||
*
|
||||
* @param state the page state produced by {@link #process}
|
||||
|
|
@ -603,10 +635,33 @@ public class Page extends SimpleComponent implements Container {
|
|||
if (Kernel.getConfig().isDebugEnabled() && debugStructure(state.
|
||||
getRequest())) {
|
||||
|
||||
Element structure = page.newChildElement("bebop:structure", BEBOP_XML_NS);
|
||||
Element structure = page.newChildElement("bebop:structure",
|
||||
BEBOP_XML_NS);
|
||||
|
||||
showStructure(state, structure);
|
||||
}
|
||||
|
||||
final HttpServletRequest request = state.getRequest();
|
||||
final HttpServletResponse response = state.getResponse();
|
||||
if (response.isCommitted()) {
|
||||
s_log.warn("Response already committed!!!");
|
||||
}
|
||||
final WebConfig webConfig = WebConfig.getInstanceOf();
|
||||
if (webConfig.getVaryHeaders() != null
|
||||
&& !webConfig.getVaryHeaders().isEmpty()) {
|
||||
response.addHeader("Vary", webConfig.getVaryHeaders());
|
||||
}
|
||||
response.addHeader("Content-Language",
|
||||
GlobalizationHelper.getNegotiatedLocale().toString());
|
||||
final HttpSession session = request.getSession();
|
||||
if (session != null && session.getAttribute(
|
||||
GlobalizationHelper.LANG_PARAM) != null) {
|
||||
|
||||
response.addCookie(new Cookie(
|
||||
GlobalizationHelper.LANG_PARAM,
|
||||
(String) session.getAttribute(
|
||||
GlobalizationHelper.LANG_PARAM)));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean debugStructure(HttpServletRequest req) {
|
||||
|
|
@ -623,11 +678,11 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a PageState object and processes it by calling the respond method on the selected
|
||||
* component. Processes a request by notifying the component from which the process originated
|
||||
* and {@link #fireActionEvent
|
||||
* broadcasts} an {@link ActionEvent} to all the listeners that registered with
|
||||
* {@link #addActionListener addActionListener}.
|
||||
* Creates a PageState object and processes it by calling the respond method
|
||||
* on the selected component. Processes a request by notifying the component
|
||||
* from which the process originated and {@link #fireActionEvent
|
||||
* broadcasts} an {@link ActionEvent} to all the listeners that registered
|
||||
* with {@link #addActionListener addActionListener}.
|
||||
*
|
||||
* @see #generateXML(PageState,Document) generateXML
|
||||
*
|
||||
|
|
@ -656,8 +711,8 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Processes the supplied PageState object according to this PageModel. Calls the respond method
|
||||
* on the selected Bebop component.
|
||||
* Processes the supplied PageState object according to this PageModel.
|
||||
* Calls the respond method on the selected Bebop component.
|
||||
*/
|
||||
public void process(PageState state) throws ServletException {
|
||||
Assert.isLocked(this);
|
||||
|
|
@ -689,11 +744,13 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Builds a DOM Document from the current request state by doing a depth-first tree walk on the
|
||||
* current set of components in this Page, calling generateXML on each. Does NOT do the
|
||||
* rendering. If the HTTP response has already been committed, does not build the XML document.
|
||||
* Builds a DOM Document from the current request state by doing a
|
||||
* depth-first tree walk on the current set of components in this Page,
|
||||
* calling generateXML on each. Does NOT do the rendering. If the HTTP
|
||||
* response has already been committed, does not build the XML document.
|
||||
*
|
||||
* @return a DOM ready for rendering, or null if the response has already been committed.
|
||||
* @return a DOM ready for rendering, or null if the response has already
|
||||
* been committed.
|
||||
*
|
||||
* @post res.isCommitted() == (return == null)
|
||||
*/
|
||||
|
|
@ -725,8 +782,8 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Finishes building the page. The tree of components is traversed and each component is told to
|
||||
* add its state parameters to the page's state model.
|
||||
* Finishes building the page. The tree of components is traversed and each
|
||||
* component is told to add its state parameters to the page's state model.
|
||||
*
|
||||
* @pre ! isLocked()
|
||||
*/
|
||||
|
|
@ -760,7 +817,8 @@ public class Page extends SimpleComponent implements Container {
|
|||
* Locks the page and all its components against further modifications.
|
||||
*
|
||||
* <p>
|
||||
* Locking a page helps in finding mistakes that result from modifying a page's structure.</P>
|
||||
* Locking a page helps in finding mistakes that result from modifying a
|
||||
* page's structure.</P>
|
||||
*/
|
||||
@Override
|
||||
public void lock() {
|
||||
|
|
@ -788,8 +846,8 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Registers a listener that is notified whenever a request to this page is made, after the
|
||||
* selected component has had a chance to respond.
|
||||
* Registers a listener that is notified whenever a request to this page is
|
||||
* made, after the selected component has had a chance to respond.
|
||||
*
|
||||
* @pre l != null
|
||||
* @pre ! isLocked()
|
||||
|
|
@ -811,8 +869,8 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Registers a listener that is notified whenever a request to this page is made, before the
|
||||
* selected component has had a chance to respond.
|
||||
* Registers a listener that is notified whenever a request to this page is
|
||||
* made, before the selected component has had a chance to respond.
|
||||
*
|
||||
* @pre l != null
|
||||
* @pre ! isLocked()
|
||||
|
|
@ -836,9 +894,9 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Broadcasts an {@link ActionEvent} to all registered listeners. The source of the event is
|
||||
* this page, and the state recorded in the event is the one resulting from processing the
|
||||
* current request.
|
||||
* Broadcasts an {@link ActionEvent} to all registered listeners. The source
|
||||
* of the event is this page, and the state recorded in the event is the one
|
||||
* resulting from processing the current request.
|
||||
*
|
||||
* @param the state for this event
|
||||
*
|
||||
|
|
@ -863,9 +921,9 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Broadcasts a {@link RequestEvent} to all registered listeners. The source of the event is
|
||||
* this page, and the state recorded in the event is the one resulting from processing the
|
||||
* current request.
|
||||
* Broadcasts a {@link RequestEvent} to all registered listeners. The source
|
||||
* of the event is this page, and the state recorded in the event is the one
|
||||
* resulting from processing the current request.
|
||||
*
|
||||
* @param state the state for this event
|
||||
*
|
||||
|
|
@ -890,9 +948,9 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Export page generator information if set. The m_pageGenerator is a HashMap containing the
|
||||
* information as key value. In general this should include generator name and generator
|
||||
* version.
|
||||
* Export page generator information if set. The m_pageGenerator is a
|
||||
* HashMap containing the information as key value. In general this should
|
||||
* include generator name and generator version.
|
||||
*
|
||||
* @param page parent element - should be bebeop:page
|
||||
*
|
||||
|
|
@ -901,7 +959,8 @@ public class Page extends SimpleComponent implements Container {
|
|||
final protected void exportSystemInformation(Element page) {
|
||||
SystemInformation sysInfo = SystemInformation.getInstance();
|
||||
if (!sysInfo.isEmpty()) {
|
||||
Element gen = page.newChildElement("bebop:systemInformation", BEBOP_XML_NS);
|
||||
Element gen = page.newChildElement("bebop:systemInformation",
|
||||
BEBOP_XML_NS);
|
||||
|
||||
Iterator<Map.Entry<String, String>> keyValues = sysInfo.iterator();
|
||||
while (keyValues.hasNext()) {
|
||||
|
|
@ -944,7 +1003,8 @@ public class Page extends SimpleComponent implements Container {
|
|||
if (!stateContains(c)) {
|
||||
if (c == null) {
|
||||
s_log.error("c is null");
|
||||
} /*else {
|
||||
}
|
||||
/*else {
|
||||
s_log.error("c: " + c.toString());
|
||||
}*/
|
||||
|
||||
|
|
@ -963,10 +1023,12 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Registers a state parameter for a component. It is permissible to register the same state
|
||||
* parameter several times, from the same or different components. The name of the parameter
|
||||
* will be changed to ensure that it won't clash with any other component's parameter. If the
|
||||
* parameter is added more than once, the name is only changed the first time it is added.
|
||||
* Registers a state parameter for a component. It is permissible to
|
||||
* register the same state parameter several times, from the same or
|
||||
* different components. The name of the parameter will be changed to ensure
|
||||
* that it won't clash with any other component's parameter. If the
|
||||
* parameter is added more than once, the name is only changed the first
|
||||
* time it is added.
|
||||
*
|
||||
* @param c the component to register the parameter for
|
||||
* @param p the state parameter to register
|
||||
|
|
@ -986,7 +1048,8 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
if (!m_stateModel.containsFormParam(p)) {
|
||||
String name = parameterName(c, p.getName());
|
||||
s_log.debug(String.format("Setting name of parameter to add to '%s'",
|
||||
s_log.debug(String
|
||||
.format("Setting name of parameter to add to '%s'",
|
||||
name));
|
||||
p.setName(name);
|
||||
m_stateModel.addFormParam(p);
|
||||
|
|
@ -1009,17 +1072,17 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the state index of a component. This is the number assigned to the component in the
|
||||
* register traveral
|
||||
* Gets the state index of a component. This is the number assigned to the
|
||||
* component in the register traveral
|
||||
*
|
||||
* @param c the component to search for
|
||||
*
|
||||
* @return the index in this list of the first occurrence of the specified element, or -1 if
|
||||
* this list does not contain this element.
|
||||
* @return the index in this list of the first occurrence of the specified
|
||||
* element, or -1 if this list does not contain this element.
|
||||
*
|
||||
* @pre c != null
|
||||
* @post contains(c) implies (return >= 0) && (return < size()) @pos
|
||||
* t !contains(c) implies return == -1
|
||||
* @post contains(c) implies (return >= 0) && (return < size()) @pos t
|
||||
* !contains(c) implies return == -1
|
||||
*/
|
||||
public int stateIndex(Component c) {
|
||||
return m_components.indexOf(c);
|
||||
|
|
@ -1046,8 +1109,7 @@ public class Page extends SimpleComponent implements Container {
|
|||
/**
|
||||
* Gets a page component by index.
|
||||
*
|
||||
* @pre (i >= 0) && (i < size()) @pos
|
||||
* t return != null
|
||||
* @pre (i >= 0) && (i < size()) @pos t return != null
|
||||
*/
|
||||
public Component getComponent(int i) {
|
||||
return (Component) m_components.get(i);
|
||||
|
|
@ -1083,8 +1145,8 @@ public class Page extends SimpleComponent implements Container {
|
|||
*
|
||||
* @param c a component contained in the page
|
||||
*
|
||||
* @return <code>true</code> if the component is visible by default; <code>false</code>
|
||||
* otherwise.
|
||||
* @return <code>true</code> if the component is visible by default;
|
||||
* <code>false</code> otherwise.
|
||||
*
|
||||
* @see #setVisibleDefault setVisibleDefault
|
||||
* @see Component#setVisible Component.setVisible
|
||||
|
|
@ -1096,16 +1158,18 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets whether the specified component is visible by default. The default visibility is used
|
||||
* when a page is displayed for the first time and on subsequent requests until the visibility
|
||||
* of a component is changed explicitly with {@link Component#setVisible
|
||||
* Sets whether the specified component is visible by default. The default
|
||||
* visibility is used when a page is displayed for the first time and on
|
||||
* subsequent requests until the visibility of a component is changed
|
||||
* explicitly with {@link Component#setVisible
|
||||
* Component.setVisible}.
|
||||
*
|
||||
* <p>
|
||||
* When a component is first added to a page, it is visible.
|
||||
*
|
||||
* @param c a component whose visibility is to be set
|
||||
* @param v <code>true</code> if the component is visible; <code>false</code> otherwise.
|
||||
* @param v <code>true</code> if the component is visible;
|
||||
* <code>false</code> otherwise.
|
||||
*
|
||||
* @see Component#setVisible Component.setVisible
|
||||
* @see Component#register Component.register
|
||||
|
|
@ -1123,7 +1187,8 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* The global name of the parameter <code>name</code> in the component <code>c</code>.
|
||||
* The global name of the parameter <code>name</code> in the component
|
||||
* <code>c</code>.
|
||||
*/
|
||||
public String parameterName(Component c, String name) {
|
||||
if (c == null || !stateContains(c)) {
|
||||
|
|
@ -1161,7 +1226,8 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Return the prefix that is prepended to each component's state parameters to keep them unique.
|
||||
* Return the prefix that is prepended to each component's state parameters
|
||||
* to keep them unique.
|
||||
*/
|
||||
private final String componentPrefix(Component c) {
|
||||
if (c == null) {
|
||||
|
|
@ -1219,10 +1285,12 @@ public class Page extends SimpleComponent implements Container {
|
|||
selected.setText(sel);
|
||||
|
||||
// Control event
|
||||
Element eventName = state.newChildElement("bebop:eventName", BEBOP_XML_NS);
|
||||
Element eventName = state.newChildElement("bebop:eventName",
|
||||
BEBOP_XML_NS);
|
||||
eventName.addAttribute(NAME, m_controlEvent.getName());
|
||||
eventName.setText(req.getParameter(m_controlEvent.getName()));
|
||||
Element eventValue = state.newChildElement("bebop:eventValue", BEBOP_XML_NS);
|
||||
Element eventValue = state.newChildElement("bebop:eventValue",
|
||||
BEBOP_XML_NS);
|
||||
eventValue.addAttribute(NAME, m_controlValue.getName());
|
||||
eventValue.setText(req.getParameter(m_controlValue.getName()));
|
||||
|
||||
|
|
@ -1231,7 +1299,8 @@ public class Page extends SimpleComponent implements Container {
|
|||
for (Iterator ii = getStateModel().getParameters(); ii.hasNext();) {
|
||||
ParameterModel p = (ParameterModel) ii.next();
|
||||
if (!p.getName().startsWith(COMPONENT_PREFIX)) {
|
||||
Element param = globalState.newChildElement("bebop:param", BEBOP_XML_NS);
|
||||
Element param = globalState.newChildElement("bebop:param",
|
||||
BEBOP_XML_NS);
|
||||
param.addAttribute(NAME, p.getName());
|
||||
param.setText(String.valueOf(s.getValue(p)));
|
||||
}
|
||||
|
|
@ -1260,11 +1329,13 @@ public class Page extends SimpleComponent implements Container {
|
|||
continue;
|
||||
}
|
||||
|
||||
Element param = parent.newChildElement("bebop:param", BEBOP_XML_NS);
|
||||
Element param = parent.newChildElement("bebop:param",
|
||||
BEBOP_XML_NS);
|
||||
param.addAttribute(NAME, unmangle(p.getName()));
|
||||
param.addAttribute("defaultValue",
|
||||
String.valueOf(req.getParameter(p.getName())));
|
||||
param.addAttribute("currentValue", String.valueOf(s.getValue(p)));
|
||||
param
|
||||
.addAttribute("currentValue", String.valueOf(s.getValue(p)));
|
||||
}
|
||||
}
|
||||
for (Iterator i = c.children(); i.hasNext();) {
|
||||
|
|
@ -1282,9 +1353,9 @@ public class Page extends SimpleComponent implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* return a string that represents an ordered list of component ids used on the page. For
|
||||
* situations where only the components present is of importance, this may be used by
|
||||
* implementations of hashCode & equals
|
||||
* return a string that represents an ordered list of component ids used on
|
||||
* the page. For situations where only the components present is of
|
||||
* importance, this may be used by implementations of hashCode & equals
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
|
|
@ -1304,7 +1375,8 @@ public class Page extends SimpleComponent implements Container {
|
|||
String componentId = (String) it.next();
|
||||
hashString.append(componentId);
|
||||
}
|
||||
s_log.debug("Time to create hashCode for page: " + (new Date().getTime() - start.
|
||||
s_log.debug("Time to create hashCode for page: " + (new Date().getTime()
|
||||
- start.
|
||||
getTime()));
|
||||
return hashString.toString();
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import javax.servlet.http.HttpSession;
|
|||
public class GlobalizationHelper {
|
||||
|
||||
public static final String LANG_INDEPENDENT = Kernel.getConfig().getLanguagesIndependentCode();
|
||||
private static final String LANG_PARAM = "lang";
|
||||
public static final String LANG_PARAM = "lang";
|
||||
|
||||
// Don't instantiate
|
||||
private GlobalizationHelper() {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import com.arsdigita.developersupport.DeveloperSupport;
|
|||
import com.arsdigita.dispatcher.DispatcherHelper;
|
||||
import com.arsdigita.dispatcher.RequestEvent;
|
||||
import com.arsdigita.domain.DataObjectNotFoundException;
|
||||
import com.arsdigita.globalization.GlobalizationHelper;
|
||||
import com.arsdigita.persistence.SessionManager;
|
||||
import com.arsdigita.persistence.TransactionContext;
|
||||
import com.arsdigita.profiler.Profiler;
|
||||
|
|
@ -40,23 +41,26 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
// NOTE
|
||||
// Combines and replaces the previous classes DispatcherServlet and BaseDispatcher
|
||||
// Most of their code and their separation are abundant as old style applications
|
||||
// are no longer supported.
|
||||
|
||||
|
||||
/**
|
||||
* <p>The CCM main dispatcher. This servlet serves as the main servlet / main
|
||||
* entry point (mapped to "/someprefix/*") for requests to any CCM webapp.</p>
|
||||
* <p>
|
||||
* The CCM main dispatcher. This servlet serves as the main servlet / main entry
|
||||
* point (mapped to "/someprefix/*") for requests to any CCM webapp.</p>
|
||||
*
|
||||
* <p>Upon finding an {@link com.arsdigita.web.Application application} at the
|
||||
* <p>
|
||||
* Upon finding an {@link com.arsdigita.web.Application application} at the
|
||||
* requested URL, this class sets a request attribute storing the ID of the
|
||||
* application and forwards to the servlet associated with that application.
|
||||
* If instead no application is found, a 404 response is generated.</p>
|
||||
* application and forwards to the servlet associated with that application. If
|
||||
* instead no application is found, a 404 response is generated.</p>
|
||||
*
|
||||
* <p>This servlet has to be deployed using web.xml entries like these:</p>
|
||||
* <p>
|
||||
* This servlet has to be deployed using web.xml entries like these:</p>
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* <servlet>
|
||||
|
|
@ -70,7 +74,8 @@ import org.apache.log4j.Logger;
|
|||
* </servlet-mapping>
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* <p>It's important to also edit the com.arsdigita.web.WebConfig m_servlet
|
||||
* <p>
|
||||
* It's important to also edit the com.arsdigita.web.WebConfig m_servlet
|
||||
* parameter to reflect where you've put your dispatcher.</p>
|
||||
*
|
||||
* <blockquote><pre>
|
||||
|
|
@ -84,39 +89,47 @@ import org.apache.log4j.Logger;
|
|||
* </pre></blockquote>
|
||||
*
|
||||
* @see com.arsdigita.web.BaseApplicationServlet
|
||||
* @author Justin Ross <<a href="mailto:jross@redhat.com">jross@redhat.com</a>>
|
||||
* @author Peter Boy <<a href="mailto:pboy@barkhof.uni-bremen.de">Peter Boy</a>>
|
||||
* @author Justin Ross
|
||||
* <<a href="mailto:jross@redhat.com">jross@redhat.com</a>>
|
||||
* @author Peter Boy <<a href="mailto:pboy@barkhof.uni-bremen.de">Peter
|
||||
* Boy</a>>
|
||||
* @version $Id: DispatcherServlet.java 738 2005-09-01 12:36:52Z sskracic $
|
||||
*/
|
||||
public class CCMDispatcherServlet extends BaseServlet {
|
||||
|
||||
/** Internal logger instance to faciliate debugging. Enable logging output
|
||||
* by editing /WEB-INF/conf/log4j.properties int hte runtime environment
|
||||
* and set com.arsdigita.web.CCMDispatcherServlet=DEBUG by uncommenting
|
||||
* or adding the line. */
|
||||
/**
|
||||
* Internal logger instance to faciliate debugging. Enable logging output by
|
||||
* editing /WEB-INF/conf/log4j.properties int hte runtime environment and
|
||||
* set com.arsdigita.web.CCMDispatcherServlet=DEBUG by uncommenting or
|
||||
* adding the line.
|
||||
*/
|
||||
private static final Logger s_log = Logger.getLogger(
|
||||
CCMDispatcherServlet.class);
|
||||
|
||||
static final String DISPATCHED_ATTRIBUTE =
|
||||
CCMDispatcherServlet.class.getName() + ".dispatched";
|
||||
static final String DISPATCHED_ATTRIBUTE = CCMDispatcherServlet.class
|
||||
.getName() + ".dispatched";
|
||||
|
||||
/** Instance of the private Cache class */
|
||||
/**
|
||||
* Instance of the private Cache class
|
||||
*/
|
||||
private final static Cache s_cache = new Cache();
|
||||
|
||||
/** String containing the web context path portion of the WEB application
|
||||
/**
|
||||
* String containing the web context path portion of the WEB application
|
||||
* where this CCMDispatcherServlet is executed. (I.e. where the WEB-INF
|
||||
* directory containing the web.xml configuring this CCMDispatcherServlet
|
||||
* is located in the servlet container webapps directory.
|
||||
* */
|
||||
* directory containing the web.xml configuring this CCMDispatcherServlet is
|
||||
* located in the servlet container webapps directory.
|
||||
*
|
||||
*/
|
||||
private static String s_contextPath;
|
||||
|
||||
public final boolean isApplicationInCache(String path) {
|
||||
return s_cache.isCached(path);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Servlet initializer uses the extension point of parent class.
|
||||
*
|
||||
* @throws ServletException
|
||||
*/
|
||||
@Override
|
||||
|
|
@ -134,51 +147,58 @@ public class CCMDispatcherServlet extends BaseServlet {
|
|||
/**
|
||||
* Extends the standard service() method of the parent BaseServlet class.
|
||||
* Looks up and identifies the web application addressed in the url and
|
||||
* forwards to that application's ApplicationServlet.
|
||||
* (new style legacy free)
|
||||
* forwards to that application's ApplicationServlet. (new style legacy
|
||||
* free)
|
||||
*
|
||||
* @param servletRequest
|
||||
* @param servletResponse
|
||||
*
|
||||
* @param sreq
|
||||
* @param sresp
|
||||
* @throws ServletException
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
protected void doService(final HttpServletRequest sreq,
|
||||
final HttpServletResponse sresp)
|
||||
protected void doService(final HttpServletRequest servletRequest,
|
||||
final HttpServletResponse servletResponse)
|
||||
throws ServletException, IOException {
|
||||
|
||||
DeveloperSupport.requestStart(new RequestEvent(sreq, sresp,
|
||||
DeveloperSupport.requestStart(new RequestEvent(servletRequest,
|
||||
servletResponse,
|
||||
null, true, false));
|
||||
if (s_log.isDebugEnabled()) {
|
||||
s_log.debug("Dispatching request " + sreq.getRequestURI() + " [" +
|
||||
sreq.getContextPath() + "," +
|
||||
sreq.getServletPath() + "," +
|
||||
sreq.getPathInfo() + "," +
|
||||
sreq.getQueryString() + "]");
|
||||
s_log.debug("Dispatching request " + servletRequest.getRequestURI()
|
||||
+ " ["
|
||||
+ servletRequest.getContextPath() + ","
|
||||
+ servletRequest
|
||||
.getServletPath()
|
||||
+ "," + servletRequest.getPathInfo() + ","
|
||||
+ servletRequest
|
||||
.getQueryString()
|
||||
+ "]");
|
||||
}
|
||||
DeveloperSupport.startStage("CCMDispatcherServlet.doService");
|
||||
|
||||
|
||||
final String path = sreq.getPathInfo();
|
||||
final String path = servletRequest.getPathInfo();
|
||||
|
||||
if (requiresTrailingSlash(path)) {
|
||||
s_log.debug("The request URI needs a trailing slash; " +
|
||||
"redirecting");
|
||||
s_log.debug("The request URI needs a trailing slash; "
|
||||
+ "redirecting");
|
||||
|
||||
final String prefix = DispatcherHelper.getDispatcherPrefix(sreq);
|
||||
String uri = sreq.getRequestURI();
|
||||
final String prefix = DispatcherHelper.getDispatcherPrefix(
|
||||
servletRequest);
|
||||
String uri = servletRequest.getRequestURI();
|
||||
if (prefix != null && prefix.trim().length() > 0) {
|
||||
uri = prefix + uri;
|
||||
}
|
||||
final String query = sreq.getQueryString();
|
||||
final String query = servletRequest.getQueryString();
|
||||
|
||||
String url = null;
|
||||
|
||||
if (query == null) {
|
||||
sresp.sendRedirect(sresp.encodeRedirectURL(uri + "/"));
|
||||
servletResponse.sendRedirect(servletResponse.encodeRedirectURL(
|
||||
uri + "/"));
|
||||
} else {
|
||||
sresp.sendRedirect
|
||||
(sresp.encodeRedirectURL(uri + "/?" + query));
|
||||
servletResponse.sendRedirect(servletResponse.encodeRedirectURL(
|
||||
uri + "/?" + query));
|
||||
}
|
||||
|
||||
// return true;
|
||||
|
|
@ -186,41 +206,64 @@ public class CCMDispatcherServlet extends BaseServlet {
|
|||
|
||||
Assert.exists(path, String.class);
|
||||
|
||||
s_log.debug("Storing the path elements of the current request as " +
|
||||
"the original path elements");
|
||||
s_log.debug("Storing the path elements of the current request as "
|
||||
+ "the original path elements");
|
||||
|
||||
sreq.setAttribute(BaseServlet.REQUEST_URL_ATTRIBUTE, new URL(sreq));
|
||||
servletRequest.setAttribute(BaseServlet.REQUEST_URL_ATTRIBUTE,
|
||||
new URL(servletRequest));
|
||||
|
||||
if (s_log.isDebugEnabled()) {
|
||||
s_log.debug("Using path '" + path + "' to lookup application");
|
||||
}
|
||||
|
||||
DeveloperSupport.startStage("CCMDispatcherServlet.lookupApplicationSpec");
|
||||
DeveloperSupport.startStage(
|
||||
"CCMDispatcherServlet.lookupApplicationSpec");
|
||||
|
||||
final ApplicationSpec spec = lookupApplicationSpec(path);
|
||||
|
||||
DeveloperSupport.endStage("CCMDispatcherServlet.lookupApplicationSpec");
|
||||
DeveloperSupport.endStage(
|
||||
"CCMDispatcherServlet.lookupApplicationSpec");
|
||||
|
||||
if (spec == null) {
|
||||
s_log.debug("No application was found; doing nothing");
|
||||
// return false;
|
||||
// we have to create a 404 page here!
|
||||
String requestUri = sreq.getRequestURI(); // same as ctx.getRemainingURLPart()
|
||||
sresp.sendError(404, requestUri + " not found on this server.");
|
||||
String requestUri = servletRequest.getRequestURI(); // same as ctx.getRemainingURLPart()
|
||||
servletResponse.sendError(404, requestUri
|
||||
+ " not found on this server.");
|
||||
} else {
|
||||
if (s_log.isDebugEnabled()) {
|
||||
s_log.debug("Found application " + spec.getAppID() + "; " +
|
||||
"dispatching to its servlet");
|
||||
s_log.debug("Found application " + spec.getAppID() + "; "
|
||||
+ "dispatching to its servlet");
|
||||
}
|
||||
|
||||
sreq.setAttribute
|
||||
(BaseApplicationServlet.APPLICATION_ID_ATTRIBUTE,
|
||||
servletRequest.setAttribute(
|
||||
BaseApplicationServlet.APPLICATION_ID_ATTRIBUTE,
|
||||
spec.getAppID());
|
||||
sreq.setAttribute(DISPATCHED_ATTRIBUTE, Boolean.TRUE);
|
||||
servletRequest.setAttribute(DISPATCHED_ATTRIBUTE, Boolean.TRUE);
|
||||
Profiler.startOp("APP"); // +spec.getAppID() XXX get app name?
|
||||
forward(spec.getTypeContextPath(), spec.target(path), sreq, sresp);
|
||||
|
||||
// final WebConfig webConfig = WebConfig.getInstanceOf();
|
||||
// if (webConfig.getVaryHeaders() != null
|
||||
// && !webConfig.getVaryHeaders().isEmpty()) {
|
||||
// servletResponse
|
||||
// .addHeader("Vary", webConfig.getVaryHeaders());
|
||||
// }
|
||||
// final HttpSession session = servletRequest.getSession();
|
||||
// if (session != null && session.getAttribute(
|
||||
// GlobalizationHelper.LANG_PARAM) != null) {
|
||||
//
|
||||
// servletResponse.addCookie(new Cookie(
|
||||
// GlobalizationHelper.LANG_PARAM,
|
||||
// (String) session.getAttribute(
|
||||
// GlobalizationHelper.LANG_PARAM)));
|
||||
// }
|
||||
forward(spec.getTypeContextPath(),
|
||||
spec.target(path),
|
||||
servletRequest,
|
||||
servletResponse);
|
||||
Profiler.stopOp("APP"); // +spec.getAppID()
|
||||
// return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -229,10 +272,10 @@ public class CCMDispatcherServlet extends BaseServlet {
|
|||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param path
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private boolean requiresTrailingSlash(final String path) {
|
||||
|
|
@ -241,8 +284,8 @@ public class CCMDispatcherServlet extends BaseServlet {
|
|||
}
|
||||
|
||||
if (path == null) {
|
||||
s_log.debug("The path is null; the request needs a trailing " +
|
||||
"slash");
|
||||
s_log.debug("The path is null; the request needs a trailing "
|
||||
+ "slash");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -252,13 +295,13 @@ public class CCMDispatcherServlet extends BaseServlet {
|
|||
}
|
||||
|
||||
if (path.lastIndexOf(".") < path.lastIndexOf("/")) {
|
||||
s_log.debug("The last fragment of the path has no '.', so we " +
|
||||
"assume a directory was requested; a trailing " +
|
||||
"slash is required");
|
||||
s_log.debug("The last fragment of the path has no '.', so we "
|
||||
+ "assume a directory was requested; a trailing "
|
||||
+ "slash is required");
|
||||
return true;
|
||||
} else {
|
||||
s_log.debug("The last fragment of the path appears to be a file " +
|
||||
"name; no trailing slash is needed");
|
||||
s_log.debug("The last fragment of the path appears to be a file "
|
||||
+ "name; no trailing slash is needed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -269,6 +312,7 @@ public class CCMDispatcherServlet extends BaseServlet {
|
|||
* @param target
|
||||
* @param sreq
|
||||
* @param sresp
|
||||
*
|
||||
* @throws ServletException
|
||||
* @throws IOException
|
||||
*/
|
||||
|
|
@ -294,8 +338,8 @@ public class CCMDispatcherServlet extends BaseServlet {
|
|||
.getContext(contextPath);
|
||||
|
||||
if (s_log.isDebugEnabled()) {
|
||||
s_log.debug("From context " + Web.getServletContext() +
|
||||
" to context " + context);
|
||||
s_log.debug("From context " + Web.getServletContext()
|
||||
+ " to context " + context);
|
||||
}
|
||||
|
||||
final RequestDispatcher rd = context.getRequestDispatcher(target);
|
||||
|
|
@ -310,6 +354,7 @@ public class CCMDispatcherServlet extends BaseServlet {
|
|||
* @param rd
|
||||
* @param sreq
|
||||
* @param sresp
|
||||
*
|
||||
* @throws ServletException
|
||||
* @throws IOException
|
||||
*/
|
||||
|
|
@ -317,8 +362,8 @@ public class CCMDispatcherServlet extends BaseServlet {
|
|||
HttpServletRequest sreq,
|
||||
final HttpServletResponse sresp)
|
||||
throws ServletException, IOException {
|
||||
s_log.debug("Checking if this request needs to be forwarded or " +
|
||||
"included " + sreq);
|
||||
s_log.debug("Checking if this request needs to be forwarded or "
|
||||
+ "included " + sreq);
|
||||
|
||||
// Just in case sreq is wrapped in one of our own classes (spec.
|
||||
// MultipartHttpServletRequest), return unwrapped request, otherwise
|
||||
|
|
@ -326,32 +371,52 @@ public class CCMDispatcherServlet extends BaseServlet {
|
|||
sreq = DispatcherHelper.restoreOriginalRequest(sreq);
|
||||
|
||||
if (sreq.getAttribute("javax.servlet.include.request_uri") == null) {
|
||||
s_log.debug("The attribute javax.servlet.include.request_uri " +
|
||||
"is not set; forwarding " + sreq);
|
||||
s_log.debug("The attribute javax.servlet.include.request_uri "
|
||||
+ "is not set; forwarding " + sreq);
|
||||
|
||||
rd.forward(sreq, sresp);
|
||||
} else {
|
||||
s_log.debug("The attribute javax.servlet.include.request_uri " +
|
||||
"is set; including " + sreq);
|
||||
s_log.debug("The attribute javax.servlet.include.request_uri "
|
||||
+ "is set; including " + sreq);
|
||||
|
||||
rd.include(sreq, sresp);
|
||||
}
|
||||
|
||||
// if (sresp.isCommitted()) {
|
||||
// s_log.warn("Response already committed!!!");
|
||||
// }
|
||||
// final WebConfig webConfig = WebConfig.getInstanceOf();
|
||||
// if (webConfig.getVaryHeaders() != null
|
||||
// && !webConfig.getVaryHeaders().isEmpty()) {
|
||||
// sresp
|
||||
// .addHeader("Vary", webConfig.getVaryHeaders());
|
||||
// }
|
||||
// final HttpSession session = sreq.getSession();
|
||||
// if (session != null && session.getAttribute(
|
||||
// GlobalizationHelper.LANG_PARAM) != null) {
|
||||
//
|
||||
// sresp.addCookie(new Cookie(
|
||||
// GlobalizationHelper.LANG_PARAM,
|
||||
// (String) session.getAttribute(
|
||||
// GlobalizationHelper.LANG_PARAM)));
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param path
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private ApplicationSpec lookupApplicationSpec(final String path) {
|
||||
if (s_log.isDebugEnabled()) {
|
||||
s_log.debug("*** Starting application lookup for path '" +
|
||||
path + "' ***");
|
||||
s_log.debug("*** Starting application lookup for path '" + path
|
||||
+ "' ***");
|
||||
}
|
||||
|
||||
ApplicationSpec spec = s_cache.getAppSpec(path);
|
||||
|
||||
if ( spec == null ) {
|
||||
if (spec == null) {
|
||||
s_log.debug("There's no application to be found");
|
||||
}
|
||||
return spec;
|
||||
|
|
@ -376,13 +441,11 @@ public class CCMDispatcherServlet extends BaseServlet {
|
|||
protected void doDestroy() {
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Private class.
|
||||
*/
|
||||
private static class ApplicationSpec {
|
||||
|
||||
private final BigDecimal m_id;
|
||||
private final String m_instanceURI;
|
||||
private final String m_typeURI;
|
||||
|
|
@ -393,7 +456,9 @@ public class CCMDispatcherServlet extends BaseServlet {
|
|||
* @param app
|
||||
*/
|
||||
ApplicationSpec(Application app) {
|
||||
if ( app == null ) { throw new NullPointerException("app"); }
|
||||
if (app == null) {
|
||||
throw new NullPointerException("app");
|
||||
}
|
||||
|
||||
m_id = app.getID();
|
||||
m_instanceURI = app.getPath();
|
||||
|
|
@ -412,18 +477,21 @@ public class CCMDispatcherServlet extends BaseServlet {
|
|||
*
|
||||
* @return
|
||||
*/
|
||||
BigDecimal getAppID() { return m_id; }
|
||||
BigDecimal getAppID() {
|
||||
return m_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the context the application is executing. Usually all CCM
|
||||
* applications will now execute in the same webapp context. The
|
||||
* app.getContextPath() return "" in this case where an application is
|
||||
* executing in no specific context but CCM's default.
|
||||
*
|
||||
* @return The context path of the application's url, "" in case of
|
||||
* executing in the ROOT context.
|
||||
*/
|
||||
String getTypeContextPath() {
|
||||
if (m_typeContextPath.equals("") ) {
|
||||
if (m_typeContextPath.equals("")) {
|
||||
// app is running in CCM's default context, determine the
|
||||
// actual one
|
||||
return Web.getWebappContextPath();
|
||||
|
|
@ -435,12 +503,13 @@ public class CCMDispatcherServlet extends BaseServlet {
|
|||
/**
|
||||
*
|
||||
* @param path
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String target(final String path) {
|
||||
if (s_log.isDebugEnabled()) {
|
||||
s_log.debug("Building the target path from the request path '" +
|
||||
path + "' and the spec " + this);
|
||||
s_log.debug("Building the target path from the request path '"
|
||||
+ path + "' and the spec " + this);
|
||||
}
|
||||
|
||||
final StringBuffer target = new StringBuffer(128);
|
||||
|
|
@ -462,17 +531,20 @@ public class CCMDispatcherServlet extends BaseServlet {
|
|||
/**
|
||||
*
|
||||
* @param obj
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if ( obj==null ) { return false; }
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ApplicationSpec other = (ApplicationSpec) obj;
|
||||
return m_id.equals(other.m_id) &&
|
||||
equal(m_instanceURI, other.m_instanceURI) &&
|
||||
equal(m_typeURI, other.m_typeURI) &&
|
||||
equal(m_typeContextPath, other.m_typeContextPath);
|
||||
return m_id.equals(other.m_id) && equal(m_instanceURI,
|
||||
other.m_instanceURI)
|
||||
&& equal(m_typeURI, other.m_typeURI) && equal(
|
||||
m_typeContextPath, other.m_typeContextPath);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -480,11 +552,16 @@ public class CCMDispatcherServlet extends BaseServlet {
|
|||
*
|
||||
* @param s1
|
||||
* @param s2
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private boolean equal(String s1, String s2) {
|
||||
if (s1==s2) { return true; }
|
||||
if (s1==null) { return equal(s2, s1); }
|
||||
if (s1 == s2) {
|
||||
return true;
|
||||
}
|
||||
if (s1 == null) {
|
||||
return equal(s2, s1);
|
||||
}
|
||||
return s1.equals(s2);
|
||||
}
|
||||
|
||||
|
|
@ -512,21 +589,21 @@ public class CCMDispatcherServlet extends BaseServlet {
|
|||
sb.append("typeContextPath=").append(m_typeContextPath);
|
||||
return sb.append("]").toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Private class Cache caches (path, AppSpec) mappings.
|
||||
*/
|
||||
private static class Cache extends PathMapCache {
|
||||
|
||||
/** */
|
||||
private static final ThreadLocal s_handleHere = new ThreadLocal() {
|
||||
|
||||
@Override
|
||||
protected Object initialValue() {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -539,23 +616,28 @@ public class CCMDispatcherServlet extends BaseServlet {
|
|||
// implements the PathMapCache interface
|
||||
@Override
|
||||
public String normalize(String path) {
|
||||
if ( path==null ) { throw new NullPointerException("path"); }
|
||||
if ( !path.startsWith("/") ) {
|
||||
throw new DataObjectNotFoundException
|
||||
("The URL path specified must begin with a '/'.");
|
||||
if (path == null) {
|
||||
throw new NullPointerException("path");
|
||||
}
|
||||
return path.endsWith("/") ?
|
||||
path : path.substring(0, path.lastIndexOf('/') + 1);
|
||||
if (!path.startsWith("/")) {
|
||||
throw new DataObjectNotFoundException(
|
||||
"The URL path specified must begin with a '/'.");
|
||||
}
|
||||
return path.endsWith("/") ? path : path.substring(0, path
|
||||
.lastIndexOf('/')
|
||||
+ 1);
|
||||
}
|
||||
|
||||
// implements the PathMapCache interface
|
||||
@Override
|
||||
public Object retrieve(String path) {
|
||||
if ( "/".equals(path) ) { return null; }
|
||||
if ("/".equals(path)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final TransactionContext context =
|
||||
SessionManager.getSession().getTransactionContext();
|
||||
if ( !context.inTxn() ) {
|
||||
final TransactionContext context = SessionManager.getSession()
|
||||
.getTransactionContext();
|
||||
if (!context.inTxn()) {
|
||||
s_log.debug("Beginning transaction");
|
||||
context.beginTxn();
|
||||
s_handleHere.set(Boolean.TRUE);
|
||||
|
|
@ -563,7 +645,7 @@ public class CCMDispatcherServlet extends BaseServlet {
|
|||
|
||||
Application app = Application.retrieveApplicationForPath(path);
|
||||
|
||||
return app==null ? null : new ApplicationSpec(app);
|
||||
return app == null ? null : new ApplicationSpec(app);
|
||||
}
|
||||
|
||||
// implements the PathMapCache interface
|
||||
|
|
@ -580,12 +662,14 @@ public class CCMDispatcherServlet extends BaseServlet {
|
|||
try {
|
||||
return (ApplicationSpec) super.get(path);
|
||||
} finally {
|
||||
if ( s_handleHere.get() == Boolean.TRUE ) {
|
||||
if (s_handleHere.get() == Boolean.TRUE) {
|
||||
s_handleHere.set(Boolean.FALSE);
|
||||
SessionManager.getSession().getTransactionContext().
|
||||
commitTxn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ import org.apache.log4j.Logger;
|
|||
/**
|
||||
* A record containing server-session scoped configuration properties.
|
||||
*
|
||||
* Accessors of this class may return null. Developers should take
|
||||
* care to trap null return values in their code.
|
||||
* Accessors of this class may return null. Developers should take care to trap
|
||||
* null return values in their code.
|
||||
*
|
||||
* @see com.arsdigita.web.Web
|
||||
* @author Justin Ross <jross@redhat.com>
|
||||
|
|
@ -48,13 +48,17 @@ import org.apache.log4j.Logger;
|
|||
*/
|
||||
public final class WebConfig extends AbstractConfig {
|
||||
|
||||
/** Internal logger instance to faciliate debugging. Enable logging output
|
||||
* by editing /WEB-INF/conf/log4j.properties int the runtime environment
|
||||
* and set com.arsdigita.web.WebConfig=DEBUG by uncommenting it */
|
||||
/**
|
||||
* Internal logger instance to faciliate debugging. Enable logging output by
|
||||
* editing /WEB-INF/conf/log4j.properties int the runtime environment and
|
||||
* set com.arsdigita.web.WebConfig=DEBUG by uncommenting it
|
||||
*/
|
||||
private static final Logger s_log = Logger.getLogger(WebConfig.class);
|
||||
|
||||
/** Private Object to hold one's own instance to return to users. */
|
||||
private static WebConfig s_config ;
|
||||
/**
|
||||
* Private Object to hold one's own instance to return to users.
|
||||
*/
|
||||
private static WebConfig s_config;
|
||||
|
||||
/**
|
||||
* Returns the singleton configuration record for the content section
|
||||
|
|
@ -73,28 +77,36 @@ public final class WebConfig extends AbstractConfig {
|
|||
// /////////////////////////////////////////////////////////////////////////
|
||||
// Configuration parameter section
|
||||
// /////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** Determines what HTTP scheme prefix is used by default to generate URLs
|
||||
* (either http od https) */
|
||||
private final Parameter m_scheme = new DefaultSchemeParameter
|
||||
("waf.web.default_scheme",
|
||||
/**
|
||||
* Determines what HTTP scheme prefix is used by default to generate URLs
|
||||
* (either http od https)
|
||||
*/
|
||||
private final Parameter m_scheme = new DefaultSchemeParameter(
|
||||
"waf.web.default_scheme",
|
||||
Parameter.REQUIRED, "http");
|
||||
/** Sets the name and port that users of a site will see in URLs generated
|
||||
* by CCM for the site. This is a required parameter during installation,
|
||||
* e.g. example.com:80 */
|
||||
private final Parameter m_server = new HttpHostParameter
|
||||
("waf.web.server");
|
||||
/** Name and port that users of a site will see in secure URLs generated
|
||||
* by CCM for the site. As an example: example.com:443 */
|
||||
private final Parameter m_secureServer = new HttpHostParameter
|
||||
("waf.web.secure_server",
|
||||
/**
|
||||
* Sets the name and port that users of a site will see in URLs generated by
|
||||
* CCM for the site. This is a required parameter during installation, e.g.
|
||||
* example.com:80
|
||||
*/
|
||||
private final Parameter m_server = new HttpHostParameter("waf.web.server");
|
||||
/**
|
||||
* Name and port that users of a site will see in secure URLs generated by
|
||||
* CCM for the site. As an example: example.com:443
|
||||
*/
|
||||
private final Parameter m_secureServer = new HttpHostParameter(
|
||||
"waf.web.secure_server",
|
||||
Parameter.OPTIONAL, null);
|
||||
/** The name of your website, for use in page footers for example. It's
|
||||
* not necessarily the URL but rather a title, e.g. "House of HTML".
|
||||
* If not specified set to the server's URL. */
|
||||
private final Parameter m_site= new StringParameter
|
||||
("waf.web.site_name",
|
||||
Parameter.OPTIONAL, null) { @Override
|
||||
/**
|
||||
* The name of your website, for use in page footers for example. It's not
|
||||
* necessarily the URL but rather a title, e.g. "House of HTML". If not
|
||||
* specified set to the server's URL.
|
||||
*/
|
||||
private final Parameter m_site = new StringParameter("waf.web.site_name",
|
||||
Parameter.OPTIONAL,
|
||||
null) {
|
||||
|
||||
@Override
|
||||
public final Object getDefaultValue() {
|
||||
final HttpHost host = getServer();
|
||||
if (host == null) {
|
||||
|
|
@ -103,54 +115,77 @@ public final class WebConfig extends AbstractConfig {
|
|||
return host.toString();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
/** Sets the name and port of the machine on which the CCM instance is
|
||||
/**
|
||||
* Sets the name and port of the machine on which the CCM instance is
|
||||
* running. Used to fetch some resources by a local URL avoiding external
|
||||
* internet traffic (and delay). If not specified set to the servers's
|
||||
* name redirecting all traffic to external internet address. */
|
||||
private final Parameter m_host = new HttpHostParameter
|
||||
("waf.web.host",
|
||||
Parameter.OPTIONAL, null) { @Override
|
||||
* internet traffic (and delay). If not specified set to the servers's name
|
||||
* redirecting all traffic to external internet address.
|
||||
*/
|
||||
private final Parameter m_host = new HttpHostParameter("waf.web.host",
|
||||
Parameter.OPTIONAL,
|
||||
null) {
|
||||
|
||||
@Override
|
||||
public final Object getDefaultValue() {
|
||||
return getServer();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/** List of URLs which accessed by insecure (normal HTTP) connection
|
||||
* produce a redirect to a HTTPS equivalent. List is comma separated. */
|
||||
private final Parameter m_secureRequired = new StringArrayParameter
|
||||
("waf.web.secure_required", Parameter.OPTIONAL, null);
|
||||
/** List of URLs which accessed by secure (HTTPS) connection produce a
|
||||
* redirect to a HTTP equivalent. List is comma separated. */
|
||||
private final Parameter m_secureSwitchBack = new StringArrayParameter
|
||||
("waf.web.secure_switchback", Parameter.OPTIONAL, null);
|
||||
/**
|
||||
* List of URLs which accessed by insecure (normal HTTP) connection produce
|
||||
* a redirect to a HTTPS equivalent. List is comma separated.
|
||||
*/
|
||||
private final Parameter m_secureRequired = new StringArrayParameter(
|
||||
"waf.web.secure_required", Parameter.OPTIONAL, null);
|
||||
/**
|
||||
* List of URLs which accessed by secure (HTTPS) connection produce a
|
||||
* redirect to a HTTP equivalent. List is comma separated.
|
||||
*/
|
||||
private final Parameter m_secureSwitchBack = new StringArrayParameter(
|
||||
"waf.web.secure_switchback", Parameter.OPTIONAL, null);
|
||||
|
||||
/** Dispatcher servlet path. It's the prefix to the main entry point for
|
||||
* any application request (CCMDispatcherServlet). By default /ccm */
|
||||
private final Parameter m_servlet = new StringParameter
|
||||
("waf.web.dispatcher_servlet_path", Parameter.REQUIRED, "/ccm");
|
||||
/**
|
||||
* Dispatcher servlet path. It's the prefix to the main entry point for any
|
||||
* application request (CCMDispatcherServlet). By default /ccm
|
||||
*/
|
||||
private final Parameter m_servlet = new StringParameter(
|
||||
"waf.web.dispatcher_servlet_path", Parameter.REQUIRED, "/ccm");
|
||||
|
||||
/** Specifies by name which implementation of ApplicationFileResolver is
|
||||
* used to dynamically resolve static files. By default
|
||||
* DefaultApplicationFileResolver() is used. */
|
||||
private final Parameter m_resolver = new SingletonParameter
|
||||
("waf.web.application_file_resolver",
|
||||
/**
|
||||
* Specifies by name which implementation of ApplicationFileResolver is used
|
||||
* to dynamically resolve static files. By default
|
||||
* DefaultApplicationFileResolver() is used.
|
||||
*/
|
||||
private final Parameter m_resolver = new SingletonParameter(
|
||||
"waf.web.application_file_resolver",
|
||||
Parameter.OPTIONAL,
|
||||
new DefaultApplicationFileResolver());
|
||||
private final Parameter m_default_cache_policy = new CachePolicyParameter
|
||||
("waf.web.cache_policy",
|
||||
private final Parameter m_default_cache_policy = new CachePolicyParameter(
|
||||
"waf.web.cache_policy",
|
||||
Parameter.OPTIONAL, null);
|
||||
private final Parameter m_deactivate_cache_host_notifications = new BooleanParameter
|
||||
("waf.web.deactivate_cache_host_notifications",
|
||||
private final Parameter m_deactivate_cache_host_notifications
|
||||
= new BooleanParameter(
|
||||
"waf.web.deactivate_cache_host_notifications",
|
||||
Parameter.OPTIONAL, Boolean.FALSE);
|
||||
|
||||
private final Parameter m_dynamic_host_provider = new StringParameter
|
||||
("waf.web.dynamic_host_provider",
|
||||
private final Parameter m_dynamic_host_provider = new StringParameter(
|
||||
"waf.web.dynamic_host_provider",
|
||||
Parameter.OPTIONAL, "");
|
||||
|
||||
/**
|
||||
* Specifies the values set as {@code vary} HTTP header in the response.
|
||||
*/
|
||||
private final Parameter m_varyHeaders = new StringParameter(
|
||||
"waf.web.vary_headers",
|
||||
Parameter.OPTIONAL,
|
||||
"accept-language");
|
||||
|
||||
/**
|
||||
* Constructor, but do NOT instantiate this class directly, use
|
||||
* getInstanceOf() instead. (Singelton pattern!)
|
||||
* getInstanceOf() instead. (Singleton pattern!)
|
||||
*
|
||||
*/
|
||||
public WebConfig() {
|
||||
|
|
@ -167,6 +202,7 @@ public final class WebConfig extends AbstractConfig {
|
|||
register(m_default_cache_policy);
|
||||
register(m_deactivate_cache_host_notifications);
|
||||
register(m_dynamic_host_provider);
|
||||
register(m_varyHeaders);
|
||||
|
||||
loadInfo();
|
||||
}
|
||||
|
|
@ -177,8 +213,9 @@ public final class WebConfig extends AbstractConfig {
|
|||
|
||||
/**
|
||||
* Provide the name and port that users of a site will see in URLs generated
|
||||
* by CCM for the site. (Value of parameter waf.web.server)
|
||||
* E.g. example.com:80
|
||||
* by CCM for the site. (Value of parameter waf.web.server) E.g.
|
||||
* example.com:80
|
||||
*
|
||||
* @return HttpHost object, contains public name & port of the server (site)
|
||||
*/
|
||||
public final HttpHost getServer() {
|
||||
|
|
@ -190,9 +227,9 @@ public final class WebConfig extends AbstractConfig {
|
|||
}
|
||||
|
||||
public final boolean isSecureRequired(String uri) {
|
||||
String[] secured = (String[])get(m_secureRequired);
|
||||
String[] secured = (String[]) get(m_secureRequired);
|
||||
if (secured != null) {
|
||||
for (int i=0, n=secured.length; i<n; i++) {
|
||||
for (int i = 0, n = secured.length; i < n; i++) {
|
||||
if (uri.startsWith(secured[i])) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -202,9 +239,9 @@ public final class WebConfig extends AbstractConfig {
|
|||
}
|
||||
|
||||
public final boolean isNonSecureSwitchRequired(String uri) {
|
||||
String[] switchBack = (String[])get(m_secureSwitchBack);
|
||||
String[] switchBack = (String[]) get(m_secureSwitchBack);
|
||||
if (switchBack != null) {
|
||||
for (int i=0, n=switchBack.length; i<n; i++) {
|
||||
for (int i = 0, n = switchBack.length; i < n; i++) {
|
||||
if (uri.startsWith(switchBack[i])) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -217,9 +254,9 @@ public final class WebConfig extends AbstractConfig {
|
|||
* Provide the name and port of the machine on which the CCM instance is
|
||||
* running. (Value of parameter waf.web.host)
|
||||
*
|
||||
* Used to fetch some resources by a local URL avoiding external
|
||||
* internet traffic (and delay). If not specified set to the servers's
|
||||
* name redirecting all traffic to external internet address.
|
||||
* Used to fetch some resources by a local URL avoiding external internet
|
||||
* traffic (and delay). If not specified set to the servers's name
|
||||
* redirecting all traffic to external internet address.
|
||||
*
|
||||
* @return HttpHost object, contains internal name & port of the machine
|
||||
* hosting a CCM instance
|
||||
|
|
@ -238,9 +275,8 @@ public final class WebConfig extends AbstractConfig {
|
|||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
* @deprecated use Web.getContextPath() instead. The installation context
|
||||
* must no longer manually configured
|
||||
* @return @deprecated use Web.getContextPath() instead. The installation
|
||||
* context must no longer manually configured
|
||||
*/
|
||||
// NO LONGER configured by configuration option but determined at runtime
|
||||
// by CCMDispatcherServlet itself.
|
||||
|
|
@ -261,12 +297,13 @@ public final class WebConfig extends AbstractConfig {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the system default cache policy. This value is set via
|
||||
* the <code>com.arsdigita.web.cache_policy</code> system property
|
||||
* using one fo the following values: <code>user</code> for
|
||||
* per-user caching, <code>world</code> for globally enabled
|
||||
* caching, <code>disable</code> to prevent HTTP header caching, and
|
||||
* <code>none</code>to always prevent caching in any case.
|
||||
* Gets the system default cache policy. This value is set via the
|
||||
* <code>com.arsdigita.web.cache_policy</code> system property using one fo
|
||||
* the following values: <code>user</code> for per-user caching,
|
||||
* <code>world</code> for globally enabled caching, <code>disable</code> to
|
||||
* prevent HTTP header caching, and <code>none</code>to always prevent
|
||||
* caching in any case.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public final CachePolicy getCachePolicy() {
|
||||
|
|
@ -275,6 +312,7 @@ public final class WebConfig extends AbstractConfig {
|
|||
|
||||
private static class DispatcherServletPathParameter
|
||||
extends StringParameter {
|
||||
|
||||
DispatcherServletPathParameter(final String name) {
|
||||
super(name);
|
||||
}
|
||||
|
|
@ -284,14 +322,16 @@ public final class WebConfig extends AbstractConfig {
|
|||
final String string = (String) value;
|
||||
|
||||
if (string.endsWith("/")) {
|
||||
final ParameterError error = new ParameterError
|
||||
(this, "The value must not end in a '/'");
|
||||
final ParameterError error = new ParameterError(this,
|
||||
"The value must not end in a '/'");
|
||||
errors.add(error);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class DefaultSchemeParameter extends EnumerationParameter {
|
||||
|
||||
DefaultSchemeParameter(final String name,
|
||||
final int multiplicity,
|
||||
final Object defaalt) {
|
||||
|
|
@ -300,9 +340,11 @@ public final class WebConfig extends AbstractConfig {
|
|||
put("http", "http");
|
||||
put("https", "https");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class CachePolicyParameter extends EnumerationParameter {
|
||||
|
||||
CachePolicyParameter(final String name,
|
||||
final int multiplicity,
|
||||
final Object defaalt) {
|
||||
|
|
@ -313,6 +355,7 @@ public final class WebConfig extends AbstractConfig {
|
|||
put("user", CachePolicy.USER);
|
||||
put("world", CachePolicy.WORLD);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected DynamicHostProvider dhProvider = null;
|
||||
|
|
@ -326,7 +369,9 @@ public final class WebConfig extends AbstractConfig {
|
|||
Class klass = Class.forName(classname);
|
||||
dhProvider = (DynamicHostProvider) klass.newInstance();
|
||||
} catch (Exception e) {
|
||||
s_log.error("Could not instantiate DynamicHostProvider using classname : "+classname, e);
|
||||
s_log.error(
|
||||
"Could not instantiate DynamicHostProvider using classname : "
|
||||
+ classname, e);
|
||||
}
|
||||
}
|
||||
dhProviderInited = true;
|
||||
|
|
@ -335,32 +380,29 @@ public final class WebConfig extends AbstractConfig {
|
|||
}
|
||||
|
||||
public final boolean getDeactivateCacheHostNotifications() {
|
||||
return ((Boolean) get(m_deactivate_cache_host_notifications)).booleanValue();
|
||||
return ((Boolean) get(m_deactivate_cache_host_notifications))
|
||||
.booleanValue();
|
||||
}
|
||||
|
||||
//
|
||||
// Deprecated classes and methods
|
||||
//
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @deprecated Use <code>getServer().getName()</code> instead.
|
||||
* @return @deprecated Use <code>getServer().getName()</code> instead.
|
||||
*/
|
||||
public final String getServerName() {
|
||||
return getServer().getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @deprecated Use <code>getServer().getPort()</code> instead.
|
||||
* @return @deprecated Use <code>getServer().getPort()</code> instead.
|
||||
*/
|
||||
public final int getServerPort() {
|
||||
return getServer().getPort();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @deprecated Use
|
||||
* @return @deprecated Use
|
||||
* <code>Host.retrieve(Web.getConfig().getHost())</code> instead.
|
||||
*/
|
||||
public final Host getCurrentHost() {
|
||||
|
|
@ -368,8 +410,7 @@ public final class WebConfig extends AbstractConfig {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @deprecated Use <code>Host.retrieveAll()</code> instead.
|
||||
* @return @deprecated Use <code>Host.retrieveAll()</code> instead.
|
||||
*/
|
||||
public final Host[] getHosts() {
|
||||
final List hosts = new ArrayList();
|
||||
|
|
@ -383,4 +424,13 @@ public final class WebConfig extends AbstractConfig {
|
|||
|
||||
return (Host[]) hosts.toArray(new Host[hosts.size()]);
|
||||
}
|
||||
|
||||
public final String getVaryHeaders() {
|
||||
return (String) get(m_varyHeaders);
|
||||
}
|
||||
|
||||
public void setVaryHeaders(final String value) {
|
||||
set(m_varyHeaders, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,3 +57,8 @@ waf.web.dynamic_host_provider.title=Dynamic Host Provider
|
|||
waf.web.dynamic_host_provider.purpose=Class name of the DynamicHostProvider to use
|
||||
waf.web.dynamic_host_provider.example=com.arsdigita.web.ServerDynamicHostProvider
|
||||
waf.web.dynamic_host_provider.format=[string]
|
||||
|
||||
waf.web.vary_headers.title=Value of vary header
|
||||
waf.web.vary_headers.purpose=Value of the vary header in the HTTP response. Set the an empty string to disable.
|
||||
waf.web.vary_headers.example=accept-language
|
||||
waf.web.vary_headers.format=[string]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
package com.arsdigita.bundle;
|
||||
|
||||
import com.arsdigita.globalization.GlobalizationHelper;
|
||||
import com.arsdigita.web.WebConfig;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
|
@ -8,7 +11,10 @@ import javax.servlet.FilterConfig;
|
|||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -31,7 +37,24 @@ public class AddVaryHeaderFilter implements Filter {
|
|||
final HttpServletResponse response
|
||||
= (HttpServletResponse) servletResponse;
|
||||
|
||||
response.addHeader("Vary", "accept-language");
|
||||
final WebConfig webConfig = WebConfig.getInstanceOf();
|
||||
if (webConfig.getVaryHeaders() != null
|
||||
&& !webConfig.getVaryHeaders().isEmpty()) {
|
||||
response
|
||||
.addHeader("Vary", webConfig.getVaryHeaders());
|
||||
}
|
||||
final HttpSession session = ((HttpServletRequest) servletRequest)
|
||||
.getSession();
|
||||
if (session != null && session.getAttribute(
|
||||
GlobalizationHelper.LANG_PARAM) != null) {
|
||||
|
||||
response.addCookie(new Cookie(
|
||||
GlobalizationHelper.LANG_PARAM,
|
||||
(String) session.getAttribute(
|
||||
GlobalizationHelper.LANG_PARAM)));
|
||||
}
|
||||
|
||||
// response.addHeader("Vary", "accept-language");
|
||||
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue