001/* 002 * (C) Copyright 2006-2007 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Nuxeo - initial API and implementation 018 * 019 * $Id: JOOoConvertPluginImpl.java 18651 2007-05-13 20:28:53Z sfermigier $ 020 */ 021 022package org.nuxeo.ecm.platform.ui.web.rest; 023 024import static org.jboss.seam.ScopeType.EVENT; 025 026import java.io.IOException; 027import java.io.Serializable; 028import java.util.HashMap; 029import java.util.Map; 030import java.util.regex.Pattern; 031 032import javax.faces.component.UIViewRoot; 033import javax.faces.context.FacesContext; 034import javax.servlet.http.HttpServletRequest; 035import javax.servlet.http.HttpServletResponse; 036 037import org.apache.commons.lang3.StringUtils; 038import org.jboss.seam.ScopeType; 039import org.jboss.seam.annotations.Begin; 040import org.jboss.seam.annotations.Factory; 041import org.jboss.seam.annotations.In; 042import org.jboss.seam.annotations.Name; 043import org.jboss.seam.annotations.Scope; 044import org.jboss.seam.contexts.Contexts; 045import org.jboss.seam.core.Manager; 046import org.jboss.seam.international.LocaleSelector; 047import org.nuxeo.ecm.core.api.DocumentLocation; 048import org.nuxeo.ecm.core.api.DocumentModel; 049import org.nuxeo.ecm.core.api.DocumentRef; 050import org.nuxeo.ecm.core.api.impl.DocumentLocationImpl; 051import org.nuxeo.ecm.platform.types.adapter.TypeInfo; 052import org.nuxeo.ecm.platform.ui.web.api.NavigationContext; 053import org.nuxeo.ecm.platform.ui.web.api.WebActions; 054import org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants; 055import org.nuxeo.ecm.platform.ui.web.tag.fn.DocumentModelFunctions; 056import org.nuxeo.ecm.platform.ui.web.util.BaseURL; 057import org.nuxeo.ecm.platform.url.DocumentViewImpl; 058import org.nuxeo.ecm.platform.url.api.DocumentView; 059import org.nuxeo.ecm.platform.util.RepositoryLocation; 060 061/** 062 * Helper for generation of URLs and related update of document context. 063 * 064 * @author tiry 065 * @author <a href="mailto:[email protected]">Anahide Tchertchian</a> 066 * @author Florent Guillaume 067 */ 068@Name("restHelper") 069@Scope(EVENT) 070public class RestHelper implements Serializable { 071 072 private static final long serialVersionUID = 1L; 073 074 @In(create = true) 075 protected transient NavigationContext navigationContext; 076 077 @In(create = true) 078 protected transient WebActions webActions; 079 080 protected DocumentView docView; 081 082 protected String baseURL = ""; 083 084 @In(create = true) 085 protected transient LocaleSelector localeSelector; 086 087 /** 088 * Sets current server location (core repository) and core document as provided by the document view. 089 * <p> 090 * Only sets current server location if the document reference is null. 091 */ 092 @Begin(id = "#{conversationIdGenerator.currentOrNewMainConversationId}", join = true) 093 public String initContextFromRestRequest(DocumentView docView) { 094 String outcome = null; 095 096 if (docView != null) { 097 DocumentLocation docLoc = docView.getDocumentLocation(); 098 String serverName = docLoc.getServerName(); 099 if (serverName != null) { 100 DocumentRef docRef = docLoc.getDocRef(); 101 RepositoryLocation repoLoc = new RepositoryLocation(serverName); 102 if (docRef != null) { 103 if (docView.getParameter(WebActions.MAIN_TAB_ID_PARAMETER) == null 104 && !webActions.hasCurrentTabId(WebActions.MAIN_TABS_CATEGORY)) { 105 webActions.setCurrentTabId(WebActions.MAIN_TABS_CATEGORY, WebActions.DOCUMENTS_MAIN_TAB_ID); 106 } 107 outcome = navigationContext.navigateTo(repoLoc, docRef); 108 } else { 109 navigationContext.setCurrentServerLocation(repoLoc); 110 } 111 } 112 if (outcome == null) { 113 outcome = docView.getViewId(); 114 } 115 } 116 117 return outcome; 118 } 119 120 public void setDocumentView(DocumentView docView) { 121 this.docView = docView; 122 } 123 124 public DocumentView getNewDocumentView(String mainTabId) { 125 DocumentView docView = null; 126 DocumentModel currentDocument = navigationContext.getCurrentDocument(); 127 if (currentDocument != null) { 128 DocumentLocation docLoc = new DocumentLocationImpl(currentDocument); 129 TypeInfo typeInfo = currentDocument.getAdapter(TypeInfo.class); 130 Map<String, String> params = new HashMap<String, String>(); 131 if (currentDocument.isVersion()) { 132 params.put("version", "true"); 133 } 134 if (!StringUtils.isEmpty(mainTabId)) { 135 params.put(WebActions.MAIN_TAB_ID_PARAMETER, WebActions.MAIN_TABS_CATEGORY + ":" + mainTabId); 136 } 137 // additional params will be set according to the url pattern, 138 // calling getters on bindings. 139 docView = new DocumentViewImpl(docLoc, typeInfo.getDefaultView(), params); 140 } 141 return docView; 142 } 143 144 public DocumentView getNewDocumentView() { 145 return getNewDocumentView("documents"); 146 } 147 148 public DocumentView getDocumentView() { 149 return docView; 150 } 151 152 /** 153 * @return the Seam conversation manager. 154 */ 155 public static Manager getConversationManager() { 156 if (Contexts.isEventContextActive()) { 157 return Manager.instance(); 158 } 159 return null; 160 } 161 162 protected static String addConversationRequestParameters(String url, Manager conversationManager, 163 String conversationId) { 164 Map<String, Object> params = new HashMap<String, Object>(); 165 params.put(conversationManager.getConversationIdParameter(), conversationId); 166 return conversationManager.encodeParameters(url, params); 167 } 168 169 /** 170 * Adds current conversation request parameters to the given url. 171 * 172 * @param url 173 * @return the url with additional conversation request parameters 174 */ 175 public static String addCurrentConversationParameters(String url) { 176 Manager conversationManager = getConversationManager(); 177 if (conversationManager == null) { 178 return url; 179 } 180 // XXX : deprecated 181 return conversationManager.encodeConversationId(url); 182 } 183 184 /** 185 * Adds main conversation request parameters to the given url. 186 * 187 * @param url 188 * @return the url with additional conversation request parameters 189 */ 190 public static String addMainConversationParameters(String url) { 191 Manager conversationManager = getConversationManager(); 192 if (conversationManager == null) { 193 return url; 194 } else { 195 String conversationId; 196 if (conversationManager.isNestedConversation()) { 197 conversationId = conversationManager.getParentConversationId(); 198 } else { 199 conversationId = conversationManager.getCurrentConversationId(); 200 } 201 return addConversationRequestParameters(url, conversationManager, conversationId); 202 } 203 } 204 205 public String getDocumentUrl(DocumentModel doc) { 206 return DocumentModelFunctions.documentUrl(doc); 207 } 208 209 public String getDocumentUrl(DocumentModel doc, String viewId, boolean newConversation) { 210 return DocumentModelFunctions.documentUrl(null, doc, viewId, null, newConversation, BaseURL.getBaseURL()); 211 } 212 213 public String getDocumentUrl(String patternName, DocumentModel doc, String viewId, Map<String, String> parameters, 214 boolean newConversation) { 215 return DocumentModelFunctions.documentUrl(patternName, doc, viewId, parameters, newConversation, 216 BaseURL.getBaseURL()); 217 } 218 219 @Factory(value = "baseURL", scope = ScopeType.CONVERSATION) 220 public String getBaseURL() { 221 if (baseURL.equals("")) { 222 baseURL = BaseURL.getBaseURL(); 223 } 224 return baseURL; 225 } 226 227 @Factory(value = "contextPath", scope = ScopeType.CONVERSATION) 228 public String getContextPath() { 229 return BaseURL.getContextPath(); 230 } 231 232 public String doPrint(String defaultTheme) throws IOException { 233 return doPrint(navigationContext.getCurrentDocument(), defaultTheme); 234 } 235 236 public String doPrint(DocumentModel doc, String defaultTheme) throws IOException { 237 FacesContext facesContext = FacesContext.getCurrentInstance(); 238 if (facesContext == null) { 239 return null; 240 } 241 HttpServletResponse response = getHttpServletResponse(); 242 if (response != null) { 243 handleRedirect(response, getPrintUrl(doc, defaultTheme)); 244 } 245 return null; 246 } 247 248 public String getPrintUrl(String defaultTheme) { 249 return getPrintUrl(navigationContext.getCurrentDocument(), defaultTheme); 250 } 251 252 public String getPrintUrl(DocumentModel doc, String defaultTheme) { 253 Map<String, String> parameters = new HashMap<String, String>(); 254 int separatorIndex = defaultTheme.indexOf("/"); 255 if (separatorIndex != -1) { 256 // defaultTheme includes the default page 257 defaultTheme = defaultTheme.substring(0, separatorIndex); 258 StringBuilder sb = new StringBuilder(); 259 sb.append(defaultTheme); 260 sb.append("/print"); 261 parameters.put("page", sb.toString()); 262 } 263 return DocumentModelFunctions.documentUrl(null, doc, null, parameters, false, BaseURL.getBaseURL()); 264 } 265 266 public static HttpServletResponse getHttpServletResponse() { 267 final FacesContext facesContext = FacesContext.getCurrentInstance(); 268 return facesContext == null ? null : (HttpServletResponse) facesContext.getExternalContext().getResponse(); 269 } 270 271 public static HttpServletRequest getHttpServletRequest() { 272 final FacesContext facesContext = FacesContext.getCurrentInstance(); 273 return (HttpServletRequest) facesContext.getExternalContext().getRequest(); 274 } 275 276 public static void handleRedirect(HttpServletResponse response, String url) throws IOException { 277 response.resetBuffer(); 278 response.sendRedirect(url); 279 response.flushBuffer(); 280 getHttpServletRequest().setAttribute(NXAuthConstants.DISABLE_REDIRECT_REQUEST_KEY, Boolean.TRUE); 281 FacesContext.getCurrentInstance().responseComplete(); 282 } 283 284 /** 285 * Returns the locale string. 286 * <p> 287 * Useful for url pattern bindings. 288 * 289 * @since 5.4.2 290 */ 291 public String getLocaleString() { 292 return localeSelector.getLocaleString(); 293 } 294 295 public static final Pattern VALID_LOCALE = Pattern.compile("[A-Za-z0-9-_]*"); 296 297 /** 298 * Sets the locale string if given string is not null and not empty, as well as on faces context view root in case 299 * it was already created so that it holds the new locale for future lookups by JSF components. 300 * <p> 301 * Useful for url pattern bindings. 302 */ 303 public void setLocaleString(String localeString) { 304 // injected directly in JavaScript in a number of places, so should be sanitized 305 if (!StringUtils.isBlank(localeString) && VALID_LOCALE.matcher(localeString).matches()) { 306 localeSelector.setLocaleString(localeString.trim()); 307 FacesContext ctx = FacesContext.getCurrentInstance(); 308 if (ctx != null) { 309 UIViewRoot viewRoot = ctx.getViewRoot(); 310 if (viewRoot != null) { 311 viewRoot.setLocale(localeSelector.getLocale()); 312 } 313 } 314 } 315 } 316 317}