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 * Jean-Marc Orliaguet, Chalmers 018 * 019 * $Id$ 020 */ 021 022package org.nuxeo.theme.resources; 023 024import java.net.MalformedURLException; 025import java.net.URL; 026import java.util.ArrayList; 027import java.util.HashMap; 028import java.util.List; 029 030import org.apache.commons.logging.Log; 031import org.apache.commons.logging.LogFactory; 032import org.nuxeo.runtime.api.Framework; 033import org.nuxeo.runtime.services.event.Event; 034import org.nuxeo.runtime.services.event.EventService; 035import org.nuxeo.theme.Manager; 036import org.nuxeo.theme.Registrable; 037import org.nuxeo.theme.themes.ThemeException; 038import org.nuxeo.theme.themes.ThemeManager; 039import org.nuxeo.theme.types.TypeFamily; 040import org.nuxeo.theme.types.TypeRegistry; 041 042public final class ResourceManager implements Registrable { 043 044 private static final Log log = LogFactory.getLog(ResourceManager.class); 045 046 public static final String GLOBAL_RESOURCES_REGISTERED_EVENT = "themeGlobalResourcesRegistered"; 047 048 private final HashMap<URL, List<String>> globalCache = new HashMap<URL, List<String>>(); 049 050 private final ThreadLocal<List<String>> localCache = new ThreadLocal<List<String>>() { 051 @Override 052 protected List<String> initialValue() { 053 return new ArrayList<String>(); 054 } 055 }; 056 057 private final TypeRegistry typeRegistry = Manager.getTypeRegistry(); 058 059 public void addResource(String name, URL themeUrl) { 060 addResource(name, themeUrl, false); 061 } 062 063 public void addResource(String name, URL themeUrl, boolean local) { 064 if (local) { 065 log.debug("Added local resource: " + name); 066 } else { 067 log.debug("Added theme resource: " + name); 068 } 069 ResourceType resourceType = (ResourceType) typeRegistry.lookup(TypeFamily.RESOURCE, name); 070 if (resourceType != null) { 071 for (String dependency : resourceType.getDependencies()) { 072 log.debug(" Subresource dependency: " + name + " -> " + dependency); 073 addResource(dependency, themeUrl, local); 074 } 075 List<String> scripts; 076 if (local) { 077 scripts = getLocalResources(); 078 } else { 079 scripts = getGlobalResourcesFor(themeUrl); 080 } 081 if (!scripts.contains(name)) { 082 scripts.add(name); 083 } 084 } else { 085 log.warn("Resource not found: " + name); 086 } 087 } 088 089 public void flush() { 090 getLocalResources().clear(); 091 } 092 093 private List<String> getLocalResources() { 094 return localCache.get(); 095 } 096 097 public List<String> getResourcesFor(String themeUrl) { 098 List<String> resources = new ArrayList<String>(); 099 resources.addAll(getGlobalResourcesFor(themeUrl)); 100 for (String localResource : getLocalResources()) { 101 if (!resources.contains(localResource)) { 102 resources.add(localResource); 103 } 104 } 105 return resources; 106 } 107 108 public List<String> getGlobalResourcesFor(String themeUrl) { 109 try { 110 return getGlobalResourcesFor(new URL(themeUrl)); 111 } catch (MalformedURLException e) { 112 log.warn(e); 113 return null; 114 } 115 } 116 117 public synchronized List<String> getGlobalResourcesFor(URL themeUrl) { 118 if (!globalCache.containsKey(themeUrl)) { 119 globalCache.put(themeUrl, new ArrayList<String>()); 120 // hook to notify potential listeners that the resources for given 121 // theme url need to be built 122 EventService eventService = Framework.getLocalService(EventService.class); 123 eventService.sendEvent(new Event(ThemeManager.THEME_TOPIC, GLOBAL_RESOURCES_REGISTERED_EVENT, this, 124 themeUrl)); 125 } 126 return globalCache.get(themeUrl); 127 } 128 129 public void clearGlobalCache(String themeName) { 130 List<URL> toRemove = new ArrayList<URL>(); 131 for (URL themeUrl : globalCache.keySet()) { 132 String name = ThemeManager.getThemeNameByUrl(themeUrl); 133 if (themeName.equals(name)) { 134 toRemove.add(themeUrl); 135 136 } 137 } 138 for (URL themeUrl : toRemove) { 139 globalCache.remove(themeUrl); 140 } 141 } 142 143 public static byte[] getBinaryBankResource(String resourceBankName, String collectionName, String typeName, 144 String resourceName) throws ThemeException { 145 byte[] data = null; 146 ResourceBank resourceBank = ThemeManager.getResourceBank(resourceBankName); 147 data = resourceBank.getResourceContent(collectionName, typeName, resourceName); 148 if (data == null) { 149 throw new ThemeException("Resource bank content could not be read: " + resourceName); 150 } 151 return data; 152 } 153 154 public static String getBankResource(String resourceBankName, String collectionName, String typeName, 155 String resourceName) throws ThemeException { 156 byte[] data = getBinaryBankResource(resourceBankName, collectionName, typeName, resourceName); 157 if (data == null) { 158 throw new ThemeException("Could not get bank resource: " + resourceName); 159 } 160 return new String(data); 161 } 162 163 @Override 164 public void clear() { 165 globalCache.clear(); 166 } 167 168}