001/* 002 * (C) Copyright 2006-2011 Nuxeo SAS (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * rux, tdelprat 016 * 017 */ 018 019package org.nuxeo.ecm.webapp.liveedit; 020 021import static org.jboss.seam.ScopeType.SESSION; 022import static org.jboss.seam.annotations.Install.FRAMEWORK; 023 024import java.io.Serializable; 025import java.util.ArrayList; 026import java.util.List; 027import java.util.Map; 028 029import javax.faces.context.FacesContext; 030 031import org.apache.commons.logging.Log; 032import org.apache.commons.logging.LogFactory; 033import org.jboss.seam.annotations.Install; 034import org.jboss.seam.annotations.Name; 035import org.jboss.seam.annotations.Scope; 036import org.nuxeo.runtime.api.Framework; 037 038/** 039 * This Seam component is used to represent the client configuration for LiveEdit. 040 * <p> 041 * On the client side, the LiveEdit plugin advertise its feature via the Accept Header of the browser. This information 042 * may be used to decide if LiveEdit links must be displayed or not. 043 * <p> 044 * The behavior can be configured via the property: org.nuxeo.ecm.platform.liveedit.config 045 * <p> 046 * There are 3 possible values : 047 * <ul> 048 * <li>client : let the client choose what is live editable => use the mime-types send by the client to define what must 049 * be live editable 050 * <li>server : let the server decide => use the mime-type registry define what types are liveEditable 051 * <li>both : use client and server intersection => in order to be liveEditable a type must be advertised by the client 052 * and set to liveEditable in the mimetypeRegistry 053 * </ul> 054 * Client advertising is done in the Accept header: Accept : application/x-nuxeo-liveedit:mimetype1;mimetype2 Starting 055 * the 5.2, the addon can send the standardized accept header, as Accept : 056 * application/x-nuxeo-liveedit;ext0="mimetype1";ext1="mimetype2".. Also, the addon can still send the old way, so the 057 * both forms are accepted. See NXP-3257 058 * 059 * @author Thierry Delprat 060 * @author rux 061 */ 062@Scope(SESSION) 063@Name("liveEditClientConfig") 064@Install(precedence = FRAMEWORK) 065public class LiveEditClientConfig implements Serializable { 066 067 private static final long serialVersionUID = 1L; 068 069 private static final Log log = LogFactory.getLog(LiveEditClientConfig.class); 070 071 protected Boolean clientHasLiveEditInstalled; 072 073 protected List<String> advertizedLiveEditableMimeTypes; 074 075 protected static String liveEditConfigPolicy; 076 077 public static final String LE_MIME_TYPE = "application/x-nuxeo-liveedit"; 078 079 public static final String LE_CONFIG_PROPERTY = "org.nuxeo.ecm.platform.liveedit.config"; 080 081 public static final String LE_CONFIG_CLIENTSIDE = "client"; 082 083 public static final String LE_CONFIG_SERVERSIDE = "server"; 084 085 public static final String LE_CONFIG_BOTHSIDES = "both"; 086 087 protected void detectLiveEditClientConfig() { 088 clientHasLiveEditInstalled = false; 089 advertizedLiveEditableMimeTypes = new ArrayList<String>(); 090 091 if (getLiveEditConfigurationPolicy().equals(LE_CONFIG_SERVERSIDE)) { 092 // in case if Server side config, consider liveEdit is installed 093 clientHasLiveEditInstalled = true; 094 return; 095 } 096 097 FacesContext fContext = FacesContext.getCurrentInstance(); 098 if (fContext == null) { 099 log.error("unable to fetch facesContext, can not detect liveEdit client config"); 100 } else { 101 Map<String, String> headers = fContext.getExternalContext().getRequestHeaderMap(); 102 String accept = headers.get("Accept"); 103 if (accept == null) { 104 return; 105 } 106 107 String[] accepted = accept.split(","); 108 for (String acceptHeader : accepted) { 109 if (acceptHeader != null) { 110 acceptHeader = acceptHeader.trim(); 111 } else { 112 continue; 113 } 114 if (acceptHeader.startsWith(LE_MIME_TYPE)) { 115 clientHasLiveEditInstalled = true; 116 String[] subTypes = acceptHeader.split(";"); 117 118 for (String subType : subTypes) { 119 // accept both forms: 120 // application/x-nuxeo-liveedit:mimetype1;mimetype2 121 // application/x-nuxeo-liveedit;ext0="mimetype1";ext1="mimetype2" 122 int equalQuoteIndex = subType.indexOf("=\""); 123 String valueSubType = subType; 124 if (equalQuoteIndex >= 0 && subType.length() > equalQuoteIndex + 3) { 125 valueSubType = subType.substring(equalQuoteIndex + 2, subType.length() - 1); 126 } 127 advertizedLiveEditableMimeTypes.add(valueSubType.replace("!", "/")); 128 } 129 } 130 } 131 } 132 } 133 134 public boolean isLiveEditInstalled() { 135 if (clientHasLiveEditInstalled == null) { 136 detectLiveEditClientConfig(); 137 } 138 139 return clientHasLiveEditInstalled; 140 } 141 142 public String getLiveEditConfigurationPolicy() { 143 if (liveEditConfigPolicy == null) { 144 liveEditConfigPolicy = Framework.getProperty(LE_CONFIG_PROPERTY, LE_CONFIG_CLIENTSIDE); 145 } 146 return liveEditConfigPolicy; 147 } 148 149 public boolean isMimeTypeLiveEditable(String mimetype) { 150 if (advertizedLiveEditableMimeTypes == null) { 151 detectLiveEditClientConfig(); 152 } 153 return advertizedLiveEditableMimeTypes.contains(mimetype); 154 } 155 156}