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