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