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