001/* 002 * (C) Copyright 2006-2018 Nuxeo (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.lang3.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<>(); 059 codecs = new ConcurrentHashMap<>(); 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 if (desc.getDefaultCodec()) { 083 defaultCodecName = codecName; 084 } 085 // try to instantiate it 086 String className = desc.getClassName(); 087 if (className == null) { 088 throw new IllegalArgumentException( 089 String.format("Invalid class for codec '%s': check ERROR logs" + " at startup", codecName)); 090 } 091 DocumentViewCodec codec; 092 try { 093 // Thread context loader is not working in isolated EARs 094 codec = (DocumentViewCodec) DocumentViewCodecManager.class.getClassLoader() 095 .loadClass(className) 096 .newInstance(); 097 } catch (ReflectiveOperationException e) { 098 String msg = String.format("Caught error when instantiating codec '%s' with " + "class '%s' ", 099 codecName, className); 100 throw new IllegalArgumentException(msg, e); 101 } 102 String prefix = desc.getPrefix(); 103 if (prefix != null) { 104 codec.setPrefix(prefix); 105 } 106 if (!descriptors.containsKey(codecName) || desc.getPriority() > descriptors.get(codecName).getPriority()) { 107 descriptors.put(codecName, desc); 108 codecs.put(codecName, codec); 109 } 110 log.debug("Added URL codec: " + codecName); 111 } 112 } 113 114 @Override 115 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 116 if (CODECS_EXTENSION_POINT.equals(extensionPoint)) { 117 DocumentViewCodecDescriptor codecDesc = (DocumentViewCodecDescriptor) contribution; 118 String codecName = codecDesc.getName(); 119 descriptors.remove(codecName); 120 codecs.remove(codecName); 121 log.debug("Removed URL codec: " + codecName); 122 } 123 } 124 125 public List<String> getDocumentViewCodecDescriptorNames() { 126 List<String> lst = new ArrayList<>(); 127 for (String k : descriptors.keySet()) { 128 if (descriptors.get(k).getEnabled()) { 129 lst.add(k); 130 } 131 } 132 return lst; 133 } 134 135 @Override 136 public String getDefaultCodecName() { 137 String name = defaultCodecName; 138 if (name == null) { 139 // take first one 140 List<String> descs = getDocumentViewCodecDescriptorNames(); 141 if (descs != null && !descs.isEmpty()) { 142 Collections.sort(descs); 143 name = descs.get(0); 144 } 145 } 146 return name; 147 } 148 149 public DocumentViewCodec getCodec() { 150 return getCodec(defaultCodecName); 151 } 152 153 @Override 154 public DocumentViewCodec getCodec(String codecName) { 155 if (StringUtils.isBlank(codecName)) { 156 return null; 157 } 158 return codecs.get(codecName); 159 } 160 161 @Override 162 public String getUrlFromDocumentView(DocumentView docView, boolean needBaseUrl, String baseUrl) { 163 String url = null; 164 DocumentViewCodec codec = getCodec(getDefaultCodecName()); 165 if (codec != null && codec.handleDocumentView(docView)) { 166 url = getUrlFromDocumentView(codec, docView, needBaseUrl, baseUrl); 167 } 168 if (url == null) { 169 for (String codecName : descriptors.keySet()) { 170 if (!codecName.equals(defaultCodecName)) { 171 codec = getCodec(codecName); 172 if (codec != null && codec.handleDocumentView(docView)) { 173 url = getUrlFromDocumentView(codec, docView, needBaseUrl, baseUrl); 174 if (url != null) { 175 break; 176 } 177 } 178 } 179 } 180 } 181 return url; 182 } 183 184 @Override 185 public String getUrlFromDocumentView(String codecName, DocumentView docView, boolean needBaseUrl, String baseUrl) { 186 DocumentViewCodec codec = getCodec(codecName); 187 return getUrlFromDocumentView(codec, docView, needBaseUrl, baseUrl); 188 } 189 190 protected String getUrlFromDocumentView(DocumentViewCodec codec, DocumentView docView, boolean needBaseUrl, 191 String baseUrl) { 192 if (codec != null) { 193 String partialUrl = codec.getUrlFromDocumentView(docView); 194 if (partialUrl != null) { 195 if (needBaseUrl && !StringUtils.isBlank(baseUrl)) { 196 if (baseUrl.endsWith("/") || partialUrl.startsWith("/")) { 197 return baseUrl + partialUrl; 198 } else { 199 return baseUrl + "/" + partialUrl; 200 } 201 } else { 202 return partialUrl; 203 } 204 } 205 } 206 return null; 207 } 208 209 @Override 210 public DocumentView getDocumentViewFromUrl(String url, boolean hasBaseUrl, String baseUrl) { 211 DocumentView docView = null; 212 String finalUrl = getUrlWithoutBase(url, hasBaseUrl, baseUrl); 213 DocumentViewCodec codec = getCodec(getDefaultCodecName()); 214 if (codec != null && codec.handleUrl(finalUrl)) { 215 docView = getDocumentViewFromUrl(codec, finalUrl); 216 } 217 if (docView == null) { 218 for (String codecName : descriptors.keySet()) { 219 if (!codecName.equals(defaultCodecName)) { 220 codec = getCodec(codecName); 221 if (codec != null && codec.handleUrl(finalUrl)) { 222 docView = getDocumentViewFromUrl(codec, finalUrl); 223 if (docView != null) { 224 break; 225 } 226 } 227 } 228 } 229 } 230 return docView; 231 } 232 233 @Override 234 public DocumentView getDocumentViewFromUrl(String codecName, String url, boolean hasBaseUrl, String baseUrl) { 235 DocumentViewCodec codec = getCodec(codecName); 236 String finalUrl = getUrlWithoutBase(url, hasBaseUrl, baseUrl); 237 return getDocumentViewFromUrl(codec, finalUrl); 238 } 239 240 protected String getUrlWithoutBase(String url, boolean hasBaseUrl, String baseUrl) { 241 if (hasBaseUrl && baseUrl != null) { 242 if (url.startsWith(baseUrl)) { 243 url = url.substring(baseUrl.length()); 244 } 245 } 246 return url; 247 } 248 249 protected DocumentView getDocumentViewFromUrl(DocumentViewCodec codec, String finalUrl) { 250 if (codec != null) { 251 DocumentView docView = codec.getDocumentViewFromUrl(finalUrl); 252 return docView; 253 } 254 return null; 255 } 256 257}