package er.extensions.appserver; import com.webobjects.appserver.WOApplication; import com.webobjects.appserver.WOComponent; import com.webobjects.appserver.WOContext; import com.webobjects.appserver.WOResponse; import com.webobjects.appserver.WOSession; import com.webobjects.foundation.NSDictionary; import com.webobjects.foundation.NSMutableDictionary; import er.extensions.appserver.ajax.ERXAjaxApplication; import er.extensions.foundation.ERXMutableURL; /** * <span class="en"> * ERXRedirect is like a WORedirect except that you can give it a * component instance to redirect to (as well as several other convenient * methods of redirecting). This is useful for situations like in an Ajax * request where you want to do a full page reload that points to the component * that you would normally return from your action method. If your redirect is * in an Ajax request, this will generate a script tag that reassigns * document.location.href to the generated url. * </span> * * <span class="ja"> * ERXRedirect は WORedirect と同様ですが、レダイレクトはコンポーネント・インスタンスへ実行できることです。 * 他にもレダイレクトに便利なメソッドもあります。 * * Ajax リクエストなどでとても有効です。例えば、全ページのリロード(普段はアクション・メソッドのコール)へポイントします。 * リダイレクトが Ajax リクエストの場合にはスクリプト・タグの document.location.href で URL 生成されます。 * </span> * * @author mschrag */ public class ERXRedirect extends WOComponent { /** * Do I need to update serialVersionUID? * See section 5.6 <cite>Type Changes Affecting Serialization</cite> on page 51 of the * <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object Serialization Spec</a> */ private static final long serialVersionUID = 1L; private String _url; private String _requestHandlerKey; private String _requestHandlerPath; private Boolean _secure; private boolean _includeSessionID; private String _directActionClass; private String _directActionName; private WOComponent _originalComponent; private WOComponent _component; private NSDictionary<String, ? extends Object> _queryParameters; public ERXRedirect(WOContext context) { super(context); _originalComponent = context.page(); _includeSessionID = false; } /** * <span class="en"> * Sets whether or not a secure URL should be generated. This does not apply * if you set a URL directly. * * @param secure * whether or not a secure URL should be generated * </span> * * <span class="ja"> * 生成される URL がセキュリティー URL であるかどうかをセットします * URL を直接でセットする時には使用されません。 * * @param secure - セキュリティー URL を生成するかどうか * </span> */ public void setSecure(boolean secure) { _secure = Boolean.valueOf(secure); } /** * Sets whether or not a direct action URL should contain the session ID. * This defaults to <code>false</code> to maintain backward compatibility. * * @param includeSessionID * whether or not a sessionID should be included */ public void setIncludeSessionID(boolean includeSessionID) { _includeSessionID = includeSessionID; } /** * <span class="en"> * Sets the request handler key to redirect to. You typically want to also * set requestHandlerPath if you set this. * * @param requestHandlerKey * the redirected request handler key * </span> * * <span class="ja"> * リダイレクト先のリダイレクト・リクエスト・ハンドラーをセットします * requestHandlerPath も同時にセットすること * * @param requestHandlerKey - リダイレクト・リクエスト・ハンドラー * </span> */ public void setRequestHandlerKey(String requestHandlerKey) { _requestHandlerKey = requestHandlerKey; } /** * <span class="en"> * Sets the request handler path to redirect to. This requires that you also * set requestHandlerKey. * * @param requestHandlerPath * the request handler path to redirect to * </span> * * <span class="ja"> * リダイレクト先のリクエスト・ハンドラー・パスをセットします * requestHandlerKey も同時にセットすること * * @param requestHandlerPath - リクエスト・ハンドラー・パス * </span> */ public void setRequestHandlerPath(String requestHandlerPath) { _requestHandlerPath = requestHandlerPath; } /** * <span class="en"> * Sets the direct action class to redirect to. You typically want to also * set directActionName if you set this. * * @param directActionClass * the direct action class to redirect to * </span> * * <span class="ja"> * リダイレクト先のダイレクトアクション・クラスをセットします * directActionName も同時にセットすること * * @param directActionClass - ダイレクトアクション・クラス * </span> */ public void setDirectActionClass(String directActionClass) { _directActionClass = directActionClass; } /** * <span class="en"> * The direct action name to redirect to. * * @param directActionName * the direct action name * </span> * * <span class="ja"> * リダイレクト先のダイレクトアクション名をセットします * * @param directActionName - ダイレクトアクション名 * </span> */ public void setDirectActionName(String directActionName) { _directActionName = directActionName; } /** * <span class="en"> * Sets the URL to redirect to. * * @param url * the URL to redirect to * </span> * * <span class="ja"> * リダイレクト先の URL をセットします * * @param url - リダイレクト先の URL * </span> */ public void setUrl(String url) { _url = url; } /** * <span class="en"> * Sets the redirect component to be the original page that we were just on. * </span> * * <span class="ja"> * 現時点にいるコンポーネントをリダイレクト先コンポーネントにすること * </span> */ public void setComponentToPage() { _component = _originalComponent; } /** * <span class="en"> * Sets the component instance to redirect to. This component gets replaced * as the page in the current context, and a URL is generated to the current * context, which causes the request for that context ID to return the * component you are redirecting to. When you set a redirect component, the * component is also put into the normal page cache (rather than the ajax * page cache), and the ajax cache is disabled for this request. As a * result, redirecting to a component WILL burn a backtrack cache entry * (just like a normal hyperlink). * * @param component * the component instance to redirect to * </span> * * <span class="ja"> * リダイレクト先のコンポーネント・インスタンスをセットします。 * このコンポーネントはカレント・コンテクストのページとして置き換わり、 * コンテクスト ID のリクエストがリダイレクトするコンポーネントを戻すカレント・コンテクストへの URL が生成されます。 * リダイレクト・コンポーネントをセットすることでコンポーネントは一般ページ・キャシュ(Ajax ページ・キャシュではなく) * に登録され、このリクエストでの Ajax キャシュは使用禁止されます。結果としてコンポーネントへのリダイレクトは * (ハイパーリンクと同じく)バックトラック・キャシュを作成します。 * * @param component - リダイレクト先のコンポーネント・インスタンス * </span> */ public void setComponent(WOComponent component) { _component = component; } /** * <span class="en"> * Sets the query parameters for this redirect. * * @param queryParameters * the query parameters for this redirect * </span> * * <span class="ja"> * リダイレクトのクエリー・パラメータをセットします * * @param queryParameters - リダイレクトのクエリー・パラメータ * </span> */ public void setQueryParameters(NSDictionary<String, ? extends Object> queryParameters) { _queryParameters = queryParameters; } /** * <span class="en"> * Returns the query parameters dictionary as a string. * * @return the query parameters as a string * </span> * * <span class="ja"> * クエリー・パラメータ・ディクショナリーを文字列として戻します。 * * @return クエリー・パラメータ文字列 * </span> */ protected String queryParametersString() { String queryParametersString = null; if (_queryParameters != null && _queryParameters.count() > 0) { ERXMutableURL u = new ERXMutableURL(); u.setQueryParameters(_queryParameters); queryParametersString = u.toExternalForm(); } return queryParametersString; } protected NSDictionary<String, Object> directActionQueryParameters() { NSMutableDictionary<String, Object> params = null; if (_queryParameters != null) { params = (NSMutableDictionary<String, Object>) _queryParameters.mutableClone(); } else { params = new NSMutableDictionary<>(); } if (!_includeSessionID) { params.takeValueForKey(Boolean.FALSE.toString(), WOApplication.application().sessionIdKey()); } return params; } @Override public void appendToResponse(WOResponse response, WOContext context) { String url; // Use secure binding if present, otherwise default to request setting boolean secure = (_secure == null) ? ERXRequest.isRequestSecure(context.request()) : _secure.booleanValue(); // Check whether we are currently generating complete URL's. We'll use this in finally() to reset the context to it's behavior before calling this. boolean generatingCompleteURLs = context.doesGenerateCompleteURLs(); // Generate a full URL if changing between secure and insecure boolean generateCompleteURLs = secure != ERXRequest.isRequestSecure(context.request()); if (generateCompleteURLs) { context.generateCompleteURLs(); } try { WOComponent component = _component; if (component != null) { // Build request handler path with session ID if needed WOSession aSession = session(); String aContextId = context.contextID(); StringBuilder requestHandlerPath = new StringBuilder(); if (WOApplication.application().pageCacheSize() == 0) { if (aSession.storesIDsInURLs()) { requestHandlerPath.append(component.name()); requestHandlerPath.append('/'); requestHandlerPath.append(aSession.sessionID()); requestHandlerPath.append('/'); requestHandlerPath.append(aContextId); requestHandlerPath.append(".0"); } else { requestHandlerPath.append(component.name()); requestHandlerPath.append('/'); requestHandlerPath.append(aContextId); requestHandlerPath.append(".0"); } } else if (aSession.storesIDsInURLs()) { requestHandlerPath.append(aSession.sessionID()); requestHandlerPath.append('/'); requestHandlerPath.append(aContextId); requestHandlerPath.append(".0"); } else { requestHandlerPath.append(aContextId); requestHandlerPath.append(".0"); } url = context._urlWithRequestHandlerKey(WOApplication.application().componentRequestHandlerKey(), requestHandlerPath.toString(), queryParametersString(), secure); context._setPageComponent(component); } else if (_url != null) { if (_secure != null) { throw new IllegalArgumentException("You specified a value for 'url' and for 'secure', which is not supported."); } url = _url; // the external url don't need it but if the url is a internal CMS Link then queryParamers is nice to have if (_queryParameters != null && _queryParameters.count() > 0) url += "?" + queryParametersString(); } else if (_requestHandlerKey != null) { url = context._urlWithRequestHandlerKey(_requestHandlerKey, _requestHandlerPath, queryParametersString(), secure); } else if (_directActionName != null) { String requestHandlerPath; if (_directActionClass != null) { requestHandlerPath = _directActionClass + "/" + _directActionName; } else { requestHandlerPath = _directActionName; } url = context.directActionURLForActionNamed(requestHandlerPath, directActionQueryParameters(), secure, 0, false); } else { throw new IllegalStateException("You must provide a component, url, requestHandlerKey, or directActionName to this ERXRedirect."); } if (ERXAjaxApplication.isAjaxRequest(context.request())) { boolean hasUpdateContainer = context.request().stringFormValueForKey(ERXAjaxApplication.KEY_UPDATE_CONTAINER_ID) != null; if (hasUpdateContainer) { response.appendContentString("<script type=\"text/javascript\">"); } else { response.setHeader("text/javascript", "Content-Type"); } response.appendContentString("document.location.href='" + url + "';"); if (hasUpdateContainer) { response.appendContentString("</script>"); } } else { response.setHeader(url, "location"); response.setStatus(302); } if (component != null) { ERXAjaxApplication.setForceStorePage(response); } } finally { // Switch the context back to the original url behaviour. if (generatingCompleteURLs) { context.generateCompleteURLs(); } else { context.generateRelativeURLs(); } } } }