You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by mr...@apache.org on 2005/08/26 07:46:58 UTC
svn commit: r240168 [6/30] - in /struts/sandbox/trunk/ti: ./
core/src/java/org/apache/ti/ core/src/java/org/apache/ti/config/
core/src/java/org/apache/ti/config/mapper/
core/src/java/org/apache/ti/core/ core/src/java/org/apache/ti/core/factory/
core/sr...
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/PageFlowController.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/PageFlowController.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/PageFlowController.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/PageFlowController.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,787 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+package org.apache.ti.pageflow;
+
+import org.apache.ti.pageflow.handler.Handlers;
+import org.apache.ti.pageflow.handler.StorageHandler;
+import org.apache.ti.pageflow.internal.CachedPageFlowInfo;
+import org.apache.ti.pageflow.internal.CachedSharedFlowRefInfo;
+import org.apache.ti.pageflow.internal.InternalConstants;
+import org.apache.ti.pageflow.internal.InternalUtils;
+import org.apache.ti.pageflow.internal.ViewRenderer;
+import org.apache.ti.pageflow.xwork.PageFlowActionContext;
+import org.apache.ti.pageflow.xwork.PageFlowPathResult;
+import org.apache.ti.pageflow.xwork.PageFlowResult;
+import org.apache.ti.util.internal.DiscoveryUtils;
+import org.apache.ti.util.internal.FileUtils;
+import org.apache.ti.util.internal.cache.ClassLevelCache;
+import org.apache.ti.util.logging.Logger;
+
+import javax.servlet.http.HttpSessionBindingEvent;
+import java.lang.reflect.Field;
+import java.util.Map;
+
+
+/**
+ * <p/>
+ * Base class for controller logic, exception handlers, and state associated with a particular web directory path.
+ * The class is configured through the
+ * {@link org.apache.ti.pageflow.annotations.ti.controller @ti.controller} annotation.
+ * </p>
+ * <p/>
+ * <p/>
+ * When a page flow request (the page flow URI itself, or any ".do" or page URI in the directory path), arrives, an
+ * instance of the associated PageFlowController class is set as the <i>current page flow</i>, and remains stored in the
+ * session until a different one becomes active ("long lived" page flows stay in the session indefinitely;
+ * see {@link org.apache.ti.pageflow.annotations.ti.controller#longLived longLived}
+ * on {@link org.apache.ti.pageflow.annotations.ti.controller @ti.controller}).
+ * </p>
+ * <p/>
+ * <p/>
+ * The page flow class handles <i>actions</i> that are most commonly raised by user interaction with pages. The actions
+ * are handled by <i>action methods</i> or <i>action annotations</i> that determine the next URI to be displayed, after
+ * optionally performing arbitrary logic.
+ * </p>
+ * <p/>
+ * <p/>
+ * If the PageFlowController is a "nested page flow"
+ * ({@link org.apache.ti.pageflow.annotations.ti.controller#nested nested} is set to <code>true</code>
+ * on {@link org.apache.ti.pageflow.annotations.ti.controller @ti.controller}), then this
+ * is a reusable, modular flow that can be "nested" during other flows. It has entry points (actions with optional form
+ * bean arguments), and exit points ({@link org.apache.ti.pageflow.annotations.ti.forward @ti.forward},
+ * {@link org.apache.ti.pageflow.annotations.ti.simpleAction @ti.simpleAction}, or
+ * {@link org.apache.ti.pageflow.annotations.ti.conditionalForward @ti.conditionalForward} annotations
+ * that have <code>returnAction</code> attributes).
+ * </p>
+ * <p/>
+ * <p/>
+ * The page flow class also handles exceptions thrown by actions or during page execution
+ * (see {@link org.apache.ti.pageflow.annotations.ti.controller#catches catches} on
+ * {@link org.apache.ti.pageflow.annotations.ti.controller @ti.controller}). Unhandled exceptions are
+ * handled in order by declared {@link SharedFlowController}s
+ * (see {@link org.apache.ti.pageflow.annotations.ti.controller#sharedFlowRefs sharedFlowRefs} on
+ * {@link org.apache.ti.pageflow.annotations.ti.controller @ti.controller}).
+ * </p>
+ * <p/>
+ * <p/>
+ * Properties in the current page flow instance can be accessed from JSP 2.0-style expressions like this one:
+ * <code>${pageFlow.someProperty}</code>.
+ * </p>
+ * <p/>
+ * <p/>
+ * There may only be one page flow in any package.
+ * </p>
+ *
+ * @see SharedFlowController
+ */
+public abstract class PageFlowController
+ extends FlowController
+ implements InternalConstants {
+
+ /**
+ * A 'return-to="page"' forward brings the user back to the previous page. This object
+ * stores information about the current state of affairs, such as the origin URI and
+ * its form bean.
+ */
+ private PreviousPageInfo _previousPageInfo = null;
+ private PreviousPageInfo _currentPageInfo = null;
+
+ /**
+ * A 'return-to="action"' forward reruns the previous action. This object stores the previous
+ * action URI and its form bean.
+ */
+ private PreviousActionInfo _previousActionInfo;
+
+ private boolean _isOnNestingStack = false;
+ private ViewRenderer _returnActionViewRenderer = null;
+
+ private static final String SAVED_PREVIOUS_PAGE_INFO_ATTR = InternalConstants.ATTR_PREFIX + "savedPrevPageInfo";
+ private static final String CACHED_INFO_KEY = "cachedInfo";
+ private static final Logger _log = Logger.getInstance(PageFlowController.class);
+
+
+ /**
+ * Default constructor.
+ */
+ protected PageFlowController() {
+ }
+
+ /**
+ * Get the namespace for this page flow.
+ *
+ * @return a String that is the namespace for this controller, and which is also
+ * the directory path from the web application root to this PageFlowController
+ * (not including the action filename).
+ */
+ public String getNamespace() {
+ return getCachedInfo().getNamespace();
+ }
+
+ /**
+ * Get the path for addressing this object within an application.
+ *
+ * @return a String that is the path which will execute the begin action on this controller.
+ */
+ public String getPath() {
+ return getCachedInfo().getPath();
+ }
+
+ /**
+ * Tell whether this PageFlowController can be "nested", i.e., if it can be invoked from another page
+ * flow with the intention of returning to the original one. Page flows are declared to be nested by specifying
+ * <code>{@link org.apache.ti.pageflow.annotations.ti.controller#nested nested}=true</code> on the
+ * {@link org.apache.ti.pageflow.annotations.ti.controller @ti.controller} annotation.
+ *
+ * @return <code>true</code> if this PageFlowController can be nested.
+ */
+ protected boolean isNestedFlow() {
+ return getModuleConfig().isNestedFlow();
+ }
+
+ /**
+ * Tell whether this is a "long lived" page flow. Once it is invoked, a long lived page flow is never
+ * removed from the session unless {@link #remove} is called. Navigating to another page flow hides
+ * the current long lived controller, but does not remove it.
+ */
+ protected boolean isLongLivedFlow() {
+ return getModuleConfig().isLongLivedFlow();
+ }
+
+ /**
+ * Remove this instance from the session. When inside a page flow action, {@link #remove} may be called instead.
+ */
+ protected synchronized void removeFromSession() {
+ // This request attribute is used in persistInSession to prevent re-saving of this instance.
+ getContext().setRemovingFlowController(this);
+
+ if (isLongLivedFlow()) {
+ PageFlowUtils.removeLongLivedPageFlow(getNamespace());
+ } else {
+ InternalUtils.removeCurrentPageFlow();
+ }
+ }
+
+ /**
+ * Store this object in the user session, in the appropriate place. Used by the framework; normally should not be
+ * called directly.
+ */
+ public void persistInSession() {
+ PageFlowController currentPageFlow = PageFlowUtils.getCurrentPageFlow();
+
+ if (currentPageFlow != null && !currentPageFlow.isOnNestingStack()) {
+ //
+ // We're going to be implicitly destroying the current page flow. Synchronize on it so we don't mess
+ // with concurrent requests.
+ //
+ synchronized (currentPageFlow) {
+ InternalUtils.setCurrentPageFlow(this);
+ }
+ } else {
+ InternalUtils.setCurrentPageFlow(this);
+ }
+ }
+
+ /**
+ * @exclude
+ */
+ protected Forward internalExecute(Object form)
+ throws Exception {
+ initializeSharedFlowFields();
+ return super.internalExecute();
+ }
+
+ private void initializeSharedFlowFields() {
+ //
+ // Initialize the shared flow fields.
+ //
+ CachedSharedFlowRefInfo.SharedFlowFieldInfo[] sharedFlowMemberFields =
+ getCachedInfo().getSharedFlowMemberFields();
+
+ if (sharedFlowMemberFields != null) {
+ for (int i = 0; i < sharedFlowMemberFields.length; i++) {
+ CachedSharedFlowRefInfo.SharedFlowFieldInfo fi = sharedFlowMemberFields[i];
+ Field field = fi.field;
+
+ if (fieldIsUninitialized(field)) {
+ Map/*< String, SharedFlowController >*/ sharedFlows = PageFlowUtils.getSharedFlows();
+ String name = fi.sharedFlowName;
+ assert name != null;
+ SharedFlowController sf = (SharedFlowController) sharedFlows.get(name);
+
+ if (sf != null) {
+ initializeField(field, sf);
+ } else {
+ _log.error("Could not find shared flow with name \"" + fi.sharedFlowName
+ + "\" to initialize field " + field.getName() + " in " + getClass().getName());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Get the a map of shared flow name to shared flow instance.
+ *
+ * @return a Map of shared flow name (string) to shared flow instance ({@link SharedFlowController}).
+ */
+ public Map/*< String, SharedFlowController >*/ getSharedFlows() {
+ return PageFlowUtils.getSharedFlows();
+ }
+
+ /**
+ * Get a shared flow, based on its name as defined in this page flow's
+ * {@link org.apache.ti.pageflow.annotations.ti.controller#sharedFlowRefs sharedFlowRefs}
+ * attribute on {@link org.apache.ti.pageflow.annotations.ti.controller @ti.controller}.
+ * To retrieve any shared flow based on its class name, use {@link PageFlowUtils#getSharedFlow}.
+ *
+ * @param sharedFlowName the name of the shared flow, as in this page flows's
+ * {@link org.apache.ti.pageflow.annotations.ti.controller#sharedFlowRefs sharedFlowRefs}
+ * attribute on the {@link org.apache.ti.pageflow.annotations.ti.controller @ti.controller}
+ * annotation.
+ * @return the {@link SharedFlowController} with the given name.
+ */
+ public SharedFlowController getSharedFlow(String sharedFlowName) {
+ return (SharedFlowController) PageFlowUtils.getSharedFlows().get(sharedFlowName);
+ }
+
+ /**
+ * Remove a shared flow from the session, based on its name as defined in this page flow's
+ * {@link org.apache.ti.pageflow.annotations.ti.controller#sharedFlowRefs sharedFlowRefs}
+ * attribute on {@link org.apache.ti.pageflow.annotations.ti.controller @ti.controller}.
+ * To remove any shared flow based on its class name, use {@link PageFlowUtils#removeSharedFlow}.
+ *
+ * @param sharedFlowName the name of the shared flow, as in this page flows's
+ * {@link org.apache.ti.pageflow.annotations.ti.controller#sharedFlowRefs sharedFlowRefs}
+ * attribute on the {@link org.apache.ti.pageflow.annotations.ti.controller @ti.controller}
+ * annotation.
+ */
+ public void removeSharedFlow(String sharedFlowName) {
+ SharedFlowController sf = getSharedFlow(sharedFlowName);
+ if (sf != null) sf.removeFromSession();
+ }
+
+ /**
+ * This is a framework method for initializing a newly-created page flow, and should not normally be called
+ * directly.
+ */
+ public final synchronized void create() {
+ reinitialize();
+ initializeSharedFlowFields();
+
+ if (isNestedFlow()) {
+ //
+ // Initialize a ViewRenderer for exiting the nested page flow.
+ //
+ String vrClassName = (String) getRequestScope().get(InternalConstants.RETURN_ACTION_VIEW_RENDERER_PARAM);
+
+ if (vrClassName != null) {
+ ViewRenderer vr =
+ (ViewRenderer) DiscoveryUtils.newImplementorInstance(vrClassName, ViewRenderer.class);
+
+ if (vr != null) {
+ vr.init();
+ _returnActionViewRenderer = vr;
+ }
+ }
+ }
+
+ super.create();
+ }
+
+ /**
+ * Get the submitted form bean from the most recent action execution in this PageFlowController.
+ * <p/>
+ * <i>Note: if the current page flow does not contain a
+ * </i>{@link org.apache.ti.pageflow.annotations.ti.forward @ti.forward}<i> or a
+ * </i>{@link org.apache.ti.pageflow.annotations.ti.simpleAction @ti.simpleAction}<i> with
+ * </i><code>navigateTo={@link org.apache.ti.pageflow.annotations.ti.NavigateTo#previousAction ti.NavigateTo.previousAction}</code><i>,
+ * then this method will always return </i><code>null</code><i> by default. To enable it in this
+ * situation, add the following method to the page flow:</i><br>
+ * <blockquote>
+ * <code>
+ * protected boolean alwaysTrackPreviousAction()<br>
+ * {<br>
+ * return true;<br>
+ * }<br>
+ * </code>
+ * </blockquote>
+ *
+ * @return the form bean instance from the most recent action execution, or <code>null</code>
+ * if there was no form bean submitted.
+ * @see #getPreviousPageInfo
+ * @see #getCurrentPageInfo
+ * @see #getPreviousActionInfo
+ * @see #getPreviousActionURI
+ * @see #getPreviousForwardPath
+ * @see #getCurrentForwardPath
+ */
+ protected Object getPreviousFormBean() {
+ checkPreviousActionInfoDisabled();
+ return _previousActionInfo != null ? _previousActionInfo.getFormBean() : null;
+ }
+
+ /**
+ * Get the URI for the most recent action in this PageFlowController.
+ * <p/>
+ * <i>Note: if the current page flow does not use a
+ * {@link org.apache.ti.pageflow.annotations.ti.forward @ti.forward},
+ * {@link org.apache.ti.pageflow.annotations.ti.simpleAction @ti.simpleAction}, or
+ * {@link org.apache.ti.pageflow.annotations.ti.conditionalForward @ti.conditionalForward}
+ * with <code>navigateTo={@link org.apache.ti.pageflow.annotations.ti.NavigateTo#previousAction previousAction}</code>,
+ * then this method will always return </i><code>null</code><i> by default. To enable it in this situation, add the
+ * following method to the page flow:</i><br>
+ * <blockquote>
+ * <code>
+ * protected boolean alwaysTrackPreviousAction()<br>
+ * {<br>
+ * return true;<br>
+ * }<br>
+ * </code>
+ * </blockquote>
+ *
+ * @return a String that is the most recent URI.
+ * @see #getPreviousPageInfo
+ * @see #getCurrentPageInfo
+ * @see #getPreviousActionInfo
+ * @see #getPreviousFormBean
+ * @see #getPreviousForwardPath
+ * @see #getCurrentForwardPath
+ */
+ protected String getPreviousActionURI() {
+ checkPreviousActionInfoDisabled();
+ return _previousActionInfo != null ? _previousActionInfo.getActionURI() : null;
+ }
+
+ /**
+ * Get the webapp-relative URI for the most recent page (in this page flow) shown to the user.
+ * <p/>
+ * <i>Note: if the current page flow does not use a
+ * {@link org.apache.ti.pageflow.annotations.ti.forward @ti.forward},
+ * {@link org.apache.ti.pageflow.annotations.ti.simpleAction @ti.simpleAction}, or
+ * {@link org.apache.ti.pageflow.annotations.ti.conditionalForward @ti.conditionalForward}
+ * with <code>navigateTo={@link org.apache.ti.pageflow.annotations.ti.NavigateTo#currentPage currentPage}</code>
+ * or <code>navigateTo={@link org.apache.ti.pageflow.annotations.ti.NavigateTo#previousPage previousPage}</code>,
+ * then this method will always return </i><code>null</code><i> by default. To enable it in this situation, add the
+ * following method to the page flow:</i><br>
+ * <blockquote>
+ * <code>
+ * protected boolean alwaysTrackPreviousPage()<br>
+ * {<br>
+ * return true;<br>
+ * }<br>
+ * </code>
+ * </blockquote>
+ *
+ * @return a String that is the URI path for the most recent page shown to the user.
+ * @see #getPreviousPageInfo
+ * @see #getCurrentPageInfo
+ * @see #getPreviousActionInfo
+ * @see #getPreviousActionURI
+ * @see #getPreviousFormBean
+ * @see #getPreviousForwardPath
+ */
+ public String getCurrentForwardPath() {
+ PreviousPageInfo curPageInfo = getCurrentPageInfo();
+ String path = null;
+
+ if (curPageInfo != null) {
+ String resultPath = curPageInfo.getResult().getLocation();
+
+ if (resultPath != null) {
+ if (resultPath.startsWith("/")) {
+ path = resultPath;
+ } else {
+ path = getNamespace() + '/' + resultPath;
+ }
+ }
+ }
+ return path;
+ }
+
+ /**
+ * Get the webapp-relative URI for the previous page (in this page flow) shown to the user.
+ * The previous page is the one shown before the most recent page.
+ * <p/>
+ * <i>Note: if the current page flow does not use a
+ * {@link org.apache.ti.pageflow.annotations.ti.forward @ti.forward},
+ * {@link org.apache.ti.pageflow.annotations.ti.simpleAction @ti.simpleAction}, or
+ * {@link org.apache.ti.pageflow.annotations.ti.conditionalForward @ti.conditionalForward}
+ * with <code>navigateTo={@link org.apache.ti.pageflow.annotations.ti.NavigateTo#currentPage currentPage}</code>
+ * or <code>navigateTo={@link org.apache.ti.pageflow.annotations.ti.NavigateTo#previousPage previousPage}</code>,
+ * then this method will always return </i><code>null</code><i> by default. To enable it in this situation, add the
+ * following method to the page flow:</i><br>
+ * <blockquote>
+ * <code>
+ * protected boolean alwaysTrackPreviousPage()<br>
+ * {<br>
+ * return true;<br>
+ * }<br>
+ * </code>
+ * </blockquote>
+ *
+ * @return a String that is the URI path for the previous page shown to the user.
+ * @see #getPreviousPageInfo
+ * @see #getCurrentPageInfo
+ * @see #getPreviousActionInfo
+ * @see #getPreviousActionURI
+ * @see #getPreviousFormBean
+ * @see #getCurrentForwardPath
+ */
+ protected String getPreviousForwardPath() {
+ PreviousPageInfo prevPageInfo = getPreviousPageInfo();
+
+ if (prevPageInfo != null) {
+ PageFlowResult prevResult = prevPageInfo.getResult();
+ return prevResult != null ? prevResult.getLocation() : null;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get information about the most recent page (in this page flow) shown to the user.
+ * <p/>
+ * <i>Note: if the current page flow does not use a
+ * {@link org.apache.ti.pageflow.annotations.ti.forward @ti.forward},
+ * {@link org.apache.ti.pageflow.annotations.ti.simpleAction @ti.simpleAction}, or
+ * {@link org.apache.ti.pageflow.annotations.ti.conditionalForward @ti.conditionalForward}
+ * with <code>navigateTo={@link org.apache.ti.pageflow.annotations.ti.NavigateTo#currentPage currentPage}</code>
+ * or <code>navigateTo={@link org.apache.ti.pageflow.annotations.ti.NavigateTo#previousPage previousPage}</code>,
+ * then this method will always return </i><code>null</code><i> by default. To enable it in this situation, add the
+ * following method to the page flow:</i><br>
+ * <blockquote>
+ * <code>
+ * protected boolean alwaysTrackPreviousPage()<br>
+ * {<br>
+ * return true;<br>
+ * }<br>
+ * </code>
+ * </blockquote>
+ *
+ * @return a PreviousPageInfo with information about the most recent page shown to the user.
+ * @see #getPreviousPageInfo
+ * @see #getPreviousActionInfo
+ * @see #getPreviousActionURI
+ * @see #getPreviousFormBean
+ * @see #getPreviousForwardPath
+ * @see #getCurrentForwardPath
+ */
+ public final PreviousPageInfo getCurrentPageInfo() {
+ checkPreviousPageInfoDisabled();
+
+ if (_currentPageInfo != null) {
+ // Allows it to reconstruct transient members after session failover
+ _currentPageInfo.reinitialize(this);
+ }
+
+ return _currentPageInfo;
+ }
+
+ /**
+ * Get information about the previous page (in this page flow) shown to the user. The previous
+ * page is the one shown before the most recent page.
+ * <p/>
+ * <i>Note: if the current page flow does not use a
+ * {@link org.apache.ti.pageflow.annotations.ti.forward @ti.forward},
+ * {@link org.apache.ti.pageflow.annotations.ti.simpleAction @ti.simpleAction}, or
+ * {@link org.apache.ti.pageflow.annotations.ti.conditionalForward @ti.conditionalForward}
+ * with <code>navigateTo={@link org.apache.ti.pageflow.annotations.ti.NavigateTo#currentPage currentPage}</code>
+ * or <code>navigateTo={@link org.apache.ti.pageflow.annotations.ti.NavigateTo#previousPage previousPage}</code>,
+ * then this method will always return </i><code>null</code><i> by default. To enable it in this situation, add the
+ * following method to the page flow:</i><br>
+ * </blockquote>
+ *
+ * @return a PreviousPageInfo with information about the previous page shown to the user.
+ * @see #getCurrentPageInfo
+ * @see #getPreviousActionInfo
+ * @see #getPreviousActionURI
+ * @see #getPreviousFormBean
+ * @see #getPreviousForwardPath
+ * @see #getCurrentForwardPath
+ */
+ public final PreviousPageInfo getPreviousPageInfo() {
+ checkPreviousPageInfoDisabled();
+
+ PreviousPageInfo ret = _previousPageInfo != null ? _previousPageInfo : _currentPageInfo;
+
+ if (ret != null) {
+ ret.reinitialize(this); // Allows it to reconstruct transient members after session failover
+ }
+
+ return ret;
+ }
+
+ /**
+ * Get information about the most recent action run in this page flow.
+ * <p/>
+ * <i>Note: if the current page flow does not use a
+ * {@link org.apache.ti.pageflow.annotations.ti.forward @ti.forward},
+ * {@link org.apache.ti.pageflow.annotations.ti.simpleAction @ti.simpleAction}, or
+ * {@link org.apache.ti.pageflow.annotations.ti.conditionalForward @ti.conditionalForward}
+ * with <code>navigateTo={@link org.apache.ti.pageflow.annotations.ti.NavigateTo#previousAction previousAction}</code>,
+ * then this method will always return </i><code>null</code><i> by default. To enable it in this situation, add the
+ * following method to the page flow:</i><br>
+ * <blockquote>
+ * <code>
+ * protected boolean alwaysTrackPreviousAction()<br>
+ * {<br>
+ * return true;<br>
+ * }<br>
+ * </code>
+ * </blockquote>
+ *
+ * @return a PreviousActionInfo with information about the most recent action run in this page flow.
+ * @see #getPreviousPageInfo
+ * @see #getCurrentPageInfo
+ * @see #getPreviousActionURI
+ * @see #getPreviousFormBean
+ * @see #getPreviousForwardPath
+ * @see #getCurrentForwardPath
+ */
+ public final PreviousActionInfo getPreviousActionInfo() {
+ checkPreviousActionInfoDisabled();
+
+ PageFlowActionContext actionContext = PageFlowActionContext.get();
+ PreviousActionInfo inContext = (PreviousActionInfo) actionContext.get("ttttt");
+ if (inContext != null) return inContext;
+
+ return _previousActionInfo;
+ }
+
+ private void checkPreviousActionInfoDisabled() {
+ if (isPreviousActionInfoDisabled()) {
+ throw new IllegalStateException("Previous action information has been disabled in this page flow. Override alwaysTrackPreviousAction() to enable it.");
+ }
+ }
+
+ private void checkPreviousPageInfoDisabled() {
+ if (isPreviousPageInfoDisabled()) {
+ throw new IllegalStateException("Previous page information has been disabled in this page flow. Override alwaysTrackPreviousPage() to enable it.");
+ }
+ }
+
+ /**
+ * Get the display name of this page flow.
+ *
+ * @return the display name (the URI) of this page flow.
+ */
+ public String getDisplayName() {
+ return getPath();
+ }
+
+ public boolean isPreviousActionInfoDisabled() {
+ if (alwaysTrackPreviousAction()) return false;
+ return getModuleConfig().isReturnToActionDisabled();
+ }
+
+ public boolean isPreviousPageInfoDisabled() {
+ if (alwaysTrackPreviousPage()) return false;
+ return getModuleConfig().isReturnToPageDisabled();
+ }
+
+ /**
+ * Called from {@link FlowController#execute}.
+ */
+ void savePreviousActionInfo() {
+ //
+ // If previous-action is disabled (unused in this pageflow), just return.
+ //
+ if (isPreviousActionInfoDisabled()) return;
+
+ // Keep the current PreviousActionInstance until this context is finished.
+ PageFlowActionContext actionContext = PageFlowActionContext.get();
+ actionContext.put("ttttt", _previousActionInfo);
+ _previousActionInfo = new PreviousActionInfo();
+ }
+
+ /**
+ * Store information about recent pages displayed. This is a framework-invoked method that should not normally be
+ * called directly.
+ */
+ public void savePreviousPageInfo(PageFlowResult result, Forward fwd, Object form) {
+ PageFlowActionContext actionContext = PageFlowActionContext.get();
+
+ if (result != null) {
+ Object formBean = actionContext.getFormBean();
+
+ //
+ // If previous-page is disabled (unused in this pageflow), or if we've already saved prevous-page info in
+ // this request (for example, forward to foo.faces which forwards to foo.jsp), just return.
+ //
+ if (getRequestScope().get(SAVED_PREVIOUS_PAGE_INFO_ATTR) == this || isPreviousPageInfoDisabled()) return;
+
+ String path = result.getLocation();
+ int queryPos = path.indexOf('?');
+ if (queryPos != -1) path = path.substring(0, queryPos);
+
+ //
+ // If a form bean was generated in this request, add it to the most recent PreviousPageInfo, so when we
+ // go back to that page, the *updated* field values are restored (i.e., we don't revert to the values of
+ // the form that was passed into the page originally).
+ //
+ if (formBean != null && _currentPageInfo != null) {
+ Object oldForm = _currentPageInfo.getFormBean();
+ if (oldForm == null || oldForm.getClass().equals(formBean.getClass())) {
+ _currentPageInfo.setFormBean(formBean);
+ _currentPageInfo.setAction(actionContext.getAction());
+ }
+ }
+
+ //
+ // Only keep track of *pages* forwarded to -- not actions or pageflows.
+ //
+ if (!FileUtils.osSensitiveEndsWith(path, ACTION_EXTENSION)) {
+ //
+ // Only save previous-page info if the page is within this pageflow.
+ //
+ if (isLocalFile(result)) // || PageFlowUtils.osSensitiveEndsWith( path, JPF_EXTENSION ) )
+ {
+ _previousPageInfo = _currentPageInfo;
+ _currentPageInfo = new PreviousPageInfo(result, fwd);
+ getRequestScope().put(SAVED_PREVIOUS_PAGE_INFO_ATTR, this);
+ }
+ }
+ }
+ }
+
+ private boolean isLocalFile(PageFlowResult result) {
+ String path = result.getLocation();
+ if (!path.startsWith("/")) return true;
+
+ // TODO: re-evaluate whether path and namespace can be linked this way
+ String modulePath = getNamespace();
+
+ if (!path.startsWith(modulePath)) {
+ return false;
+ } else {
+ return path.indexOf('/', modulePath.length() + 1) == -1;
+ }
+ }
+
+ private boolean isOnNestingStack() {
+ return _isOnNestingStack;
+ }
+
+ /**
+ * Callback when this object is removed from the user session. Causes {@link #onDestroy} to be called. This is a
+ * framework-invoked method that should not normally be called indirectly.
+ */
+ public void valueUnbound(HttpSessionBindingEvent event) {
+ //
+ // Unless this pageflow has been pushed onto the nesting stack, do the onDestroy() callback.
+ //
+ if (!_isOnNestingStack) {
+ super.valueUnbound(event);
+ }
+ }
+
+ void setIsOnNestingStack(boolean isOnNestingStack) {
+ _isOnNestingStack = isOnNestingStack;
+ }
+
+ private CachedPageFlowInfo getCachedInfo() {
+ ClassLevelCache cache = ClassLevelCache.getCache(getClass());
+ CachedPageFlowInfo info = (CachedPageFlowInfo) cache.getCacheObject(CACHED_INFO_KEY);
+
+ if (info == null) {
+ info = new CachedPageFlowInfo(getClass());
+ cache.setCacheObject(CACHED_INFO_KEY, info);
+ }
+
+ return info;
+ }
+
+ /**
+ * Trigger before-page logic. This is a framework-invoked method that should not normally be called directly.
+ */
+ public final void beforePage() {
+ //
+ // We may need to save the previous page info if the page was called directly (not forwarded through an action)
+ // and we do not yet have the forward path in the page flow or it is a different path.
+ //
+ if (!isPreviousPageInfoDisabled()) {
+ String relativeUri = getContext().getRequestPath();
+
+ String path = getCurrentForwardPath();
+ if (path == null || !path.equals(relativeUri)) {
+ PageFlowPathResult result = new PageFlowPathResult();
+ result.setLocation(relativeUri);
+ savePreviousPageInfo(result, null, null);
+ }
+ }
+ }
+
+ public Forward exitNesting() {
+ if (_returnActionViewRenderer != null) getContext().setViewRenderer(_returnActionViewRenderer);
+
+ try {
+ onExitNesting();
+ } catch (Throwable th) {
+ try {
+ return handleException(th);
+ } catch (Exception e) {
+ _log.error("Exception thrown while handling exception.", e);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Callback that is invoked when this controller instance is exiting nesting (through a return action).
+ */
+ protected void onExitNesting()
+ throws Exception {
+ }
+
+ /**
+ * Ensures that any changes to this object will be replicated in a cluster (for failover),
+ * even if the replication scheme uses a change-detection algorithm that relies on
+ * HttpSession.setAttribute to be aware of changes. Note that this method is used by the framework
+ * and does not need to be called explicitly in most cases.
+ */
+ public void ensureFailover() {
+ //
+ // remove() puts the pageflow instance into a request attribute. Make sure not to re-save this
+ // instance if it's being removed. Also, if the session is null (after having been invalidated
+ // by the user), don't recreate it.
+ //
+ if (getContext().getRemovingFlowController() != this && sessionExists()) {
+ StorageHandler sh = Handlers.get().getStorageHandler();
+
+ //
+ // If this is a long-lived page flow, there are two attributes to deal with.
+ //
+ if (isLongLivedFlow()) {
+ String longLivedAttrName = InternalUtils.getLongLivedFlowAttr(getNamespace());
+ longLivedAttrName = InternalUtils.getScopedAttrName(longLivedAttrName);
+ String currentLongLivedAttrName =
+ InternalUtils.getScopedAttrName(CURRENT_LONGLIVED_ATTR);
+ sh.ensureFailover(longLivedAttrName, this);
+ sh.ensureFailover(currentLongLivedAttrName, getNamespace());
+ } else {
+ String attrName = InternalUtils.getScopedAttrName(CURRENT_JPF_ATTR);
+ sh.ensureFailover(attrName, this);
+ }
+ }
+ }
+
+ protected boolean sessionExists() {
+ return true;
+ }
+}
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/PageFlowEventReporter.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/PageFlowEventReporter.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/PageFlowEventReporter.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/PageFlowEventReporter.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+package org.apache.ti.pageflow;
+
+
+/**
+ * An event reporter, which will be notified of events like "page flow created", "action raised", etc.
+ */
+public abstract class PageFlowEventReporter {
+
+ protected PageFlowEventReporter() {
+ }
+
+ /**
+ * Event fired when an action is raised on a FlowController (a page flow or a shared flow).
+ *
+ * @param flowController the FlowController on which the action is being raised (a
+ * {@link PageFlowController} or a {@link SharedFlowController}).
+ */
+ public abstract void actionRaised(FlowController flowController);
+
+ /**
+ * Event fired when an action successfully completes on a FlowController (a page flow or a shared flow).
+ *
+ * @param flowController the FlowController on which the action was raised (a
+ * {@link PageFlowController} or a {@link SharedFlowController}).
+ * @param result the forward result returned from the action.
+ * @param timeTakenMillis the length of time in milliseconds for the action to be run.
+ */
+ public abstract void actionSuccess(FlowController flowController, Forward result, long timeTakenMillis);
+
+ /**
+ * Event fired when an exception is raised during processing of an action request.
+ *
+ * @param ex the Throwable that was raised.
+ * @param flowController the FlowController associated with the action request. This parameter will be
+ * <code>null</code> if the request did not get to the point where a FlowController could be created or
+ * looked up.
+ * @see #beginActionRequest
+ */
+ public abstract void exceptionRaised(Throwable ex, FlowController flowController);
+
+ /**
+ * Event fired when an exception is handled successfully during processing of an action request.
+ *
+ * @param ex the Throwable that was raised.
+ * @param flowController the FlowController associated with the action request. This parameter will be
+ * <code>null</code> if the request did not get to the point where a FlowController could be created or
+ * looked up.
+ * @param result the forward result returned from the exception handler.
+ * @param timeTakenMillis the length of time in milliseconds for the exception to be handled.
+ * @see #beginActionRequest
+ */
+ public abstract void exceptionHandled(Throwable ex, FlowController flowController, Forward result,
+ long timeTakenMillis);
+
+ /**
+ * Event fired when a FlowController (a page flow or a shared flow) is created.
+ *
+ * @param flowController the FlowController (a {@link PageFlowController} or a {@link SharedFlowController})
+ * that was created.
+ */
+ public abstract void flowControllerCreated(FlowController flowController);
+
+ /**
+ * Event fired when a FlowController (a page flow or a shared flow) is "destroyed", i.e., removed from wherever it
+ * is being stored.
+ *
+ * @param flowController the FlowController (a {@link PageFlowController} or a {@link SharedFlowController})
+ * that is being destroyed.
+ * @param storageLocation The storage location. For session-scoped FlowControllers, this is a
+ * <code>javax.servlet.http.HttpSession</code>.
+ */
+ public abstract void flowControllerDestroyed(FlowController flowController, Object storageLocation);
+
+ /**
+ * Event fired at the beginning of an action request. Note that this is called on all action requests, even those
+ * that do not successfully run actions.
+ */
+ public abstract void beginActionRequest();
+
+ /**
+ * Event fired at the end of an action request. Note that this is called on all action requests, even those
+ * that do not successfully run actions.
+ *
+ * @param timeTakenMillis the length of time in milliseconds for the action request to be processed.
+ */
+ public abstract void endActionRequest(long timeTakenMillis);
+
+ /**
+ * Event fired at the end of an action request. Note that this is called on all action requests, even those
+ * that do not successfully run actions.
+ */
+ public abstract void beginPageRequest();
+
+ /**
+ * Event fired at the end of a page request.
+ *
+ * @param timeTakenMillis the length of time in milliseconds for the page request to be processed.
+ */
+ public abstract void endPageRequest(long timeTakenMillis);
+
+ /**
+ * Event fired when a page flow or shared flow is registered lazily (once per webapp deployment).
+ *
+ * @param moduleConfig the {@link ModuleConfig} associated with the controller.
+ */
+ public abstract void flowControllerRegistered(ModuleConfig moduleConfig);
+}
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/PageFlowException.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/PageFlowException.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/PageFlowException.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/PageFlowException.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+package org.apache.ti.pageflow;
+
+public class PageFlowException extends Exception {
+
+ public PageFlowException(Throwable cause) {
+ super(cause);
+ }
+}
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/PageFlowManagedObject.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/PageFlowManagedObject.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/PageFlowManagedObject.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/PageFlowManagedObject.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+package org.apache.ti.pageflow;
+
+import org.apache.ti.pageflow.handler.Handlers;
+import org.apache.ti.pageflow.xwork.PageFlowAction;
+import org.apache.ti.pageflow.xwork.PageFlowActionContext;
+import org.apache.ti.util.logging.Logger;
+
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionBindingListener;
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.util.Map;
+
+/**
+ * Base class for Page Flow managed objects (like page flows and JavaServer Faces backing beans).
+ */
+public abstract class PageFlowManagedObject
+ implements Serializable, HttpSessionBindingListener {
+
+ private static final long serialVersionUID = 1;
+ private static final Logger _log = Logger.getInstance(PageFlowManagedObject.class);
+
+ /**
+ * Creation time. This is non-transient, so it gets replicated in a cluster.
+ */
+ private long _createTime;
+
+ protected PageFlowManagedObject() {
+ _createTime = System.currentTimeMillis();
+ }
+
+ /**
+ * Reinitialize the object for a new request. Used by the framework; normally should not be called directly.
+ */
+ public void reinitialize() {
+ }
+
+ /**
+ * Initialize after object creation. This is a framework-invoked method; it should not normally be called directly.
+ */
+ public synchronized void create()
+ throws Exception {
+ reinitialize();
+ // TODO: re-add Controls support
+// JavaControlUtils.initJavaControls( this );
+ onCreate();
+ }
+
+ /**
+ * Internal destroy method that is invoked when this object is being removed from the session. This is a
+ * framework-invoked method; it should not normally be called directly.
+ */
+ void destroy() {
+ onDestroy();
+ // TODO: re-add Controls support
+// JavaControlUtils.uninitJavaControls( this );
+ }
+
+ /**
+ * Create-time callback. Occurs after internal initialization (e.g., Control fields) is done.
+ *
+ * @throws Exception
+ */
+ protected void onCreate()
+ throws Exception {
+ }
+
+ /**
+ * Callback that occurs when this object is "destroyed", i.e., removed from the session.
+ */
+ protected void onDestroy() {
+ }
+
+ /**
+ * Callback when this object is added to the user session.
+ */
+ public void valueBound(HttpSessionBindingEvent event) {
+ }
+
+ /**
+ * Callback when this object is removed from the user session. Causes {@link #onDestroy} to be called. This is a
+ * framework-invoked method that should not normally be called indirectly.
+ */
+ public void valueUnbound(HttpSessionBindingEvent event) {
+ if (Handlers.get().getStorageHandler().allowBindingEvent(event)) {
+ destroy();
+ }
+ }
+
+ /**
+ * Remove this instance from the session.
+ */
+ protected abstract void removeFromSession();
+
+ /**
+ * Store this object in the user session, in the appropriate place. Used by the framework; normally should not be
+ * called directly.
+ */
+ public abstract void persistInSession();
+
+ /**
+ * Ensures that any changes to this object will be replicated in a cluster (for failover),
+ * even if the replication scheme uses a change-detection algorithm that relies on
+ * HttpSession.setAttribute to be aware of changes. Note that this method is used by the framework
+ * and does not need to be called explicitly in most cases.
+ */
+ public abstract void ensureFailover();
+
+ /**
+ * Get the display name for this managed object.
+ */
+ public abstract String getDisplayName();
+
+ /**
+ * Tell whether the given Field is uninitialized.
+ *
+ * @return <code>true</code> if the field is non-<code>null</code> and its value is <code>null</code>.
+ */
+ protected boolean fieldIsUninitialized(Field field) {
+ try {
+ return field != null && field.get(this) == null;
+ } catch (IllegalAccessException e) {
+ _log.error("Error initializing field " + field.getName() + " in " + getDisplayName(), e);
+ return false;
+ }
+ }
+
+ /**
+ * Initialize the given field with an instance. Mainly useful for the error handling.
+ */
+ protected void initializeField(Field field, Object instance) {
+ if (instance != null) {
+ if (_log.isTraceEnabled()) {
+ _log.trace("Initializing field " + field.getName() + " in " + getDisplayName() + " with " + instance);
+ }
+
+ try {
+ field.set(this, instance);
+ } catch (IllegalArgumentException e) {
+ _log.error("Could not set field " + field.getName() + " on " + getDisplayName() +
+ "; instance is of type " + instance.getClass().getName() + ", field type is "
+ + field.getType().getName());
+ } catch (IllegalAccessException e) {
+ _log.error("Error initializing field " + field.getName() + " in " + getDisplayName(), e);
+ }
+ }
+ }
+
+ /**
+ * Get the time at which this object was created.
+ *
+ * @return the system time, in milliseconds, at which this object was created.
+ */
+ public long getCreateTime() {
+ return _createTime;
+ }
+
+ /**
+ * Get the current Struts ActionConfig, which is information from the Struts-XML <action>
+ * tag that corresponds to the current action being executed. This call is only valid
+ * during {@link FlowController#execute} (where any user action method is invoked), and during the lifecycle
+ * methods {@link FlowController#beforeAction} and {@link FlowController#afterAction}.
+ *
+ * @return the current Struts ActionConfig.
+ * @throws IllegalStateException if this method is invoked outside of action method
+ * execution (i.e., outside of the call to {@link FlowController#execute}, and outside of
+ * {@link FlowController#onCreate}, {@link FlowController#beforeAction}, {@link FlowController#afterAction}.
+ */
+ protected static PageFlowAction getAction() {
+ return getContext().getAction();
+ }
+
+ protected static PageFlowActionContext getContext() {
+ return PageFlowActionContext.get();
+ }
+
+ protected static Map getRequestScope() {
+ return getContext().getRequestScope();
+ }
+
+ protected static Map getSessionScope() {
+ return getContext().getSession();
+ }
+}
Added: struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/PageFlowManagedObjectException.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/PageFlowManagedObjectException.java?rev=240168&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/PageFlowManagedObjectException.java (added)
+++ struts/sandbox/trunk/ti/core/src/java/org/apache/ti/pageflow/PageFlowManagedObjectException.java Thu Aug 25 22:46:03 2005
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+package org.apache.ti.pageflow;
+
+import org.apache.ti.pageflow.internal.InternalUtils;
+import org.apache.ti.util.Bundle;
+import org.apache.ti.util.internal.InternalStringBuilder;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+
+/**
+ * Base class for exceptions related to Page Flow managed objects.
+ *
+ * @see PageFlowManagedObject
+ */
+public abstract class PageFlowManagedObjectException
+ extends RuntimeException {
+
+ private PageFlowManagedObject _managedObject;
+ private String _messageKeyPrefix;
+
+
+ protected PageFlowManagedObjectException(PageFlowManagedObject object) {
+ super();
+ init(object);
+ }
+
+ protected PageFlowManagedObjectException(PageFlowManagedObject object, Throwable rootCause) {
+ super(rootCause);
+ init(object);
+ }
+
+ protected void init(PageFlowManagedObject object) {
+ _managedObject = object;
+
+ String className = getClass().getName();
+ int lastDot = className.lastIndexOf('.');
+ assert lastDot != -1;
+ _messageKeyPrefix = "PageFlow_" + className.substring(lastDot + 1);
+ }
+
+ /**
+ * Get the related PageFlowManagedObject.
+ *
+ * @return the {@link PageFlowManagedObject} associated with this exception.
+ */
+ public PageFlowManagedObject getManagedObject() {
+ return _managedObject;
+ }
+
+ /**
+ * Set the related PageFlowManagedObject.
+ *
+ * @param managedObject the {@link PageFlowManagedObject} associated with this exception.
+ */
+ protected void setManagedObject(PageFlowManagedObject managedObject) {
+ _managedObject = managedObject;
+ }
+
+ /**
+ * Handle the error by writing a message to the response.
+ */
+ void sendError(int productionTimeErrorCode)
+ throws IOException {
+ InternalUtils.sendDevTimeError(_messageKeyPrefix, null, productionTimeErrorCode, getMessageArgs());
+ }
+
+ /**
+ * Handle the error by writing a message to the response.
+ */
+ public void sendError()
+ throws IOException {
+ InternalUtils.sendError(_messageKeyPrefix, getMessageArgs(), null, InternalUtils.avoidDirectResponseOutput());
+ }
+
+ /**
+ * Print a formatted message.
+ *
+ * @param writer a writer to which to print the formatted message.
+ */
+ public void printError(PrintWriter writer) {
+ writer.println(Bundle.getString(_messageKeyPrefix + "_Page", getMessageArgs()));
+ }
+
+ public String getLocalizedMessage() {
+ return Bundle.getString(_messageKeyPrefix + "_Message", getMessageArgs());
+ }
+
+ public String getMessage() {
+ InternalStringBuilder buf = new InternalStringBuilder();
+ String[] parts = getMessageParts();
+ Object[] args = getMessageArgs();
+
+ assert parts.length > args.length : parts.length + ", " + args.length;
+
+ for (int i = 0; i < parts.length; ++i) {
+ buf.append(parts[i]);
+
+ if (i < args.length) {
+ buf.append(args[i]);
+ }
+ }
+
+ return buf.toString();
+ }
+
+ protected abstract Object[] getMessageArgs();
+
+ protected abstract String[] getMessageParts();
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org