001/* 002 * (C) Copyright 2006-2007 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 * Nuxeo - initial API and implementation 016 * 017 * $Id: DocumentViewCodecService.java 22535 2007-07-13 14:57:58Z atchertchian $ 018 */ 019 020package org.nuxeo.ecm.platform.url.service; 021 022import java.util.ArrayList; 023import java.util.Collections; 024import java.util.List; 025import java.util.Map; 026import java.util.concurrent.ConcurrentHashMap; 027 028import org.apache.commons.lang.StringUtils; 029import org.apache.commons.logging.Log; 030import org.apache.commons.logging.LogFactory; 031import org.nuxeo.ecm.platform.url.api.DocumentView; 032import org.nuxeo.ecm.platform.url.api.DocumentViewCodecManager; 033import org.nuxeo.ecm.platform.url.codec.api.DocumentViewCodec; 034import org.nuxeo.ecm.platform.url.codec.descriptor.DocumentViewCodecDescriptor; 035import org.nuxeo.runtime.model.ComponentContext; 036import org.nuxeo.runtime.model.ComponentInstance; 037import org.nuxeo.runtime.model.DefaultComponent; 038 039public class DocumentViewCodecService extends DefaultComponent implements DocumentViewCodecManager { 040 041 private static final long serialVersionUID = -4521897334653742494L; 042 043 private static final Log log = LogFactory.getLog(DocumentViewCodecService.class); 044 045 public static final String NAME = DocumentViewCodecService.class.getName(); 046 047 public static final String CODECS_EXTENSION_POINT = "codecs"; 048 049 protected String defaultCodecName; 050 051 protected final Map<String, DocumentViewCodecDescriptor> descriptors; 052 053 protected final Map<String, DocumentViewCodec> codecs; 054 055 public DocumentViewCodecService() { 056 descriptors = new ConcurrentHashMap<String, DocumentViewCodecDescriptor>(); 057 codecs = new ConcurrentHashMap<String, DocumentViewCodec>(); 058 } 059 060 @Override 061 public void deactivate(ComponentContext context) { 062 descriptors.clear(); 063 codecs.clear(); 064 } 065 066 @Override 067 @SuppressWarnings("unchecked") 068 public <T> T getAdapter(Class<T> adapter) { 069 if (adapter.isAssignableFrom(DocumentViewCodecManager.class)) { 070 return (T) this; 071 } 072 return null; 073 } 074 075 @Override 076 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 077 if (CODECS_EXTENSION_POINT.equals(extensionPoint)) { 078 DocumentViewCodecDescriptor desc = (DocumentViewCodecDescriptor) contribution; 079 String codecName = desc.getName(); 080 descriptors.put(codecName, desc); 081 if (desc.getDefaultCodec()) { 082 defaultCodecName = codecName; 083 } 084 // try to instantiate it 085 String className = desc.getClassName(); 086 if (className == null) { 087 throw new IllegalArgumentException(String.format("Invalid class for codec '%s': check ERROR logs" 088 + " at startup", codecName)); 089 } 090 DocumentViewCodec codec; 091 try { 092 // Thread context loader is not working in isolated EARs 093 codec = (DocumentViewCodec) DocumentViewCodecManager.class.getClassLoader().loadClass(className).newInstance(); 094 } catch (ReflectiveOperationException e) { 095 String msg = String.format("Caught error when instantiating codec '%s' with " + "class '%s' ", 096 codecName, className); 097 throw new IllegalArgumentException(msg, e); 098 } 099 String prefix = desc.getPrefix(); 100 if (prefix != null) { 101 codec.setPrefix(prefix); 102 } 103 codecs.put(codecName, codec); 104 log.debug("Added URL codec: " + codecName); 105 } 106 } 107 108 @Override 109 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 110 if (CODECS_EXTENSION_POINT.equals(extensionPoint)) { 111 DocumentViewCodecDescriptor codecDesc = (DocumentViewCodecDescriptor) contribution; 112 String codecName = codecDesc.getName(); 113 descriptors.remove(codecName); 114 codecs.remove(codecName); 115 log.debug("Removed URL codec: " + codecName); 116 } 117 } 118 119 public List<String> getDocumentViewCodecDescriptorNames() { 120 List<String> lst = new ArrayList<String>(); 121 for (String k : descriptors.keySet()) { 122 if (descriptors.get(k).getEnabled()) { 123 lst.add(k); 124 } 125 } 126 return lst; 127 } 128 129 public String getDefaultCodecName() { 130 String name = defaultCodecName; 131 if (name == null) { 132 // take first one 133 List<String> descs = getDocumentViewCodecDescriptorNames(); 134 if (descs != null && !descs.isEmpty()) { 135 Collections.sort(descs); 136 name = descs.get(0); 137 } 138 } 139 return name; 140 } 141 142 public DocumentViewCodec getCodec() { 143 return getCodec(defaultCodecName); 144 } 145 146 public DocumentViewCodec getCodec(String codecName) { 147 if (StringUtils.isBlank(codecName)) { 148 return null; 149 } 150 return codecs.get(codecName); 151 } 152 153 public String getUrlFromDocumentView(DocumentView docView, boolean needBaseUrl, String baseUrl) { 154 String url = null; 155 DocumentViewCodec codec = getCodec(getDefaultCodecName()); 156 if (codec != null && codec.handleDocumentView(docView)) { 157 url = getUrlFromDocumentView(codec, docView, needBaseUrl, baseUrl); 158 } 159 if (url == null) { 160 for (String codecName : descriptors.keySet()) { 161 if (!codecName.equals(defaultCodecName)) { 162 codec = getCodec(codecName); 163 if (codec != null && codec.handleDocumentView(docView)) { 164 url = getUrlFromDocumentView(codec, docView, needBaseUrl, baseUrl); 165 if (url != null) { 166 break; 167 } 168 } 169 } 170 } 171 } 172 return url; 173 } 174 175 public String getUrlFromDocumentView(String codecName, DocumentView docView, boolean needBaseUrl, String baseUrl) { 176 DocumentViewCodec codec = getCodec(codecName); 177 return getUrlFromDocumentView(codec, docView, needBaseUrl, baseUrl); 178 } 179 180 protected String getUrlFromDocumentView(DocumentViewCodec codec, DocumentView docView, boolean needBaseUrl, 181 String baseUrl) { 182 if (codec != null) { 183 String partialUrl = codec.getUrlFromDocumentView(docView); 184 if (partialUrl != null) { 185 if (needBaseUrl && !StringUtils.isBlank(baseUrl)) { 186 if (baseUrl.endsWith("/") || partialUrl.startsWith("/")) { 187 return baseUrl + partialUrl; 188 } else { 189 return baseUrl + "/" + partialUrl; 190 } 191 } else { 192 return partialUrl; 193 } 194 } 195 } 196 return null; 197 } 198 199 public DocumentView getDocumentViewFromUrl(String url, boolean hasBaseUrl, String baseUrl) { 200 DocumentView docView = null; 201 String finalUrl = getUrlWithoutBase(url, hasBaseUrl, baseUrl); 202 DocumentViewCodec codec = getCodec(getDefaultCodecName()); 203 if (codec != null && codec.handleUrl(finalUrl)) { 204 docView = getDocumentViewFromUrl(codec, finalUrl); 205 } 206 if (docView == null) { 207 for (String codecName : descriptors.keySet()) { 208 if (!codecName.equals(defaultCodecName)) { 209 codec = getCodec(codecName); 210 if (codec != null && codec.handleUrl(finalUrl)) { 211 docView = getDocumentViewFromUrl(codec, finalUrl); 212 if (docView != null) { 213 break; 214 } 215 } 216 } 217 } 218 } 219 return docView; 220 } 221 222 public DocumentView getDocumentViewFromUrl(String codecName, String url, boolean hasBaseUrl, String baseUrl) { 223 DocumentViewCodec codec = getCodec(codecName); 224 String finalUrl = getUrlWithoutBase(url, hasBaseUrl, baseUrl); 225 return getDocumentViewFromUrl(codec, finalUrl); 226 } 227 228 protected String getUrlWithoutBase(String url, boolean hasBaseUrl, String baseUrl) { 229 if (hasBaseUrl && baseUrl != null) { 230 if (url.startsWith(baseUrl)) { 231 url = url.substring(baseUrl.length()); 232 } 233 } 234 return url; 235 } 236 237 protected DocumentView getDocumentViewFromUrl(DocumentViewCodec codec, String finalUrl) { 238 if (codec != null) { 239 DocumentView docView = codec.getDocumentViewFromUrl(finalUrl); 240 return docView; 241 } 242 return null; 243 } 244 245}