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